@agimon-ai/doompi 0.0.1-alpha.48 → 0.0.1-alpha.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/adapters/composer.cjs +1 -1
- package/dist/src/adapters/composer.cjs.map +1 -1
- package/dist/src/adapters/composer.d.cts.map +1 -1
- package/dist/src/adapters/composer.d.mts.map +1 -1
- package/dist/src/adapters/composer.mjs +1 -1
- package/dist/src/adapters/composer.mjs.map +1 -1
- package/dist/src/adapters/config/harnessState.d.mts +2 -2
- package/dist/src/adapters/piExtensionDispatcher.cjs +1 -1
- package/dist/src/adapters/piExtensionDispatcher.cjs.map +1 -1
- package/dist/src/adapters/piExtensionDispatcher.mjs +1 -1
- package/dist/src/adapters/piExtensionDispatcher.mjs.map +1 -1
- package/dist/src/commands/syncCommand.cjs +7 -6
- package/dist/src/commands/syncCommand.cjs.map +1 -1
- package/dist/src/commands/syncCommand.d.cts.map +1 -1
- package/dist/src/commands/syncCommand.d.mts.map +1 -1
- package/dist/src/commands/syncCommand.mjs +7 -6
- package/dist/src/commands/syncCommand.mjs.map +1 -1
- package/dist/src/extensions/entries/modeCatalog.cjs +1 -1
- package/dist/src/extensions/entries/modeCatalog.cjs.map +1 -1
- package/dist/src/extensions/entries/modeCatalog.d.cts.map +1 -1
- package/dist/src/extensions/entries/modeCatalog.d.mts.map +1 -1
- package/dist/src/extensions/entries/modeCatalog.mjs +1 -1
- package/dist/src/extensions/entries/modeCatalog.mjs.map +1 -1
- package/dist/src/services/contextCatalog.cjs +2 -0
- package/dist/src/services/contextCatalog.cjs.map +1 -0
- package/dist/src/services/contextCatalog.mjs +2 -0
- package/dist/src/services/contextCatalog.mjs.map +1 -0
- package/dist/src/services/contextProjection.cjs +2 -0
- package/dist/src/services/contextProjection.cjs.map +1 -0
- package/dist/src/services/contextProjection.mjs +2 -0
- package/dist/src/services/contextProjection.mjs.map +1 -0
- package/dist/src/services/extensionAssembler.cjs +1 -1
- package/dist/src/services/extensionAssembler.cjs.map +1 -1
- package/dist/src/services/extensionAssembler.d.cts +19 -1
- package/dist/src/services/extensionAssembler.d.cts.map +1 -1
- package/dist/src/services/extensionAssembler.d.mts +19 -1
- package/dist/src/services/extensionAssembler.d.mts.map +1 -1
- package/dist/src/services/extensionAssembler.mjs +1 -1
- package/dist/src/services/extensionAssembler.mjs.map +1 -1
- package/package.json +13 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modeCatalog.cjs","names":["readDoomNotificationService","connectDoomCordisHost","DOOM_HELP_SERVICE","requireDoomHelpService","DOOM_CORDIS_SESSION_SERVICE","DOOM_TRANSITION_SERVICE","requireDoomTransitionCoordinator","consumeMinorModeReloadHandoff","createMinorModeCatalogHost","DOOM_MINOR_MODE_CATALOG_SERVICE","projectMinorModes","DOOM_MINOR_MODE_ENTRY_TYPE"],"sources":["../../../../src/extensions/entries/modeCatalog.ts"],"sourcesContent":["import {\n DOOM_MINOR_MODE_CATALOG_SERVICE,\n DOOM_MINOR_MODE_ENTRY_TYPE,\n type MinorModeActionResponse,\n type MinorModeCatalogService,\n} from '@agimon-ai/doompi-extension-contracts/mode';\nimport {\n connectDoomCordisHost,\n DOOM_CORDIS_SESSION_SERVICE,\n type DoomCordisSessionService,\n} from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_HELP_SERVICE, requireDoomHelpService } from '@agimon-ai/doompi-extension-contracts/help';\nimport {\n type DoomNotificationLevel,\n readDoomNotificationService,\n} from '@agimon-ai/doompi-extension-contracts/notification';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport {\n consumeMinorModeReloadHandoff,\n discardMinorModeReloadHandoff,\n type MinorModeCatalogHost,\n DOOM_TRANSITION_SERVICE,\n requireDoomTransitionCoordinator,\n type TransitionSource,\n} from '@agimon-ai/doompi-extension-contracts/transition';\nimport type { Context } from '@deepseek-ai/cordis';\nimport { projectMinorModes } from '../../services/minorModeProjection.ts';\nimport { createMinorModeCatalogHost } from '../../services/modeCatalog.ts';\nimport { registerMinorModeCommand } from './minorModeCommand.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi/mode-catalog';\nconst HELP_CONTRIBUTION_SOURCE = '@agimon-ai/doompi';\n/** Registrations and state flips arrive in bursts; one entry covers a burst. */\nconst PROJECTION_SETTLE_MS = 50;\n/**\n * Pi's rpc mode subscribes to session events only after bindExtensions()\n * returns, which is after session_start has run, so an entry journaled during\n * startup never reaches a client. A publish deferred past that point does.\n */\nconst BOOT_PUBLISH_DELAY_MS = 500;\n\ninterface CatalogBinding {\n current: MinorModeCatalogService | undefined;\n /** Journals the projection even if unchanged; set while a session is bound. */\n republish?: () => void;\n}\n\nfunction notify(cordis: Context, context: ExtensionContext, body: string, level: DoomNotificationLevel): void {\n const service = readDoomNotificationService(cordis);\n if (service) {\n try {\n void Promise.resolve(service.request({ body, level })).catch(() => undefined);\n } catch {\n // Notification delivery is best effort and does not fall back after routing.\n }\n return;\n }\n context.ui.notify(body, level);\n}\n\nfunction transitionSource(requesterSource: string): TransitionSource {\n if (requesterSource.includes('voice')) return 'voice';\n if (requesterSource.includes('leader')) return 'leader';\n if (requesterSource.includes('ui')) return 'ui';\n return 'system';\n}\n\nexport async function modeCatalogExtension(pi: ExtensionAPI): Promise<void> {\n // The command outlives any one session: it is registered once and reads the\n // catalog binding the session-scoped inject below sets and clears.\n const activeCatalog: CatalogBinding = { current: undefined };\n registerMinorModeCommand(pi, () => activeCatalog.current);\n pi.on('session_start', () => {\n setTimeout(() => activeCatalog.republish?.(), BOOT_PUBLISH_DELAY_MS);\n });\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin((cordis: Context) => {\n modeCatalogPlugin(cordis, pi, activeCatalog);\n });\n try {\n await fiber;\n } catch (error) {\n await fiber.dispose();\n await connection.dispose();\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\nfunction modeCatalogPlugin(\n cordis: Context,\n pi: Pick<ExtensionAPI, 'appendEntry'>,\n activeCatalog: CatalogBinding,\n): void {\n cordis.inject([DOOM_HELP_SERVICE], (helpContext) => {\n const contribution = requireDoomHelpService(helpContext).register({\n source: HELP_CONTRIBUTION_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-author-extension',\n description:\n 'Create or update a DoomPi extension package inside the DoomPi monorepo or as an external npm package. Use for package layout, Pi discovery entries, shared Cordis lifecycle, package-owned Help, and extension verification.',\n },\n ],\n });\n return () => contribution.dispose();\n });\n\n cordis.inject([DOOM_CORDIS_SESSION_SERVICE, DOOM_TRANSITION_SERVICE], (sessionContext) => {\n const session = sessionContext.get(DOOM_CORDIS_SESSION_SERVICE) as DoomCordisSessionService;\n const context = session.context;\n const coordinator = requireDoomTransitionCoordinator(sessionContext);\n const reloadSession = session.reason === 'reload';\n const sessionId = session.sessionId;\n const restoreSnapshot = reloadSession ? consumeMinorModeReloadHandoff(sessionId) : undefined;\n if (!reloadSession) discardMinorModeReloadHandoff(sessionId);\n const sessionKind = context.hasUI && context.mode === 'tui' ? 'tui' : 'headless';\n const catalog: MinorModeCatalogHost = createMinorModeCatalogHost({\n sessionKind,\n context,\n restoreSnapshot,\n onRestorationError(error) {\n notify(\n sessionContext,\n context,\n `Could not restore a minor mode after reload: ${error instanceof Error ? error.message : String(error)}`,\n 'warning',\n );\n },\n async routeInvocation(request, requesterSource, invoke) {\n let response: MinorModeActionResponse | undefined;\n const result = await coordinator.execute(\n {\n sessionId: context.sessionManager.getSessionId(),\n hostGeneration: coordinator.hostGeneration,\n operationId: request.operationId,\n source: transitionSource(requesterSource),\n target: { axis: 'minor-mode', action: request, requesterSource },\n },\n async () => {\n response = await invoke();\n return 'applied';\n },\n );\n if (result.outcome !== 'applied' || !response) {\n throw new Error(`Minor-mode transition was ${result.outcome}: ${result.diagnostics.join(', ')}`);\n }\n return response;\n },\n });\n sessionContext.provide(DOOM_MINOR_MODE_CATALOG_SERVICE, catalog);\n activeCatalog.current = catalog;\n\n // Journal the projection so RPC clients see catalog state live and on\n // replay; identical projections are skipped so detail churn stays cheap.\n let published: string | undefined;\n let settle: NodeJS.Timeout | undefined;\n const publish = (): void => {\n settle = undefined;\n const projection = projectMinorModes(catalog.getSnapshot(), sessionKind);\n const serialized = JSON.stringify(projection);\n if (serialized === published) return;\n published = serialized;\n pi.appendEntry(DOOM_MINOR_MODE_ENTRY_TYPE, projection);\n };\n const unsubscribe = catalog.subscribe(() => {\n settle ??= setTimeout(publish, PROJECTION_SETTLE_MS);\n });\n activeCatalog.republish = () => {\n published = undefined;\n publish();\n };\n\n return () => {\n if (settle) clearTimeout(settle);\n unsubscribe();\n activeCatalog.republish = undefined;\n activeCatalog.current = undefined;\n catalog.dispose();\n };\n });\n}\n\nexport default modeCatalogExtension;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"modeCatalog.cjs","names":["readDoomNotificationService","connectDoomCordisHost","createContextPublisher","DOOM_HELP_SERVICE","requireDoomHelpService","DOOM_CORDIS_SESSION_SERVICE","DOOM_TRANSITION_SERVICE","requireDoomTransitionCoordinator","consumeMinorModeReloadHandoff","createMinorModeCatalogHost","DOOM_MINOR_MODE_CATALOG_SERVICE","projectMinorModes","DOOM_MINOR_MODE_ENTRY_TYPE"],"sources":["../../../../src/extensions/entries/modeCatalog.ts"],"sourcesContent":["import {\n DOOM_MINOR_MODE_CATALOG_SERVICE,\n DOOM_MINOR_MODE_ENTRY_TYPE,\n type MinorModeActionResponse,\n type MinorModeCatalogService,\n} from '@agimon-ai/doompi-extension-contracts/mode';\nimport {\n connectDoomCordisHost,\n DOOM_CORDIS_SESSION_SERVICE,\n type DoomCordisSessionService,\n} from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_HELP_SERVICE, requireDoomHelpService } from '@agimon-ai/doompi-extension-contracts/help';\nimport {\n type DoomNotificationLevel,\n readDoomNotificationService,\n} from '@agimon-ai/doompi-extension-contracts/notification';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport {\n consumeMinorModeReloadHandoff,\n discardMinorModeReloadHandoff,\n type MinorModeCatalogHost,\n DOOM_TRANSITION_SERVICE,\n requireDoomTransitionCoordinator,\n type TransitionSource,\n} from '@agimon-ai/doompi-extension-contracts/transition';\nimport type { Context } from '@deepseek-ai/cordis';\nimport { type ContextPublisher, createContextPublisher } from '../../services/contextCatalog.ts';\nimport { projectMinorModes } from '../../services/minorModeProjection.ts';\nimport { createMinorModeCatalogHost } from '../../services/modeCatalog.ts';\nimport { registerMinorModeCommand } from './minorModeCommand.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi/mode-catalog';\nconst HELP_CONTRIBUTION_SOURCE = '@agimon-ai/doompi';\n/** Registrations and state flips arrive in bursts; one entry covers a burst. */\nconst PROJECTION_SETTLE_MS = 50;\n/**\n * Pi's rpc mode subscribes to session events only after bindExtensions()\n * returns, which is after session_start has run, so an entry journaled during\n * startup never reaches a client. A publish deferred past that point does.\n */\nconst BOOT_PUBLISH_DELAY_MS = 500;\n\ninterface CatalogBinding {\n current: MinorModeCatalogService | undefined;\n /** Journals the projection even if unchanged; set while a session is bound. */\n republish?: () => void;\n}\n\nfunction notify(cordis: Context, context: ExtensionContext, body: string, level: DoomNotificationLevel): void {\n const service = readDoomNotificationService(cordis);\n if (service) {\n try {\n void Promise.resolve(service.request({ body, level })).catch(() => undefined);\n } catch {\n // Notification delivery is best effort and does not fall back after routing.\n }\n return;\n }\n context.ui.notify(body, level);\n}\n\nfunction transitionSource(requesterSource: string): TransitionSource {\n if (requesterSource.includes('voice')) return 'voice';\n if (requesterSource.includes('leader')) return 'leader';\n if (requesterSource.includes('ui')) return 'ui';\n return 'system';\n}\n\nexport async function modeCatalogExtension(pi: ExtensionAPI): Promise<void> {\n // The command outlives any one session: it is registered once and reads the\n // catalog binding the session-scoped inject below sets and clears.\n const activeCatalog: CatalogBinding = { current: undefined };\n registerMinorModeCommand(pi, () => activeCatalog.current);\n // The composition is only complete once every extension has registered, so\n // the inventory is read on the same deferred tick the catalog republishes on.\n const contextBinding: { publisher?: ContextPublisher } = {};\n pi.on('session_start', () => {\n setTimeout(() => {\n activeCatalog.republish?.();\n void contextBinding.publisher?.publish();\n }, BOOT_PUBLISH_DELAY_MS);\n });\n // MCP status is pull-only and servers connect long after startup, so the\n // boot read above cannot see them. A turn is the moment the composition is\n // actually sent, which makes it both the freshest and the most meaningful\n // time to price. Identical compositions are skipped, so a quiet session\n // journals nothing extra.\n pi.on('turn_start', () => {\n void contextBinding.publisher?.publish();\n });\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin((cordis: Context) => {\n contextBinding.publisher = createContextPublisher(pi, cordis);\n modeCatalogPlugin(cordis, pi, activeCatalog, () => void contextBinding.publisher?.publish());\n return () => {\n contextBinding.publisher?.dispose();\n contextBinding.publisher = undefined;\n };\n });\n try {\n await fiber;\n } catch (error) {\n await fiber.dispose();\n await connection.dispose();\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\nfunction modeCatalogPlugin(\n cordis: Context,\n pi: Pick<ExtensionAPI, 'appendEntry'>,\n activeCatalog: CatalogBinding,\n onCatalogChanged: () => void,\n): void {\n cordis.inject([DOOM_HELP_SERVICE], (helpContext) => {\n const contribution = requireDoomHelpService(helpContext).register({\n source: HELP_CONTRIBUTION_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-author-extension',\n description:\n 'Create or update a DoomPi extension package inside the DoomPi monorepo or as an external npm package. Use for package layout, Pi discovery entries, shared Cordis lifecycle, package-owned Help, and extension verification.',\n },\n ],\n });\n return () => contribution.dispose();\n });\n\n cordis.inject([DOOM_CORDIS_SESSION_SERVICE, DOOM_TRANSITION_SERVICE], (sessionContext) => {\n const session = sessionContext.get(DOOM_CORDIS_SESSION_SERVICE) as DoomCordisSessionService;\n const context = session.context;\n const coordinator = requireDoomTransitionCoordinator(sessionContext);\n const reloadSession = session.reason === 'reload';\n const sessionId = session.sessionId;\n const restoreSnapshot = reloadSession ? consumeMinorModeReloadHandoff(sessionId) : undefined;\n if (!reloadSession) discardMinorModeReloadHandoff(sessionId);\n const sessionKind = context.hasUI && context.mode === 'tui' ? 'tui' : 'headless';\n const catalog: MinorModeCatalogHost = createMinorModeCatalogHost({\n sessionKind,\n context,\n restoreSnapshot,\n onRestorationError(error) {\n notify(\n sessionContext,\n context,\n `Could not restore a minor mode after reload: ${error instanceof Error ? error.message : String(error)}`,\n 'warning',\n );\n },\n async routeInvocation(request, requesterSource, invoke) {\n let response: MinorModeActionResponse | undefined;\n const result = await coordinator.execute(\n {\n sessionId: context.sessionManager.getSessionId(),\n hostGeneration: coordinator.hostGeneration,\n operationId: request.operationId,\n source: transitionSource(requesterSource),\n target: { axis: 'minor-mode', action: request, requesterSource },\n },\n async () => {\n response = await invoke();\n return 'applied';\n },\n );\n if (result.outcome !== 'applied' || !response) {\n throw new Error(`Minor-mode transition was ${result.outcome}: ${result.diagnostics.join(', ')}`);\n }\n return response;\n },\n });\n sessionContext.provide(DOOM_MINOR_MODE_CATALOG_SERVICE, catalog);\n activeCatalog.current = catalog;\n\n // Journal the projection so RPC clients see catalog state live and on\n // replay; identical projections are skipped so detail churn stays cheap.\n let published: string | undefined;\n let settle: NodeJS.Timeout | undefined;\n const publish = (): void => {\n settle = undefined;\n const projection = projectMinorModes(catalog.getSnapshot(), sessionKind);\n const serialized = JSON.stringify(projection);\n if (serialized === published) return;\n published = serialized;\n pi.appendEntry(DOOM_MINOR_MODE_ENTRY_TYPE, projection);\n // A mode changing is the usual reason the toolbox changed too.\n onCatalogChanged();\n };\n const unsubscribe = catalog.subscribe(() => {\n settle ??= setTimeout(publish, PROJECTION_SETTLE_MS);\n });\n activeCatalog.republish = () => {\n published = undefined;\n publish();\n };\n\n return () => {\n if (settle) clearTimeout(settle);\n unsubscribe();\n activeCatalog.republish = undefined;\n activeCatalog.current = undefined;\n catalog.dispose();\n };\n });\n}\n\nexport default modeCatalogExtension;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modeCatalog.d.cts","names":[],"sources":["../../../../src/extensions/entries/modeCatalog.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"modeCatalog.d.cts","names":[],"sources":["../../../../src/extensions/entries/modeCatalog.ts"],"mappings":";;iBAoEsB,qBAAqB,IAAI,eAAe"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modeCatalog.d.mts","names":[],"sources":["../../../../src/extensions/entries/modeCatalog.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"modeCatalog.d.mts","names":[],"sources":["../../../../src/extensions/entries/modeCatalog.ts"],"mappings":";;iBAoEsB,qBAAqB,IAAI,eAAe"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createMinorModeCatalogHost as e}from"../../services/modeCatalog.mjs";import{
|
|
1
|
+
import{createMinorModeCatalogHost as e}from"../../services/modeCatalog.mjs";import{createContextPublisher as t}from"../../services/contextCatalog.mjs";import{projectMinorModes as n}from"../../services/minorModeProjection.mjs";import{registerMinorModeCommand as r}from"./minorModeCommand.mjs";import{DOOM_CORDIS_SESSION_SERVICE as i,connectDoomCordisHost as a}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{DOOM_MINOR_MODE_CATALOG_SERVICE as o,DOOM_MINOR_MODE_ENTRY_TYPE as s}from"@agimon-ai/doompi-extension-contracts/mode";import{DOOM_HELP_SERVICE as c,requireDoomHelpService as l}from"@agimon-ai/doompi-extension-contracts/help";import{readDoomNotificationService as u}from"@agimon-ai/doompi-extension-contracts/notification";import{DOOM_TRANSITION_SERVICE as d,consumeMinorModeReloadHandoff as f,discardMinorModeReloadHandoff as p,requireDoomTransitionCoordinator as m}from"@agimon-ai/doompi-extension-contracts/transition";function h(e,t,n,r){let i=u(e);if(i){try{Promise.resolve(i.request({body:n,level:r})).catch(()=>void 0)}catch{}return}t.ui.notify(n,r)}function g(e){return e.includes(`voice`)?`voice`:e.includes(`leader`)?`leader`:e.includes(`ui`)?`ui`:`system`}async function _(e){let n={current:void 0};r(e,()=>n.current);let i={};e.on(`session_start`,()=>{setTimeout(()=>{n.republish?.(),i.publisher?.publish()},500)}),e.on(`turn_start`,()=>{i.publisher?.publish()});let o=await a(e,`@agimon-ai/doompi/mode-catalog`),s=o.root.plugin(r=>(i.publisher=t(e,r),v(r,e,n,()=>void i.publisher?.publish()),()=>{i.publisher?.dispose(),i.publisher=void 0}));try{await s}catch(e){throw await s.dispose(),await o.dispose(),e}let c;e.on(`session_shutdown`,()=>c??=(async()=>{try{await s.dispose()}finally{await o.dispose()}})())}function v(t,r,a,u){t.inject([c],e=>{let t=l(e).register({source:`@agimon-ai/doompi`,moduleUrl:import.meta.url,skills:[{name:`doompi-author-extension`,description:`Create or update a DoomPi extension package inside the DoomPi monorepo or as an external npm package. Use for package layout, Pi discovery entries, shared Cordis lifecycle, package-owned Help, and extension verification.`}]});return()=>t.dispose()}),t.inject([i,d],t=>{let c=t.get(i),l=c.context,d=m(t),_=c.reason===`reload`,v=c.sessionId,y=_?f(v):void 0;_||p(v);let b=l.hasUI&&l.mode===`tui`?`tui`:`headless`,x=e({sessionKind:b,context:l,restoreSnapshot:y,onRestorationError(e){h(t,l,`Could not restore a minor mode after reload: ${e instanceof Error?e.message:String(e)}`,`warning`)},async routeInvocation(e,t,n){let r,i=await d.execute({sessionId:l.sessionManager.getSessionId(),hostGeneration:d.hostGeneration,operationId:e.operationId,source:g(t),target:{axis:`minor-mode`,action:e,requesterSource:t}},async()=>(r=await n(),`applied`));if(i.outcome!==`applied`||!r)throw Error(`Minor-mode transition was ${i.outcome}: ${i.diagnostics.join(`, `)}`);return r}});t.provide(o,x),a.current=x;let S,C,w=()=>{C=void 0;let e=n(x.getSnapshot(),b),t=JSON.stringify(e);t!==S&&(S=t,r.appendEntry(s,e),u())},T=x.subscribe(()=>{C??=setTimeout(w,50)});return a.republish=()=>{S=void 0,w()},()=>{C&&clearTimeout(C),T(),a.republish=void 0,a.current=void 0,x.dispose()}})}export{_ as default,_ as modeCatalogExtension};
|
|
2
2
|
//# sourceMappingURL=modeCatalog.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modeCatalog.mjs","names":[],"sources":["../../../../src/extensions/entries/modeCatalog.ts"],"sourcesContent":["import {\n DOOM_MINOR_MODE_CATALOG_SERVICE,\n DOOM_MINOR_MODE_ENTRY_TYPE,\n type MinorModeActionResponse,\n type MinorModeCatalogService,\n} from '@agimon-ai/doompi-extension-contracts/mode';\nimport {\n connectDoomCordisHost,\n DOOM_CORDIS_SESSION_SERVICE,\n type DoomCordisSessionService,\n} from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_HELP_SERVICE, requireDoomHelpService } from '@agimon-ai/doompi-extension-contracts/help';\nimport {\n type DoomNotificationLevel,\n readDoomNotificationService,\n} from '@agimon-ai/doompi-extension-contracts/notification';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport {\n consumeMinorModeReloadHandoff,\n discardMinorModeReloadHandoff,\n type MinorModeCatalogHost,\n DOOM_TRANSITION_SERVICE,\n requireDoomTransitionCoordinator,\n type TransitionSource,\n} from '@agimon-ai/doompi-extension-contracts/transition';\nimport type { Context } from '@deepseek-ai/cordis';\nimport { projectMinorModes } from '../../services/minorModeProjection.ts';\nimport { createMinorModeCatalogHost } from '../../services/modeCatalog.ts';\nimport { registerMinorModeCommand } from './minorModeCommand.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi/mode-catalog';\nconst HELP_CONTRIBUTION_SOURCE = '@agimon-ai/doompi';\n/** Registrations and state flips arrive in bursts; one entry covers a burst. */\nconst PROJECTION_SETTLE_MS = 50;\n/**\n * Pi's rpc mode subscribes to session events only after bindExtensions()\n * returns, which is after session_start has run, so an entry journaled during\n * startup never reaches a client. A publish deferred past that point does.\n */\nconst BOOT_PUBLISH_DELAY_MS = 500;\n\ninterface CatalogBinding {\n current: MinorModeCatalogService | undefined;\n /** Journals the projection even if unchanged; set while a session is bound. */\n republish?: () => void;\n}\n\nfunction notify(cordis: Context, context: ExtensionContext, body: string, level: DoomNotificationLevel): void {\n const service = readDoomNotificationService(cordis);\n if (service) {\n try {\n void Promise.resolve(service.request({ body, level })).catch(() => undefined);\n } catch {\n // Notification delivery is best effort and does not fall back after routing.\n }\n return;\n }\n context.ui.notify(body, level);\n}\n\nfunction transitionSource(requesterSource: string): TransitionSource {\n if (requesterSource.includes('voice')) return 'voice';\n if (requesterSource.includes('leader')) return 'leader';\n if (requesterSource.includes('ui')) return 'ui';\n return 'system';\n}\n\nexport async function modeCatalogExtension(pi: ExtensionAPI): Promise<void> {\n // The command outlives any one session: it is registered once and reads the\n // catalog binding the session-scoped inject below sets and clears.\n const activeCatalog: CatalogBinding = { current: undefined };\n registerMinorModeCommand(pi, () => activeCatalog.current);\n pi.on('session_start', () => {\n setTimeout(() => activeCatalog.republish?.(), BOOT_PUBLISH_DELAY_MS);\n });\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin((cordis: Context) => {\n modeCatalogPlugin(cordis, pi, activeCatalog);\n });\n try {\n await fiber;\n } catch (error) {\n await fiber.dispose();\n await connection.dispose();\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\nfunction modeCatalogPlugin(\n cordis: Context,\n pi: Pick<ExtensionAPI, 'appendEntry'>,\n activeCatalog: CatalogBinding,\n): void {\n cordis.inject([DOOM_HELP_SERVICE], (helpContext) => {\n const contribution = requireDoomHelpService(helpContext).register({\n source: HELP_CONTRIBUTION_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-author-extension',\n description:\n 'Create or update a DoomPi extension package inside the DoomPi monorepo or as an external npm package. Use for package layout, Pi discovery entries, shared Cordis lifecycle, package-owned Help, and extension verification.',\n },\n ],\n });\n return () => contribution.dispose();\n });\n\n cordis.inject([DOOM_CORDIS_SESSION_SERVICE, DOOM_TRANSITION_SERVICE], (sessionContext) => {\n const session = sessionContext.get(DOOM_CORDIS_SESSION_SERVICE) as DoomCordisSessionService;\n const context = session.context;\n const coordinator = requireDoomTransitionCoordinator(sessionContext);\n const reloadSession = session.reason === 'reload';\n const sessionId = session.sessionId;\n const restoreSnapshot = reloadSession ? consumeMinorModeReloadHandoff(sessionId) : undefined;\n if (!reloadSession) discardMinorModeReloadHandoff(sessionId);\n const sessionKind = context.hasUI && context.mode === 'tui' ? 'tui' : 'headless';\n const catalog: MinorModeCatalogHost = createMinorModeCatalogHost({\n sessionKind,\n context,\n restoreSnapshot,\n onRestorationError(error) {\n notify(\n sessionContext,\n context,\n `Could not restore a minor mode after reload: ${error instanceof Error ? error.message : String(error)}`,\n 'warning',\n );\n },\n async routeInvocation(request, requesterSource, invoke) {\n let response: MinorModeActionResponse | undefined;\n const result = await coordinator.execute(\n {\n sessionId: context.sessionManager.getSessionId(),\n hostGeneration: coordinator.hostGeneration,\n operationId: request.operationId,\n source: transitionSource(requesterSource),\n target: { axis: 'minor-mode', action: request, requesterSource },\n },\n async () => {\n response = await invoke();\n return 'applied';\n },\n );\n if (result.outcome !== 'applied' || !response) {\n throw new Error(`Minor-mode transition was ${result.outcome}: ${result.diagnostics.join(', ')}`);\n }\n return response;\n },\n });\n sessionContext.provide(DOOM_MINOR_MODE_CATALOG_SERVICE, catalog);\n activeCatalog.current = catalog;\n\n // Journal the projection so RPC clients see catalog state live and on\n // replay; identical projections are skipped so detail churn stays cheap.\n let published: string | undefined;\n let settle: NodeJS.Timeout | undefined;\n const publish = (): void => {\n settle = undefined;\n const projection = projectMinorModes(catalog.getSnapshot(), sessionKind);\n const serialized = JSON.stringify(projection);\n if (serialized === published) return;\n published = serialized;\n pi.appendEntry(DOOM_MINOR_MODE_ENTRY_TYPE, projection);\n };\n const unsubscribe = catalog.subscribe(() => {\n settle ??= setTimeout(publish, PROJECTION_SETTLE_MS);\n });\n activeCatalog.republish = () => {\n published = undefined;\n publish();\n };\n\n return () => {\n if (settle) clearTimeout(settle);\n unsubscribe();\n activeCatalog.republish = undefined;\n activeCatalog.current = undefined;\n catalog.dispose();\n };\n });\n}\n\nexport default modeCatalogExtension;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"modeCatalog.mjs","names":[],"sources":["../../../../src/extensions/entries/modeCatalog.ts"],"sourcesContent":["import {\n DOOM_MINOR_MODE_CATALOG_SERVICE,\n DOOM_MINOR_MODE_ENTRY_TYPE,\n type MinorModeActionResponse,\n type MinorModeCatalogService,\n} from '@agimon-ai/doompi-extension-contracts/mode';\nimport {\n connectDoomCordisHost,\n DOOM_CORDIS_SESSION_SERVICE,\n type DoomCordisSessionService,\n} from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_HELP_SERVICE, requireDoomHelpService } from '@agimon-ai/doompi-extension-contracts/help';\nimport {\n type DoomNotificationLevel,\n readDoomNotificationService,\n} from '@agimon-ai/doompi-extension-contracts/notification';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport {\n consumeMinorModeReloadHandoff,\n discardMinorModeReloadHandoff,\n type MinorModeCatalogHost,\n DOOM_TRANSITION_SERVICE,\n requireDoomTransitionCoordinator,\n type TransitionSource,\n} from '@agimon-ai/doompi-extension-contracts/transition';\nimport type { Context } from '@deepseek-ai/cordis';\nimport { type ContextPublisher, createContextPublisher } from '../../services/contextCatalog.ts';\nimport { projectMinorModes } from '../../services/minorModeProjection.ts';\nimport { createMinorModeCatalogHost } from '../../services/modeCatalog.ts';\nimport { registerMinorModeCommand } from './minorModeCommand.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi/mode-catalog';\nconst HELP_CONTRIBUTION_SOURCE = '@agimon-ai/doompi';\n/** Registrations and state flips arrive in bursts; one entry covers a burst. */\nconst PROJECTION_SETTLE_MS = 50;\n/**\n * Pi's rpc mode subscribes to session events only after bindExtensions()\n * returns, which is after session_start has run, so an entry journaled during\n * startup never reaches a client. A publish deferred past that point does.\n */\nconst BOOT_PUBLISH_DELAY_MS = 500;\n\ninterface CatalogBinding {\n current: MinorModeCatalogService | undefined;\n /** Journals the projection even if unchanged; set while a session is bound. */\n republish?: () => void;\n}\n\nfunction notify(cordis: Context, context: ExtensionContext, body: string, level: DoomNotificationLevel): void {\n const service = readDoomNotificationService(cordis);\n if (service) {\n try {\n void Promise.resolve(service.request({ body, level })).catch(() => undefined);\n } catch {\n // Notification delivery is best effort and does not fall back after routing.\n }\n return;\n }\n context.ui.notify(body, level);\n}\n\nfunction transitionSource(requesterSource: string): TransitionSource {\n if (requesterSource.includes('voice')) return 'voice';\n if (requesterSource.includes('leader')) return 'leader';\n if (requesterSource.includes('ui')) return 'ui';\n return 'system';\n}\n\nexport async function modeCatalogExtension(pi: ExtensionAPI): Promise<void> {\n // The command outlives any one session: it is registered once and reads the\n // catalog binding the session-scoped inject below sets and clears.\n const activeCatalog: CatalogBinding = { current: undefined };\n registerMinorModeCommand(pi, () => activeCatalog.current);\n // The composition is only complete once every extension has registered, so\n // the inventory is read on the same deferred tick the catalog republishes on.\n const contextBinding: { publisher?: ContextPublisher } = {};\n pi.on('session_start', () => {\n setTimeout(() => {\n activeCatalog.republish?.();\n void contextBinding.publisher?.publish();\n }, BOOT_PUBLISH_DELAY_MS);\n });\n // MCP status is pull-only and servers connect long after startup, so the\n // boot read above cannot see them. A turn is the moment the composition is\n // actually sent, which makes it both the freshest and the most meaningful\n // time to price. Identical compositions are skipped, so a quiet session\n // journals nothing extra.\n pi.on('turn_start', () => {\n void contextBinding.publisher?.publish();\n });\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin((cordis: Context) => {\n contextBinding.publisher = createContextPublisher(pi, cordis);\n modeCatalogPlugin(cordis, pi, activeCatalog, () => void contextBinding.publisher?.publish());\n return () => {\n contextBinding.publisher?.dispose();\n contextBinding.publisher = undefined;\n };\n });\n try {\n await fiber;\n } catch (error) {\n await fiber.dispose();\n await connection.dispose();\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\nfunction modeCatalogPlugin(\n cordis: Context,\n pi: Pick<ExtensionAPI, 'appendEntry'>,\n activeCatalog: CatalogBinding,\n onCatalogChanged: () => void,\n): void {\n cordis.inject([DOOM_HELP_SERVICE], (helpContext) => {\n const contribution = requireDoomHelpService(helpContext).register({\n source: HELP_CONTRIBUTION_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-author-extension',\n description:\n 'Create or update a DoomPi extension package inside the DoomPi monorepo or as an external npm package. Use for package layout, Pi discovery entries, shared Cordis lifecycle, package-owned Help, and extension verification.',\n },\n ],\n });\n return () => contribution.dispose();\n });\n\n cordis.inject([DOOM_CORDIS_SESSION_SERVICE, DOOM_TRANSITION_SERVICE], (sessionContext) => {\n const session = sessionContext.get(DOOM_CORDIS_SESSION_SERVICE) as DoomCordisSessionService;\n const context = session.context;\n const coordinator = requireDoomTransitionCoordinator(sessionContext);\n const reloadSession = session.reason === 'reload';\n const sessionId = session.sessionId;\n const restoreSnapshot = reloadSession ? consumeMinorModeReloadHandoff(sessionId) : undefined;\n if (!reloadSession) discardMinorModeReloadHandoff(sessionId);\n const sessionKind = context.hasUI && context.mode === 'tui' ? 'tui' : 'headless';\n const catalog: MinorModeCatalogHost = createMinorModeCatalogHost({\n sessionKind,\n context,\n restoreSnapshot,\n onRestorationError(error) {\n notify(\n sessionContext,\n context,\n `Could not restore a minor mode after reload: ${error instanceof Error ? error.message : String(error)}`,\n 'warning',\n );\n },\n async routeInvocation(request, requesterSource, invoke) {\n let response: MinorModeActionResponse | undefined;\n const result = await coordinator.execute(\n {\n sessionId: context.sessionManager.getSessionId(),\n hostGeneration: coordinator.hostGeneration,\n operationId: request.operationId,\n source: transitionSource(requesterSource),\n target: { axis: 'minor-mode', action: request, requesterSource },\n },\n async () => {\n response = await invoke();\n return 'applied';\n },\n );\n if (result.outcome !== 'applied' || !response) {\n throw new Error(`Minor-mode transition was ${result.outcome}: ${result.diagnostics.join(', ')}`);\n }\n return response;\n },\n });\n sessionContext.provide(DOOM_MINOR_MODE_CATALOG_SERVICE, catalog);\n activeCatalog.current = catalog;\n\n // Journal the projection so RPC clients see catalog state live and on\n // replay; identical projections are skipped so detail churn stays cheap.\n let published: string | undefined;\n let settle: NodeJS.Timeout | undefined;\n const publish = (): void => {\n settle = undefined;\n const projection = projectMinorModes(catalog.getSnapshot(), sessionKind);\n const serialized = JSON.stringify(projection);\n if (serialized === published) return;\n published = serialized;\n pi.appendEntry(DOOM_MINOR_MODE_ENTRY_TYPE, projection);\n // A mode changing is the usual reason the toolbox changed too.\n onCatalogChanged();\n };\n const unsubscribe = catalog.subscribe(() => {\n settle ??= setTimeout(publish, PROJECTION_SETTLE_MS);\n });\n activeCatalog.republish = () => {\n published = undefined;\n publish();\n };\n\n return () => {\n if (settle) clearTimeout(settle);\n unsubscribe();\n activeCatalog.republish = undefined;\n activeCatalog.current = undefined;\n catalog.dispose();\n };\n });\n}\n\nexport default modeCatalogExtension;\n"],"mappings":"+6BAgDA,SAAS,EAAO,EAAiB,EAA2B,EAAc,EAAoC,CAC5G,IAAM,EAAU,EAA4B,CAAM,EAClD,GAAI,EAAS,CACX,GAAI,CACF,QAAa,QAAQ,EAAQ,QAAQ,CAAE,OAAM,OAAM,CAAC,CAAC,CAAC,CAAC,UAAY,IAAA,EAAS,CAC9E,MAAQ,CAER,CACA,MACF,CACA,EAAQ,GAAG,OAAO,EAAM,CAAK,CAC/B,CAEA,SAAS,EAAiB,EAA2C,CAInE,OAHI,EAAgB,SAAS,OAAO,EAAU,QAC1C,EAAgB,SAAS,QAAQ,EAAU,SAC3C,EAAgB,SAAS,IAAI,EAAU,KACpC,QACT,CAEA,eAAsB,EAAqB,EAAiC,CAG1E,IAAM,EAAgC,CAAE,QAAS,IAAA,EAAU,EAC3D,EAAyB,MAAU,EAAc,OAAO,EAGxD,IAAM,EAAmD,CAAC,EAC1D,EAAG,GAAG,oBAAuB,CAC3B,eAAiB,CACf,EAAc,YAAY,EAC1B,EAAoB,WAAW,QAAQ,CACzC,EAAG,GAAqB,CAC1B,CAAC,EAMD,EAAG,GAAG,iBAAoB,CACxB,EAAoB,WAAW,QAAQ,CACzC,CAAC,EACD,IAAM,EAAa,MAAM,EAAsB,EAAI,gCAAc,EAC3D,EAAQ,EAAW,KAAK,OAAQ,IACpC,EAAe,UAAY,EAAuB,EAAI,CAAM,EAC5D,EAAkB,EAAQ,EAAI,MAAqB,KAAK,EAAe,WAAW,QAAQ,CAAC,MAC9E,CACX,EAAe,WAAW,QAAQ,EAClC,EAAe,UAAY,IAAA,EAC7B,EACD,EACD,GAAI,CACF,MAAM,CACR,OAAS,EAAO,CAGd,MAFA,MAAM,EAAM,QAAQ,EACpB,MAAM,EAAW,QAAQ,EACnB,CACR,CACA,IAAI,EACJ,EAAG,GACD,uBAEG,KAAc,SAAY,CACzB,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACF,EAAA,CAAG,CACP,CACF,CAEA,SAAS,EACP,EACA,EACA,EACA,EACM,CACN,EAAO,OAAO,CAAC,CAAiB,EAAI,GAAgB,CAClD,IAAM,EAAe,EAAuB,CAAW,CAAC,CAAC,SAAS,CAChE,OAAQ,oBACR,UAAW,YAAY,IACvB,OAAQ,CACN,CACE,KAAM,0BACN,YACE,8NACJ,CACF,CACF,CAAC,EACD,UAAa,EAAa,QAAQ,CACpC,CAAC,EAED,EAAO,OAAO,CAAC,EAA6B,CAAuB,EAAI,GAAmB,CACxF,IAAM,EAAU,EAAe,IAAI,CAA2B,EACxD,EAAU,EAAQ,QAClB,EAAc,EAAiC,CAAc,EAC7D,EAAgB,EAAQ,SAAW,SACnC,EAAY,EAAQ,UACpB,EAAkB,EAAgB,EAA8B,CAAS,EAAI,IAAA,GAC9E,GAAe,EAA8B,CAAS,EAC3D,IAAM,EAAc,EAAQ,OAAS,EAAQ,OAAS,MAAQ,MAAQ,WAChE,EAAgC,EAA2B,CAC/D,cACA,UACA,kBACA,mBAAmB,EAAO,CACxB,EACE,EACA,EACA,gDAAgD,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,IACrG,SACF,CACF,EACA,MAAM,gBAAgB,EAAS,EAAiB,EAAQ,CACtD,IAAI,EACE,EAAS,MAAM,EAAY,QAC/B,CACE,UAAW,EAAQ,eAAe,aAAa,EAC/C,eAAgB,EAAY,eAC5B,YAAa,EAAQ,YACrB,OAAQ,EAAiB,CAAe,EACxC,OAAQ,CAAE,KAAM,aAAc,OAAQ,EAAS,iBAAgB,CACjE,EACA,UACE,EAAW,MAAM,EAAO,EACjB,UAEX,EACA,GAAI,EAAO,UAAY,WAAa,CAAC,EACnC,MAAU,MAAM,6BAA6B,EAAO,QAAQ,IAAI,EAAO,YAAY,KAAK,IAAI,GAAG,EAEjG,OAAO,CACT,CACF,CAAC,EACD,EAAe,QAAQ,EAAiC,CAAO,EAC/D,EAAc,QAAU,EAIxB,IAAI,EACA,EACE,MAAsB,CAC1B,EAAS,IAAA,GACT,IAAM,EAAa,EAAkB,EAAQ,YAAY,EAAG,CAAW,EACjE,EAAa,KAAK,UAAU,CAAU,EACxC,IAAe,IACnB,EAAY,EACZ,EAAG,YAAY,EAA4B,CAAU,EAErD,EAAiB,EACnB,EACM,EAAc,EAAQ,cAAgB,CAC1C,IAAW,WAAW,EAAS,EAAoB,CACrD,CAAC,EAMD,MALA,GAAc,cAAkB,CAC9B,EAAY,IAAA,GACZ,EAAQ,CACV,MAEa,CACP,GAAQ,aAAa,CAAM,EAC/B,EAAY,EACZ,EAAc,UAAY,IAAA,GAC1B,EAAc,QAAU,IAAA,GACxB,EAAQ,QAAQ,CAClB,CACF,CAAC,CACH"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./contextProjection.cjs");let t=require("@agimon-ai/doompi-config/domains"),n=require("@agimon-ai/doompi-ui/extensionName"),r=require("@agimon-ai/doompi-config/harnessStore"),i=require("@agimon-ai/doompi-skill/catalog"),a=require("@agimon-ai/doompi-extension-contracts/mcp-status"),o=require("@agimon-ai/doompi-extension-contracts/skills"),s=require("@agimon-ai/doompi-ui/toolInventory");function c(e){return e.flatMap(e=>e.owners.flatMap(e=>e.skills))}function l(e,n,i){let a={...(0,r.getHarnessState)().packageAttribution};try{for(let r of(0,t.resolvePluginEntries)(e,[...n],[...i]))r.name&&r.domain&&(a[r.name]={kind:`domain`,mode:r.domain})}catch{}return a}function u(t,u){let d,f=0,p=!1,m=async()=>{if(p)return;let m=(0,r.getHarnessState)(),h=(0,a.readDoomMcpStatus)(u)?.getSnapshot().servers,g=(0,s.buildToolSources)({tools:t.getAllTools(),activeTools:t.getActiveTools(),...h?{mcpServers:h}:{},resolveExtensionName:n.extensionName,resolveExtensionPackageName:n.extensionPackageName,resolveExtensionToolSource:e=>(0,n.extensionToolSource)(t,e)}),_=(0,r.harnessRoot)(m),v=[];try{v=c((await(0,i.buildSkillCatalog)({repoRoot:_,activeSkillDirectories:m.skillDirectories,extensionSources:(0,o.readDoomSkillSourcesService)(u)?.list()??[]})).groups)}catch{}let y=e.projectContext({revision:f+1,majorMode:m.majorMode,minorModes:[],sources:g,skills:v,attribution:l(_,m.domains,m.pluginDirectories),countTokens:await(0,i.counter)()}),b=JSON.stringify({...y,revision:0});b===d||p||(d=b,f+=1,t.appendEntry(e.DOOM_CONTEXT_ENTRY_TYPE,{...y,revision:f}))};return{publish:async()=>{try{await m()}catch{}},dispose:()=>{p=!0}}}exports.createContextPublisher=u;
|
|
2
|
+
//# sourceMappingURL=contextCatalog.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextCatalog.cjs","names":["getHarnessState","resolvePluginEntries","readDoomMcpStatus","buildToolSources","extensionName","extensionPackageName","extensionToolSource","harnessRoot","buildSkillCatalog","readDoomSkillSourcesService","projectContext","counter","DOOM_CONTEXT_ENTRY_TYPE"],"sources":["../../../src/services/contextCatalog.ts"],"sourcesContent":["import { resolvePluginEntries } from '@agimon-ai/doompi-config/domains';\nimport { getHarnessState, harnessRoot } from '@agimon-ai/doompi-config/harnessStore';\nimport type { PackageAttribution } from '@agimon-ai/doompi-config/types';\nimport { readDoomMcpStatus } from '@agimon-ai/doompi-extension-contracts/mcp-status';\nimport { readDoomSkillSourcesService } from '@agimon-ai/doompi-extension-contracts/skills';\nimport { buildSkillCatalog, counter, type SkillEntry } from '@agimon-ai/doompi-skill/catalog';\nimport { extensionName, extensionPackageName, extensionToolSource } from '@agimon-ai/doompi-ui/extensionName';\nimport { buildToolSources } from '@agimon-ai/doompi-ui/toolInventory';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { DOOM_CONTEXT_ENTRY_TYPE, projectContext } from './contextProjection.ts';\n\n/**\n * Publishes what the session is composed of, and what it costs.\n *\n * Read at publish time rather than accumulated, because the answer changes for\n * reasons this module does not see: a reconnected MCP server, a domain switch,\n * a plan-mode tool swap. Reading the live inventory is cheap next to being\n * wrong about it.\n */\nexport interface ContextPublisher {\n /** Never rejects: callers fire this and forget it. */\n publish: () => Promise<void>;\n dispose: () => void;\n}\n\n/** Skills sit under owners, which is one level deeper than a flat list. */\nfunction flattenSkills(groups: Awaited<ReturnType<typeof buildSkillCatalog>>['groups']): SkillEntry[] {\n return groups.flatMap((group) => group.owners.flatMap((owner) => owner.skills));\n}\n\n/**\n * Package and plugin names to the mode that admitted them.\n *\n * Two halves meet here. Layer packages come from the harness, recorded when the\n * composition resolved. Domain plugins are re-resolved, because only the plugin\n * entry knows the domain that carried it.\n */\nfunction attributionFor(repoRoot: string, domains: readonly string[], pluginDirectories: readonly string[]) {\n const harness = getHarnessState();\n const attribution: Record<string, PackageAttribution> = { ...harness.packageAttribution };\n try {\n for (const entry of resolvePluginEntries(repoRoot, [...domains], [...pluginDirectories])) {\n if (entry.name && entry.domain) attribution[entry.name] = { kind: 'domain', mode: entry.domain };\n }\n } catch {\n // A domain that no longer resolves must not cost the reader the tool list.\n // Anything unmatched simply lands under core.\n }\n return attribution;\n}\n\nexport function createContextPublisher(pi: ExtensionAPI, cordis: Context): ContextPublisher {\n let published: string | undefined;\n let revision = 0;\n let disposed = false;\n\n const build = async (): Promise<void> => {\n if (disposed) return;\n const harness = getHarnessState();\n const mcpServers = readDoomMcpStatus(cordis)?.getSnapshot().servers;\n const sources = buildToolSources({\n tools: pi.getAllTools(),\n activeTools: pi.getActiveTools(),\n ...(mcpServers ? { mcpServers } : {}),\n resolveExtensionName: extensionName,\n resolveExtensionPackageName: extensionPackageName,\n resolveExtensionToolSource: (toolName) => extensionToolSource(pi, toolName),\n });\n\n const repoRoot = harnessRoot(harness);\n let skills: SkillEntry[] = [];\n try {\n const catalog = await buildSkillCatalog({\n repoRoot,\n activeSkillDirectories: harness.skillDirectories,\n extensionSources: readDoomSkillSourcesService(cordis)?.list() ?? [],\n });\n skills = flattenSkills(catalog.groups);\n } catch {\n // Tools are the larger cost and are already in hand; a skill walk that\n // fails should not take the whole figure down with it.\n }\n\n const projection = projectContext({\n revision: revision + 1,\n majorMode: harness.majorMode,\n minorModes: [],\n sources,\n skills,\n attribution: attributionFor(repoRoot, harness.domains, harness.pluginDirectories),\n countTokens: await counter(),\n });\n\n // Revision is compared out, so a republish that changed nothing is silent\n // rather than a new journal entry saying the same thing.\n const serialized = JSON.stringify({ ...projection, revision: 0 });\n if (serialized === published || disposed) return;\n published = serialized;\n revision += 1;\n pi.appendEntry(DOOM_CONTEXT_ENTRY_TYPE, { ...projection, revision });\n };\n\n /**\n * Reporting the composition is a convenience, so it fails quietly.\n *\n * Callers publish without awaiting, and an escaping rejection would surface\n * as an unhandled error in a live session. A panel that cannot say what the\n * toolbox costs is a far smaller problem than that.\n */\n const publish = async (): Promise<void> => {\n try {\n await build();\n } catch {\n // Left unreported on purpose: the next composition change tries again.\n }\n };\n\n return {\n publish,\n dispose: () => {\n disposed = true;\n },\n };\n}\n"],"mappings":"qZA2BA,SAAS,EAAc,EAA+E,CACpG,OAAO,EAAO,QAAS,GAAU,EAAM,OAAO,QAAS,GAAU,EAAM,MAAM,CAAC,CAChF,CASA,SAAS,EAAe,EAAkB,EAA4B,EAAsC,CAE1G,IAAM,EAAkD,CAAE,IAAA,EAD1CA,EAAAA,gBAAAA,CACmD,CAAC,CAAC,kBAAmB,EACxF,GAAI,CACF,IAAK,IAAM,KAAA,EAASC,EAAAA,qBAAAA,CAAqB,EAAU,CAAC,GAAG,CAAO,EAAG,CAAC,GAAG,CAAiB,CAAC,EACjF,EAAM,MAAQ,EAAM,SAAQ,EAAY,EAAM,MAAQ,CAAE,KAAM,SAAU,KAAM,EAAM,MAAO,EAEnG,MAAQ,CAGR,CACA,OAAO,CACT,CAEA,SAAgB,EAAuB,EAAkB,EAAmC,CAC1F,IAAI,EACA,EAAW,EACX,EAAW,GAET,EAAQ,SAA2B,CACvC,GAAI,EAAU,OACd,IAAM,GAAA,EAAUD,EAAAA,gBAAAA,CAAgB,EAC1B,GAAA,EAAaE,EAAAA,kBAAAA,CAAkB,CAAM,CAAC,EAAE,YAAY,CAAC,CAAC,QACtD,GAAA,EAAUC,EAAAA,iBAAAA,CAAiB,CAC/B,MAAO,EAAG,YAAY,EACtB,YAAa,EAAG,eAAe,EAC/B,GAAI,EAAa,CAAE,YAAW,EAAI,CAAC,EACnC,qBAAsBC,EAAAA,cACtB,4BAA6BC,EAAAA,qBAC7B,2BAA6B,IAAA,EAAaC,EAAAA,oBAAAA,CAAoB,EAAI,CAAQ,CAC5E,CAAC,EAEK,GAAA,EAAWC,EAAAA,YAAAA,CAAY,CAAO,EAChC,EAAuB,CAAC,EAC5B,GAAI,CAMF,EAAS,GAAc,MAAA,EALDC,EAAAA,kBAAAA,CAAkB,CACtC,WACA,uBAAwB,EAAQ,iBAChC,kBAAA,EAAkBC,EAAAA,4BAAAA,CAA4B,CAAM,CAAC,EAAE,KAAK,GAAK,CAAC,CACpE,CAAC,EAAA,CAC8B,MAAM,CACvC,MAAQ,CAGR,CAEA,IAAM,EAAaC,EAAAA,eAAe,CAChC,SAAU,EAAW,EACrB,UAAW,EAAQ,UACnB,WAAY,CAAC,EACb,UACA,SACA,YAAa,EAAe,EAAU,EAAQ,QAAS,EAAQ,iBAAiB,EAChF,YAAa,MAAA,EAAMC,EAAAA,QAAAA,CAAQ,CAC7B,CAAC,EAIK,EAAa,KAAK,UAAU,CAAE,GAAG,EAAY,SAAU,CAAE,CAAC,EAC5D,IAAe,GAAa,IAChC,EAAY,EACZ,GAAY,EACZ,EAAG,YAAYC,EAAAA,wBAAyB,CAAE,GAAG,EAAY,UAAS,CAAC,EACrE,EAiBA,MAAO,CACL,iBATyC,CACzC,GAAI,CACF,MAAM,EAAM,CACd,MAAQ,CAER,CACF,EAIE,YAAe,CACb,EAAW,EACb,CACF,CACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{DOOM_CONTEXT_ENTRY_TYPE as e,projectContext as t}from"./contextProjection.mjs";import{resolvePluginEntries as n}from"@agimon-ai/doompi-config/domains";import{extensionName as r,extensionPackageName as i,extensionToolSource as a}from"@agimon-ai/doompi-ui/extensionName";import{getHarnessState as o,harnessRoot as s}from"@agimon-ai/doompi-config/harnessStore";import{buildSkillCatalog as c,counter as l}from"@agimon-ai/doompi-skill/catalog";import{readDoomMcpStatus as u}from"@agimon-ai/doompi-extension-contracts/mcp-status";import{readDoomSkillSourcesService as d}from"@agimon-ai/doompi-extension-contracts/skills";import{buildToolSources as f}from"@agimon-ai/doompi-ui/toolInventory";function p(e){return e.flatMap(e=>e.owners.flatMap(e=>e.skills))}function m(e,t,r){let i={...o().packageAttribution};try{for(let a of n(e,[...t],[...r]))a.name&&a.domain&&(i[a.name]={kind:`domain`,mode:a.domain})}catch{}return i}function h(n,h){let g,_=0,v=!1,y=async()=>{if(v)return;let y=o(),b=u(h)?.getSnapshot().servers,x=f({tools:n.getAllTools(),activeTools:n.getActiveTools(),...b?{mcpServers:b}:{},resolveExtensionName:r,resolveExtensionPackageName:i,resolveExtensionToolSource:e=>a(n,e)}),S=s(y),C=[];try{C=p((await c({repoRoot:S,activeSkillDirectories:y.skillDirectories,extensionSources:d(h)?.list()??[]})).groups)}catch{}let w=t({revision:_+1,majorMode:y.majorMode,minorModes:[],sources:x,skills:C,attribution:m(S,y.domains,y.pluginDirectories),countTokens:await l()}),T=JSON.stringify({...w,revision:0});T===g||v||(g=T,_+=1,n.appendEntry(e,{...w,revision:_}))};return{publish:async()=>{try{await y()}catch{}},dispose:()=>{v=!0}}}export{h as createContextPublisher};
|
|
2
|
+
//# sourceMappingURL=contextCatalog.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextCatalog.mjs","names":[],"sources":["../../../src/services/contextCatalog.ts"],"sourcesContent":["import { resolvePluginEntries } from '@agimon-ai/doompi-config/domains';\nimport { getHarnessState, harnessRoot } from '@agimon-ai/doompi-config/harnessStore';\nimport type { PackageAttribution } from '@agimon-ai/doompi-config/types';\nimport { readDoomMcpStatus } from '@agimon-ai/doompi-extension-contracts/mcp-status';\nimport { readDoomSkillSourcesService } from '@agimon-ai/doompi-extension-contracts/skills';\nimport { buildSkillCatalog, counter, type SkillEntry } from '@agimon-ai/doompi-skill/catalog';\nimport { extensionName, extensionPackageName, extensionToolSource } from '@agimon-ai/doompi-ui/extensionName';\nimport { buildToolSources } from '@agimon-ai/doompi-ui/toolInventory';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { DOOM_CONTEXT_ENTRY_TYPE, projectContext } from './contextProjection.ts';\n\n/**\n * Publishes what the session is composed of, and what it costs.\n *\n * Read at publish time rather than accumulated, because the answer changes for\n * reasons this module does not see: a reconnected MCP server, a domain switch,\n * a plan-mode tool swap. Reading the live inventory is cheap next to being\n * wrong about it.\n */\nexport interface ContextPublisher {\n /** Never rejects: callers fire this and forget it. */\n publish: () => Promise<void>;\n dispose: () => void;\n}\n\n/** Skills sit under owners, which is one level deeper than a flat list. */\nfunction flattenSkills(groups: Awaited<ReturnType<typeof buildSkillCatalog>>['groups']): SkillEntry[] {\n return groups.flatMap((group) => group.owners.flatMap((owner) => owner.skills));\n}\n\n/**\n * Package and plugin names to the mode that admitted them.\n *\n * Two halves meet here. Layer packages come from the harness, recorded when the\n * composition resolved. Domain plugins are re-resolved, because only the plugin\n * entry knows the domain that carried it.\n */\nfunction attributionFor(repoRoot: string, domains: readonly string[], pluginDirectories: readonly string[]) {\n const harness = getHarnessState();\n const attribution: Record<string, PackageAttribution> = { ...harness.packageAttribution };\n try {\n for (const entry of resolvePluginEntries(repoRoot, [...domains], [...pluginDirectories])) {\n if (entry.name && entry.domain) attribution[entry.name] = { kind: 'domain', mode: entry.domain };\n }\n } catch {\n // A domain that no longer resolves must not cost the reader the tool list.\n // Anything unmatched simply lands under core.\n }\n return attribution;\n}\n\nexport function createContextPublisher(pi: ExtensionAPI, cordis: Context): ContextPublisher {\n let published: string | undefined;\n let revision = 0;\n let disposed = false;\n\n const build = async (): Promise<void> => {\n if (disposed) return;\n const harness = getHarnessState();\n const mcpServers = readDoomMcpStatus(cordis)?.getSnapshot().servers;\n const sources = buildToolSources({\n tools: pi.getAllTools(),\n activeTools: pi.getActiveTools(),\n ...(mcpServers ? { mcpServers } : {}),\n resolveExtensionName: extensionName,\n resolveExtensionPackageName: extensionPackageName,\n resolveExtensionToolSource: (toolName) => extensionToolSource(pi, toolName),\n });\n\n const repoRoot = harnessRoot(harness);\n let skills: SkillEntry[] = [];\n try {\n const catalog = await buildSkillCatalog({\n repoRoot,\n activeSkillDirectories: harness.skillDirectories,\n extensionSources: readDoomSkillSourcesService(cordis)?.list() ?? [],\n });\n skills = flattenSkills(catalog.groups);\n } catch {\n // Tools are the larger cost and are already in hand; a skill walk that\n // fails should not take the whole figure down with it.\n }\n\n const projection = projectContext({\n revision: revision + 1,\n majorMode: harness.majorMode,\n minorModes: [],\n sources,\n skills,\n attribution: attributionFor(repoRoot, harness.domains, harness.pluginDirectories),\n countTokens: await counter(),\n });\n\n // Revision is compared out, so a republish that changed nothing is silent\n // rather than a new journal entry saying the same thing.\n const serialized = JSON.stringify({ ...projection, revision: 0 });\n if (serialized === published || disposed) return;\n published = serialized;\n revision += 1;\n pi.appendEntry(DOOM_CONTEXT_ENTRY_TYPE, { ...projection, revision });\n };\n\n /**\n * Reporting the composition is a convenience, so it fails quietly.\n *\n * Callers publish without awaiting, and an escaping rejection would surface\n * as an unhandled error in a live session. A panel that cannot say what the\n * toolbox costs is a far smaller problem than that.\n */\n const publish = async (): Promise<void> => {\n try {\n await build();\n } catch {\n // Left unreported on purpose: the next composition change tries again.\n }\n };\n\n return {\n publish,\n dispose: () => {\n disposed = true;\n },\n };\n}\n"],"mappings":"orBA2BA,SAAS,EAAc,EAA+E,CACpG,OAAO,EAAO,QAAS,GAAU,EAAM,OAAO,QAAS,GAAU,EAAM,MAAM,CAAC,CAChF,CASA,SAAS,EAAe,EAAkB,EAA4B,EAAsC,CAE1G,IAAM,EAAkD,CAAE,GAD1C,EACmD,CAAC,CAAC,kBAAmB,EACxF,GAAI,CACF,IAAK,IAAM,KAAS,EAAqB,EAAU,CAAC,GAAG,CAAO,EAAG,CAAC,GAAG,CAAiB,CAAC,EACjF,EAAM,MAAQ,EAAM,SAAQ,EAAY,EAAM,MAAQ,CAAE,KAAM,SAAU,KAAM,EAAM,MAAO,EAEnG,MAAQ,CAGR,CACA,OAAO,CACT,CAEA,SAAgB,EAAuB,EAAkB,EAAmC,CAC1F,IAAI,EACA,EAAW,EACX,EAAW,GAET,EAAQ,SAA2B,CACvC,GAAI,EAAU,OACd,IAAM,EAAU,EAAgB,EAC1B,EAAa,EAAkB,CAAM,CAAC,EAAE,YAAY,CAAC,CAAC,QACtD,EAAU,EAAiB,CAC/B,MAAO,EAAG,YAAY,EACtB,YAAa,EAAG,eAAe,EAC/B,GAAI,EAAa,CAAE,YAAW,EAAI,CAAC,EACnC,qBAAsB,EACtB,4BAA6B,EAC7B,2BAA6B,GAAa,EAAoB,EAAI,CAAQ,CAC5E,CAAC,EAEK,EAAW,EAAY,CAAO,EAChC,EAAuB,CAAC,EAC5B,GAAI,CAMF,EAAS,GAAc,MALD,EAAkB,CACtC,WACA,uBAAwB,EAAQ,iBAChC,iBAAkB,EAA4B,CAAM,CAAC,EAAE,KAAK,GAAK,CAAC,CACpE,CAAC,EAAA,CAC8B,MAAM,CACvC,MAAQ,CAGR,CAEA,IAAM,EAAa,EAAe,CAChC,SAAU,EAAW,EACrB,UAAW,EAAQ,UACnB,WAAY,CAAC,EACb,UACA,SACA,YAAa,EAAe,EAAU,EAAQ,QAAS,EAAQ,iBAAiB,EAChF,YAAa,MAAM,EAAQ,CAC7B,CAAC,EAIK,EAAa,KAAK,UAAU,CAAE,GAAG,EAAY,SAAU,CAAE,CAAC,EAC5D,IAAe,GAAa,IAChC,EAAY,EACZ,GAAY,EACZ,EAAG,YAAY,EAAyB,CAAE,GAAG,EAAY,UAAS,CAAC,EACrE,EAiBA,MAAO,CACL,iBATyC,CACzC,GAAI,CACF,MAAM,EAAM,CACd,MAAQ,CAER,CACF,EAIE,YAAe,CACb,EAAW,EACb,CACF,CACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
let e=require("@agimon-ai/doompi-ui/toolInventory");const t=`gpt-tokenizer`,n=`core`,r={major:0,minor:1,domain:2,core:3},i={extension:0,mcp:1,plugin:2,core:3};function a(e){return e===`plugins`?`plugin`:e===`extensions`?`extension`:`core`}function o(e,t){return i[e.source]-i[t.source]||e.name.localeCompare(t.name)}function s(i){let s=new Map,c=(e,t,n)=>{s.has(e)||s.set(e,{kind:n,label:t,items:[]})};i.majorMode&&c(i.majorMode,i.majorMode,`major`);for(let e of i.minorModes)c(e.id,e.label,`minor`);let l=(e,t)=>{let r=i.attribution[e],a=r?.mode??n;c(a,a,r?r.kind===`domain`?`domain`:`major`:`core`),s.get(a)?.items.push(t)};for(let t of i.sources){let r=t.kind===`extension`?t.packageName??t.key:t.kind===`mcp`?t.key.slice(4):`pi`;for(let a of t.tools){let o=(0,e.tokensForTool)(a,i.countTokens),u={name:a.name,itemKind:`tool`,source:t.kind===`core`?`core`:t.kind,owner:r,tokens:o.totalTokens,active:a.active};t.kind===`core`?(c(n,n,`core`),s.get(n)?.items.push(u)):l(r,u)}}for(let e of i.skills)l(e.owner,{name:e.name,itemKind:`skill`,source:a(e.group),owner:e.owner,tokens:e.promptTokens??0,active:!0});let u=[...s.entries()].map(([e,t])=>{let n=[...t.items].sort(o);return{id:e,label:t.label,kind:t.kind,items:n,tokens:n.reduce((e,t)=>e+(t.active?t.tokens:0),0),inactiveTokens:n.reduce((e,t)=>e+(t.active?0:t.tokens),0)}}).sort((e,t)=>r[e.kind]-r[t.kind]||e.label.localeCompare(t.label));return{version:1,revision:i.revision,groups:u,totalTokens:u.reduce((e,t)=>e+t.tokens,0),inactiveTokens:u.reduce((e,t)=>e+t.inactiveTokens,0),estimator:t}}exports.CONTEXT_PROJECTION_ESTIMATOR=t,exports.DOOM_CONTEXT_ENTRY_TYPE=`doom-context`,exports.projectContext=s;
|
|
2
|
+
//# sourceMappingURL=contextProjection.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextProjection.cjs","names":["tokensForTool"],"sources":["../../../src/services/contextProjection.ts"],"sourcesContent":["import type { PackageAttribution } from '@agimon-ai/doompi-config/types';\nimport type { SkillEntry } from '@agimon-ai/doompi-skill/catalog';\nimport { type CountTokens, type ToolSource, tokensForTool } from '@agimon-ai/doompi-ui/toolInventory';\n\n/**\n * What the session is carrying, and what carrying it costs.\n *\n * Grouped by the mode that admitted each package rather than by where the tool\n * came from, because a mode is the thing a reader can switch off. The mechanism\n * (extension, MCP server, plugin) orders rows inside a group instead, so the\n * expensive thing is still easy to find.\n *\n * Schemas never travel. Only names, kinds, owners and integer counts do, which\n * keeps the payload small enough to republish whenever the composition changes.\n */\nexport const CONTEXT_PROJECTION_VERSION = 1;\n\n/** Journal entry the cockpit reads; mirrored by CONTEXT_ENTRY_TYPE in doompi-web. */\nexport const DOOM_CONTEXT_ENTRY_TYPE = 'doom-context';\n\n/** The tokenizer these counts came from, so a reader can judge them. */\nexport const CONTEXT_PROJECTION_ESTIMATOR = 'gpt-tokenizer';\n\nexport type ContextGroupKind = 'major' | 'minor' | 'domain' | 'core';\nexport type ContextItemSource = 'extension' | 'mcp' | 'plugin' | 'core';\n\n/** Everything the runtime could not attribute lands here rather than vanishing. */\nconst CORE_GROUP = 'core';\n/** Pi's own tools have no package; the runtime itself is the owner. */\nconst CORE_OWNER = 'pi';\nconst MCP_KEY_PREFIX = 'mcp:';\n\nconst KIND_ORDER: Record<ContextGroupKind, number> = { major: 0, minor: 1, domain: 2, core: 3 };\nconst SOURCE_ORDER: Record<ContextItemSource, number> = { extension: 0, mcp: 1, plugin: 2, core: 3 };\n\nexport interface ContextItemProjection {\n readonly name: string;\n readonly itemKind: 'tool' | 'skill';\n readonly source: ContextItemSource;\n /** The package, server, or plugin that registered it. */\n readonly owner: string;\n readonly tokens: number;\n readonly active: boolean;\n}\n\nexport interface ContextGroupProjection {\n readonly id: string;\n readonly label: string;\n readonly kind: ContextGroupKind;\n readonly items: readonly ContextItemProjection[];\n /** What the group costs now: active items only. */\n readonly tokens: number;\n /** What its gated items would add if switched on. */\n readonly inactiveTokens: number;\n}\n\nexport interface ContextProjection {\n readonly version: typeof CONTEXT_PROJECTION_VERSION;\n readonly revision: number;\n readonly groups: readonly ContextGroupProjection[];\n readonly totalTokens: number;\n readonly inactiveTokens: number;\n readonly estimator: typeof CONTEXT_PROJECTION_ESTIMATOR;\n}\n\nexport interface ContextProjectionInput {\n readonly revision: number;\n readonly majorMode: string;\n /** Active minor modes, in the order the catalog reports them. */\n readonly minorModes: readonly { readonly id: string; readonly label: string }[];\n readonly sources: readonly ToolSource[];\n readonly skills: readonly SkillEntry[];\n /**\n * Owner identifier to the mode that admitted it.\n *\n * Keys are package names for extensions and layer packages, and plugin or\n * server names for anything a domain carries. The caller owns this join\n * because only it knows how a given deployment resolved its plugins.\n */\n readonly attribution: Readonly<Record<string, PackageAttribution>>;\n readonly countTokens: CountTokens;\n}\n\ninterface Bucket {\n kind: ContextGroupKind;\n label: string;\n items: ContextItemProjection[];\n}\n\nfunction skillSource(group: SkillEntry['group']): ContextItemSource {\n if (group === 'plugins') return 'plugin';\n if (group === 'extensions') return 'extension';\n return 'core';\n}\n\nfunction byRow(left: ContextItemProjection, right: ContextItemProjection): number {\n return SOURCE_ORDER[left.source] - SOURCE_ORDER[right.source] || left.name.localeCompare(right.name);\n}\n\nexport function projectContext(input: ContextProjectionInput): ContextProjection {\n const buckets = new Map<string, Bucket>();\n\n // Declared before anything is placed, so a mode with nothing attributed to it\n // still appears. An empty group is a fact worth showing: it says the mode is\n // on and cheap, not that the runtime forgot about it.\n const declare = (id: string, label: string, kind: ContextGroupKind): void => {\n if (!buckets.has(id)) buckets.set(id, { kind, label, items: [] });\n };\n if (input.majorMode) declare(input.majorMode, input.majorMode, 'major');\n for (const mode of input.minorModes) declare(mode.id, mode.label, 'minor');\n\n const place = (owner: string, item: ContextItemProjection): void => {\n const attributed = input.attribution[owner];\n const id = attributed?.mode ?? CORE_GROUP;\n declare(id, id, attributed ? (attributed.kind === 'domain' ? 'domain' : 'major') : 'core');\n buckets.get(id)?.items.push(item);\n };\n\n for (const source of input.sources) {\n // An extension is owned by its package, an MCP tool by the server that\n // advertised it. `label` is display text like `scaffold · mcp`, so the\n // identifier comes from the key instead: an owner is joined on, not read.\n const owner =\n source.kind === 'extension'\n ? (source.packageName ?? source.key)\n : source.kind === 'mcp'\n ? source.key.slice(MCP_KEY_PREFIX.length)\n : CORE_OWNER;\n for (const tool of source.tools) {\n const cost = tokensForTool(tool, input.countTokens);\n const item: ContextItemProjection = {\n name: tool.name,\n itemKind: 'tool',\n source: source.kind === 'core' ? 'core' : source.kind,\n owner,\n tokens: cost.totalTokens,\n active: tool.active,\n };\n if (source.kind === 'core') {\n declare(CORE_GROUP, CORE_GROUP, 'core');\n buckets.get(CORE_GROUP)?.items.push(item);\n } else {\n place(owner, item);\n }\n }\n }\n\n for (const skill of input.skills) {\n place(skill.owner, {\n name: skill.name,\n itemKind: 'skill',\n source: skillSource(skill.group),\n owner: skill.owner,\n tokens: skill.promptTokens ?? 0,\n // A skill is always offered to the model; there is no inactive state for\n // it the way there is for a tool Pi has filtered out.\n active: true,\n });\n }\n\n const groups: ContextGroupProjection[] = [...buckets.entries()]\n .map(([id, bucket]) => {\n const items = [...bucket.items].sort(byRow);\n // Only what is actually sent counts. Pi builds the prompt from its\n // active tools, so a gated one costs nothing until it is switched on,\n // and folding it into the total would overstate the bill by a third.\n return {\n id,\n label: bucket.label,\n kind: bucket.kind,\n items,\n tokens: items.reduce((total, item) => total + (item.active ? item.tokens : 0), 0),\n inactiveTokens: items.reduce((total, item) => total + (item.active ? 0 : item.tokens), 0),\n };\n })\n .sort((left, right) => KIND_ORDER[left.kind] - KIND_ORDER[right.kind] || left.label.localeCompare(right.label));\n\n return {\n version: CONTEXT_PROJECTION_VERSION,\n revision: input.revision,\n groups,\n totalTokens: groups.reduce((total, group) => total + group.tokens, 0),\n inactiveTokens: groups.reduce((total, group) => total + group.inactiveTokens, 0),\n estimator: CONTEXT_PROJECTION_ESTIMATOR,\n };\n}\n"],"mappings":"oDAkBA,MAGa,EAA+B,gBAMtC,EAAa,OAKb,EAA+C,CAAE,MAAO,EAAG,MAAO,EAAG,OAAQ,EAAG,KAAM,CAAE,EACxF,EAAkD,CAAE,UAAW,EAAG,IAAK,EAAG,OAAQ,EAAG,KAAM,CAAE,EAwDnG,SAAS,EAAY,EAA+C,CAGlE,OAFI,IAAU,UAAkB,SAC5B,IAAU,aAAqB,YAC5B,MACT,CAEA,SAAS,EAAM,EAA6B,EAAsC,CAChF,OAAO,EAAa,EAAK,QAAU,EAAa,EAAM,SAAW,EAAK,KAAK,cAAc,EAAM,IAAI,CACrG,CAEA,SAAgB,EAAe,EAAkD,CAC/E,IAAM,EAAU,IAAI,IAKd,GAAW,EAAY,EAAe,IAAiC,CACtE,EAAQ,IAAI,CAAE,GAAG,EAAQ,IAAI,EAAI,CAAE,OAAM,QAAO,MAAO,CAAC,CAAE,CAAC,CAClE,EACI,EAAM,WAAW,EAAQ,EAAM,UAAW,EAAM,UAAW,OAAO,EACtE,IAAK,IAAM,KAAQ,EAAM,WAAY,EAAQ,EAAK,GAAI,EAAK,MAAO,OAAO,EAEzE,IAAM,GAAS,EAAe,IAAsC,CAClE,IAAM,EAAa,EAAM,YAAY,GAC/B,EAAK,GAAY,MAAQ,EAC/B,EAAQ,EAAI,EAAI,EAAc,EAAW,OAAS,SAAW,SAAW,QAAW,MAAM,EACzF,EAAQ,IAAI,CAAE,CAAC,EAAE,MAAM,KAAK,CAAI,CAClC,EAEA,IAAK,IAAM,KAAU,EAAM,QAAS,CAIlC,IAAM,EACJ,EAAO,OAAS,YACX,EAAO,aAAe,EAAO,IAC9B,EAAO,OAAS,MACd,EAAO,IAAI,MAAM,CAAqB,EACtC,KACR,IAAK,IAAM,KAAQ,EAAO,MAAO,CAC/B,IAAM,GAAA,EAAOA,EAAAA,cAAAA,CAAc,EAAM,EAAM,WAAW,EAC5C,EAA8B,CAClC,KAAM,EAAK,KACX,SAAU,OACV,OAAQ,EAAO,OAAS,OAAS,OAAS,EAAO,KACjD,QACA,OAAQ,EAAK,YACb,OAAQ,EAAK,MACf,EACI,EAAO,OAAS,QAClB,EAAQ,EAAY,EAAY,MAAM,EACtC,EAAQ,IAAI,CAAU,CAAC,EAAE,MAAM,KAAK,CAAI,GAExC,EAAM,EAAO,CAAI,CAErB,CACF,CAEA,IAAK,IAAM,KAAS,EAAM,OACxB,EAAM,EAAM,MAAO,CACjB,KAAM,EAAM,KACZ,SAAU,QACV,OAAQ,EAAY,EAAM,KAAK,EAC/B,MAAO,EAAM,MACb,OAAQ,EAAM,cAAgB,EAG9B,OAAQ,EACV,CAAC,EAGH,IAAM,EAAmC,CAAC,GAAG,EAAQ,QAAQ,CAAC,CAAC,CAC5D,KAAK,CAAC,EAAI,KAAY,CACrB,IAAM,EAAQ,CAAC,GAAG,EAAO,KAAK,CAAC,CAAC,KAAK,CAAK,EAI1C,MAAO,CACL,KACA,MAAO,EAAO,MACd,KAAM,EAAO,KACb,QACA,OAAQ,EAAM,QAAQ,EAAO,IAAS,GAAS,EAAK,OAAS,EAAK,OAAS,GAAI,CAAC,EAChF,eAAgB,EAAM,QAAQ,EAAO,IAAS,GAAS,EAAK,OAAS,EAAI,EAAK,QAAS,CAAC,CAC1F,CACF,CAAC,CAAC,CACD,MAAM,EAAM,IAAU,EAAW,EAAK,MAAQ,EAAW,EAAM,OAAS,EAAK,MAAM,cAAc,EAAM,KAAK,CAAC,EAEhH,MAAO,CACL,QAAA,EACA,SAAU,EAAM,SAChB,SACA,YAAa,EAAO,QAAQ,EAAO,IAAU,EAAQ,EAAM,OAAQ,CAAC,EACpE,eAAgB,EAAO,QAAQ,EAAO,IAAU,EAAQ,EAAM,eAAgB,CAAC,EAC/E,UAAW,CACb,CACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{tokensForTool as e}from"@agimon-ai/doompi-ui/toolInventory";const t=`doom-context`,n=`gpt-tokenizer`,r=`core`,i={major:0,minor:1,domain:2,core:3},a={extension:0,mcp:1,plugin:2,core:3};function o(e){return e===`plugins`?`plugin`:e===`extensions`?`extension`:`core`}function s(e,t){return a[e.source]-a[t.source]||e.name.localeCompare(t.name)}function c(t){let a=new Map,c=(e,t,n)=>{a.has(e)||a.set(e,{kind:n,label:t,items:[]})};t.majorMode&&c(t.majorMode,t.majorMode,`major`);for(let e of t.minorModes)c(e.id,e.label,`minor`);let l=(e,n)=>{let i=t.attribution[e],o=i?.mode??r;c(o,o,i?i.kind===`domain`?`domain`:`major`:`core`),a.get(o)?.items.push(n)};for(let n of t.sources){let i=n.kind===`extension`?n.packageName??n.key:n.kind===`mcp`?n.key.slice(4):`pi`;for(let o of n.tools){let s=e(o,t.countTokens),u={name:o.name,itemKind:`tool`,source:n.kind===`core`?`core`:n.kind,owner:i,tokens:s.totalTokens,active:o.active};n.kind===`core`?(c(r,r,`core`),a.get(r)?.items.push(u)):l(i,u)}}for(let e of t.skills)l(e.owner,{name:e.name,itemKind:`skill`,source:o(e.group),owner:e.owner,tokens:e.promptTokens??0,active:!0});let u=[...a.entries()].map(([e,t])=>{let n=[...t.items].sort(s);return{id:e,label:t.label,kind:t.kind,items:n,tokens:n.reduce((e,t)=>e+(t.active?t.tokens:0),0),inactiveTokens:n.reduce((e,t)=>e+(t.active?0:t.tokens),0)}}).sort((e,t)=>i[e.kind]-i[t.kind]||e.label.localeCompare(t.label));return{version:1,revision:t.revision,groups:u,totalTokens:u.reduce((e,t)=>e+t.tokens,0),inactiveTokens:u.reduce((e,t)=>e+t.inactiveTokens,0),estimator:n}}export{n as CONTEXT_PROJECTION_ESTIMATOR,t as DOOM_CONTEXT_ENTRY_TYPE,c as projectContext};
|
|
2
|
+
//# sourceMappingURL=contextProjection.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextProjection.mjs","names":[],"sources":["../../../src/services/contextProjection.ts"],"sourcesContent":["import type { PackageAttribution } from '@agimon-ai/doompi-config/types';\nimport type { SkillEntry } from '@agimon-ai/doompi-skill/catalog';\nimport { type CountTokens, type ToolSource, tokensForTool } from '@agimon-ai/doompi-ui/toolInventory';\n\n/**\n * What the session is carrying, and what carrying it costs.\n *\n * Grouped by the mode that admitted each package rather than by where the tool\n * came from, because a mode is the thing a reader can switch off. The mechanism\n * (extension, MCP server, plugin) orders rows inside a group instead, so the\n * expensive thing is still easy to find.\n *\n * Schemas never travel. Only names, kinds, owners and integer counts do, which\n * keeps the payload small enough to republish whenever the composition changes.\n */\nexport const CONTEXT_PROJECTION_VERSION = 1;\n\n/** Journal entry the cockpit reads; mirrored by CONTEXT_ENTRY_TYPE in doompi-web. */\nexport const DOOM_CONTEXT_ENTRY_TYPE = 'doom-context';\n\n/** The tokenizer these counts came from, so a reader can judge them. */\nexport const CONTEXT_PROJECTION_ESTIMATOR = 'gpt-tokenizer';\n\nexport type ContextGroupKind = 'major' | 'minor' | 'domain' | 'core';\nexport type ContextItemSource = 'extension' | 'mcp' | 'plugin' | 'core';\n\n/** Everything the runtime could not attribute lands here rather than vanishing. */\nconst CORE_GROUP = 'core';\n/** Pi's own tools have no package; the runtime itself is the owner. */\nconst CORE_OWNER = 'pi';\nconst MCP_KEY_PREFIX = 'mcp:';\n\nconst KIND_ORDER: Record<ContextGroupKind, number> = { major: 0, minor: 1, domain: 2, core: 3 };\nconst SOURCE_ORDER: Record<ContextItemSource, number> = { extension: 0, mcp: 1, plugin: 2, core: 3 };\n\nexport interface ContextItemProjection {\n readonly name: string;\n readonly itemKind: 'tool' | 'skill';\n readonly source: ContextItemSource;\n /** The package, server, or plugin that registered it. */\n readonly owner: string;\n readonly tokens: number;\n readonly active: boolean;\n}\n\nexport interface ContextGroupProjection {\n readonly id: string;\n readonly label: string;\n readonly kind: ContextGroupKind;\n readonly items: readonly ContextItemProjection[];\n /** What the group costs now: active items only. */\n readonly tokens: number;\n /** What its gated items would add if switched on. */\n readonly inactiveTokens: number;\n}\n\nexport interface ContextProjection {\n readonly version: typeof CONTEXT_PROJECTION_VERSION;\n readonly revision: number;\n readonly groups: readonly ContextGroupProjection[];\n readonly totalTokens: number;\n readonly inactiveTokens: number;\n readonly estimator: typeof CONTEXT_PROJECTION_ESTIMATOR;\n}\n\nexport interface ContextProjectionInput {\n readonly revision: number;\n readonly majorMode: string;\n /** Active minor modes, in the order the catalog reports them. */\n readonly minorModes: readonly { readonly id: string; readonly label: string }[];\n readonly sources: readonly ToolSource[];\n readonly skills: readonly SkillEntry[];\n /**\n * Owner identifier to the mode that admitted it.\n *\n * Keys are package names for extensions and layer packages, and plugin or\n * server names for anything a domain carries. The caller owns this join\n * because only it knows how a given deployment resolved its plugins.\n */\n readonly attribution: Readonly<Record<string, PackageAttribution>>;\n readonly countTokens: CountTokens;\n}\n\ninterface Bucket {\n kind: ContextGroupKind;\n label: string;\n items: ContextItemProjection[];\n}\n\nfunction skillSource(group: SkillEntry['group']): ContextItemSource {\n if (group === 'plugins') return 'plugin';\n if (group === 'extensions') return 'extension';\n return 'core';\n}\n\nfunction byRow(left: ContextItemProjection, right: ContextItemProjection): number {\n return SOURCE_ORDER[left.source] - SOURCE_ORDER[right.source] || left.name.localeCompare(right.name);\n}\n\nexport function projectContext(input: ContextProjectionInput): ContextProjection {\n const buckets = new Map<string, Bucket>();\n\n // Declared before anything is placed, so a mode with nothing attributed to it\n // still appears. An empty group is a fact worth showing: it says the mode is\n // on and cheap, not that the runtime forgot about it.\n const declare = (id: string, label: string, kind: ContextGroupKind): void => {\n if (!buckets.has(id)) buckets.set(id, { kind, label, items: [] });\n };\n if (input.majorMode) declare(input.majorMode, input.majorMode, 'major');\n for (const mode of input.minorModes) declare(mode.id, mode.label, 'minor');\n\n const place = (owner: string, item: ContextItemProjection): void => {\n const attributed = input.attribution[owner];\n const id = attributed?.mode ?? CORE_GROUP;\n declare(id, id, attributed ? (attributed.kind === 'domain' ? 'domain' : 'major') : 'core');\n buckets.get(id)?.items.push(item);\n };\n\n for (const source of input.sources) {\n // An extension is owned by its package, an MCP tool by the server that\n // advertised it. `label` is display text like `scaffold · mcp`, so the\n // identifier comes from the key instead: an owner is joined on, not read.\n const owner =\n source.kind === 'extension'\n ? (source.packageName ?? source.key)\n : source.kind === 'mcp'\n ? source.key.slice(MCP_KEY_PREFIX.length)\n : CORE_OWNER;\n for (const tool of source.tools) {\n const cost = tokensForTool(tool, input.countTokens);\n const item: ContextItemProjection = {\n name: tool.name,\n itemKind: 'tool',\n source: source.kind === 'core' ? 'core' : source.kind,\n owner,\n tokens: cost.totalTokens,\n active: tool.active,\n };\n if (source.kind === 'core') {\n declare(CORE_GROUP, CORE_GROUP, 'core');\n buckets.get(CORE_GROUP)?.items.push(item);\n } else {\n place(owner, item);\n }\n }\n }\n\n for (const skill of input.skills) {\n place(skill.owner, {\n name: skill.name,\n itemKind: 'skill',\n source: skillSource(skill.group),\n owner: skill.owner,\n tokens: skill.promptTokens ?? 0,\n // A skill is always offered to the model; there is no inactive state for\n // it the way there is for a tool Pi has filtered out.\n active: true,\n });\n }\n\n const groups: ContextGroupProjection[] = [...buckets.entries()]\n .map(([id, bucket]) => {\n const items = [...bucket.items].sort(byRow);\n // Only what is actually sent counts. Pi builds the prompt from its\n // active tools, so a gated one costs nothing until it is switched on,\n // and folding it into the total would overstate the bill by a third.\n return {\n id,\n label: bucket.label,\n kind: bucket.kind,\n items,\n tokens: items.reduce((total, item) => total + (item.active ? item.tokens : 0), 0),\n inactiveTokens: items.reduce((total, item) => total + (item.active ? 0 : item.tokens), 0),\n };\n })\n .sort((left, right) => KIND_ORDER[left.kind] - KIND_ORDER[right.kind] || left.label.localeCompare(right.label));\n\n return {\n version: CONTEXT_PROJECTION_VERSION,\n revision: input.revision,\n groups,\n totalTokens: groups.reduce((total, group) => total + group.tokens, 0),\n inactiveTokens: groups.reduce((total, group) => total + group.inactiveTokens, 0),\n estimator: CONTEXT_PROJECTION_ESTIMATOR,\n };\n}\n"],"mappings":"mEAkBA,MAAa,EAA0B,eAG1B,EAA+B,gBAMtC,EAAa,OAKb,EAA+C,CAAE,MAAO,EAAG,MAAO,EAAG,OAAQ,EAAG,KAAM,CAAE,EACxF,EAAkD,CAAE,UAAW,EAAG,IAAK,EAAG,OAAQ,EAAG,KAAM,CAAE,EAwDnG,SAAS,EAAY,EAA+C,CAGlE,OAFI,IAAU,UAAkB,SAC5B,IAAU,aAAqB,YAC5B,MACT,CAEA,SAAS,EAAM,EAA6B,EAAsC,CAChF,OAAO,EAAa,EAAK,QAAU,EAAa,EAAM,SAAW,EAAK,KAAK,cAAc,EAAM,IAAI,CACrG,CAEA,SAAgB,EAAe,EAAkD,CAC/E,IAAM,EAAU,IAAI,IAKd,GAAW,EAAY,EAAe,IAAiC,CACtE,EAAQ,IAAI,CAAE,GAAG,EAAQ,IAAI,EAAI,CAAE,OAAM,QAAO,MAAO,CAAC,CAAE,CAAC,CAClE,EACI,EAAM,WAAW,EAAQ,EAAM,UAAW,EAAM,UAAW,OAAO,EACtE,IAAK,IAAM,KAAQ,EAAM,WAAY,EAAQ,EAAK,GAAI,EAAK,MAAO,OAAO,EAEzE,IAAM,GAAS,EAAe,IAAsC,CAClE,IAAM,EAAa,EAAM,YAAY,GAC/B,EAAK,GAAY,MAAQ,EAC/B,EAAQ,EAAI,EAAI,EAAc,EAAW,OAAS,SAAW,SAAW,QAAW,MAAM,EACzF,EAAQ,IAAI,CAAE,CAAC,EAAE,MAAM,KAAK,CAAI,CAClC,EAEA,IAAK,IAAM,KAAU,EAAM,QAAS,CAIlC,IAAM,EACJ,EAAO,OAAS,YACX,EAAO,aAAe,EAAO,IAC9B,EAAO,OAAS,MACd,EAAO,IAAI,MAAM,CAAqB,EACtC,KACR,IAAK,IAAM,KAAQ,EAAO,MAAO,CAC/B,IAAM,EAAO,EAAc,EAAM,EAAM,WAAW,EAC5C,EAA8B,CAClC,KAAM,EAAK,KACX,SAAU,OACV,OAAQ,EAAO,OAAS,OAAS,OAAS,EAAO,KACjD,QACA,OAAQ,EAAK,YACb,OAAQ,EAAK,MACf,EACI,EAAO,OAAS,QAClB,EAAQ,EAAY,EAAY,MAAM,EACtC,EAAQ,IAAI,CAAU,CAAC,EAAE,MAAM,KAAK,CAAI,GAExC,EAAM,EAAO,CAAI,CAErB,CACF,CAEA,IAAK,IAAM,KAAS,EAAM,OACxB,EAAM,EAAM,MAAO,CACjB,KAAM,EAAM,KACZ,SAAU,QACV,OAAQ,EAAY,EAAM,KAAK,EAC/B,MAAO,EAAM,MACb,OAAQ,EAAM,cAAgB,EAG9B,OAAQ,EACV,CAAC,EAGH,IAAM,EAAmC,CAAC,GAAG,EAAQ,QAAQ,CAAC,CAAC,CAC5D,KAAK,CAAC,EAAI,KAAY,CACrB,IAAM,EAAQ,CAAC,GAAG,EAAO,KAAK,CAAC,CAAC,KAAK,CAAK,EAI1C,MAAO,CACL,KACA,MAAO,EAAO,MACd,KAAM,EAAO,KACb,QACA,OAAQ,EAAM,QAAQ,EAAO,IAAS,GAAS,EAAK,OAAS,EAAK,OAAS,GAAI,CAAC,EAChF,eAAgB,EAAM,QAAQ,EAAO,IAAS,GAAS,EAAK,OAAS,EAAI,EAAK,QAAS,CAAC,CAC1F,CACF,CAAC,CAAC,CACD,MAAM,EAAM,IAAU,EAAW,EAAK,MAAQ,EAAW,EAAM,OAAS,EAAK,MAAM,cAAc,EAAM,KAAK,CAAC,EAEhH,MAAO,CACL,QAAA,EACA,SAAU,EAAM,SAChB,SACA,YAAa,EAAO,QAAQ,EAAO,IAAU,EAAQ,EAAM,OAAQ,CAAC,EACpE,eAAgB,EAAO,QAAQ,EAAO,IAAU,EAAQ,EAAM,eAAgB,CAAC,EAC/E,UAAW,CACb,CACF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../adapters/modules/moduleResolution.cjs"),t=require("../adapters/runtimeIdentity.cjs");let n=require("@agimon-ai/doompi-config/majorModes");
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../adapters/modules/moduleResolution.cjs"),t=require("../adapters/runtimeIdentity.cjs");let n=require("@agimon-ai/doompi-config/majorModes"),r=require("@agimon-ai/doompi-ui/extensionName");function i(e){let t={},n=e.majorMode?.name;if(n===void 0)return t;for(let i of e.selections){if(i.entryKind!==`package`||i.outcome!==`resolved`)continue;let e={kind:`major`,mode:n,layer:i.layer},a=i.path===void 0?void 0:(0,r.extensionPackageName)(i.path);a!==void 0&&t[a]===void 0&&(t[a]=e),t[i.selector]===void 0&&(t[i.selector]=e)}return t}const a=new Set([`@agimon-ai/doompi`,`@agimon-ai/doompi-autostop`,`@agimon-ai/doompi-cache`,`@agimon-ai/doompi-config`,`@agimon-ai/doompi-domain`,`@agimon-ai/doompi-major-mode`,`@agimon-ai/doompi-notification`,`@agimon-ai/doompi-profile`,`@agimon-ai/doompi-skill`,`@agimon-ai/doompi-ui`]),o={cordisFinalizer:`cordisFinalizer`,cordisHost:`cordisHost`,effort:`effort`,modeCatalog:`modeCatalog`,ollamaProvider:`ollamaProvider`,transitionCoordinator:`transitionCoordinator`},s={autostop:`@agimon-ai/doompi-autostop/extensions/pi`,cache:`@agimon-ai/doompi-cache/extensions/pi`,config:`@agimon-ai/doompi-config/extensions/pi`,domain:`@agimon-ai/doompi-domain/extensions/pi`,majorMode:`@agimon-ai/doompi-major-mode/extensions/pi`,notification:`@agimon-ai/doompi-notification/extensions/pi`,profile:`@agimon-ai/doompi-profile/extensions/pi`,skill:`@agimon-ai/doompi-skill/extensions/pi`,ui:`@agimon-ai/doompi-ui/extensions/pi`},c={ownEntry:e.ownEntry,packageEntry:e.packageEntry,optionalPackageEntry:e.optionalPackageEntry,packageEntries:e.packageEntries,optionalPackageEntries:e.optionalPackageEntries,localEntry:e.localEntry,localEntries:e.localEntries,localPackageEntries:e.localPackageEntries,localPackageName:e.localPackageName};function l(e,t){return Error(`Cannot resolve configured package "${e}" from ${t}.`)}function u(t){if(!t)return c;let n=t=>a.has(d(t))?e.optionalPackageEntry(t):void 0,r=t=>a.has(d(t))?e.optionalPackageEntries(t):void 0;return{ownEntry:e.ownEntry,packageEntry:r=>{let i=e.consumerPackageEntry(r,t)??n(r);if(!i)throw l(r,t);return i},optionalPackageEntry:r=>e.consumerPackageEntry(r,t)??n(r),packageEntries:n=>{let i=e.consumerPackageEntries(n,t)??r(n);if(!i)throw l(n,t);return i},optionalPackageEntries:n=>e.consumerPackageEntries(n,t)??r(n),localEntry:e.localEntry,localEntries:e.localEntries,localPackageEntries:e.localPackageEntries,localPackageName:e.localPackageName}}function d(e){let t=e.split(`/`);return e.startsWith(`@`)?t.slice(0,2).join(`/`):t[0]??e}function f(e,t){let n=d(e);if(a.has(n))throw Error(`Layer "${t}" cannot select fixed DoomPi host package "${n}" as a feature extension.`)}function p(e,t,n){let r=e.localEntries?.(t,n);if(r!==void 0)return r;let i=e.localEntry(t,n);return i?[i]:void 0}function m(e,t,n){let r=e.localPackageEntries?.(t,n);return r===void 0?p(e,t,n):r}function h(e,n,r){return{...e,manifestIndex:n,outcome:`resolved`,path:r,canonicalPath:t.canonicalModulePath(r)}}function g(e,t){return{...e,manifestIndex:0,outcome:`missing-optional`,diagnostic:t}}function _(e){return e instanceof Error?e.message:String(e)}function v(e,t,r,i){let a=[],o=e.extensions??[];for(let[s,c]of o.entries()){let o={layer:t,layerIndex:r,entryKind:`extension`,entryIndex:s,selector:c,...e.filePath?{sourceFile:e.filePath}:{},baseDirectory:e.baseDirectory,optional:!1};if(!(0,n.isLocalPackageSpecifier)(c)){a.push(h(o,0,i.ownEntry(c)));continue}let l=p(i,c,e.baseDirectory);if(!l?.length)throw Error(`Layer "${t}" extension "${c}" does not resolve under ${e.baseDirectory}. Point it at a Pi extension file or directory.`);l.forEach((e,t)=>{a.push(h(o,t,e))})}let s=o.length;for(let[o,c]of(e.packages??[]).entries()){let l=typeof c==`string`?c:c.name,u=typeof c!=`string`&&c.optional===!0,d=typeof c==`string`?void 0:c.config,p={layer:t,layerIndex:r,entryKind:`package`,entryIndex:s+o,selector:l,...e.filePath?{sourceFile:e.filePath}:{},baseDirectory:e.baseDirectory,optional:u,...d===void 0?{}:{config:d}},v;try{if((0,n.isLocalPackageSpecifier)(l)){let n=i.localPackageName?.(l,e.baseDirectory);n&&f(n,t),v=m(i,l,e.baseDirectory)}else if(f(l,t),u){if(v=i.optionalPackageEntries?.(l),v===void 0&&!i.optionalPackageEntries){let e=i.optionalPackageEntry(l);v=e?[e]:void 0}}else v=i.packageEntries?.(l)??[i.packageEntry(l)]}catch(e){if(u){a.push(g(p,_(e)));continue}throw e}if(!v?.length){if(u){a.push(g(p,`Optional package "${l}" is unavailable or declares no Pi extensions.`));continue}throw(0,n.isLocalPackageSpecifier)(l)?Error(`Layer "${t}" package "${l}" does not resolve under ${e.baseDirectory}. Point it at an extension file, or a directory whose package.json declares pi.extensions.`):Error(`Layer "${t}" package "${l}" declares no Pi extensions.`)}v.forEach((e,t)=>{a.push(h(p,t,e))})}return a}function y(e,t,n,r){let i=e.layers[t];if(!i)throw Error(`Unknown layer: ${t}`);return v(i,t,n,r)}function b(e,t){return e.default?v(e.default,`default`,-1,t):[]}function x(e){let t=e.resolvers??c;return e.layers.flatMap((n,r)=>y(e.majorModesConfig,n,r,t))}function S(e){let n=new Set,r=[];for(let i of e){let e=t.canonicalModulePath(i);n.has(e)||(n.add(e),r.push(i))}return r}function C(e){return S(e.flatMap(e=>e.outcome===`resolved`&&e.path?[e.path]:[]))}function w(e,t,n){let r=e.resolvers??c,i=[r.ownEntry(o.cordisHost),r.ownEntry(o.modeCatalog),r.packageEntry(s.config),r.ownEntry(o.transitionCoordinator),r.packageEntry(s.ui)];return e.mute||i.push(r.packageEntry(s.notification)),i.push(r.packageEntry(s.profile),r.packageEntry(s.majorMode),r.packageEntry(s.skill),r.packageEntry(s.domain),r.ownEntry(o.effort)),e.preset===`ollama`&&i.push(r.ownEntry(o.ollamaProvider)),i.push(...t,...n),e.personaEntry&&i.push(e.personaEntry),e.autoStop&&i.push(r.packageEntry(s.autostop)),i.push(r.packageEntry(s.cache)),i.push(r.ownEntry(o.cordisFinalizer)),S(i)}function T(e,t,n){let r=e.resolvers??c,i=[r.ownEntry(o.cordisHost),r.packageEntry(s.config),...t,...n];return e.preset===`ollama`&&i.push(r.ownEntry(o.ollamaProvider)),e.personaEntry&&i.push(e.personaEntry),i.push(r.ownEntry(o.cordisFinalizer)),S(i)}function E(e){return Array.isArray(e)?e.map(E):typeof e!=`object`||!e?e:Object.fromEntries(Object.entries(e).filter(([,e])=>e!==void 0).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,E(t)]))}function D(e){return t.sha256(JSON.stringify(E({...e,contract:{composition:4,standardPiExtension:2,fixedCorePackages:[...a]},parentCanonicalActivation:e.parentActivation.map(t.canonicalModulePath),childCanonicalActivation:e.childActivation.map(t.canonicalModulePath)})))}function O(e){let t=e.resolvers??c,n=b(e.majorModesConfig,t),r=x(e),i=[...n,...r],a=C(n),o=C(r),s=e.layers.map((t,n)=>{let r=e.majorModesConfig.layers[t];if(!r)throw Error(`Unknown layer: ${t}`);return{name:t,index:n,...r.filePath?{sourceFile:r.filePath}:{},baseDirectory:r.baseDirectory}}),l=e.majorMode?e.majorModesConfig.majorModeSources?.[e.majorMode]:void 0,u={version:4,...e.majorMode?{majorMode:{name:e.majorMode,...l?.filePath?{sourceFile:l.filePath}:{},...l?.baseDirectory?{baseDirectory:l.baseDirectory}:{}}}:{},layers:s,selections:i,parentActivation:w(e,a,o),childActivation:T(e,a,o)};return{...u,fingerprint:D(u)}}function k(e){return[...O(e).parentActivation]}function A(e){return[...O(e).childActivation]}exports.COMPOSITION_FINGERPRINT_VERSION=4,exports.LAYER_RESOLVERS=c,exports.OLLAMA_PRESET=`ollama`,exports.PERSONA_ENTRY=`@agimon-ai/doompi-profile/extensions/persona`,exports.STANDARD_PI_EXTENSION_CONTRACT_VERSION=2,exports.assembleChildExtensions=A,exports.assembleExtensions=k,exports.createLayerResolvers=u,exports.packageAttribution=i,exports.resolveExtensionComposition=O;
|
|
2
2
|
//# sourceMappingURL=extensionAssembler.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extensionAssembler.cjs","names":["resolvePackageEntry","resolveOptionalPackageEntry","resolvePackageEntries","resolveOptionalPackageEntries","resolveLocalPackageName","consumerPackageEntry","consumerPackageEntries","canonicalModulePath","isLocalPackageSpecifier","sha256"],"sources":["../../../src/services/extensionAssembler.ts"],"sourcesContent":["import {\n isLocalPackageSpecifier,\n type LayerResolvers,\n type MajorModesConfig,\n} from '@agimon-ai/doompi-config/majorModes';\nimport {\n consumerPackageEntries,\n consumerPackageEntry,\n localEntries,\n localEntry,\n localPackageEntries,\n ownEntry,\n localPackageName as resolveLocalPackageName,\n optionalPackageEntries as resolveOptionalPackageEntries,\n optionalPackageEntry as resolveOptionalPackageEntry,\n packageEntries as resolvePackageEntries,\n packageEntry as resolvePackageEntry,\n} from '../adapters/modules/moduleResolution';\nimport { canonicalModulePath, sha256 } from '../adapters/runtimeIdentity';\n\nexport interface ExtensionLayerResolvers extends LayerResolvers {\n /** Resolves a path authored under packages through its standard Pi manifest. */\n localPackageEntries?: (specifier: string, baseDirectory: string) => string[] | undefined;\n /** Canonical manifest name for a path that represents a package directory. */\n localPackageName?: (specifier: string, baseDirectory: string) => string | undefined;\n}\n\nexport interface ExtensionContext {\n agents: boolean;\n autoStop: boolean;\n mute?: boolean;\n preset?: string;\n personaEntry?: string;\n /** Named mode whose occurrence is part of composition identity. */\n majorMode?: string;\n /** Ordered layer occurrences selected by the active major mode. */\n layers: string[];\n majorModesConfig: MajorModesConfig;\n /** Resolver override used by synchronized replay. */\n resolvers?: ExtensionLayerResolvers;\n}\n\nexport type SelectedEntryKind = 'extension' | 'package';\ntype ExtensionResolutionOutcome = 'resolved' | 'missing-optional';\n\n/**\n * One resolver-derived extension occurrence.\n *\n * This remains private to DoomPi composition. It is not package metadata and\n * deliberately retains authored duplicates even though activation paths are\n * deduplicated later.\n */\ninterface ResolvedExtensionSelection {\n readonly layer: string;\n readonly layerIndex: number;\n readonly entryKind: SelectedEntryKind;\n readonly entryIndex: number;\n readonly manifestIndex: number;\n readonly selector: string;\n readonly sourceFile?: string;\n readonly baseDirectory: string;\n readonly optional: boolean;\n readonly outcome: ExtensionResolutionOutcome;\n readonly path?: string;\n readonly canonicalPath?: string;\n readonly diagnostic?: string;\n readonly config?: Record<string, unknown>;\n}\n\nexport interface CompositionLayerOccurrence {\n readonly name: string;\n readonly index: number;\n readonly sourceFile?: string;\n readonly baseDirectory: string;\n}\n\n/** Internal normalized composition shared by launch, sync, bundles, and replay. */\nexport interface ExtensionComposition {\n readonly version: number;\n readonly majorMode?: {\n readonly name: string;\n readonly sourceFile?: string;\n readonly baseDirectory?: string;\n };\n readonly layers: readonly CompositionLayerOccurrence[];\n readonly selections: readonly ResolvedExtensionSelection[];\n /** Actual Pi factory activation order, not CLI argument construction order. */\n readonly parentActivation: readonly string[];\n /** Actual Pi factory activation order inherited by detached children. */\n readonly childActivation: readonly string[];\n readonly fingerprint: string;\n}\n\nexport const COMPOSITION_FINGERPRINT_VERSION = 4;\nexport const STANDARD_PI_EXTENSION_CONTRACT_VERSION = 2;\n\nconst DEFAULT_SELECTION_LAYER = 'default';\nconst DEFAULT_SELECTION_LAYER_INDEX = -1;\n\nconst FIXED_CORE_PACKAGES = new Set([\n '@agimon-ai/doompi',\n '@agimon-ai/doompi-autostop',\n '@agimon-ai/doompi-cache',\n '@agimon-ai/doompi-config',\n '@agimon-ai/doompi-domain',\n '@agimon-ai/doompi-major-mode',\n '@agimon-ai/doompi-notification',\n '@agimon-ai/doompi-profile',\n '@agimon-ai/doompi-skill',\n '@agimon-ai/doompi-ui',\n]);\n\nconst OWN_ENTRIES = {\n cordisFinalizer: 'cordisFinalizer',\n cordisHost: 'cordisHost',\n effort: 'effort',\n modeCatalog: 'modeCatalog',\n ollamaProvider: 'ollamaProvider',\n transitionCoordinator: 'transitionCoordinator',\n} as const;\n\nconst CORE_PACKAGE_ENTRIES = {\n autostop: '@agimon-ai/doompi-autostop/extensions/pi',\n cache: '@agimon-ai/doompi-cache/extensions/pi',\n config: '@agimon-ai/doompi-config/extensions/pi',\n domain: '@agimon-ai/doompi-domain/extensions/pi',\n majorMode: '@agimon-ai/doompi-major-mode/extensions/pi',\n notification: '@agimon-ai/doompi-notification/extensions/pi',\n profile: '@agimon-ai/doompi-profile/extensions/pi',\n skill: '@agimon-ai/doompi-skill/extensions/pi',\n ui: '@agimon-ai/doompi-ui/extensions/pi',\n} as const;\n\nexport const OLLAMA_PRESET = 'ollama';\n\n/**\n * Always available so /profile can pick a persona later, and the one entry a\n * detached child shares with its parent: children get the persona without the\n * command, because they have no transition coordinator to run a switch through.\n *\n * An explicit subpath rather than the bare package name, so it resolves to\n * exactly this file rather than to whatever pi.extensions lists.\n */\nexport const PERSONA_ENTRY = '@agimon-ai/doompi-profile/extensions/persona';\n\nexport const LAYER_RESOLVERS: ExtensionLayerResolvers = {\n ownEntry,\n packageEntry: resolvePackageEntry,\n optionalPackageEntry: resolveOptionalPackageEntry,\n packageEntries: resolvePackageEntries,\n optionalPackageEntries: resolveOptionalPackageEntries,\n localEntry,\n localEntries,\n localPackageEntries,\n localPackageName: resolveLocalPackageName,\n};\n\nfunction missingConsumerPackage(name: string, consumerRoot: string): Error {\n return new Error(`Cannot resolve configured package \"${name}\" from ${consumerRoot}.`);\n}\n\n/**\n * Resolves configured packages only from the consumer, while fixed core entries\n * may fall back to the host package's private dependency closure.\n */\nexport function createLayerResolvers(consumerRoot?: string): ExtensionLayerResolvers {\n if (!consumerRoot) return LAYER_RESOLVERS;\n const fallbackEntry = (name: string): string | undefined =>\n FIXED_CORE_PACKAGES.has(packageName(name)) ? resolveOptionalPackageEntry(name) : undefined;\n const fallbackEntries = (name: string): string[] | undefined =>\n FIXED_CORE_PACKAGES.has(packageName(name)) ? resolveOptionalPackageEntries(name) : undefined;\n const requiredEntry = (name: string): string => {\n const entry = consumerPackageEntry(name, consumerRoot) ?? fallbackEntry(name);\n if (!entry) throw missingConsumerPackage(name, consumerRoot);\n return entry;\n };\n const requiredEntries = (name: string): string[] => {\n const entries = consumerPackageEntries(name, consumerRoot) ?? fallbackEntries(name);\n if (!entries) throw missingConsumerPackage(name, consumerRoot);\n return entries;\n };\n return {\n ownEntry,\n packageEntry: requiredEntry,\n optionalPackageEntry: (name) => consumerPackageEntry(name, consumerRoot) ?? fallbackEntry(name),\n packageEntries: requiredEntries,\n optionalPackageEntries: (name) => consumerPackageEntries(name, consumerRoot) ?? fallbackEntries(name),\n localEntry,\n localEntries,\n localPackageEntries,\n localPackageName: resolveLocalPackageName,\n };\n}\n\nfunction packageName(specifier: string): string {\n const segments = specifier.split('/');\n return specifier.startsWith('@') ? segments.slice(0, 2).join('/') : (segments[0] ?? specifier);\n}\n\nfunction assertFeaturePackage(specifier: string, layer: string): void {\n const selectedPackage = packageName(specifier);\n if (FIXED_CORE_PACKAGES.has(selectedPackage)) {\n throw new Error(\n `Layer \"${layer}\" cannot select fixed DoomPi host package \"${selectedPackage}\" as a feature extension.`,\n );\n }\n}\n\nfunction resolveLocalExtensionEntries(\n resolvers: ExtensionLayerResolvers,\n specifier: string,\n baseDirectory: string,\n): string[] | undefined {\n const resolved = resolvers.localEntries?.(specifier, baseDirectory);\n if (resolved !== undefined) return resolved;\n const single = resolvers.localEntry(specifier, baseDirectory);\n return single ? [single] : undefined;\n}\n\nfunction resolveLocalPackageSelections(\n resolvers: ExtensionLayerResolvers,\n specifier: string,\n baseDirectory: string,\n): string[] | undefined {\n const resolved = resolvers.localPackageEntries?.(specifier, baseDirectory);\n if (resolved !== undefined) return resolved;\n return resolveLocalExtensionEntries(resolvers, specifier, baseDirectory);\n}\n\ninterface SelectionIdentity {\n layer: string;\n layerIndex: number;\n entryKind: SelectedEntryKind;\n entryIndex: number;\n selector: string;\n sourceFile?: string;\n baseDirectory: string;\n optional: boolean;\n config?: Record<string, unknown>;\n}\n\nfunction resolvedSelection(\n identity: SelectionIdentity,\n manifestIndex: number,\n resolvedPath: string,\n): ResolvedExtensionSelection {\n return {\n ...identity,\n manifestIndex,\n outcome: 'resolved',\n path: resolvedPath,\n canonicalPath: canonicalModulePath(resolvedPath),\n };\n}\n\nfunction missingOptionalSelection(identity: SelectionIdentity, diagnostic: string): ResolvedExtensionSelection {\n return {\n ...identity,\n manifestIndex: 0,\n outcome: 'missing-optional',\n diagnostic,\n };\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction resolveDefinitionSelections(\n definition: MajorModesConfig['layers'][string],\n layer: string,\n layerIndex: number,\n resolvers: ExtensionLayerResolvers,\n): ResolvedExtensionSelection[] {\n const resolvedSelections: ResolvedExtensionSelection[] = [];\n const extensionEntries = definition.extensions ?? [];\n for (const [entryIndex, selector] of extensionEntries.entries()) {\n const identity: SelectionIdentity = {\n layer,\n layerIndex,\n entryKind: 'extension',\n entryIndex,\n selector,\n ...(definition.filePath ? { sourceFile: definition.filePath } : {}),\n baseDirectory: definition.baseDirectory,\n optional: false,\n };\n if (!isLocalPackageSpecifier(selector)) {\n resolvedSelections.push(resolvedSelection(identity, 0, resolvers.ownEntry(selector)));\n continue;\n }\n const resolved = resolveLocalExtensionEntries(resolvers, selector, definition.baseDirectory);\n if (!resolved?.length) {\n throw new Error(\n `Layer \"${layer}\" extension \"${selector}\" does not resolve under ${definition.baseDirectory}. ` +\n 'Point it at a Pi extension file or directory.',\n );\n }\n resolved.forEach((resolvedPath, manifestIndex) => {\n resolvedSelections.push(resolvedSelection(identity, manifestIndex, resolvedPath));\n });\n }\n\n const packageOffset = extensionEntries.length;\n for (const [packageIndex, configured] of (definition.packages ?? []).entries()) {\n const selector = typeof configured === 'string' ? configured : configured.name;\n const optional = typeof configured === 'string' ? false : configured.optional === true;\n const configValue = typeof configured === 'string' ? undefined : configured.config;\n const identity: SelectionIdentity = {\n layer,\n layerIndex,\n entryKind: 'package',\n entryIndex: packageOffset + packageIndex,\n selector,\n ...(definition.filePath ? { sourceFile: definition.filePath } : {}),\n baseDirectory: definition.baseDirectory,\n optional,\n ...(configValue === undefined ? {} : { config: configValue }),\n };\n\n let resolved: string[] | undefined;\n try {\n if (isLocalPackageSpecifier(selector)) {\n const manifestName = resolvers.localPackageName?.(selector, definition.baseDirectory);\n if (manifestName) assertFeaturePackage(manifestName, layer);\n resolved = resolveLocalPackageSelections(resolvers, selector, definition.baseDirectory);\n } else {\n assertFeaturePackage(selector, layer);\n if (optional) {\n resolved = resolvers.optionalPackageEntries?.(selector);\n if (resolved === undefined && !resolvers.optionalPackageEntries) {\n const single = resolvers.optionalPackageEntry(selector);\n resolved = single ? [single] : undefined;\n }\n } else {\n resolved = resolvers.packageEntries?.(selector) ?? [resolvers.packageEntry(selector)];\n }\n }\n } catch (error) {\n if (optional) {\n resolvedSelections.push(missingOptionalSelection(identity, errorMessage(error)));\n continue;\n }\n throw error;\n }\n\n if (!resolved?.length) {\n if (optional) {\n resolvedSelections.push(\n missingOptionalSelection(\n identity,\n `Optional package \"${selector}\" is unavailable or declares no Pi extensions.`,\n ),\n );\n continue;\n }\n if (isLocalPackageSpecifier(selector)) {\n throw new Error(\n `Layer \"${layer}\" package \"${selector}\" does not resolve under ${definition.baseDirectory}. ` +\n 'Point it at an extension file, or a directory whose package.json declares pi.extensions.',\n );\n }\n throw new Error(`Layer \"${layer}\" package \"${selector}\" declares no Pi extensions.`);\n }\n\n resolved.forEach((resolvedPath, manifestIndex) => {\n resolvedSelections.push(resolvedSelection(identity, manifestIndex, resolvedPath));\n });\n }\n\n return resolvedSelections;\n}\n\nfunction resolveLayerSelections(\n config: MajorModesConfig,\n layer: string,\n layerIndex: number,\n resolvers: ExtensionLayerResolvers,\n): ResolvedExtensionSelection[] {\n const definition = config.layers[layer];\n if (!definition) throw new Error(`Unknown layer: ${layer}`);\n return resolveDefinitionSelections(definition, layer, layerIndex, resolvers);\n}\n\nfunction resolveDefaultSelections(\n config: MajorModesConfig,\n resolvers: ExtensionLayerResolvers,\n): ResolvedExtensionSelection[] {\n if (!config.default) return [];\n return resolveDefinitionSelections(config.default, DEFAULT_SELECTION_LAYER, DEFAULT_SELECTION_LAYER_INDEX, resolvers);\n}\n\nfunction resolveSelectedExtensions(context: ExtensionContext): ResolvedExtensionSelection[] {\n const resolvers = context.resolvers ?? LAYER_RESOLVERS;\n return context.layers.flatMap((layer, layerIndex) =>\n resolveLayerSelections(context.majorModesConfig, layer, layerIndex, resolvers),\n );\n}\n\nfunction deduplicatePaths(paths: readonly string[]): string[] {\n const seen = new Set<string>();\n const selected: string[] = [];\n for (const entry of paths) {\n const identity = canonicalModulePath(entry);\n if (seen.has(identity)) continue;\n seen.add(identity);\n selected.push(entry);\n }\n return selected;\n}\n\nfunction selectedFeaturePaths(selections: readonly ResolvedExtensionSelection[]): string[] {\n return deduplicatePaths(\n selections.flatMap((entry) => (entry.outcome === 'resolved' && entry.path ? [entry.path] : [])),\n );\n}\n\nfunction parentActivation(\n context: ExtensionContext,\n distributionPaths: readonly string[],\n featurePaths: readonly string[],\n): string[] {\n const resolve = context.resolvers ?? LAYER_RESOLVERS;\n const activation = [\n resolve.ownEntry(OWN_ENTRIES.cordisHost),\n resolve.ownEntry(OWN_ENTRIES.modeCatalog),\n resolve.packageEntry(CORE_PACKAGE_ENTRIES.config),\n resolve.ownEntry(OWN_ENTRIES.transitionCoordinator),\n resolve.packageEntry(CORE_PACKAGE_ENTRIES.ui),\n ];\n if (!context.mute) activation.push(resolve.packageEntry(CORE_PACKAGE_ENTRIES.notification));\n activation.push(\n resolve.packageEntry(CORE_PACKAGE_ENTRIES.profile),\n resolve.packageEntry(CORE_PACKAGE_ENTRIES.majorMode),\n resolve.packageEntry(CORE_PACKAGE_ENTRIES.skill),\n resolve.packageEntry(CORE_PACKAGE_ENTRIES.domain),\n resolve.ownEntry(OWN_ENTRIES.effort),\n );\n if (context.preset === OLLAMA_PRESET) activation.push(resolve.ownEntry(OWN_ENTRIES.ollamaProvider));\n activation.push(...distributionPaths, ...featurePaths);\n if (context.personaEntry) activation.push(context.personaEntry);\n if (context.autoStop) activation.push(resolve.packageEntry(CORE_PACKAGE_ENTRIES.autostop));\n activation.push(resolve.packageEntry(CORE_PACKAGE_ENTRIES.cache));\n activation.push(resolve.ownEntry(OWN_ENTRIES.cordisFinalizer));\n return deduplicatePaths(activation);\n}\n\nfunction childActivation(\n context: ExtensionContext,\n distributionPaths: readonly string[],\n featurePaths: readonly string[],\n): string[] {\n const resolve = context.resolvers ?? LAYER_RESOLVERS;\n const activation = [\n resolve.ownEntry(OWN_ENTRIES.cordisHost),\n resolve.packageEntry(CORE_PACKAGE_ENTRIES.config),\n ...distributionPaths,\n ...featurePaths,\n ];\n if (context.preset === OLLAMA_PRESET) activation.push(resolve.ownEntry(OWN_ENTRIES.ollamaProvider));\n if (context.personaEntry) activation.push(context.personaEntry);\n activation.push(resolve.ownEntry(OWN_ENTRIES.cordisFinalizer));\n return deduplicatePaths(activation);\n}\n\nfunction canonicalValue(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(canonicalValue);\n if (value === null || typeof value !== 'object') return value;\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .filter(([, entry]) => entry !== undefined)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, entry]) => [key, canonicalValue(entry)]),\n );\n}\n\nfunction compositionFingerprint(composition: Omit<ExtensionComposition, 'fingerprint'>): string {\n return sha256(\n JSON.stringify(\n canonicalValue({\n ...composition,\n contract: {\n composition: COMPOSITION_FINGERPRINT_VERSION,\n standardPiExtension: STANDARD_PI_EXTENSION_CONTRACT_VERSION,\n fixedCorePackages: [...FIXED_CORE_PACKAGES],\n },\n parentCanonicalActivation: composition.parentActivation.map(canonicalModulePath),\n childCanonicalActivation: composition.childActivation.map(canonicalModulePath),\n }),\n ),\n );\n}\n\n/** Resolve one deterministic parent/child composition from authored layer occurrences. */\nexport function resolveExtensionComposition(context: ExtensionContext): ExtensionComposition {\n const resolvers = context.resolvers ?? LAYER_RESOLVERS;\n const defaultSelections = resolveDefaultSelections(context.majorModesConfig, resolvers);\n const layerSelections = resolveSelectedExtensions(context);\n const selections = [...defaultSelections, ...layerSelections];\n const distributionPaths = selectedFeaturePaths(defaultSelections);\n const featurePaths = selectedFeaturePaths(layerSelections);\n const layers = context.layers.map((name, index): CompositionLayerOccurrence => {\n const definition = context.majorModesConfig.layers[name];\n if (!definition) throw new Error(`Unknown layer: ${name}`);\n return {\n name,\n index,\n ...(definition.filePath ? { sourceFile: definition.filePath } : {}),\n baseDirectory: definition.baseDirectory,\n };\n });\n const modeSource = context.majorMode ? context.majorModesConfig.majorModeSources?.[context.majorMode] : undefined;\n const withoutFingerprint: Omit<ExtensionComposition, 'fingerprint'> = {\n version: COMPOSITION_FINGERPRINT_VERSION,\n ...(context.majorMode\n ? {\n majorMode: {\n name: context.majorMode,\n ...(modeSource?.filePath ? { sourceFile: modeSource.filePath } : {}),\n ...(modeSource?.baseDirectory ? { baseDirectory: modeSource.baseDirectory } : {}),\n },\n }\n : {}),\n layers,\n selections,\n parentActivation: parentActivation(context, distributionPaths, featurePaths),\n childActivation: childActivation(context, distributionPaths, featurePaths),\n };\n return { ...withoutFingerprint, fingerprint: compositionFingerprint(withoutFingerprint) };\n}\n\n/** Assemble parent entries in actual Pi factory activation order. */\nexport function assembleExtensions(context: ExtensionContext): string[] {\n return [...resolveExtensionComposition(context).parentActivation];\n}\n\n/** Assemble detached-child entries in actual Pi factory activation order. */\nexport function assembleChildExtensions(context: ExtensionContext): string[] {\n return [...resolveExtensionComposition(context).childActivation];\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"extensionAssembler.cjs","names":["extensionPackageName","resolvePackageEntry","resolveOptionalPackageEntry","resolvePackageEntries","resolveOptionalPackageEntries","resolveLocalPackageName","consumerPackageEntry","consumerPackageEntries","canonicalModulePath","isLocalPackageSpecifier","sha256"],"sources":["../../../src/services/extensionAssembler.ts"],"sourcesContent":["import {\n isLocalPackageSpecifier,\n type LayerResolvers,\n type MajorModesConfig,\n} from '@agimon-ai/doompi-config/majorModes';\nimport type { PackageAttribution } from '@agimon-ai/doompi-config/types';\nimport { extensionPackageName } from '@agimon-ai/doompi-ui/extensionName';\nimport {\n consumerPackageEntries,\n consumerPackageEntry,\n localEntries,\n localEntry,\n localPackageEntries,\n ownEntry,\n localPackageName as resolveLocalPackageName,\n optionalPackageEntries as resolveOptionalPackageEntries,\n optionalPackageEntry as resolveOptionalPackageEntry,\n packageEntries as resolvePackageEntries,\n packageEntry as resolvePackageEntry,\n} from '../adapters/modules/moduleResolution';\nimport { canonicalModulePath, sha256 } from '../adapters/runtimeIdentity';\n\nexport interface ExtensionLayerResolvers extends LayerResolvers {\n /** Resolves a path authored under packages through its standard Pi manifest. */\n localPackageEntries?: (specifier: string, baseDirectory: string) => string[] | undefined;\n /** Canonical manifest name for a path that represents a package directory. */\n localPackageName?: (specifier: string, baseDirectory: string) => string | undefined;\n}\n\nexport interface ExtensionContext {\n agents: boolean;\n autoStop: boolean;\n mute?: boolean;\n preset?: string;\n personaEntry?: string;\n /** Named mode whose occurrence is part of composition identity. */\n majorMode?: string;\n /** Ordered layer occurrences selected by the active major mode. */\n layers: string[];\n majorModesConfig: MajorModesConfig;\n /** Resolver override used by synchronized replay. */\n resolvers?: ExtensionLayerResolvers;\n}\n\nexport type SelectedEntryKind = 'extension' | 'package';\ntype ExtensionResolutionOutcome = 'resolved' | 'missing-optional';\n\n/**\n * One resolver-derived extension occurrence.\n *\n * This remains private to DoomPi composition. It is not package metadata and\n * deliberately retains authored duplicates even though activation paths are\n * deduplicated later.\n */\ninterface ResolvedExtensionSelection {\n readonly layer: string;\n readonly layerIndex: number;\n readonly entryKind: SelectedEntryKind;\n readonly entryIndex: number;\n readonly manifestIndex: number;\n readonly selector: string;\n readonly sourceFile?: string;\n readonly baseDirectory: string;\n readonly optional: boolean;\n readonly outcome: ExtensionResolutionOutcome;\n readonly path?: string;\n readonly canonicalPath?: string;\n readonly diagnostic?: string;\n readonly config?: Record<string, unknown>;\n}\n\nexport interface CompositionLayerOccurrence {\n readonly name: string;\n readonly index: number;\n readonly sourceFile?: string;\n readonly baseDirectory: string;\n}\n\n/** Internal normalized composition shared by launch, sync, bundles, and replay. */\nexport interface ExtensionComposition {\n readonly version: number;\n readonly majorMode?: {\n readonly name: string;\n readonly sourceFile?: string;\n readonly baseDirectory?: string;\n };\n readonly layers: readonly CompositionLayerOccurrence[];\n readonly selections: readonly ResolvedExtensionSelection[];\n /** Actual Pi factory activation order, not CLI argument construction order. */\n readonly parentActivation: readonly string[];\n /** Actual Pi factory activation order inherited by detached children. */\n readonly childActivation: readonly string[];\n readonly fingerprint: string;\n}\n\n/**\n * Which layer of which major mode admitted each package.\n *\n * The composition already holds this join while it resolves package names to\n * entry paths, then drops it, so a session cannot afterwards say why a tool is\n * present. Reducing it here keeps the selection type private and costs one pass\n * over an array the caller already has.\n *\n * Only `package` entries appear. A bare `extension` selector is a path rather\n * than a package name, so it has nothing a registered tool could be joined on.\n *\n * Keyed by manifest name first, because that is what a registered tool resolves\n * to. The selector is kept as an alias: a layer may name a package as\n * `@agimon-ai/doompi-team` when published or `./layers/team/doompi-team` in a\n * checkout, and both have to find the same layer.\n */\nexport function packageAttribution(composition: ExtensionComposition): Record<string, PackageAttribution> {\n const attribution: Record<string, PackageAttribution> = {};\n const mode = composition.majorMode?.name;\n if (mode === undefined) return attribution;\n for (const selection of composition.selections) {\n if (selection.entryKind !== 'package') continue;\n if (selection.outcome !== 'resolved') continue;\n // First layer wins, matching activation order: the earlier layer is the one\n // whose copy of a duplicated package actually loaded.\n const value: PackageAttribution = { kind: 'major', mode, layer: selection.layer };\n const manifest = selection.path === undefined ? undefined : extensionPackageName(selection.path);\n if (manifest !== undefined && attribution[manifest] === undefined) attribution[manifest] = value;\n if (attribution[selection.selector] === undefined) attribution[selection.selector] = value;\n }\n return attribution;\n}\nexport const COMPOSITION_FINGERPRINT_VERSION = 4;\nexport const STANDARD_PI_EXTENSION_CONTRACT_VERSION = 2;\n\nconst DEFAULT_SELECTION_LAYER = 'default';\nconst DEFAULT_SELECTION_LAYER_INDEX = -1;\n\nconst FIXED_CORE_PACKAGES = new Set([\n '@agimon-ai/doompi',\n '@agimon-ai/doompi-autostop',\n '@agimon-ai/doompi-cache',\n '@agimon-ai/doompi-config',\n '@agimon-ai/doompi-domain',\n '@agimon-ai/doompi-major-mode',\n '@agimon-ai/doompi-notification',\n '@agimon-ai/doompi-profile',\n '@agimon-ai/doompi-skill',\n '@agimon-ai/doompi-ui',\n]);\n\nconst OWN_ENTRIES = {\n cordisFinalizer: 'cordisFinalizer',\n cordisHost: 'cordisHost',\n effort: 'effort',\n modeCatalog: 'modeCatalog',\n ollamaProvider: 'ollamaProvider',\n transitionCoordinator: 'transitionCoordinator',\n} as const;\n\nconst CORE_PACKAGE_ENTRIES = {\n autostop: '@agimon-ai/doompi-autostop/extensions/pi',\n cache: '@agimon-ai/doompi-cache/extensions/pi',\n config: '@agimon-ai/doompi-config/extensions/pi',\n domain: '@agimon-ai/doompi-domain/extensions/pi',\n majorMode: '@agimon-ai/doompi-major-mode/extensions/pi',\n notification: '@agimon-ai/doompi-notification/extensions/pi',\n profile: '@agimon-ai/doompi-profile/extensions/pi',\n skill: '@agimon-ai/doompi-skill/extensions/pi',\n ui: '@agimon-ai/doompi-ui/extensions/pi',\n} as const;\n\nexport const OLLAMA_PRESET = 'ollama';\n\n/**\n * Always available so /profile can pick a persona later, and the one entry a\n * detached child shares with its parent: children get the persona without the\n * command, because they have no transition coordinator to run a switch through.\n *\n * An explicit subpath rather than the bare package name, so it resolves to\n * exactly this file rather than to whatever pi.extensions lists.\n */\nexport const PERSONA_ENTRY = '@agimon-ai/doompi-profile/extensions/persona';\n\nexport const LAYER_RESOLVERS: ExtensionLayerResolvers = {\n ownEntry,\n packageEntry: resolvePackageEntry,\n optionalPackageEntry: resolveOptionalPackageEntry,\n packageEntries: resolvePackageEntries,\n optionalPackageEntries: resolveOptionalPackageEntries,\n localEntry,\n localEntries,\n localPackageEntries,\n localPackageName: resolveLocalPackageName,\n};\n\nfunction missingConsumerPackage(name: string, consumerRoot: string): Error {\n return new Error(`Cannot resolve configured package \"${name}\" from ${consumerRoot}.`);\n}\n\n/**\n * Resolves configured packages only from the consumer, while fixed core entries\n * may fall back to the host package's private dependency closure.\n */\nexport function createLayerResolvers(consumerRoot?: string): ExtensionLayerResolvers {\n if (!consumerRoot) return LAYER_RESOLVERS;\n const fallbackEntry = (name: string): string | undefined =>\n FIXED_CORE_PACKAGES.has(packageName(name)) ? resolveOptionalPackageEntry(name) : undefined;\n const fallbackEntries = (name: string): string[] | undefined =>\n FIXED_CORE_PACKAGES.has(packageName(name)) ? resolveOptionalPackageEntries(name) : undefined;\n const requiredEntry = (name: string): string => {\n const entry = consumerPackageEntry(name, consumerRoot) ?? fallbackEntry(name);\n if (!entry) throw missingConsumerPackage(name, consumerRoot);\n return entry;\n };\n const requiredEntries = (name: string): string[] => {\n const entries = consumerPackageEntries(name, consumerRoot) ?? fallbackEntries(name);\n if (!entries) throw missingConsumerPackage(name, consumerRoot);\n return entries;\n };\n return {\n ownEntry,\n packageEntry: requiredEntry,\n optionalPackageEntry: (name) => consumerPackageEntry(name, consumerRoot) ?? fallbackEntry(name),\n packageEntries: requiredEntries,\n optionalPackageEntries: (name) => consumerPackageEntries(name, consumerRoot) ?? fallbackEntries(name),\n localEntry,\n localEntries,\n localPackageEntries,\n localPackageName: resolveLocalPackageName,\n };\n}\n\nfunction packageName(specifier: string): string {\n const segments = specifier.split('/');\n return specifier.startsWith('@') ? segments.slice(0, 2).join('/') : (segments[0] ?? specifier);\n}\n\nfunction assertFeaturePackage(specifier: string, layer: string): void {\n const selectedPackage = packageName(specifier);\n if (FIXED_CORE_PACKAGES.has(selectedPackage)) {\n throw new Error(\n `Layer \"${layer}\" cannot select fixed DoomPi host package \"${selectedPackage}\" as a feature extension.`,\n );\n }\n}\n\nfunction resolveLocalExtensionEntries(\n resolvers: ExtensionLayerResolvers,\n specifier: string,\n baseDirectory: string,\n): string[] | undefined {\n const resolved = resolvers.localEntries?.(specifier, baseDirectory);\n if (resolved !== undefined) return resolved;\n const single = resolvers.localEntry(specifier, baseDirectory);\n return single ? [single] : undefined;\n}\n\nfunction resolveLocalPackageSelections(\n resolvers: ExtensionLayerResolvers,\n specifier: string,\n baseDirectory: string,\n): string[] | undefined {\n const resolved = resolvers.localPackageEntries?.(specifier, baseDirectory);\n if (resolved !== undefined) return resolved;\n return resolveLocalExtensionEntries(resolvers, specifier, baseDirectory);\n}\n\ninterface SelectionIdentity {\n layer: string;\n layerIndex: number;\n entryKind: SelectedEntryKind;\n entryIndex: number;\n selector: string;\n sourceFile?: string;\n baseDirectory: string;\n optional: boolean;\n config?: Record<string, unknown>;\n}\n\nfunction resolvedSelection(\n identity: SelectionIdentity,\n manifestIndex: number,\n resolvedPath: string,\n): ResolvedExtensionSelection {\n return {\n ...identity,\n manifestIndex,\n outcome: 'resolved',\n path: resolvedPath,\n canonicalPath: canonicalModulePath(resolvedPath),\n };\n}\n\nfunction missingOptionalSelection(identity: SelectionIdentity, diagnostic: string): ResolvedExtensionSelection {\n return {\n ...identity,\n manifestIndex: 0,\n outcome: 'missing-optional',\n diagnostic,\n };\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction resolveDefinitionSelections(\n definition: MajorModesConfig['layers'][string],\n layer: string,\n layerIndex: number,\n resolvers: ExtensionLayerResolvers,\n): ResolvedExtensionSelection[] {\n const resolvedSelections: ResolvedExtensionSelection[] = [];\n const extensionEntries = definition.extensions ?? [];\n for (const [entryIndex, selector] of extensionEntries.entries()) {\n const identity: SelectionIdentity = {\n layer,\n layerIndex,\n entryKind: 'extension',\n entryIndex,\n selector,\n ...(definition.filePath ? { sourceFile: definition.filePath } : {}),\n baseDirectory: definition.baseDirectory,\n optional: false,\n };\n if (!isLocalPackageSpecifier(selector)) {\n resolvedSelections.push(resolvedSelection(identity, 0, resolvers.ownEntry(selector)));\n continue;\n }\n const resolved = resolveLocalExtensionEntries(resolvers, selector, definition.baseDirectory);\n if (!resolved?.length) {\n throw new Error(\n `Layer \"${layer}\" extension \"${selector}\" does not resolve under ${definition.baseDirectory}. ` +\n 'Point it at a Pi extension file or directory.',\n );\n }\n resolved.forEach((resolvedPath, manifestIndex) => {\n resolvedSelections.push(resolvedSelection(identity, manifestIndex, resolvedPath));\n });\n }\n\n const packageOffset = extensionEntries.length;\n for (const [packageIndex, configured] of (definition.packages ?? []).entries()) {\n const selector = typeof configured === 'string' ? configured : configured.name;\n const optional = typeof configured === 'string' ? false : configured.optional === true;\n const configValue = typeof configured === 'string' ? undefined : configured.config;\n const identity: SelectionIdentity = {\n layer,\n layerIndex,\n entryKind: 'package',\n entryIndex: packageOffset + packageIndex,\n selector,\n ...(definition.filePath ? { sourceFile: definition.filePath } : {}),\n baseDirectory: definition.baseDirectory,\n optional,\n ...(configValue === undefined ? {} : { config: configValue }),\n };\n\n let resolved: string[] | undefined;\n try {\n if (isLocalPackageSpecifier(selector)) {\n const manifestName = resolvers.localPackageName?.(selector, definition.baseDirectory);\n if (manifestName) assertFeaturePackage(manifestName, layer);\n resolved = resolveLocalPackageSelections(resolvers, selector, definition.baseDirectory);\n } else {\n assertFeaturePackage(selector, layer);\n if (optional) {\n resolved = resolvers.optionalPackageEntries?.(selector);\n if (resolved === undefined && !resolvers.optionalPackageEntries) {\n const single = resolvers.optionalPackageEntry(selector);\n resolved = single ? [single] : undefined;\n }\n } else {\n resolved = resolvers.packageEntries?.(selector) ?? [resolvers.packageEntry(selector)];\n }\n }\n } catch (error) {\n if (optional) {\n resolvedSelections.push(missingOptionalSelection(identity, errorMessage(error)));\n continue;\n }\n throw error;\n }\n\n if (!resolved?.length) {\n if (optional) {\n resolvedSelections.push(\n missingOptionalSelection(\n identity,\n `Optional package \"${selector}\" is unavailable or declares no Pi extensions.`,\n ),\n );\n continue;\n }\n if (isLocalPackageSpecifier(selector)) {\n throw new Error(\n `Layer \"${layer}\" package \"${selector}\" does not resolve under ${definition.baseDirectory}. ` +\n 'Point it at an extension file, or a directory whose package.json declares pi.extensions.',\n );\n }\n throw new Error(`Layer \"${layer}\" package \"${selector}\" declares no Pi extensions.`);\n }\n\n resolved.forEach((resolvedPath, manifestIndex) => {\n resolvedSelections.push(resolvedSelection(identity, manifestIndex, resolvedPath));\n });\n }\n\n return resolvedSelections;\n}\n\nfunction resolveLayerSelections(\n config: MajorModesConfig,\n layer: string,\n layerIndex: number,\n resolvers: ExtensionLayerResolvers,\n): ResolvedExtensionSelection[] {\n const definition = config.layers[layer];\n if (!definition) throw new Error(`Unknown layer: ${layer}`);\n return resolveDefinitionSelections(definition, layer, layerIndex, resolvers);\n}\n\nfunction resolveDefaultSelections(\n config: MajorModesConfig,\n resolvers: ExtensionLayerResolvers,\n): ResolvedExtensionSelection[] {\n if (!config.default) return [];\n return resolveDefinitionSelections(config.default, DEFAULT_SELECTION_LAYER, DEFAULT_SELECTION_LAYER_INDEX, resolvers);\n}\n\nfunction resolveSelectedExtensions(context: ExtensionContext): ResolvedExtensionSelection[] {\n const resolvers = context.resolvers ?? LAYER_RESOLVERS;\n return context.layers.flatMap((layer, layerIndex) =>\n resolveLayerSelections(context.majorModesConfig, layer, layerIndex, resolvers),\n );\n}\n\nfunction deduplicatePaths(paths: readonly string[]): string[] {\n const seen = new Set<string>();\n const selected: string[] = [];\n for (const entry of paths) {\n const identity = canonicalModulePath(entry);\n if (seen.has(identity)) continue;\n seen.add(identity);\n selected.push(entry);\n }\n return selected;\n}\n\nfunction selectedFeaturePaths(selections: readonly ResolvedExtensionSelection[]): string[] {\n return deduplicatePaths(\n selections.flatMap((entry) => (entry.outcome === 'resolved' && entry.path ? [entry.path] : [])),\n );\n}\n\nfunction parentActivation(\n context: ExtensionContext,\n distributionPaths: readonly string[],\n featurePaths: readonly string[],\n): string[] {\n const resolve = context.resolvers ?? LAYER_RESOLVERS;\n const activation = [\n resolve.ownEntry(OWN_ENTRIES.cordisHost),\n resolve.ownEntry(OWN_ENTRIES.modeCatalog),\n resolve.packageEntry(CORE_PACKAGE_ENTRIES.config),\n resolve.ownEntry(OWN_ENTRIES.transitionCoordinator),\n resolve.packageEntry(CORE_PACKAGE_ENTRIES.ui),\n ];\n if (!context.mute) activation.push(resolve.packageEntry(CORE_PACKAGE_ENTRIES.notification));\n activation.push(\n resolve.packageEntry(CORE_PACKAGE_ENTRIES.profile),\n resolve.packageEntry(CORE_PACKAGE_ENTRIES.majorMode),\n resolve.packageEntry(CORE_PACKAGE_ENTRIES.skill),\n resolve.packageEntry(CORE_PACKAGE_ENTRIES.domain),\n resolve.ownEntry(OWN_ENTRIES.effort),\n );\n if (context.preset === OLLAMA_PRESET) activation.push(resolve.ownEntry(OWN_ENTRIES.ollamaProvider));\n activation.push(...distributionPaths, ...featurePaths);\n if (context.personaEntry) activation.push(context.personaEntry);\n if (context.autoStop) activation.push(resolve.packageEntry(CORE_PACKAGE_ENTRIES.autostop));\n activation.push(resolve.packageEntry(CORE_PACKAGE_ENTRIES.cache));\n activation.push(resolve.ownEntry(OWN_ENTRIES.cordisFinalizer));\n return deduplicatePaths(activation);\n}\n\nfunction childActivation(\n context: ExtensionContext,\n distributionPaths: readonly string[],\n featurePaths: readonly string[],\n): string[] {\n const resolve = context.resolvers ?? LAYER_RESOLVERS;\n const activation = [\n resolve.ownEntry(OWN_ENTRIES.cordisHost),\n resolve.packageEntry(CORE_PACKAGE_ENTRIES.config),\n ...distributionPaths,\n ...featurePaths,\n ];\n if (context.preset === OLLAMA_PRESET) activation.push(resolve.ownEntry(OWN_ENTRIES.ollamaProvider));\n if (context.personaEntry) activation.push(context.personaEntry);\n activation.push(resolve.ownEntry(OWN_ENTRIES.cordisFinalizer));\n return deduplicatePaths(activation);\n}\n\nfunction canonicalValue(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(canonicalValue);\n if (value === null || typeof value !== 'object') return value;\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .filter(([, entry]) => entry !== undefined)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, entry]) => [key, canonicalValue(entry)]),\n );\n}\n\nfunction compositionFingerprint(composition: Omit<ExtensionComposition, 'fingerprint'>): string {\n return sha256(\n JSON.stringify(\n canonicalValue({\n ...composition,\n contract: {\n composition: COMPOSITION_FINGERPRINT_VERSION,\n standardPiExtension: STANDARD_PI_EXTENSION_CONTRACT_VERSION,\n fixedCorePackages: [...FIXED_CORE_PACKAGES],\n },\n parentCanonicalActivation: composition.parentActivation.map(canonicalModulePath),\n childCanonicalActivation: composition.childActivation.map(canonicalModulePath),\n }),\n ),\n );\n}\n\n/** Resolve one deterministic parent/child composition from authored layer occurrences. */\nexport function resolveExtensionComposition(context: ExtensionContext): ExtensionComposition {\n const resolvers = context.resolvers ?? LAYER_RESOLVERS;\n const defaultSelections = resolveDefaultSelections(context.majorModesConfig, resolvers);\n const layerSelections = resolveSelectedExtensions(context);\n const selections = [...defaultSelections, ...layerSelections];\n const distributionPaths = selectedFeaturePaths(defaultSelections);\n const featurePaths = selectedFeaturePaths(layerSelections);\n const layers = context.layers.map((name, index): CompositionLayerOccurrence => {\n const definition = context.majorModesConfig.layers[name];\n if (!definition) throw new Error(`Unknown layer: ${name}`);\n return {\n name,\n index,\n ...(definition.filePath ? { sourceFile: definition.filePath } : {}),\n baseDirectory: definition.baseDirectory,\n };\n });\n const modeSource = context.majorMode ? context.majorModesConfig.majorModeSources?.[context.majorMode] : undefined;\n const withoutFingerprint: Omit<ExtensionComposition, 'fingerprint'> = {\n version: COMPOSITION_FINGERPRINT_VERSION,\n ...(context.majorMode\n ? {\n majorMode: {\n name: context.majorMode,\n ...(modeSource?.filePath ? { sourceFile: modeSource.filePath } : {}),\n ...(modeSource?.baseDirectory ? { baseDirectory: modeSource.baseDirectory } : {}),\n },\n }\n : {}),\n layers,\n selections,\n parentActivation: parentActivation(context, distributionPaths, featurePaths),\n childActivation: childActivation(context, distributionPaths, featurePaths),\n };\n return { ...withoutFingerprint, fingerprint: compositionFingerprint(withoutFingerprint) };\n}\n\n/** Assemble parent entries in actual Pi factory activation order. */\nexport function assembleExtensions(context: ExtensionContext): string[] {\n return [...resolveExtensionComposition(context).parentActivation];\n}\n\n/** Assemble detached-child entries in actual Pi factory activation order. */\nexport function assembleChildExtensions(context: ExtensionContext): string[] {\n return [...resolveExtensionComposition(context).childActivation];\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LayerResolvers, MajorModesConfig } from "@agimon-ai/doompi-config/majorModes";
|
|
2
|
+
import { PackageAttribution } from "@agimon-ai/doompi-config/types";
|
|
2
3
|
//#region src/services/extensionAssembler.d.ts
|
|
3
4
|
interface ExtensionLayerResolvers extends LayerResolvers {
|
|
4
5
|
/** Resolves a path authored under packages through its standard Pi manifest. */
|
|
@@ -67,6 +68,23 @@ interface ExtensionComposition {
|
|
|
67
68
|
readonly childActivation: readonly string[];
|
|
68
69
|
readonly fingerprint: string;
|
|
69
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Which layer of which major mode admitted each package.
|
|
73
|
+
*
|
|
74
|
+
* The composition already holds this join while it resolves package names to
|
|
75
|
+
* entry paths, then drops it, so a session cannot afterwards say why a tool is
|
|
76
|
+
* present. Reducing it here keeps the selection type private and costs one pass
|
|
77
|
+
* over an array the caller already has.
|
|
78
|
+
*
|
|
79
|
+
* Only `package` entries appear. A bare `extension` selector is a path rather
|
|
80
|
+
* than a package name, so it has nothing a registered tool could be joined on.
|
|
81
|
+
*
|
|
82
|
+
* Keyed by manifest name first, because that is what a registered tool resolves
|
|
83
|
+
* to. The selector is kept as an alias: a layer may name a package as
|
|
84
|
+
* `@agimon-ai/doompi-team` when published or `./layers/team/doompi-team` in a
|
|
85
|
+
* checkout, and both have to find the same layer.
|
|
86
|
+
*/
|
|
87
|
+
declare function packageAttribution(composition: ExtensionComposition): Record<string, PackageAttribution>;
|
|
70
88
|
declare const COMPOSITION_FINGERPRINT_VERSION = 4;
|
|
71
89
|
declare const STANDARD_PI_EXTENSION_CONTRACT_VERSION = 2;
|
|
72
90
|
declare const OLLAMA_PRESET = "ollama";
|
|
@@ -92,5 +110,5 @@ declare function assembleExtensions(context: ExtensionContext): string[];
|
|
|
92
110
|
/** Assemble detached-child entries in actual Pi factory activation order. */
|
|
93
111
|
declare function assembleChildExtensions(context: ExtensionContext): string[];
|
|
94
112
|
//#endregion
|
|
95
|
-
export { COMPOSITION_FINGERPRINT_VERSION, CompositionLayerOccurrence, ExtensionComposition, ExtensionContext, ExtensionLayerResolvers, LAYER_RESOLVERS, OLLAMA_PRESET, PERSONA_ENTRY, STANDARD_PI_EXTENSION_CONTRACT_VERSION, SelectedEntryKind, assembleChildExtensions, assembleExtensions, createLayerResolvers, resolveExtensionComposition };
|
|
113
|
+
export { COMPOSITION_FINGERPRINT_VERSION, CompositionLayerOccurrence, ExtensionComposition, ExtensionContext, ExtensionLayerResolvers, LAYER_RESOLVERS, OLLAMA_PRESET, PERSONA_ENTRY, STANDARD_PI_EXTENSION_CONTRACT_VERSION, SelectedEntryKind, assembleChildExtensions, assembleExtensions, createLayerResolvers, packageAttribution, resolveExtensionComposition };
|
|
96
114
|
//# sourceMappingURL=extensionAssembler.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extensionAssembler.d.cts","names":[],"sources":["../../../src/services/extensionAssembler.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"extensionAssembler.d.cts","names":[],"sources":["../../../src/services/extensionAssembler.ts"],"mappings":";;;UAsBiB,gCAAgC;;EAE/C,uBAAuB,mBAAmB;;EAE1C,oBAAoB,mBAAmB;;UAGxB;EACf;EACA;EACA;EACA;EACA;;EAEA;;EAEA;EACA,kBAAkB;;EAElB,YAAY;;KAGF;KACP;;;;;;;;UASK;WACC;WACA;WACA,WAAW;WACX;WACA;WACA;WACA;WACA;WACA;WACA,SAAS;WACT;WACA;WACA;WACA,SAAS;;UAGH;WACN;WACA;WACA;WACA;;;UAIM;WACN;WACA;aACE;aACA;aACA;;WAEF,iBAAiB;WACjB,qBAAqB;;WAErB;;WAEA;WACA;;;;;;;;;;;;;;;;;;iBAmBK,mBAAmB,aAAa,uBAAuB,eAAe;cAgBzE;cACA;cAuCA;;;;;;;;;cAUA;cAEA,iBAAiB;;;;;iBAoBd,qBAAqB,wBAAwB;;iBAyU7C,4BAA4B,SAAS,mBAAmB;;iBAsCxD,mBAAmB,SAAS;;iBAK5B,wBAAwB,SAAS"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LayerResolvers, MajorModesConfig } from "@agimon-ai/doompi-config/majorModes";
|
|
2
|
+
import { PackageAttribution } from "@agimon-ai/doompi-config/types";
|
|
2
3
|
//#region src/services/extensionAssembler.d.ts
|
|
3
4
|
interface ExtensionLayerResolvers extends LayerResolvers {
|
|
4
5
|
/** Resolves a path authored under packages through its standard Pi manifest. */
|
|
@@ -67,6 +68,23 @@ interface ExtensionComposition {
|
|
|
67
68
|
readonly childActivation: readonly string[];
|
|
68
69
|
readonly fingerprint: string;
|
|
69
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Which layer of which major mode admitted each package.
|
|
73
|
+
*
|
|
74
|
+
* The composition already holds this join while it resolves package names to
|
|
75
|
+
* entry paths, then drops it, so a session cannot afterwards say why a tool is
|
|
76
|
+
* present. Reducing it here keeps the selection type private and costs one pass
|
|
77
|
+
* over an array the caller already has.
|
|
78
|
+
*
|
|
79
|
+
* Only `package` entries appear. A bare `extension` selector is a path rather
|
|
80
|
+
* than a package name, so it has nothing a registered tool could be joined on.
|
|
81
|
+
*
|
|
82
|
+
* Keyed by manifest name first, because that is what a registered tool resolves
|
|
83
|
+
* to. The selector is kept as an alias: a layer may name a package as
|
|
84
|
+
* `@agimon-ai/doompi-team` when published or `./layers/team/doompi-team` in a
|
|
85
|
+
* checkout, and both have to find the same layer.
|
|
86
|
+
*/
|
|
87
|
+
declare function packageAttribution(composition: ExtensionComposition): Record<string, PackageAttribution>;
|
|
70
88
|
declare const COMPOSITION_FINGERPRINT_VERSION = 4;
|
|
71
89
|
declare const STANDARD_PI_EXTENSION_CONTRACT_VERSION = 2;
|
|
72
90
|
declare const OLLAMA_PRESET = "ollama";
|
|
@@ -92,5 +110,5 @@ declare function assembleExtensions(context: ExtensionContext): string[];
|
|
|
92
110
|
/** Assemble detached-child entries in actual Pi factory activation order. */
|
|
93
111
|
declare function assembleChildExtensions(context: ExtensionContext): string[];
|
|
94
112
|
//#endregion
|
|
95
|
-
export { COMPOSITION_FINGERPRINT_VERSION, CompositionLayerOccurrence, ExtensionComposition, ExtensionContext, ExtensionLayerResolvers, LAYER_RESOLVERS, OLLAMA_PRESET, PERSONA_ENTRY, STANDARD_PI_EXTENSION_CONTRACT_VERSION, SelectedEntryKind, assembleChildExtensions, assembleExtensions, createLayerResolvers, resolveExtensionComposition };
|
|
113
|
+
export { COMPOSITION_FINGERPRINT_VERSION, CompositionLayerOccurrence, ExtensionComposition, ExtensionContext, ExtensionLayerResolvers, LAYER_RESOLVERS, OLLAMA_PRESET, PERSONA_ENTRY, STANDARD_PI_EXTENSION_CONTRACT_VERSION, SelectedEntryKind, assembleChildExtensions, assembleExtensions, createLayerResolvers, packageAttribution, resolveExtensionComposition };
|
|
96
114
|
//# sourceMappingURL=extensionAssembler.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extensionAssembler.d.mts","names":[],"sources":["../../../src/services/extensionAssembler.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"extensionAssembler.d.mts","names":[],"sources":["../../../src/services/extensionAssembler.ts"],"mappings":";;;UAsBiB,gCAAgC;;EAE/C,uBAAuB,mBAAmB;;EAE1C,oBAAoB,mBAAmB;;UAGxB;EACf;EACA;EACA;EACA;EACA;;EAEA;;EAEA;EACA,kBAAkB;;EAElB,YAAY;;KAGF;KACP;;;;;;;;UASK;WACC;WACA;WACA,WAAW;WACX;WACA;WACA;WACA;WACA;WACA;WACA,SAAS;WACT;WACA;WACA;WACA,SAAS;;UAGH;WACN;WACA;WACA;WACA;;;UAIM;WACN;WACA;aACE;aACA;aACA;;WAEF,iBAAiB;WACjB,qBAAqB;;WAErB;;WAEA;WACA;;;;;;;;;;;;;;;;;;iBAmBK,mBAAmB,aAAa,uBAAuB,eAAe;cAgBzE;cACA;cAuCA;;;;;;;;;cAUA;cAEA,iBAAiB;;;;;iBAoBd,qBAAqB,wBAAwB;;iBAyU7C,4BAA4B,SAAS,mBAAmB;;iBAsCxD,mBAAmB,SAAS;;iBAK5B,wBAAwB,SAAS"}
|