pluginMarketplaceService.ts ×19

Frontier kind: Joint frontier

unlabeled · c_1e9ac1f15e48

2 tests · 31493 LOC · 156 files · introduces 1 test · 110 LOC · 2 files

Introduces — evidence that enters the hierarchy at this concept

Code
22 ranges110 lines · 2 files
Tests
1 test

Contains — complete concept membership

All code (extent)
3420 ranges31493 lines · 156 files · Browse complete extent
All tests (intent)
2 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

1 test introduced at this concept.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

2 files ranked by introduced lines: 110 introduced LOC across 22 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/workbench/contrib/chat/common/plugins/pluginMarketplaceService.ts 105 introduced LOC · 19 ranges

Open complete file

257 * {@link PluginSourceKind.RelativePath} descriptor from it.
258 */
259 > function ensureSourceDescriptor(plugin: IMarketplacePlugin): IMarketplacePlugin { pluginMarketplaceService.ts
260 > if (plugin.sourceDescriptor) {
261 > return plugin;
262 > }
263 return {
264 ...plugin,
408 const unhydrated = entries.filter(e => !this._pluginMetadata.has(e.pluginUri.toString()));
409 if (unhydrated.length > 0) {
410 > this._hydratePluginMetadata(unhydrated); pluginMarketplaceService.ts
411 > }
412 }));
413 }
475 const cached = this._getCachedGitHubMarketplacePlugins(cache, reference.canonicalId);
476 if (cached) {
477 > return cached.map(c => ({ pluginMarketplaceService.ts
478 > ...c,
479 > marketplace: reference.displayLabel,
480 > marketplaceReference: reference,
481 > }));
482 > }
483
484 let repoMayBePrivate = true;
529 return undefined;
530 }
532 > if (cached.expiresAt <= Date.now()) {
533 cache.delete(cacheKey);
534 this._savePersistedGitHubMarketplaceCache(cache);
535 return undefined;
536 }
538 > return [...cached.plugins];
539 }
540
546 return cache;
547 }
549 > const revived = revive<IStoredGitHubMarketplaceCache>(stored);
550 >
551 > for (const [cacheKey, entry] of Object.entries(revived)) {
552 > if (!entry || !Array.isArray(entry.plugins) || typeof entry.expiresAt !== 'number' || entry.expiresAt <= now || typeof entry.referenceRawValue !== 'string') {
553 continue;
554 }
556 > const reference = parseMarketplaceReference(entry.referenceRawValue);
557 > if (!reference) {
558 continue;
559 }
561 > const plugins = entry.plugins.map(plugin => ensureSourceDescriptor({
562 > ...plugin,
563 > marketplace: reference.displayLabel,
564 > marketplaceReference: reference,
565 > }));
566 >
567 > cache.set(cacheKey, {
568 > plugins,
569 > expiresAt: entry.expiresAt,
570 > referenceRawValue: entry.referenceRawValue,
571 > });
572 > }
573 >
574 > return cache;
575 }
576
660 */
661 private async _hydratePluginMetadata(entries: readonly IStoredInstalledPlugin[]): Promise<void> {
662 > let hydrated = 0; pluginMarketplaceService.ts
663 >
664 > for (const entry of entries) {
665 > const key = entry.pluginUri.toString();
666 > if (this._pluginMetadata.has(key)) {
667 continue;
668 }
670 > const reference = parseMarketplaceReference(entry.marketplace);
671 > if (!reference) {
672 this._logService.debug(`[PluginMarketplaceService] Cannot parse marketplace reference '${entry.marketplace}' for ${key}`);
673 continue;
674 }
676 > try {
677 > const plugins = await this._readPluginsForInstalledEntry(reference, CancellationToken.None);
678 > const match = plugins.find(p => entry.name ? p.name === entry.name : isEqual(this._pluginRepositoryService.getPluginInstallUri(p), entry.pluginUri));
679 > if (match) {
680 > this._pluginMetadata.set(key, match);
681 > hydrated++;
682 > }
683 > } catch (err) {
684 this._logService.debug(`[PluginMarketplaceService] Failed to hydrate metadata for ${key}:`, err);
685 }
687 >
688 > if (hydrated > 0) {
689 > // Touch the store to trigger the derived observable to re-evaluate
690 > // now that _pluginMetadata has new entries.
691 > const current = this._installedPluginsStore.get();
692 > this._installedPluginsStore.set([...current], undefined);
693 > }
694 > }
695
696 private async _readPluginsForInstalledEntry(reference: IMarketplaceReference, token: CancellationToken): Promise<IMarketplacePlugin[]> {
697 > if (reference.kind === MarketplaceReferenceKind.GitHubShorthand && reference.githubRepo) { pluginMarketplaceService.ts
698 > return this._fetchFromGitHubRepo(reference, reference.githubRepo, token);
699 > }
700
701 const repoDir = this._pluginRepositoryService.getRepositoryUri(reference);
791
792 private async _runUpdateCheck(): Promise<void> {
793 > this._updateCheckTimer = undefined; pluginMarketplaceService.ts
794 >
795 > try {
796 > const installed = this.installedPlugins.get();
797 > if (installed.length === 0) {
798 return;
799 }
801 > const seenMarketplaces = new Set<string>();
802 > let hasUpdates = false;
803 >
804 > for (const entry of installed) {
805 > const ref = entry.plugin.marketplaceReference;
806 > if (seenMarketplaces.has(ref.canonicalId)) {
807 continue;
808 }
809 > seenMarketplaces.add(ref.canonicalId); pluginMarketplaceService.ts
810 >
811 > try {
812 > const behind = await this._pluginRepositoryService.fetchRepository(ref);
813 if (behind) {
814 hasUpdates = true;
815 break;
816 }
817 > } catch (err) { pluginMarketplaceService.ts
818 > this._logService.debug(`[PluginMarketplaceService] Update check failed for ${ref.displayLabel}:`, err);
819 > }
820 > }
821 >
822 > this._hasUpdatesAvailable.set(hasUpdates, undefined);
823 > this._storageService.store(
824 > PLUGIN_UPDATE_LAST_CHECK_STORAGE_KEY,
825 > Date.now(),
826 > StorageScope.APPLICATION,
827 > StorageTarget.MACHINE,
828 > );
829 > } catch (err) {
830 this._logService.debug('[PluginMarketplaceService] Periodic update check failed:', err);
831 > } finally { pluginMarketplaceService.ts
832 > // Reschedule for the next check
833 > if (this._isAutoUpdateEnabled()) {
834 > this._updateCheckTimer = setTimeout(() => this._runUpdateCheck(), PLUGIN_UPDATE_CHECK_INTERVAL_MS);
835 > }
836 > }
837 > }
838
839 private async _fetchFromClonedRepo(reference: IMarketplaceReference, token: CancellationToken): Promise<IMarketplacePlugin[]> {
src/vs/workbench/contrib/chat/common/plugins/fileBackedInstalledPluginsStore.ts 5 introduced LOC · 3 ranges

Open complete file

222 // an external file change.
223 if (scheduleWrite && this._initialized && !this._suppressFileWatch) {
224 > this._scheduleWrite(); fileBackedInstalledPluginsStore.ts
225 > }
226 }
227