From 0f975a4f73bbeb93561455b9ed2093d4c907a7a9 Mon Sep 17 00:00:00 2001 From: Neko Ayaka Date: Fri, 12 Jun 2026 19:27:23 +0800 Subject: [PATCH] refactor(stage-tamagotchi,plugin-*): unified to extension id --- .../http-server/static-assets/index.test.ts | 6 +- .../airi/http-server/static-assets/index.ts | 8 +- .../plugins/features/auto-reload/index.ts | 84 ++++++------- .../features/static-assets/index.test.ts | 18 +-- .../plugins/features/static-assets/index.ts | 16 +-- .../main/services/airi/plugins/host/debug.ts | 19 ++- .../main/services/airi/plugins/host/index.ts | 114 +++++++++--------- .../services/airi/plugins/host/registry.ts | 36 +++--- .../main/services/airi/plugins/index.test.ts | 64 +++++----- .../src/main/services/airi/plugins/index.ts | 12 +- .../main/services/airi/plugins/kits/index.ts | 4 +- .../airi/plugins/kits/widget/asset-url.ts | 16 +-- .../src/main/services/airi/plugins/types.ts | 17 ++- .../src/renderer/stores/plugin-tools.test.ts | 8 +- .../src/renderer/stores/plugin-tools.ts | 4 +- .../stores/tools/builtin/widgets.test.ts | 2 +- .../src/shared/eventa/index.ts | 4 +- .../src/shared/eventa/plugin/host.ts | 14 +-- .../src/shared/eventa/plugin/tools.ts | 10 +- .../plugin-sdk-tamagotchi/src/index.test.ts | 8 +- .../src/tools/registry.ts | 28 ++--- packages/plugin-sdk/src/plugin-host/core.ts | 4 +- .../shared/services/kit-api-bindings.test.ts | 22 ++-- .../shared/services/kit-api-bindings.ts | 46 +++---- .../runtimes/shared/services/permissions.ts | 30 ++--- .../src/plugin-host/shared/bindings.test.ts | 8 +- .../src/plugin-host/shared/bindings.ts | 4 +- .../src/pages/devtools/plugin-host.vue | 60 ++++----- .../src/stores/devtools/plugin-host-debug.ts | 22 ++-- 29 files changed, 346 insertions(+), 342 deletions(-) diff --git a/apps/stage-tamagotchi/src/main/services/airi/http-server/static-assets/index.test.ts b/apps/stage-tamagotchi/src/main/services/airi/http-server/static-assets/index.test.ts index f53210dff..4b53a221a 100644 --- a/apps/stage-tamagotchi/src/main/services/airi/http-server/static-assets/index.test.ts +++ b/apps/stage-tamagotchi/src/main/services/airi/http-server/static-assets/index.test.ts @@ -37,7 +37,7 @@ describe('createStaticAssetService', () => { const sessionStore = createStaticAssetSessionStore() const validateInputs: string[] = [] const server = createStaticAssetService({ - getManifestEntryByName: () => new Map([ + getManifestEntryByExtensionId: () => new Map([ [extensionId, { rootDir, version }], ]), sessionStore: { @@ -206,7 +206,7 @@ describe('createStaticAssetService', () => { ] let manifestReadCount = 0 const server = createStaticAssetService({ - getManifestEntryByName: () => manifestEntries[Math.min(manifestReadCount++, manifestEntries.length - 1)], + getManifestEntryByExtensionId: () => manifestEntries[Math.min(manifestReadCount++, manifestEntries.length - 1)], }) servers.push(server) await server.start() @@ -242,7 +242,7 @@ describe('createStaticAssetService', () => { const version = '1.0.0' const sessionStore = createStaticAssetSessionStore() const server = createStaticAssetService({ - getManifestEntryByName: () => new Map([ + getManifestEntryByExtensionId: () => new Map([ [extensionId, { rootDir, version }], ]), sessionStore: { diff --git a/apps/stage-tamagotchi/src/main/services/airi/http-server/static-assets/index.ts b/apps/stage-tamagotchi/src/main/services/airi/http-server/static-assets/index.ts index 4bf648950..ec731c8c8 100644 --- a/apps/stage-tamagotchi/src/main/services/airi/http-server/static-assets/index.ts +++ b/apps/stage-tamagotchi/src/main/services/airi/http-server/static-assets/index.ts @@ -39,13 +39,13 @@ export interface StaticAssetService extends ServerManager { * - A higher-level plugin asset service needs an HTTP transport adapter * * Expects: - * - `getManifestEntryByName` returns up-to-date plugin root/version map + * - `getManifestEntryByExtensionId` returns up-to-date extension root/version map * * Returns: * - Lifecycle service with session create/revoke APIs and local base URL getter */ export function createStaticAssetService(options: { - getManifestEntryByName: () => Map + getManifestEntryByExtensionId: () => Map host?: string sessionStore?: StaticAssetSessionStore getType?: (ext: string) => string | undefined @@ -60,11 +60,11 @@ export function createStaticAssetService(options: { const getManifestEntryForRequest = (extensionId: string) => { const cache = manifestEntryRequestCache.getStore() if (!cache) { - return options.getManifestEntryByName().get(extensionId) + return options.getManifestEntryByExtensionId().get(extensionId) } if (!cache.has(extensionId)) { - cache.set(extensionId, options.getManifestEntryByName().get(extensionId)) + cache.set(extensionId, options.getManifestEntryByExtensionId().get(extensionId)) } return cache.get(extensionId) diff --git a/apps/stage-tamagotchi/src/main/services/airi/plugins/features/auto-reload/index.ts b/apps/stage-tamagotchi/src/main/services/airi/plugins/features/auto-reload/index.ts index e6ffe6525..871039d44 100644 --- a/apps/stage-tamagotchi/src/main/services/airi/plugins/features/auto-reload/index.ts +++ b/apps/stage-tamagotchi/src/main/services/airi/plugins/features/auto-reload/index.ts @@ -27,9 +27,9 @@ export interface ExtensionAutoReloadFeatureOptions { log: ReturnType getConfig: () => ExtensionConfig listEntries: () => ManifestEntry[] - isLoaded: (name: string) => boolean - resolveWatchPaths: (name: string) => string[] - reload: (name: string, changedPath: string) => Promise + isLoaded: (extensionId: string) => boolean + resolveWatchPaths: (extensionId: string) => string[] + reload: (extensionId: string, changedPath: string) => Promise } /** @@ -41,7 +41,7 @@ export interface ExtensionAutoReloadFeatureOptions { * * Expects: * - Call `sync()` after registry/config/load-state changes - * - Call `clearExtension(name)` before unloading or disabling a plugin + * - Call `clearExtension(extensionId)` before unloading or disabling an extension * - Call `dispose()` during host shutdown * * Returns: @@ -52,18 +52,18 @@ export function createExtensionAutoReloadFeature(options: ExtensionAutoReloadFea const autoReloadTimers = new Map>() const autoReloadWatchers = new Map() - const clearTimer = (name: string) => { - const timer = autoReloadTimers.get(name) + const clearTimer = (extensionId: string) => { + const timer = autoReloadTimers.get(extensionId) if (!timer) { return } clearTimeout(timer) - autoReloadTimers.delete(name) + autoReloadTimers.delete(extensionId) } - const closeWatchers = (name: string) => { - const watchers = autoReloadWatchers.get(name) + const closeWatchers = (extensionId: string) => { + const watchers = autoReloadWatchers.get(extensionId) if (!watchers) { return } @@ -72,55 +72,55 @@ export function createExtensionAutoReloadFeature(options: ExtensionAutoReloadFea watcher.close() } - autoReloadWatchers.delete(name) + autoReloadWatchers.delete(extensionId) } - const reloadExtensionById = async (name: string, changedPath: string) => { - if (autoReloadInFlight.has(name)) { + const reloadExtensionById = async (extensionId: string, changedPath: string) => { + if (autoReloadInFlight.has(extensionId)) { return } - autoReloadInFlight.add(name) + autoReloadInFlight.add(extensionId) try { - await options.reload(name, changedPath) - options.log.log('extension auto-reloaded after file change', { extension: name, path: changedPath }) + await options.reload(extensionId, changedPath) + options.log.log('extension auto-reloaded after file change', { extensionId, path: changedPath }) } catch (error) { - options.log.withError(error).withFields({ extension: name, path: changedPath }).error('extension auto-reload failed') + options.log.withError(error).withFields({ extensionId, path: changedPath }).error('extension auto-reload failed') } finally { - autoReloadInFlight.delete(name) + autoReloadInFlight.delete(extensionId) } } - const scheduleReload = (name: string, changedPath: string) => { - clearTimer(name) - autoReloadTimers.set(name, setTimeout(() => { - autoReloadTimers.delete(name) - void reloadExtensionById(name, changedPath) + const scheduleReload = (extensionId: string, changedPath: string) => { + clearTimer(extensionId) + autoReloadTimers.set(extensionId, setTimeout(() => { + autoReloadTimers.delete(extensionId) + void reloadExtensionById(extensionId, changedPath) }, 180)) } return { sync() { - const enabledNames = new Set(options.getConfig().autoReload) - const desiredNames = new Set(options.listEntries() + const enabledExtensionIds = new Set(options.getConfig().autoReload) + const desiredExtensionIds = new Set(options.listEntries() .map(entry => manifestIdOf(entry.manifest)) - .filter(name => enabledNames.has(name) && options.isLoaded(name))) + .filter(extensionId => enabledExtensionIds.has(extensionId) && options.isLoaded(extensionId))) - for (const name of autoReloadWatchers.keys()) { - if (!desiredNames.has(name)) { - clearTimer(name) - closeWatchers(name) + for (const extensionId of autoReloadWatchers.keys()) { + if (!desiredExtensionIds.has(extensionId)) { + clearTimer(extensionId) + closeWatchers(extensionId) } } - for (const name of desiredNames) { - if (autoReloadWatchers.has(name)) { + for (const extensionId of desiredExtensionIds) { + if (autoReloadWatchers.has(extensionId)) { continue } - const watchPaths = options.resolveWatchPaths(name) + const watchPaths = options.resolveWatchPaths(extensionId) if (watchPaths.length === 0) { continue } @@ -128,25 +128,25 @@ export function createExtensionAutoReloadFeature(options: ExtensionAutoReloadFea const watchers: FSWatcher[] = [] for (const watchPath of watchPaths) { try { - const watcher = watchFile(watchPath, { persistent: false }, () => scheduleReload(name, watchPath)) + const watcher = watchFile(watchPath, { persistent: false }, () => scheduleReload(extensionId, watchPath)) watcher.on('error', (error) => { - options.log.withError(error).withFields({ extension: name, path: watchPath }).warn('extension auto-reload watcher error') + options.log.withError(error).withFields({ extensionId, path: watchPath }).warn('extension auto-reload watcher error') }) watchers.push(watcher) } catch (error) { - options.log.withError(error).withFields({ extension: name, path: watchPath }).warn('failed to watch extension file for auto-reload') + options.log.withError(error).withFields({ extensionId, path: watchPath }).warn('failed to watch extension file for auto-reload') } } if (watchers.length > 0) { - autoReloadWatchers.set(name, watchers) + autoReloadWatchers.set(extensionId, watchers) } } }, - clearExtension(name: string) { - clearTimer(name) - closeWatchers(name) + clearExtension(extensionId: string) { + clearTimer(extensionId) + closeWatchers(extensionId) }, dispose() { const managedNames = new Set([ @@ -154,9 +154,9 @@ export function createExtensionAutoReloadFeature(options: ExtensionAutoReloadFea ...autoReloadWatchers.keys(), ]) - for (const name of managedNames) { - clearTimer(name) - closeWatchers(name) + for (const extensionId of managedNames) { + clearTimer(extensionId) + closeWatchers(extensionId) } }, } diff --git a/apps/stage-tamagotchi/src/main/services/airi/plugins/features/static-assets/index.test.ts b/apps/stage-tamagotchi/src/main/services/airi/plugins/features/static-assets/index.test.ts index 23ae9797c..40d845cd1 100644 --- a/apps/stage-tamagotchi/src/main/services/airi/plugins/features/static-assets/index.test.ts +++ b/apps/stage-tamagotchi/src/main/services/airi/plugins/features/static-assets/index.test.ts @@ -76,12 +76,12 @@ describe('createExtensionAssetService', () => { mockState.createStaticAssetService.mockReturnValue(server) const service = createExtensionAssetService({ - getManifestEntryByName: () => new Map(), + getManifestEntryByExtensionId: () => new Map(), cookieAdapter: adapter, }) const result = await service.createAssetSession({ - pluginId: 'airi-plugin-game-chess', + extensionId: 'airi-plugin-game-chess', version: '1.0.0', ownerSessionId: 'owner-session-1', routeAssetPath: 'assets/app.js', @@ -123,12 +123,12 @@ describe('createExtensionAssetService', () => { mockState.createStaticAssetService.mockReturnValue(server) const service = createExtensionAssetService({ - getManifestEntryByName: () => new Map(), + getManifestEntryByExtensionId: () => new Map(), cookieAdapter: adapter, }) await expect(service.createAssetSession({ - pluginId: 'airi-plugin-game-chess', + extensionId: 'airi-plugin-game-chess', version: '1.0.0', ownerSessionId: 'owner-session-1', routeAssetPath: 'assets/app.js', @@ -149,12 +149,12 @@ describe('createExtensionAssetService', () => { const { adapter } = createFakeCookieAdapter() mockState.createStaticAssetService.mockReturnValue(server) const service = createExtensionAssetService({ - getManifestEntryByName: () => new Map(), + getManifestEntryByExtensionId: () => new Map(), cookieAdapter: adapter, }) await expect(service.createAssetSession({ - pluginId: 'airi-plugin-game-chess', + extensionId: 'airi-plugin-game-chess', version: '1.0.0', ownerSessionId: 'owner-session-1', routeAssetPath: '../secret.txt', @@ -169,7 +169,7 @@ describe('createExtensionAssetService', () => { adapter.setCookie.mockRejectedValueOnce(new Error('cookie jar unavailable')) await expect(service.createAssetSession({ - pluginId: 'airi-plugin-game-chess', + extensionId: 'airi-plugin-game-chess', version: '1.0.0', ownerSessionId: 'owner-session-1', routeAssetPath: 'assets/app.js', @@ -196,7 +196,7 @@ describe('createExtensionAssetService', () => { mockState.createStaticAssetService.mockReturnValue(server) const service = createExtensionAssetService({ - getManifestEntryByName: () => new Map(), + getManifestEntryByExtensionId: () => new Map(), cookieAdapter: adapter, }) @@ -252,7 +252,7 @@ describe('createExtensionAssetService', () => { mockState.createStaticAssetService.mockReturnValue(server) const service = createExtensionAssetService({ - getManifestEntryByName: () => new Map(), + getManifestEntryByExtensionId: () => new Map(), cookieAdapter: adapter, }) diff --git a/apps/stage-tamagotchi/src/main/services/airi/plugins/features/static-assets/index.ts b/apps/stage-tamagotchi/src/main/services/airi/plugins/features/static-assets/index.ts index 5985f9d6c..e56eb5aa5 100644 --- a/apps/stage-tamagotchi/src/main/services/airi/plugins/features/static-assets/index.ts +++ b/apps/stage-tamagotchi/src/main/services/airi/plugins/features/static-assets/index.ts @@ -13,7 +13,7 @@ import { buildMountedStaticAssetPath } from '../../../http-server/static-assets/ * - Snapshot builders need a transport-agnostic way to authorize one extension asset route before iframe load * * Expects: - * - `pluginId` matches a manifest entry registered in the asset host + * - `extensionId` matches a manifest entry registered in the asset host * - `routeAssetPath` identifies the iframe entry asset relative to the mounted `/ui` route * - `pathPrefix` is scoped to the mounted route prefix accepted by the session store * @@ -21,8 +21,8 @@ import { buildMountedStaticAssetPath } from '../../../http-server/static-assets/ * - N/A */ export interface ExtensionAssetSessionInput { - /** Extension/plugin manifest id that owns the static asset root. */ - pluginId: string + /** Extension manifest id that owns the static asset root. */ + extensionId: string /** Extension/plugin version expected by the server-side session validator. */ version: string /** Parent extension session id used for owner-scoped revocation. */ @@ -164,17 +164,17 @@ function createExtensionAssetCookie(baseUrl: string, session: StaticAssetSession * - Asset session lifecycle should stay inside the extension domain instead of the HTTP server layer * * Expects: - * - `getManifestEntryByName` returns the latest extension root/version map + * - `getManifestEntryByExtensionId` returns the latest extension root/version map * - `cookieAdapter` writes and removes cookies in the Electron host session used by plugin iframes * * Returns: * - An extension-facing asset host service with generic extension asset methods */ export function createExtensionAssetService(options: { - getManifestEntryByName: () => Map + getManifestEntryByExtensionId: () => Map cookieAdapter: ExtensionAssetCookieAdapter }): ExtensionAssetService { - const server = createStaticAssetService({ getManifestEntryByName: options.getManifestEntryByName }) + const server = createStaticAssetService({ getManifestEntryByExtensionId: options.getManifestEntryByExtensionId }) let lastBaseUrl: string | undefined const readBaseUrl = () => { @@ -208,7 +208,7 @@ export function createExtensionAssetService(options: { }, async createAssetSession(input) { const session = server.createSession({ - extensionId: input.pluginId, + extensionId: input.extensionId, version: input.version, ownerSessionId: input.ownerSessionId, pathPrefix: input.pathPrefix, @@ -222,7 +222,7 @@ export function createExtensionAssetService(options: { } const mountedPath = buildMountedStaticAssetPath({ - extensionId: input.pluginId, + extensionId: input.extensionId, assetSessionId: session.assetSessionId, assetPath: input.routeAssetPath, }) diff --git a/apps/stage-tamagotchi/src/main/services/airi/plugins/host/debug.ts b/apps/stage-tamagotchi/src/main/services/airi/plugins/host/debug.ts index b98803911..bbb649920 100644 --- a/apps/stage-tamagotchi/src/main/services/airi/plugins/host/debug.ts +++ b/apps/stage-tamagotchi/src/main/services/airi/plugins/host/debug.ts @@ -2,7 +2,6 @@ import type { ExtensionHost } from '@proj-airi/plugin-sdk/plugin-host' import type { PluginHostDebugSnapshot, - PluginHostModuleSummary, } from '../../../../../shared/eventa/plugin/host' import type { ExtensionAssetSnapshotService } from '../features/static-assets' import type { ExtensionConfig, ManifestEntry } from '../types' @@ -19,7 +18,7 @@ import { buildPluginRegistrySnapshot } from './registry' * * Expects: * - `host` is the initialized extension host instance - * - `manifestEntryByName` contains entries for any extension-owned modules being inspected + * - `manifestEntryByExtensionId` contains entries for any extension-owned modules being inspected * - `extensionAssetService` owns extension asset URL/session lifecycle when mounted asset URLs are needed * * Returns: @@ -31,7 +30,7 @@ export function buildPluginHostDebugSnapshot(options: { entries: ManifestEntry[] config: ExtensionConfig loaded: Set - manifestEntryByName: Map + manifestEntryByExtensionId: Map extensionAssetService?: ExtensionAssetSnapshotService }): Promise { const extensionAssetService = options.extensionAssetService @@ -39,10 +38,10 @@ export function buildPluginHostDebugSnapshot(options: { .listBindings() .map(module => rewriteWidgetModuleAssetUrl( - module as PluginHostModuleSummary, - options.manifestEntryByName, + module, + options.manifestEntryByExtensionId, { - pluginAssetBaseUrl: extensionAssetService?.getBaseUrl(), + extensionAssetBaseUrl: extensionAssetService?.getBaseUrl(), ...(extensionAssetService ? { createAssetSession: ({ extensionId, version, sessionId, routeAssetPath, sessionPathPrefix }: { @@ -52,7 +51,7 @@ export function buildPluginHostDebugSnapshot(options: { routeAssetPath: string sessionPathPrefix: string }) => extensionAssetService.createAssetSession({ - pluginId: extensionId, + extensionId, version, ownerSessionId: sessionId, routeAssetPath, @@ -62,7 +61,7 @@ export function buildPluginHostDebugSnapshot(options: { : {}), }, ), - ) as Array>) + )) return modules.then(resolvedModules => ({ registry: buildPluginRegistrySnapshot({ @@ -73,13 +72,13 @@ export function buildPluginHostDebugSnapshot(options: { }), sessions: options.host.listSessions().map(session => ({ id: session.id, - manifestName: session.manifest.id, + extensionId: session.manifest.id, phase: session.phase, runtime: session.runtime ?? 'electron', moduleId: session.extension.id, })), kits: options.host.listKits(), - modules: resolvedModules as PluginHostDebugSnapshot['modules'], + modules: resolvedModules, capabilities: options.host.listCapabilities(), refreshedAt: Date.now(), })) diff --git a/apps/stage-tamagotchi/src/main/services/airi/plugins/host/index.ts b/apps/stage-tamagotchi/src/main/services/airi/plugins/host/index.ts index de87f21a6..32af2f8e6 100644 --- a/apps/stage-tamagotchi/src/main/services/airi/plugins/host/index.ts +++ b/apps/stage-tamagotchi/src/main/services/airi/plugins/host/index.ts @@ -93,13 +93,13 @@ export interface ExtensionHostServiceInternal extends ExtensionHostService { * - Host state must remember a known manifest path for a plugin name * * Expects: - * - `payload.name` matches a discovered or previously known plugin + * - `payload.extensionId` matches a discovered or previously known extension * - `payload.path` is only needed when the manifest is not currently discoverable * * Returns: * - The updated extension registry snapshot after persistence */ - setEnabled: (payload: { name: string, enabled: boolean, path?: string }) => Promise + setEnabled: (payload: { extensionId: string, enabled: boolean, path?: string }) => Promise /** * Persists whether one loaded plugin should use auto-reload. @@ -109,12 +109,12 @@ export interface ExtensionHostServiceInternal extends ExtensionHostService { * - Host features need to resync optional watcher state after config changes * * Expects: - * - `payload.name` matches one plugin entry in config or discovery state + * - `payload.extensionId` matches one extension entry in config or discovery state * * Returns: * - The updated extension registry snapshot after persistence */ - setAutoReload: (payload: { name: string, enabled: boolean }) => Promise + setAutoReload: (payload: { extensionId: string, enabled: boolean }) => Promise /** * Loads every plugin currently marked as enabled. @@ -132,34 +132,34 @@ export interface ExtensionHostServiceInternal extends ExtensionHostService { loadEnabled: () => Promise /** - * Loads one plugin by manifest name. + * Loads one extension by manifest id. * * Use when: * - Renderer explicitly requests one plugin to start * - Host features need to restart a plugin after manifest or entrypoint changes * * Expects: - * - `name` resolves to a manifest entry in the current registry + * - `extensionId` resolves to a manifest entry in the current registry * * Returns: * - The extension registry snapshot after the load completes */ - load: (name: string) => Promise + load: (extensionId: string) => Promise /** - * Stops one loaded plugin by manifest name. + * Stops one loaded extension by manifest id. * * Use when: * - Renderer explicitly requests one plugin to stop * - Host features need to stop a plugin before reload or disposal * * Expects: - * - `name` identifies a plugin that may or may not currently be loaded + * - `extensionId` identifies an extension that may or may not currently be loaded * * Returns: * - The extension registry snapshot after unload bookkeeping completes */ - unload: (name: string) => Promise + unload: (extensionId: string) => Promise /** * Builds the full extension host debug snapshot. @@ -248,7 +248,7 @@ export async function setupExtensionHostServiceInternal( // Extension feature: Static Assets serving const extensionAssetService = createExtensionAssetService({ - getManifestEntryByName: () => extensionRegistry.getManifestEntryByName(), + getManifestEntryByExtensionId: () => extensionRegistry.getManifestEntryByExtensionId(), cookieAdapter: createElectronExtensionAssetCookieAdapter(), }) await extensionAssetService.start() @@ -290,21 +290,21 @@ export async function setupExtensionHostServiceInternal( } const createModuleAssetSession = async (input: { - pluginId: string + extensionId: string version: string ownerSessionId: string routeAssetPath: string pathPrefix: string }) => { - const { pluginId, version, ownerSessionId, routeAssetPath, pathPrefix } = input - const cacheKey = `${pluginId}:${version}:${ownerSessionId}:${routeAssetPath}:${pathPrefix}` + const { extensionId, version, ownerSessionId, routeAssetPath, pathPrefix } = input + const cacheKey = `${extensionId}:${version}:${ownerSessionId}:${routeAssetPath}:${pathPrefix}` const cachedSession = moduleAssetSessionCache.get(cacheKey) if (cachedSession) { return cachedSession } const session = await extensionAssetService.createAssetSession({ - pluginId, + extensionId, version, ownerSessionId, routeAssetPath, @@ -317,9 +317,9 @@ export async function setupExtensionHostServiceInternal( const extensionAssetSnapshotService: ExtensionAssetSnapshotService = { getBaseUrl: extensionAssetService.getBaseUrl, - createAssetSession: ({ pluginId, version, ownerSessionId, routeAssetPath, pathPrefix }) => { + createAssetSession: ({ extensionId, version, ownerSessionId, routeAssetPath, pathPrefix }) => { return createModuleAssetSession({ - pluginId, + extensionId, version, ownerSessionId, routeAssetPath, @@ -335,50 +335,50 @@ export async function setupExtensionHostServiceInternal( entries: extensionRegistry.listEntries(), config: getConfig(), loaded, - manifestEntryByName: extensionRegistry.getManifestEntryByName(), + manifestEntryByExtensionId: extensionRegistry.getManifestEntryByExtensionId(), extensionAssetService: extensionAssetSnapshotService, }) } const loadExtensionById = async ( - name: string, + extensionId: string, loadOptions: { cacheBustKey?: string } = {}, ) => { - if (loaded.has(name)) { + if (loaded.has(extensionId)) { return } - const entry = extensionRegistry.findManifestEntry(name) + const entry = extensionRegistry.findManifestEntry(extensionId) if (!entry) { - throw new Error(`Extension manifest not found: ${name}`) + throw new Error(`Extension manifest not found: ${extensionId}`) } const manifestForLoad = createManifestForLoad(entry, loadOptions) const session = await host.start(manifestForLoad, { cwd: dirname(entry.path) }) - loaded.add(name) - loadedSessionIds.set(name, session.id) - log.log('extension loaded', { extension: name, sessionId: session.id }) + loaded.add(extensionId) + loadedSessionIds.set(extensionId, session.id) + log.withFields({ extensionId, sessionId: session.id }).log('extension loaded') } - const stopLoadedExtensionById = async (name: string) => { - const sessionId = loadedSessionIds.get(name) + const stopLoadedExtensionById = async (extensionId: string) => { + const sessionId = loadedSessionIds.get(extensionId) if (!sessionId) { - loaded.delete(name) + loaded.delete(extensionId) return } await host.stop(sessionId) - loadedSessionIds.delete(name) - loaded.delete(name) + loadedSessionIds.delete(extensionId) + loaded.delete(extensionId) clearModuleAssetSessionCacheByOwnerSessionId(sessionId) await extensionAssetService.revokeByOwnerSessionId(sessionId) - log.log('extension unloaded', { extension: name, sessionId }) + log.withFields({ extensionId, sessionId }).log('extension unloaded') } - const resolveAutoReloadWatchPaths = (name: string) => { - const entry = extensionRegistry.findManifestEntry(name) + const resolveAutoReloadWatchPaths = (extensionId: string) => { + const entry = extensionRegistry.findManifestEntry(extensionId) if (!entry) { return [] } @@ -392,36 +392,36 @@ export async function setupExtensionHostServiceInternal( log, getConfig, listEntries: () => extensionRegistry.listEntries(), - isLoaded: name => loaded.has(name), + isLoaded: extensionId => loaded.has(extensionId), resolveWatchPaths: resolveAutoReloadWatchPaths, - reload: async (name) => { - await stopLoadedExtensionById(name) + reload: async (extensionId) => { + await stopLoadedExtensionById(extensionId) await refreshManifests() - await loadExtensionById(name, { cacheBustKey: `auto-reload-${Date.now()}` }) + await loadExtensionById(extensionId, { cacheBustKey: `auto-reload-${Date.now()}` }) }, }) - const unloadExtensionById = async (name: string) => { - autoReloadFeature.clearExtension(name) - await stopLoadedExtensionById(name) + const unloadExtensionById = async (extensionId: string) => { + autoReloadFeature.clearExtension(extensionId) + await stopLoadedExtensionById(extensionId) } const loadEnabledExtensions = async () => { const config = getConfig() for (const entry of extensionRegistry.listEntries()) { - const name = manifestIdOf(entry.manifest) - if (!config.enabled.includes(name)) { + const extensionId = manifestIdOf(entry.manifest) + if (!config.enabled.includes(extensionId)) { continue } - if (loaded.has(name)) { + if (loaded.has(extensionId)) { continue } try { - await loadExtensionById(name) + await loadExtensionById(extensionId) } catch (error) { - log.withError(error).withFields({ extension: name }).error('extension failed to start') + log.withError(error).withFields({ extensionId }).error('extension failed to start') } } @@ -450,22 +450,22 @@ export async function setupExtensionHostServiceInternal( const config = getConfig() const enabled = new Set(config.enabled) if (payload.enabled) { - enabled.add(payload.name) + enabled.add(payload.extensionId) } else { - enabled.delete(payload.name) - clearModuleAssetSessionCacheByExtensionId(payload.name) - await extensionAssetService.revokeByExtensionId(payload.name) + enabled.delete(payload.extensionId) + clearModuleAssetSessionCacheByExtensionId(payload.extensionId) + await extensionAssetService.revokeByExtensionId(payload.extensionId) } - const entry = extensionRegistry.findManifestEntry(payload.name) + const entry = extensionRegistry.findManifestEntry(payload.extensionId) const manifestPath = entry?.path ?? payload.path ?? '' extensionConfig.update({ enabled: [...enabled], autoReload: config.autoReload, known: { ...config.known, - [payload.name]: { path: manifestPath }, + [payload.extensionId]: { path: manifestPath }, }, }) @@ -478,10 +478,10 @@ export async function setupExtensionHostServiceInternal( const config = getConfig() const autoReload = new Set(config.autoReload) if (payload.enabled) { - autoReload.add(payload.name) + autoReload.add(payload.extensionId) } else { - autoReload.delete(payload.name) + autoReload.delete(payload.extensionId) } extensionConfig.update({ @@ -498,14 +498,14 @@ export async function setupExtensionHostServiceInternal( autoReloadFeature.sync() return listSnapshot() }, - async load(name) { + async load(extensionId) { await refreshManifests() - await loadExtensionById(name) + await loadExtensionById(extensionId) autoReloadFeature.sync() return listSnapshot() }, - async unload(name) { - await unloadExtensionById(name) + async unload(extensionId) { + await unloadExtensionById(extensionId) autoReloadFeature.sync() return listSnapshot() }, diff --git a/apps/stage-tamagotchi/src/main/services/airi/plugins/host/registry.ts b/apps/stage-tamagotchi/src/main/services/airi/plugins/host/registry.ts index 2f2a90894..2f13803b2 100644 --- a/apps/stage-tamagotchi/src/main/services/airi/plugins/host/registry.ts +++ b/apps/stage-tamagotchi/src/main/services/airi/plugins/host/registry.ts @@ -164,7 +164,7 @@ export async function loadManifestsFrom( } /** - * Builds a renderer-facing plugin summary from manifest, config, and runtime state. + * Builds a renderer-facing extension summary from manifest, config, and runtime state. * * Use when: * - Registry snapshots need one UI-friendly entry per discovered plugin @@ -182,15 +182,15 @@ export function createPluginSummary( config: ExtensionConfig, loaded: Set, ): PluginManifestSummary { - const name = manifestIdOf(entry.manifest) + const extensionId = manifestIdOf(entry.manifest) return { - name, + extensionId, entrypoints: entry.manifest.entrypoints, path: entry.path, - enabled: config.enabled.includes(name), - autoReload: config.autoReload.includes(name), - loaded: loaded.has(name), - isNew: !config.known[name], + enabled: config.enabled.includes(extensionId), + autoReload: config.autoReload.includes(extensionId), + loaded: loaded.has(extensionId), + isNew: !config.known[extensionId], } } @@ -285,7 +285,7 @@ export function createManifestForLoad( * * Use when: * - Refreshing extension manifests from disk - * - Looking up manifests by plugin name during load or inspect operations + * - Looking up manifests by extension id during load or inspect operations * * Expects: * - `refresh()` is called before consumers read entries or manifests @@ -299,8 +299,8 @@ export interface ExtensionHostRegistry { refresh: () => Promise listEntries: () => ManifestEntry[] listManifests: () => ExtensionManifestV1[] - findManifestEntry: (name: string) => ManifestEntry | undefined - getManifestEntryByName: () => Map + findManifestEntry: (extensionId: string) => ManifestEntry | undefined + getManifestEntryByExtensionId: () => Map } /** @@ -321,7 +321,7 @@ export function createExtensionHostRegistry(options: { }): ExtensionHostRegistry { let entries: ManifestEntry[] = [] let manifests: ExtensionManifestV1[] = [] - let manifestEntryByName = new Map() + let manifestEntryByExtensionId = new Map() return { getRoot() { @@ -329,11 +329,11 @@ export function createExtensionHostRegistry(options: { }, async refresh() { entries = await loadManifestsFrom(options.extensionsRoot, options.log) - manifestEntryByName = new Map() + manifestEntryByExtensionId = new Map() for (const entry of entries) { const id = manifestIdOf(entry.manifest) - if (!manifestEntryByName.has(id)) { - manifestEntryByName.set(id, entry) + if (!manifestEntryByExtensionId.has(id)) { + manifestEntryByExtensionId.set(id, entry) } } manifests = entries.map(entry => entry.manifest) @@ -345,11 +345,11 @@ export function createExtensionHostRegistry(options: { listManifests() { return manifests }, - findManifestEntry(name) { - return manifestEntryByName.get(name) + findManifestEntry(extensionId) { + return manifestEntryByExtensionId.get(extensionId) }, - getManifestEntryByName() { - return manifestEntryByName + getManifestEntryByExtensionId() { + return manifestEntryByExtensionId }, } } diff --git a/apps/stage-tamagotchi/src/main/services/airi/plugins/index.test.ts b/apps/stage-tamagotchi/src/main/services/airi/plugins/index.test.ts index 07b269ea6..84c95d6ff 100644 --- a/apps/stage-tamagotchi/src/main/services/airi/plugins/index.test.ts +++ b/apps/stage-tamagotchi/src/main/services/airi/plugins/index.test.ts @@ -426,8 +426,8 @@ describe('setupExtensionHost', () => { expect(snapshot.root).toBe(pluginsDir) expect(snapshot.plugins).toHaveLength(2) expect(snapshot.plugins).toEqual(expect.arrayContaining([ - expect.objectContaining({ name: 'test-normal', path: normalPath, enabled: false, loaded: false, isNew: true }), - expect.objectContaining({ name: 'test-error', path: errorPath, enabled: false, loaded: false, isNew: true }), + expect.objectContaining({ extensionId: 'test-normal', path: normalPath, enabled: false, loaded: false, isNew: true }), + expect.objectContaining({ extensionId: 'test-error', path: errorPath, enabled: false, loaded: false, isNew: true }), ])) }) @@ -491,7 +491,7 @@ describe('setupExtensionHost', () => { expect(snapshot.plugins).toEqual([ expect.objectContaining({ - name: 'devtools-sample-plugin', + extensionId: 'devtools-sample-plugin', path: manifestPath, enabled: false, loaded: false, @@ -528,13 +528,13 @@ describe('setupExtensionHost', () => { const invokeSetEnabled = defineInvoke(contextState.lastContext!, electronPluginSetEnabled) const invokeLoadEnabled = defineInvoke(contextState.lastContext!, electronPluginLoadEnabled) - await invokeSetEnabled({ name: 'test-normal', enabled: true }) - await invokeSetEnabled({ name: 'test-error', enabled: true }) + await invokeSetEnabled({ extensionId: 'test-normal', enabled: true }) + await invokeSetEnabled({ extensionId: 'test-error', enabled: true }) const snapshot = await invokeLoadEnabled() - const normal = snapshot.plugins.find(plugin => plugin.name === 'test-normal') - const error = snapshot.plugins.find(plugin => plugin.name === 'test-error') + const normal = snapshot.plugins.find(plugin => plugin.extensionId === 'test-normal') + const error = snapshot.plugins.find(plugin => plugin.extensionId === 'test-error') expect(normal).toEqual(expect.objectContaining({ enabled: true, loaded: true })) expect(error).toEqual(expect.objectContaining({ enabled: true, loaded: false })) @@ -557,7 +557,7 @@ describe('setupExtensionHost', () => { await setupExtensionHost() expect(contextState.lastContext).toBeDefined() - const toolsChangedEvents: Array<{ reason: string, name?: string }> = [] + const toolsChangedEvents: Array<{ reason: string, extensionId?: string }> = [] contextState.lastContext!.on(electronPluginToolsChanged, (event) => { if (!event.body) { throw new Error('Expected plugin tools changed event body.') @@ -567,12 +567,12 @@ describe('setupExtensionHost', () => { const invokeLoad = defineInvoke(contextState.lastContext!, electronPluginLoad) - await invokeLoad({ name: 'test-tools-changed' }) + await invokeLoad({ extensionId: 'test-tools-changed' }) expect(toolsChangedEvents).toEqual([ { reason: 'loaded', - name: 'test-tools-changed', + extensionId: 'test-tools-changed', }, ]) }) @@ -605,7 +605,7 @@ describe('setupExtensionHost', () => { const invokeSetEnabled = defineInvoke(contextState.lastContext!, electronPluginSetEnabled) const invokeLoadEnabled = defineInvoke(contextState.lastContext!, electronPluginLoadEnabled) - await invokeSetEnabled({ name: 'duplicate-plugin', enabled: true }) + await invokeSetEnabled({ extensionId: 'duplicate-plugin', enabled: true }) await invokeLoadEnabled() const duplicateSession = service.host @@ -631,16 +631,16 @@ describe('setupExtensionHost', () => { const invokeSetAutoReload = defineInvoke(contextState.lastContext!, electronPluginSetAutoReload) const invokeList = defineInvoke(contextState.lastContext!, electronPluginList) - await invokeSetAutoReload({ name: 'test-auto-reload', enabled: true }) + await invokeSetAutoReload({ extensionId: 'test-auto-reload', enabled: true }) let snapshot = await invokeList() expect(snapshot.plugins).toEqual(expect.arrayContaining([ - expect.objectContaining({ name: 'test-auto-reload', autoReload: true }), + expect.objectContaining({ extensionId: 'test-auto-reload', autoReload: true }), ])) - await invokeSetAutoReload({ name: 'test-auto-reload', enabled: false }) + await invokeSetAutoReload({ extensionId: 'test-auto-reload', enabled: false }) snapshot = await invokeList() expect(snapshot.plugins).toEqual(expect.arrayContaining([ - expect.objectContaining({ name: 'test-auto-reload', autoReload: false }), + expect.objectContaining({ extensionId: 'test-auto-reload', autoReload: false }), ])) }) @@ -667,12 +667,12 @@ describe('setupExtensionHost', () => { const invokeInspect = defineInvoke(contextState.lastContext!, electronPluginInspect) const invokeUnload = defineInvoke(contextState.lastContext!, electronPluginUnload) - await invokeSetEnabled({ name: 'test-auto-reload-reload', enabled: true }) + await invokeSetEnabled({ extensionId: 'test-auto-reload-reload', enabled: true }) await invokeLoadEnabled() - await invokeSetAutoReload({ name: 'test-auto-reload-reload', enabled: true }) + await invokeSetAutoReload({ extensionId: 'test-auto-reload-reload', enabled: true }) const before = await invokeInspect() - const beforeSession = before.sessions.find(session => session.manifestName === 'test-auto-reload-reload') + const beforeSession = before.sessions.find(session => session.extensionId === 'test-auto-reload-reload') expect(beforeSession).toBeDefined() const pluginSdkUrl = pathToFileURL(resolve(repoRoot, 'packages/plugin-sdk/src/index.ts')).href @@ -692,14 +692,14 @@ describe('setupExtensionHost', () => { while (Date.now() < deadline && afterSessionId === beforeSession?.id) { await new Promise(resolve => setTimeout(resolve, 100)) const snapshot = await invokeInspect() - afterSessionId = snapshot.sessions.find(session => session.manifestName === 'test-auto-reload-reload')?.id + afterSessionId = snapshot.sessions.find(session => session.extensionId === 'test-auto-reload-reload')?.id } expect(afterSessionId).toBeDefined() expect(afterSessionId).not.toEqual(beforeSession?.id) - await invokeSetAutoReload({ name: 'test-auto-reload-reload', enabled: false }) - await invokeUnload({ name: 'test-auto-reload-reload' }) + await invokeSetAutoReload({ extensionId: 'test-auto-reload-reload', enabled: false }) + await invokeUnload({ extensionId: 'test-auto-reload-reload' }) }) it('loads enabled plugins with absolute manifest entrypoints outside the plugin directory', async () => { @@ -725,10 +725,10 @@ describe('setupExtensionHost', () => { const invokeSetEnabled = defineInvoke(contextState.lastContext!, electronPluginSetEnabled) const invokeLoadEnabled = defineInvoke(contextState.lastContext!, electronPluginLoadEnabled) - await invokeSetEnabled({ name: 'test-absolute-entrypoint', enabled: true }) + await invokeSetEnabled({ extensionId: 'test-absolute-entrypoint', enabled: true }) const snapshot = await invokeLoadEnabled() - const plugin = snapshot.plugins.find(item => item.name === 'test-absolute-entrypoint') + const plugin = snapshot.plugins.find(item => item.extensionId === 'test-absolute-entrypoint') expect(plugin).toEqual(expect.objectContaining({ enabled: true, loaded: true })) } @@ -759,10 +759,10 @@ describe('setupExtensionHost', () => { const invokeSetEnabled = defineInvoke(contextState.lastContext!, electronPluginSetEnabled) const invokeLoadEnabled = defineInvoke(contextState.lastContext!, electronPluginLoadEnabled) - await invokeSetEnabled({ name: 'devtools-sample-plugin', enabled: true }) + await invokeSetEnabled({ extensionId: 'devtools-sample-plugin', enabled: true }) const snapshot = await invokeLoadEnabled() - const plugin = snapshot.plugins.find(item => item.name === 'devtools-sample-plugin') + const plugin = snapshot.plugins.find(item => item.extensionId === 'devtools-sample-plugin') expect(plugin).toEqual(expect.objectContaining({ enabled: true, loaded: true })) }) @@ -825,10 +825,10 @@ describe('setupExtensionHost', () => { const invokeLoadEnabled = defineInvoke(contextState.lastContext!, electronPluginLoadEnabled) const invokeInspect = defineInvoke(contextState.lastContext!, electronPluginInspect) - await invokeSetEnabled({ name: 'airi-plugin-game-chess', enabled: true }) + await invokeSetEnabled({ extensionId: 'airi-plugin-game-chess', enabled: true }) const registry = await invokeLoadEnabled() - const plugin = registry.plugins.find(item => item.name === 'airi-plugin-game-chess') + const plugin = registry.plugins.find(item => item.extensionId === 'airi-plugin-game-chess') expect(plugin).toEqual(expect.objectContaining({ enabled: true, loaded: true })) const snapshot = await invokeInspect() @@ -837,7 +837,7 @@ describe('setupExtensionHost', () => { expect(snapshot.modules).toEqual(expect.arrayContaining([ expect.objectContaining({ moduleId: 'chess-like-main:gamelet', - ownerPluginId: 'airi-plugin-game-chess', + ownerExtensionId: 'airi-plugin-game-chess', kitId: 'kit.gamelet', kitModuleType: 'gamelet', runtime: 'electron', @@ -912,7 +912,7 @@ describe('setupExtensionHost', () => { const invokeLoadEnabled = defineInvoke(contextState.lastContext!, electronPluginLoadEnabled) const invokeInspect = defineInvoke(contextState.lastContext!, electronPluginInspect) - await invokeSetEnabled({ name: 'test-plugin-widget-asset-url', enabled: true }) + await invokeSetEnabled({ extensionId: 'test-plugin-widget-asset-url', enabled: true }) await invokeLoadEnabled() const session = service.host .listSessions() @@ -947,7 +947,7 @@ describe('setupExtensionHost', () => { expect(snapshot.modules).toEqual(expect.arrayContaining([ expect.objectContaining({ moduleId: 'widget-shell-under-test', - ownerPluginId: 'test-plugin-widget-asset-url', + ownerExtensionId: 'test-plugin-widget-asset-url', kitId: 'kit.widget', kitModuleType: 'window', runtime: 'electron', @@ -1084,7 +1084,7 @@ describe('setupExtensionHost', () => { expect.objectContaining({ moduleId: 'widget-shell', ownerSessionId: session.id, - ownerPluginId: 'test-dynamic-module', + ownerExtensionId: 'test-dynamic-module', kitId: 'kit.widget', kitModuleType: 'window', runtime: 'electron', @@ -1183,7 +1183,7 @@ describe('setupExtensionHost', () => { expect(binding).toEqual(expect.objectContaining({ moduleId: 'kit-module:gamelet', - ownerPluginId: 'test-extension-gamelet-kit', + ownerExtensionId: 'test-extension-gamelet-kit', ownerSessionId: session.id, kitId: 'kit.gamelet', kitModuleType: 'gamelet', diff --git a/apps/stage-tamagotchi/src/main/services/airi/plugins/index.ts b/apps/stage-tamagotchi/src/main/services/airi/plugins/index.ts index 6e8a37822..82eba897c 100644 --- a/apps/stage-tamagotchi/src/main/services/airi/plugins/index.ts +++ b/apps/stage-tamagotchi/src/main/services/airi/plugins/index.ts @@ -57,7 +57,7 @@ export async function setupExtensionHost(options: SetupExtensionHostOptions): Pr const result = await hostService.setEnabled(payload) context.emit(electronPluginToolsChanged, { reason: 'enabled-state-changed', - name: payload.name, + extensionId: payload.extensionId, }) return result }) @@ -75,19 +75,19 @@ export async function setupExtensionHost(options: SetupExtensionHostOptions): Pr }) defineInvokeHandler(context, electronPluginLoad, async (payload) => { - const result = await hostService.load(payload.name) + const result = await hostService.load(payload.extensionId) context.emit(electronPluginToolsChanged, { reason: 'loaded', - name: payload.name, + extensionId: payload.extensionId, }) return result }) defineInvokeHandler(context, electronPluginUnload, async (payload) => { - const result = await hostService.unload(payload.name) + const result = await hostService.unload(payload.extensionId) context.emit(electronPluginToolsChanged, { reason: 'unloaded', - name: payload.name, + extensionId: payload.extensionId, }) return result }) @@ -109,7 +109,7 @@ export async function setupExtensionHost(options: SetupExtensionHostOptions): Pr }) defineInvokeHandler(context, electronPluginInvokeTool, async (payload) => { - return await hostService.tools.invoke(payload.ownerPluginId, payload.name, payload.input) + return await hostService.tools.invoke(payload.ownerExtensionId, payload.name, payload.input) }) defineInvokeHandler(context, electronPluginUpdateCapability, async (payload) => { diff --git a/apps/stage-tamagotchi/src/main/services/airi/plugins/kits/index.ts b/apps/stage-tamagotchi/src/main/services/airi/plugins/kits/index.ts index 4629376c8..15732cb79 100644 --- a/apps/stage-tamagotchi/src/main/services/airi/plugins/kits/index.ts +++ b/apps/stage-tamagotchi/src/main/services/airi/plugins/kits/index.ts @@ -57,7 +57,7 @@ function createHostToolKit(options: { tools: TamagotchiToolRegistry }): KitRef, + manifestEntryByExtensionId: Map, options?: { - pluginAssetBaseUrl?: string + extensionAssetBaseUrl?: string createAssetSession?: (input: { extensionId: string version: string @@ -107,7 +107,7 @@ export function rewriteWidgetModuleAssetUrl( }) => Promise<{ assetSessionId: string, url?: string }> }, ): Promise | PluginHostModuleSummary { - const entry = manifestEntryByName.get(module.ownerPluginId) + const entry = manifestEntryByExtensionId.get(module.ownerExtensionId) if (!entry) { return module } @@ -138,23 +138,23 @@ export function rewriteWidgetModuleAssetUrl( return module } - if (!options?.pluginAssetBaseUrl || !options.createAssetSession) { + if (!options?.extensionAssetBaseUrl || !options.createAssetSession) { return module } return options.createAssetSession({ - extensionId: module.ownerPluginId, + extensionId: module.ownerExtensionId, version: entry.version, sessionId: module.ownerSessionId, routeAssetPath: widgetAssetRoute.routeAssetPath, sessionPathPrefix: widgetAssetRoute.sessionPathPrefix, }).then((session) => { const mountedPath = buildMountedStaticAssetPath({ - extensionId: module.ownerPluginId, + extensionId: module.ownerExtensionId, assetSessionId: session.assetSessionId, assetPath: widgetAssetRoute.routeAssetPath, }) - const iframeUrl = session.url ?? (mountedPath ? new URL(mountedPath, options.pluginAssetBaseUrl).toString() : '') + const iframeUrl = session.url ?? (mountedPath ? new URL(mountedPath, options.extensionAssetBaseUrl).toString() : '') if (!iframeUrl) { return module } diff --git a/apps/stage-tamagotchi/src/main/services/airi/plugins/types.ts b/apps/stage-tamagotchi/src/main/services/airi/plugins/types.ts index 1c1d62073..353b4aa67 100644 --- a/apps/stage-tamagotchi/src/main/services/airi/plugins/types.ts +++ b/apps/stage-tamagotchi/src/main/services/airi/plugins/types.ts @@ -6,6 +6,11 @@ import type { WidgetsUpdatePayload, } from '../../../../shared/eventa' +/** + * Stable manifest id used as the runtime identity for one extension. + */ +export type ExtensionId = string + /** * Runtime-facing extension host service bundle returned by setup. * @@ -108,20 +113,20 @@ export interface ExtensionHostBindingListOptions { * Persisted extension configuration snapshot. * * Use when: - * - Reading/writing enabled and auto-reload plugin state + * - Reading/writing enabled and auto-reload extension state * - Keeping known extension manifest path metadata * * Expects: - * - Arrays contain extension manifest names - * - `known` maps plugin names to canonical manifest paths + * - Arrays contain extension manifest ids + * - `known` maps extension manifest ids to canonical manifest paths * * Returns: * - N/A */ export interface ExtensionConfig { - enabled: string[] - autoReload: string[] - known: Record + enabled: ExtensionId[] + autoReload: ExtensionId[] + known: Record } /** diff --git a/apps/stage-tamagotchi/src/renderer/stores/plugin-tools.test.ts b/apps/stage-tamagotchi/src/renderer/stores/plugin-tools.test.ts index a1bb37f50..02ce824dd 100644 --- a/apps/stage-tamagotchi/src/renderer/stores/plugin-tools.test.ts +++ b/apps/stage-tamagotchi/src/renderer/stores/plugin-tools.test.ts @@ -10,7 +10,7 @@ const invokeMocks = vi.hoisted(() => ({ listPluginXsaiTools: vi.fn(async () => ({ tools: [ { - ownerPluginId: 'plugin-chess', + ownerExtensionId: 'plugin-chess', name: 'play_chess', description: 'Play a chess move.', parameters: { @@ -21,7 +21,7 @@ const invokeMocks = vi.hoisted(() => ({ ], prompts: [ { - ownerPluginId: 'plugin-chess', + ownerExtensionId: 'plugin-chess', id: 'chess-tools', prompt: { id: 'airi-plugin-game-chess.prompt', @@ -84,14 +84,14 @@ describe('useTamagotchiPluginToolsStore', async () => { }, toolOptions) expect(invokeMocks.invokePluginTool).toHaveBeenCalledWith({ - ownerPluginId: 'plugin-chess', + ownerExtensionId: 'plugin-chess', name: 'play_chess', input: { move: 'e2e4', }, }) expect(executionResult).toEqual({ - ownerPluginId: 'plugin-chess', + ownerExtensionId: 'plugin-chess', name: 'play_chess', input: { move: 'e2e4', diff --git a/apps/stage-tamagotchi/src/renderer/stores/plugin-tools.ts b/apps/stage-tamagotchi/src/renderer/stores/plugin-tools.ts index 4ebb07baa..f174eff0e 100644 --- a/apps/stage-tamagotchi/src/renderer/stores/plugin-tools.ts +++ b/apps/stage-tamagotchi/src/renderer/stores/plugin-tools.ts @@ -43,7 +43,7 @@ export const useTamagotchiPluginToolsStore = defineStore('tamagotchi-plugin-tool llmToolsetPromptsStore.registerToolsetPrompts( 'plugin-tools', definitions.prompts.map(definition => ({ - id: `${definition.ownerPluginId}:${definition.id}`, + id: `${definition.ownerExtensionId}:${definition.id}`, title: definition.prompt.title, content: definition.prompt.content, })), @@ -55,7 +55,7 @@ export const useTamagotchiPluginToolsStore = defineStore('tamagotchi-plugin-tool description: definition.description, parameters: definition.parameters, execute: async input => invokePluginTool({ - ownerPluginId: definition.ownerPluginId, + ownerExtensionId: definition.ownerExtensionId, name: definition.name, input, }), diff --git a/apps/stage-tamagotchi/src/renderer/stores/tools/builtin/widgets.test.ts b/apps/stage-tamagotchi/src/renderer/stores/tools/builtin/widgets.test.ts index cc995dceb..0886ae1b8 100644 --- a/apps/stage-tamagotchi/src/renderer/stores/tools/builtin/widgets.test.ts +++ b/apps/stage-tamagotchi/src/renderer/stores/tools/builtin/widgets.test.ts @@ -571,7 +571,7 @@ describe('widgets tool helpers', () => { moduleSnapshot: { moduleId: 'module-1', ownerSessionId: 'session-1', - ownerPluginId: 'plugin-1', + ownerExtensionId: 'plugin-1', kitId: 'kit.widget', kitModuleType: 'window', state: 'active', diff --git a/apps/stage-tamagotchi/src/shared/eventa/index.ts b/apps/stage-tamagotchi/src/shared/eventa/index.ts index 79080eece..82f4b40d6 100644 --- a/apps/stage-tamagotchi/src/shared/eventa/index.ts +++ b/apps/stage-tamagotchi/src/shared/eventa/index.ts @@ -142,7 +142,7 @@ export interface WidgetSnapshot { } export interface PluginManifestSummary { - name: string + extensionId: string entrypoints: Record path: string enabled: boolean @@ -173,7 +173,7 @@ export interface PluginCapabilityState { export interface PluginHostSessionSummary { id: string - manifestName: string + extensionId: string phase: string runtime: 'electron' | 'node' | 'web' moduleId: string diff --git a/apps/stage-tamagotchi/src/shared/eventa/plugin/host.ts b/apps/stage-tamagotchi/src/shared/eventa/plugin/host.ts index 792521541..6efb2cd2a 100644 --- a/apps/stage-tamagotchi/src/shared/eventa/plugin/host.ts +++ b/apps/stage-tamagotchi/src/shared/eventa/plugin/host.ts @@ -58,7 +58,7 @@ export interface PluginModuleWidgetPayload { * - N/A */ export interface PluginManifestSummary { - name: string + extensionId: string entrypoints: Record path: string enabled: boolean @@ -98,7 +98,7 @@ export interface PluginRegistrySnapshot { */ export interface PluginHostSessionSummary { id: string - manifestName: string + extensionId: string phase: string runtime: 'electron' | 'node' | 'web' moduleId: string @@ -155,7 +155,7 @@ export interface PluginHostKitSummary { export interface PluginHostModuleSummary { moduleId: string ownerSessionId: string - ownerPluginId: string + ownerExtensionId: string kitId: string kitModuleType: string state: 'announced' | 'active' | 'degraded' | 'withdrawn' @@ -187,9 +187,9 @@ export interface PluginHostDebugSnapshot { } export const electronPluginList = defineInvokeEventa('eventa:invoke:electron:plugins:list') -export const electronPluginSetEnabled = defineInvokeEventa('eventa:invoke:electron:plugins:set-enabled') -export const electronPluginSetAutoReload = defineInvokeEventa('eventa:invoke:electron:plugins:set-auto-reload') +export const electronPluginSetEnabled = defineInvokeEventa('eventa:invoke:electron:plugins:set-enabled') +export const electronPluginSetAutoReload = defineInvokeEventa('eventa:invoke:electron:plugins:set-auto-reload') export const electronPluginLoadEnabled = defineInvokeEventa('eventa:invoke:electron:plugins:load-enabled') -export const electronPluginLoad = defineInvokeEventa('eventa:invoke:electron:plugins:load') -export const electronPluginUnload = defineInvokeEventa('eventa:invoke:electron:plugins:unload') +export const electronPluginLoad = defineInvokeEventa('eventa:invoke:electron:plugins:load') +export const electronPluginUnload = defineInvokeEventa('eventa:invoke:electron:plugins:unload') export const electronPluginInspect = defineInvokeEventa('eventa:invoke:electron:plugins:inspect') diff --git a/apps/stage-tamagotchi/src/shared/eventa/plugin/tools.ts b/apps/stage-tamagotchi/src/shared/eventa/plugin/tools.ts index fdf83094a..56475c81f 100644 --- a/apps/stage-tamagotchi/src/shared/eventa/plugin/tools.ts +++ b/apps/stage-tamagotchi/src/shared/eventa/plugin/tools.ts @@ -35,7 +35,7 @@ export interface ElectronPluginToolDescriptor { * - N/A */ export interface ElectronPluginXsaiToolDefinition { - ownerPluginId: string + ownerExtensionId: string name: string description: string parameters: Record @@ -54,7 +54,7 @@ export interface ElectronPluginXsaiToolDefinition { * - N/A */ export interface ElectronPluginToolsetPromptDefinition { - ownerPluginId: string + ownerExtensionId: string id: string prompt: { id: string @@ -87,20 +87,20 @@ export interface ElectronPluginXsaiToolsetDefinition { * - The main process notifies renderers after plugin lifecycle changes * * Expects: - * - `name` is present when the change is scoped to one plugin + * - `extensionId` is present when the change is scoped to one extension * * Returns: * - N/A */ export interface ElectronPluginToolsChangedPayload { reason: 'loaded' | 'load-enabled' | 'unloaded' | 'enabled-state-changed' - name?: string + extensionId?: string } export const electronPluginListAgentTools = defineInvokeEventa('eventa:invoke:electron:plugins:tools:list') export const electronPluginListXsaiTools = defineInvokeEventa('eventa:invoke:electron:plugins:tools:list-xsai') export const electronPluginInvokeTool = defineInvokeEventa('eventa:invoke:electron:plugins:tools:invoke') diff --git a/packages/plugin-sdk-tamagotchi/src/index.test.ts b/packages/plugin-sdk-tamagotchi/src/index.test.ts index ddc811b52..65dc5e615 100644 --- a/packages/plugin-sdk-tamagotchi/src/index.test.ts +++ b/packages/plugin-sdk-tamagotchi/src/index.test.ts @@ -467,7 +467,7 @@ describe('plugin-sdk-tamagotchi', () => { registry.register({ ownerSessionId: 'session-1', - ownerPluginId: 'airi-extension-chess', + ownerExtensionId: 'airi-extension-chess', ownerModuleId: 'chess', tool: { id: 'play_chess', @@ -486,7 +486,7 @@ describe('plugin-sdk-tamagotchi', () => { }) registry.registerToolsetPrompt({ ownerSessionId: 'session-1', - ownerPluginId: 'airi-extension-chess', + ownerExtensionId: 'airi-extension-chess', ownerModuleId: 'chess', toolset: { id: 'chess-tools', @@ -508,7 +508,7 @@ describe('plugin-sdk-tamagotchi', () => { }]) await expect(registry.listSerializedXsaiTools()).resolves.toEqual({ prompts: [{ - ownerPluginId: 'airi-extension-chess', + ownerExtensionId: 'airi-extension-chess', id: 'chess-tools', prompt: { id: 'airi-plugin-game-chess.prompt', @@ -516,7 +516,7 @@ describe('plugin-sdk-tamagotchi', () => { }, }], tools: [{ - ownerPluginId: 'airi-extension-chess', + ownerExtensionId: 'airi-extension-chess', name: 'play_chess', description: 'Open chess.', parameters: { diff --git a/packages/plugin-sdk-tamagotchi/src/tools/registry.ts b/packages/plugin-sdk-tamagotchi/src/tools/registry.ts index e61653c14..6cdf94c5d 100644 --- a/packages/plugin-sdk-tamagotchi/src/tools/registry.ts +++ b/packages/plugin-sdk-tamagotchi/src/tools/registry.ts @@ -17,7 +17,7 @@ export interface RegisteredPluginToolDescriptor { * Describes the JSON-schema side of an xsai-compatible Tamagotchi extension tool. */ export interface SerializedXsaiToolDefinition { - ownerPluginId: string + ownerExtensionId: string name: string description: string parameters: HostDataRecord @@ -36,7 +36,7 @@ export interface ToolsetPromptManifest { * Captures one registered toolset prompt with extension ownership metadata. */ export interface SerializedToolsetPromptDefinition { - ownerPluginId: string + ownerExtensionId: string id: string prompt: ToolsetPromptManifest } @@ -76,7 +76,7 @@ export interface PluginToolsetPromptDefinitionRecord { */ export interface ToolRegistryRecord { ownerSessionId: string - ownerPluginId: string + ownerExtensionId: string ownerModuleId?: string tool: PluginToolDefinitionRecord availability?: () => Promise | boolean @@ -88,7 +88,7 @@ export interface ToolRegistryRecord { */ export interface ToolsetPromptRegistryRecord { ownerSessionId: string - ownerPluginId: string + ownerExtensionId: string ownerModuleId?: string toolset: PluginToolsetPromptDefinitionRecord availability?: () => Promise | boolean @@ -112,23 +112,23 @@ export class TamagotchiToolRegistry { private readonly toolsetPrompts = new Map() register(record: ToolRegistryRecord) { - const key = `${record.ownerPluginId}:${record.tool.id}` + const key = `${record.ownerExtensionId}:${record.tool.id}` this.tools.set(key, record) return record } registerToolsetPrompt(record: ToolsetPromptRegistryRecord) { - const key = `${record.ownerPluginId}:${record.toolset.id}` + const key = `${record.ownerExtensionId}:${record.toolset.id}` this.toolsetPrompts.set(key, record) return record } - unregister(ownerPluginId: string, toolId: string) { - return this.tools.delete(`${ownerPluginId}:${toolId}`) + unregister(ownerExtensionId: string, toolId: string) { + return this.tools.delete(`${ownerExtensionId}:${toolId}`) } - unregisterToolsetPrompt(ownerPluginId: string, toolsetId: string) { - return this.toolsetPrompts.delete(`${ownerPluginId}:${toolsetId}`) + unregisterToolsetPrompt(ownerExtensionId: string, toolsetId: string) { + return this.toolsetPrompts.delete(`${ownerExtensionId}:${toolsetId}`) } unregisterOwnerSession(ownerSessionId: string) { @@ -195,7 +195,7 @@ export class TamagotchiToolRegistry { } prompts.push({ - ownerPluginId: record.ownerPluginId, + ownerExtensionId: record.ownerExtensionId, id: record.toolset.id, prompt: structuredClone(record.toolset.prompt), }) @@ -213,7 +213,7 @@ export class TamagotchiToolRegistry { } items.push({ - ownerPluginId: record.ownerPluginId, + ownerExtensionId: record.ownerExtensionId, name: record.tool.id, description: record.tool.description, parameters: structuredClone(record.tool.parameters), @@ -226,8 +226,8 @@ export class TamagotchiToolRegistry { } } - async invoke(ownerPluginId: string, toolId: string, input: unknown) { - const key = `${ownerPluginId}:${toolId}` + async invoke(ownerExtensionId: string, toolId: string, input: unknown) { + const key = `${ownerExtensionId}:${toolId}` const record = this.tools.get(key) if (!record) { throw new Error(`Tamagotchi extension tool not found: ${key}`) diff --git a/packages/plugin-sdk/src/plugin-host/core.ts b/packages/plugin-sdk/src/plugin-host/core.ts index 322f019ea..934954fc3 100644 --- a/packages/plugin-sdk/src/plugin-host/core.ts +++ b/packages/plugin-sdk/src/plugin-host/core.ts @@ -665,7 +665,7 @@ export class ExtensionHost { return cloneBindingRecord(this.modules.bind({ ...input, ownerSessionId: session.id, - ownerPluginId: session.extension.id, + ownerExtensionId: session.extension.id, runtime: session.runtime ?? this.runtime, }) as BindingRecord) } @@ -763,7 +763,7 @@ export class ExtensionHost { const binding = cloneBindingRecord(this.modules.bind({ ...input, ownerSessionId: session.id, - ownerPluginId: session.extension.id, + ownerExtensionId: session.extension.id, runtime: this.runtime, }) as BindingRecord) diff --git a/packages/plugin-sdk/src/plugin-host/runtimes/shared/services/kit-api-bindings.test.ts b/packages/plugin-sdk/src/plugin-host/runtimes/shared/services/kit-api-bindings.test.ts index 1c97bacae..1bd7205d3 100644 --- a/packages/plugin-sdk/src/plugin-host/runtimes/shared/services/kit-api-bindings.test.ts +++ b/packages/plugin-sdk/src/plugin-host/runtimes/shared/services/kit-api-bindings.test.ts @@ -9,7 +9,7 @@ describe('kitApiBindingRegistryService', () => { const binding = service.bind({ moduleId: 'chess-gamelet', ownerSessionId: 'session-1', - ownerPluginId: 'airi-extension-chess', + ownerExtensionId: 'airi-extension-chess', kitId: 'kit.gamelet', kitModuleType: 'gamelet', config: { title: 'Chess' }, @@ -26,7 +26,7 @@ describe('kitApiBindingRegistryService', () => { service.bind({ moduleId: 'm1', ownerSessionId: 'session-a', - ownerPluginId: 'plugin-a', + ownerExtensionId: 'plugin-a', kitId: 'kit.widget', kitModuleType: 'panel', config: {}, @@ -42,7 +42,7 @@ describe('kitApiBindingRegistryService', () => { const announced = service.bind({ moduleId: 'm2', ownerSessionId: 'session-a', - ownerPluginId: 'plugin-a', + ownerExtensionId: 'plugin-a', kitId: 'kit.widget', kitModuleType: 'panel', config: { mountPoint: 'widgets' }, @@ -67,7 +67,7 @@ describe('kitApiBindingRegistryService', () => { service.bind({ moduleId: 'm3', ownerSessionId: 'session-a', - ownerPluginId: 'plugin-a', + ownerExtensionId: 'plugin-a', kitId: 'kit.widget', kitModuleType: 'panel', config: {}, @@ -85,7 +85,7 @@ describe('kitApiBindingRegistryService', () => { service.bind({ moduleId: 'm4', ownerSessionId: 'session-a', - ownerPluginId: 'plugin-a', + ownerExtensionId: 'plugin-a', kitId: 'kit.widget', kitModuleType: 'panel', config: {}, @@ -96,7 +96,7 @@ describe('kitApiBindingRegistryService', () => { service.bind({ moduleId: 'm4', ownerSessionId: 'session-b', - ownerPluginId: 'plugin-b', + ownerExtensionId: 'plugin-b', kitId: 'kit.widget', kitModuleType: 'panel', config: {}, @@ -111,7 +111,7 @@ describe('kitApiBindingRegistryService', () => { const original = service.bind({ moduleId: 'm5', ownerSessionId: 'session-a', - ownerPluginId: 'plugin-a', + ownerExtensionId: 'plugin-a', kitId: 'kit.widget', kitModuleType: 'panel', config: { mountPoint: 'widgets' }, @@ -121,7 +121,7 @@ describe('kitApiBindingRegistryService', () => { const duplicate = service.bind({ moduleId: 'm5', ownerSessionId: 'session-a', - ownerPluginId: 'plugin-a', + ownerExtensionId: 'plugin-a', kitId: 'kit.widget', kitModuleType: 'dialog', config: { mountPoint: 'mutated', width: 480 }, @@ -140,7 +140,7 @@ describe('kitApiBindingRegistryService', () => { service.bind({ moduleId: 'm6', ownerSessionId: 'session-a', - ownerPluginId: 'plugin-a', + ownerExtensionId: 'plugin-a', kitId: 'kit.widget', kitModuleType: 'panel', config: {}, @@ -151,7 +151,7 @@ describe('kitApiBindingRegistryService', () => { service.bind({ moduleId: 'm6', ownerSessionId: 'session-a', - ownerPluginId: 'plugin-b', + ownerExtensionId: 'plugin-b', kitId: 'kit.widget', kitModuleType: 'panel', config: {}, @@ -166,7 +166,7 @@ describe('kitApiBindingRegistryService', () => { service.bind({ moduleId: 'm7', ownerSessionId: 'session-a', - ownerPluginId: 'plugin-a', + ownerExtensionId: 'plugin-a', kitId: 'kit.widget', kitModuleType: 'panel', config: {}, diff --git a/packages/plugin-sdk/src/plugin-host/runtimes/shared/services/kit-api-bindings.ts b/packages/plugin-sdk/src/plugin-host/runtimes/shared/services/kit-api-bindings.ts index b8f36deb0..14bffed39 100644 --- a/packages/plugin-sdk/src/plugin-host/runtimes/shared/services/kit-api-bindings.ts +++ b/packages/plugin-sdk/src/plugin-host/runtimes/shared/services/kit-api-bindings.ts @@ -20,7 +20,7 @@ import type { HostDataRecord, PluginRuntime } from '../../../shared/types' export interface BindingInput { moduleId: string ownerSessionId: string - ownerPluginId: string + ownerExtensionId: string kitId: string kitModuleType: string runtime: PluginRuntime @@ -55,14 +55,14 @@ export interface BindingUpdatePatch { * * Expects: * - `ownerSessionId` is the ephemeral runtime session id - * - `ownerPluginId` is the stable plugin identity across sessions + * - `ownerExtensionId` is the stable extension identity across sessions * * Returns: * - A compact identity tuple used in collision and ownership checks */ export interface BindingOwnerIdentity { ownerSessionId: string - ownerPluginId: string + ownerExtensionId: string } const allowedBindingTransitions: Record = { @@ -78,7 +78,7 @@ function createOwnershipError( actual: BindingOwnerIdentity, ) { return new Error( - `Ownership violation for module \`${moduleId}\`: owned by \`${expected.ownerSessionId}/${expected.ownerPluginId}\`, not \`${actual.ownerSessionId}/${actual.ownerPluginId}\`.`, + `Ownership violation for module \`${moduleId}\`: owned by \`${expected.ownerSessionId}/${expected.ownerExtensionId}\`, not \`${actual.ownerSessionId}/${actual.ownerExtensionId}\`.`, ) } @@ -88,7 +88,7 @@ function createModuleCollisionError( actual: BindingOwnerIdentity, ) { return new Error( - `Module id collision for \`${moduleId}\`: owned by \`${expected.ownerSessionId}/${expected.ownerPluginId}\`, not \`${actual.ownerSessionId}/${actual.ownerPluginId}\`.`, + `Module id collision for \`${moduleId}\`: owned by \`${expected.ownerSessionId}/${expected.ownerExtensionId}\`, not \`${actual.ownerSessionId}/${actual.ownerExtensionId}\`.`, ) } @@ -192,17 +192,17 @@ export class KitApiBindingRegistryService = { moduleId: input.moduleId, ownerSessionId: input.ownerSessionId, - ownerPluginId: input.ownerPluginId, + ownerExtensionId: input.ownerExtensionId, kitId: input.kitId, kitModuleType: input.kitModuleType, state: 'announced', @@ -343,8 +343,8 @@ export class KitApiBindingRegistryService) { - return this.transition({ ownerSessionId, ownerPluginId }, moduleId, patch.state, patch) + update(ownerSessionId: string, ownerExtensionId: string, moduleId: string, patch: BindingUpdatePatch) { + return this.transition({ ownerSessionId, ownerExtensionId }, moduleId, patch.state, patch) } /** @@ -359,8 +359,8 @@ export class KitApiBindingRegistryService { const parsed = parse(bindingRecordSchema, { moduleId: 'board-main', ownerSessionId: 'extension-session-1', - ownerPluginId: 'demo-plugin', + ownerExtensionId: 'demo-plugin', kitId: 'kit.widget', kitModuleType: 'panel', state: 'announced', @@ -27,7 +27,7 @@ describe('bindingRecordSchema', () => { parse(bindingRecordSchema, { moduleId: 'board-main', ownerSessionId: 'extension-session-1', - ownerPluginId: 'demo-plugin', + ownerExtensionId: 'demo-plugin', kitId: 'kit.widget', kitModuleType: 'panel', state: 'booting', @@ -44,7 +44,7 @@ describe('bindingRecordSchema', () => { parse(bindingRecordSchema, { moduleId: 'board-main', ownerSessionId: 'extension-session-1', - ownerPluginId: 'demo-plugin', + ownerExtensionId: 'demo-plugin', kitId: 'kit.widget', kitModuleType: 'panel', state: 'announced', @@ -65,7 +65,7 @@ describe('bindingRecordSchema', () => { parse(bindingRecordSchema, { moduleId: 'board-main', ownerSessionId: 'extension-session-1', - ownerPluginId: 'demo-plugin', + ownerExtensionId: 'demo-plugin', kitId: 'kit.widget', kitModuleType: 'panel', state: 'announced', diff --git a/packages/plugin-sdk/src/plugin-host/shared/bindings.ts b/packages/plugin-sdk/src/plugin-host/shared/bindings.ts index 42ca0cc48..0937f5f30 100644 --- a/packages/plugin-sdk/src/plugin-host/shared/bindings.ts +++ b/packages/plugin-sdk/src/plugin-host/shared/bindings.ts @@ -36,7 +36,7 @@ export const bindingStateValues = ['announced', 'active', 'degraded', 'withdrawn export const bindingRecordSchema = object({ moduleId: string(), ownerSessionId: string(), - ownerPluginId: string(), + ownerExtensionId: string(), kitId: string(), kitModuleType: string(), state: picklist(bindingStateValues), @@ -76,7 +76,7 @@ export type BindingState = typeof bindingStateValues[number] export interface BindingRecord { moduleId: string ownerSessionId: string - ownerPluginId: string + ownerExtensionId: string kitId: string kitModuleType: string state: BindingState diff --git a/packages/stage-pages/src/pages/devtools/plugin-host.vue b/packages/stage-pages/src/pages/devtools/plugin-host.vue index 9aabf130e..b089f2095 100644 --- a/packages/stage-pages/src/pages/devtools/plugin-host.vue +++ b/packages/stage-pages/src/pages/devtools/plugin-host.vue @@ -13,15 +13,15 @@ import { toast } from 'vue-sonner' const store = usePluginHostInspectorStore() const filter = ref('') -const selectedPluginName = ref('') +const selectedExtensionId = ref('') const discoveredPlugins = computed(() => { const query = filter.value.trim().toLowerCase() - const plugins = store.discoveredPlugins.slice().sort((left, right) => left.name.localeCompare(right.name)) + const plugins = store.discoveredPlugins.slice().sort((left, right) => left.extensionId.localeCompare(right.extensionId)) if (!query) return plugins return plugins.filter(plugin => - plugin.name.toLowerCase().includes(query) + plugin.extensionId.toLowerCase().includes(query) || plugin.path.toLowerCase().includes(query), ) }) @@ -34,10 +34,10 @@ const loadedPlugins = computed(() => { return discoveredPlugins.value.filter(plugin => plugin.loaded) }) -const sessionByPluginName = computed(() => { +const sessionByExtensionId = computed(() => { const map = new Map() for (const session of store.sessions) { - map.set(session.manifestName, session) + map.set(session.extensionId, session) } return map }) @@ -110,58 +110,58 @@ async function loadEnabled() { async function setAutoReload(plugin: PluginManifestSummary, enabled: boolean) { try { await store.setAutoReload({ - name: plugin.name, + extensionId: plugin.extensionId, enabled, }) } catch (error) { - toast.error(errorMessageFrom(error) ?? `Failed to update auto-reload state for ${plugin.name}.`) + toast.error(errorMessageFrom(error) ?? `Failed to update auto-reload state for ${plugin.extensionId}.`) } } async function setEnabled(plugin: PluginManifestSummary, enabled: boolean) { try { await store.setEnabled({ - name: plugin.name, + extensionId: plugin.extensionId, enabled, path: plugin.path, }) } catch (error) { - toast.error(errorMessageFrom(error) ?? `Failed to update enabled state for ${plugin.name}.`) + toast.error(errorMessageFrom(error) ?? `Failed to update enabled state for ${plugin.extensionId}.`) } } async function loadPlugin(plugin: PluginManifestSummary) { try { - await store.load({ name: plugin.name }) + await store.load({ extensionId: plugin.extensionId }) } catch (error) { - toast.error(errorMessageFrom(error) ?? `Failed to load plugin ${plugin.name}.`) + toast.error(errorMessageFrom(error) ?? `Failed to load plugin ${plugin.extensionId}.`) } } async function unloadPlugin(plugin: PluginManifestSummary) { try { - await store.unload({ name: plugin.name }) + await store.unload({ extensionId: plugin.extensionId }) } catch (error) { - toast.error(errorMessageFrom(error) ?? `Failed to unload plugin ${plugin.name}.`) + toast.error(errorMessageFrom(error) ?? `Failed to unload plugin ${plugin.extensionId}.`) } } async function loadSelectedPlugin() { - const name = selectedPluginName.value.trim() - if (!name) { - toast.error('Enter a plugin name to load.') + const extensionId = selectedExtensionId.value.trim() + if (!extensionId) { + toast.error('Enter an extension id to load.') return } try { - await store.load({ name }) + await store.load({ extensionId }) } catch (error) { - toast.error(errorMessageFrom(error) ?? `Failed to load plugin ${name}.`) + toast.error(errorMessageFrom(error) ?? `Failed to load plugin ${extensionId}.`) } } @@ -253,15 +253,15 @@ onMounted(async () => {
@@ -375,7 +375,7 @@ onMounted(async () => { :key="`enabled-${plugin.path}`" :class="['rounded-full', 'border', 'px-2', 'py-0.5', 'text-xs', ...chipClasses('emerald')]" > - {{ plugin.name }} + {{ plugin.extensionId }} @@ -395,9 +395,9 @@ onMounted(async () => { :class="['rounded-lg', 'bg-neutral-100', 'p-2', 'dark:bg-neutral-900/70']" >
- {{ plugin.name }} - - {{ sessionByPluginName.get(plugin.name)?.phase ?? 'unknown' }} + {{ plugin.extensionId }} + + {{ sessionByExtensionId.get(plugin.extensionId)?.phase ?? 'unknown' }}
diff --git a/packages/stage-ui/src/stores/devtools/plugin-host-debug.ts b/packages/stage-ui/src/stores/devtools/plugin-host-debug.ts index 9ac4d57fa..e63cdd035 100644 --- a/packages/stage-ui/src/stores/devtools/plugin-host-debug.ts +++ b/packages/stage-ui/src/stores/devtools/plugin-host-debug.ts @@ -3,7 +3,7 @@ import { defineStore } from 'pinia' import { computed, ref } from 'vue' export interface PluginManifestSummary { - name: string + extensionId: string entrypoints: Record path: string enabled: boolean @@ -28,7 +28,7 @@ export interface PluginCapabilityState { export interface PluginHostSessionSummary { id: string - manifestName: string + extensionId: string phase: string runtime: 'electron' | 'node' | 'web' moduleId: string @@ -49,7 +49,7 @@ export interface PluginHostKitSummary { export interface PluginHostModuleSummary { moduleId: string ownerSessionId: string - ownerPluginId: string + ownerExtensionId: string kitId: string kitModuleType: string state: 'announced' | 'active' | 'degraded' | 'withdrawn' @@ -70,11 +70,11 @@ export interface PluginHostDebugSnapshot { interface PluginHostDebugBridge { list: () => Promise - setEnabled: (payload: { name: string, enabled: boolean, path?: string }) => Promise - setAutoReload: (payload: { name: string, enabled: boolean }) => Promise + setEnabled: (payload: { extensionId: string, enabled: boolean, path?: string }) => Promise + setAutoReload: (payload: { extensionId: string, enabled: boolean }) => Promise loadEnabled: () => Promise - load: (payload: { name: string }) => Promise - unload: (payload: { name: string }) => Promise + load: (payload: { extensionId: string }) => Promise + unload: (payload: { extensionId: string }) => Promise inspect: () => Promise } @@ -171,14 +171,14 @@ export const usePluginHostInspectorStore = defineStore('devtools:plugin-host-deb return refreshInspection() } - async function setEnabled(payload: { name: string, enabled: boolean, path?: string }) { + async function setEnabled(payload: { extensionId: string, enabled: boolean, path?: string }) { const nextRegistry = await withBridge(activeBridge => activeBridge.setEnabled(payload)) assignRegistry(nextRegistry) await refreshInspection() return nextRegistry } - async function setAutoReload(payload: { name: string, enabled: boolean }) { + async function setAutoReload(payload: { extensionId: string, enabled: boolean }) { const nextRegistry = await withBridge(activeBridge => activeBridge.setAutoReload(payload)) assignRegistry(nextRegistry) await refreshInspection() @@ -192,14 +192,14 @@ export const usePluginHostInspectorStore = defineStore('devtools:plugin-host-deb return nextRegistry } - async function load(payload: { name: string }) { + async function load(payload: { extensionId: string }) { const nextRegistry = await withBridge(activeBridge => activeBridge.load(payload)) assignRegistry(nextRegistry) await refreshInspection() return nextRegistry } - async function unload(payload: { name: string }) { + async function unload(payload: { extensionId: string }) { const nextRegistry = await withBridge(activeBridge => activeBridge.unload(payload)) assignRegistry(nextRegistry) await refreshInspection()