@agimon-ai/doompi 0.0.1-alpha.57 → 0.0.1-alpha.58
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/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/package.json +13 -13
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../../services/modeCatalog.cjs"),t=require("../../adapters/contextDetailStore.cjs"),n=require("../../services/contextCatalog.cjs"),r=require("../../services/minorModeProjection.cjs"),i=require("./minorModeCommand.cjs");let a=require("@agimon-ai/doompi-extension-contracts/cordis-host"),o=require("@agimon-ai/doompi-extension-contracts/mode"),s=require("@agimon-ai/doompi-extension-contracts/
|
|
1
|
+
const e=require("../../services/modeCatalog.cjs"),t=require("../../adapters/contextDetailStore.cjs"),n=require("../../services/contextCatalog.cjs"),r=require("../../services/minorModeProjection.cjs"),i=require("./minorModeCommand.cjs");let a=require("@agimon-ai/doompi-extension-contracts/cordis-host"),o=require("@agimon-ai/doompi-extension-contracts/mode"),s=require("@agimon-ai/doompi-extension-contracts/mcp-status"),c=require("@agimon-ai/doompi-extension-contracts/help"),l=require("@agimon-ai/doompi-extension-contracts/notification"),u=require("@agimon-ai/doompi-extension-contracts/transition");function d(e,t,n,r){let i=(0,l.readDoomNotificationService)(e);if(i){try{Promise.resolve(i.request({body:n,level:r})).catch(()=>void 0)}catch{}return}t.ui.notify(n,r)}function f(e){return e.includes(`voice`)?`voice`:e.includes(`leader`)?`leader`:e.includes(`ui`)?`ui`:`system`}function p(e){let t=e.current?.getSnapshot();return t?t.modes.filter(e=>e.state.activation===`active`).map(e=>({id:e.descriptor.id,label:e.descriptor.label})):[]}async function m(e){let r={current:void 0};i.registerMinorModeCommand(e,()=>r.current);let o={};e.on(`session_start`,()=>{setTimeout(()=>{r.republish?.(),o.publisher?.publish()},500)}),e.on(`turn_start`,()=>{o.publisher?.publish()});let c=await(0,a.connectDoomCordisHost)(e,`@agimon-ai/doompi/mode-catalog`),l=c.root.plugin(i=>(o.publisher=n.createContextPublisher(e,i,{readMinorModes:()=>p(r),readSessionId:()=>r.sessionId,writeDetail:(e,n,r)=>void t.writeContextDetail(e,n,r),removeDetail:t.removeContextDetail}),i.inject([s.DOOM_MCP_STATUS_SERVICE],e=>{let t=()=>void o.publisher?.publish(),n=(0,s.readDoomMcpStatus)(e)?.onChange?.(t);return t(),n}),h(i,e,r,()=>void o.publisher?.publish()),()=>{o.publisher?.dispose(),o.publisher=void 0}));try{await l}catch(e){throw await l.dispose(),await c.dispose(),e}let u;e.on(`session_shutdown`,()=>u??=(async()=>{try{await l.dispose()}finally{await c.dispose()}})())}function h(t,n,i,s){t.inject([c.DOOM_HELP_SERVICE],e=>{let t=(0,c.requireDoomHelpService)(e).register({source:`@agimon-ai/doompi`,moduleUrl:require("url").pathToFileURL(__filename).href,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([a.DOOM_CORDIS_SESSION_SERVICE,u.DOOM_TRANSITION_SERVICE],t=>{let c=t.get(a.DOOM_CORDIS_SESSION_SERVICE),l=c.context,p=(0,u.requireDoomTransitionCoordinator)(t),m=c.reason===`reload`,h=c.sessionId,g=m?(0,u.consumeMinorModeReloadHandoff)(h):void 0;m||(0,u.discardMinorModeReloadHandoff)(h);let _=l.hasUI&&l.mode===`tui`?`tui`:`headless`,v=e.createMinorModeCatalogHost({sessionKind:_,context:l,restoreSnapshot:g,onRestorationError(e){d(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 p.execute({sessionId:l.sessionManager.getSessionId(),hostGeneration:p.hostGeneration,operationId:e.operationId,source:f(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.DOOM_MINOR_MODE_CATALOG_SERVICE,v),i.current=v,i.sessionId=h;let y,b,x=()=>{b=void 0;let e=r.projectMinorModes(v.getSnapshot(),_),t=JSON.stringify(e);t!==y&&(y=t,n.appendEntry(o.DOOM_MINOR_MODE_ENTRY_TYPE,e),s())},S=v.subscribe(()=>{b??=setTimeout(x,50)});return i.republish=()=>{y=void 0,x()},()=>{b&&clearTimeout(b),S(),i.republish=void 0,i.current=void 0,i.sessionId=void 0,v.dispose()}})}exports.default=m,exports.modeCatalogExtension=m;
|
|
2
2
|
//# sourceMappingURL=modeCatalog.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modeCatalog.cjs","names":["readDoomNotificationService","connectDoomCordisHost","createContextPublisher","writeContextDetail","removeContextDetail","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 { removeContextDetail, writeContextDetail } from '../../adapters/contextDetailStore.ts';\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 * The bound session, which the detail store is keyed by.\n *\n * The server launches the agent with `--session-id`, so this is the same id\n * the cockpit and the session API know the session by, and a browser asking\n * for a row's detail looks under the file this session wrote.\n */\n sessionId?: string;\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\n/**\n * The minor modes that are actually on, for the composition panel.\n *\n * Read from the bound catalog at publish time rather than passed in, because a\n * mode switching on is one of the reasons a publish happens at all, and a\n * remembered list would describe the composition before the switch.\n */\nfunction activeMinorModes(binding: CatalogBinding): { id: string; label: string }[] {\n const snapshot = binding.current?.getSnapshot();\n if (!snapshot) return [];\n return snapshot.modes\n .filter((record) => record.state.activation === 'active')\n .map((record) => ({ id: record.descriptor.id, label: record.descriptor.label }));\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 readMinorModes: () => activeMinorModes(activeCatalog),\n readSessionId: () => activeCatalog.sessionId,\n writeDetail: (sessionId, revision, items) => void writeContextDetail(sessionId, revision, items),\n removeDetail: removeContextDetail,\n });\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 activeCatalog.sessionId = sessionId;\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 activeCatalog.sessionId = 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","writeContextDetail","removeContextDetail","DOOM_MCP_STATUS_SERVICE","readDoomMcpStatus","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 { DOOM_MCP_STATUS_SERVICE, readDoomMcpStatus } from '@agimon-ai/doompi-extension-contracts/mcp-status';\nimport {\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 { removeContextDetail, writeContextDetail } from '../../adapters/contextDetailStore.ts';\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 * The bound session, which the detail store is keyed by.\n *\n * The server launches the agent with `--session-id`, so this is the same id\n * the cockpit and the session API know the session by, and a browser asking\n * for a row's detail looks under the file this session wrote.\n */\n sessionId?: string;\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\n/**\n * The minor modes that are actually on, for the composition panel.\n *\n * Read from the bound catalog at publish time rather than passed in, because a\n * mode switching on is one of the reasons a publish happens at all, and a\n * remembered list would describe the composition before the switch.\n */\nfunction activeMinorModes(binding: CatalogBinding): { id: string; label: string }[] {\n const snapshot = binding.current?.getSnapshot();\n if (!snapshot) return [];\n return snapshot.modes\n .filter((record) => record.state.activation === 'active')\n .map((record) => ({ id: record.descriptor.id, label: record.descriptor.label }));\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 // Turns still refresh active-tool costs, including for older pull-only MCP providers.\n // Identical compositions are skipped rather than journaled again.\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 readMinorModes: () => activeMinorModes(activeCatalog),\n readSessionId: () => activeCatalog.sessionId,\n writeDetail: (sessionId, revision, items) => void writeContextDetail(sessionId, revision, items),\n removeDetail: removeContextDetail,\n });\n cordis.inject([DOOM_MCP_STATUS_SERVICE], (mcpContext) => {\n const publish = () => void contextBinding.publisher?.publish();\n const unsubscribe = readDoomMcpStatus(mcpContext)?.onChange?.(publish);\n // Subscribe first, then read: discovery may already have finished before binding.\n publish();\n return unsubscribe;\n });\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 activeCatalog.sessionId = sessionId;\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 activeCatalog.sessionId = 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":";;iBA6FsB,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":";;iBA6FsB,qBAAqB,IAAI,eAAe"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createMinorModeCatalogHost as e}from"../../services/modeCatalog.mjs";import{removeContextDetail as t,writeContextDetail as n}from"../../adapters/contextDetailStore.mjs";import{createContextPublisher as r}from"../../services/contextCatalog.mjs";import{projectMinorModes as i}from"../../services/minorModeProjection.mjs";import{registerMinorModeCommand as a}from"./minorModeCommand.mjs";import{DOOM_CORDIS_SESSION_SERVICE as o,connectDoomCordisHost as s}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{DOOM_MINOR_MODE_CATALOG_SERVICE as c,DOOM_MINOR_MODE_ENTRY_TYPE as l}from"@agimon-ai/doompi-extension-contracts/mode";import{
|
|
1
|
+
import{createMinorModeCatalogHost as e}from"../../services/modeCatalog.mjs";import{removeContextDetail as t,writeContextDetail as n}from"../../adapters/contextDetailStore.mjs";import{createContextPublisher as r}from"../../services/contextCatalog.mjs";import{projectMinorModes as i}from"../../services/minorModeProjection.mjs";import{registerMinorModeCommand as a}from"./minorModeCommand.mjs";import{DOOM_CORDIS_SESSION_SERVICE as o,connectDoomCordisHost as s}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{DOOM_MINOR_MODE_CATALOG_SERVICE as c,DOOM_MINOR_MODE_ENTRY_TYPE as l}from"@agimon-ai/doompi-extension-contracts/mode";import{DOOM_MCP_STATUS_SERVICE as u,readDoomMcpStatus as d}from"@agimon-ai/doompi-extension-contracts/mcp-status";import{DOOM_HELP_SERVICE as f,requireDoomHelpService as p}from"@agimon-ai/doompi-extension-contracts/help";import{readDoomNotificationService as m}from"@agimon-ai/doompi-extension-contracts/notification";import{DOOM_TRANSITION_SERVICE as h,consumeMinorModeReloadHandoff as g,discardMinorModeReloadHandoff as _,requireDoomTransitionCoordinator as v}from"@agimon-ai/doompi-extension-contracts/transition";function y(e,t,n,r){let i=m(e);if(i){try{Promise.resolve(i.request({body:n,level:r})).catch(()=>void 0)}catch{}return}t.ui.notify(n,r)}function b(e){return e.includes(`voice`)?`voice`:e.includes(`leader`)?`leader`:e.includes(`ui`)?`ui`:`system`}function x(e){let t=e.current?.getSnapshot();return t?t.modes.filter(e=>e.state.activation===`active`).map(e=>({id:e.descriptor.id,label:e.descriptor.label})):[]}async function S(e){let i={current:void 0};a(e,()=>i.current);let o={};e.on(`session_start`,()=>{setTimeout(()=>{i.republish?.(),o.publisher?.publish()},500)}),e.on(`turn_start`,()=>{o.publisher?.publish()});let c=await s(e,`@agimon-ai/doompi/mode-catalog`),l=c.root.plugin(a=>(o.publisher=r(e,a,{readMinorModes:()=>x(i),readSessionId:()=>i.sessionId,writeDetail:(e,t,r)=>void n(e,t,r),removeDetail:t}),a.inject([u],e=>{let t=()=>void o.publisher?.publish(),n=d(e)?.onChange?.(t);return t(),n}),C(a,e,i,()=>void o.publisher?.publish()),()=>{o.publisher?.dispose(),o.publisher=void 0}));try{await l}catch(e){throw await l.dispose(),await c.dispose(),e}let f;e.on(`session_shutdown`,()=>f??=(async()=>{try{await l.dispose()}finally{await c.dispose()}})())}function C(t,n,r,a){t.inject([f],e=>{let t=p(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([o,h],t=>{let s=t.get(o),u=s.context,d=v(t),f=s.reason===`reload`,p=s.sessionId,m=f?g(p):void 0;f||_(p);let h=u.hasUI&&u.mode===`tui`?`tui`:`headless`,x=e({sessionKind:h,context:u,restoreSnapshot:m,onRestorationError(e){y(t,u,`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:u.sessionManager.getSessionId(),hostGeneration:d.hostGeneration,operationId:e.operationId,source:b(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(c,x),r.current=x,r.sessionId=p;let S,C,w=()=>{C=void 0;let e=i(x.getSnapshot(),h),t=JSON.stringify(e);t!==S&&(S=t,n.appendEntry(l,e),a())},T=x.subscribe(()=>{C??=setTimeout(w,50)});return r.republish=()=>{S=void 0,w()},()=>{C&&clearTimeout(C),T(),r.republish=void 0,r.current=void 0,r.sessionId=void 0,x.dispose()}})}export{S as default,S 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 { removeContextDetail, writeContextDetail } from '../../adapters/contextDetailStore.ts';\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 * The bound session, which the detail store is keyed by.\n *\n * The server launches the agent with `--session-id`, so this is the same id\n * the cockpit and the session API know the session by, and a browser asking\n * for a row's detail looks under the file this session wrote.\n */\n sessionId?: string;\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\n/**\n * The minor modes that are actually on, for the composition panel.\n *\n * Read from the bound catalog at publish time rather than passed in, because a\n * mode switching on is one of the reasons a publish happens at all, and a\n * remembered list would describe the composition before the switch.\n */\nfunction activeMinorModes(binding: CatalogBinding): { id: string; label: string }[] {\n const snapshot = binding.current?.getSnapshot();\n if (!snapshot) return [];\n return snapshot.modes\n .filter((record) => record.state.activation === 'active')\n .map((record) => ({ id: record.descriptor.id, label: record.descriptor.label }));\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 readMinorModes: () => activeMinorModes(activeCatalog),\n readSessionId: () => activeCatalog.sessionId,\n writeDetail: (sessionId, revision, items) => void writeContextDetail(sessionId, revision, items),\n removeDetail: removeContextDetail,\n });\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 activeCatalog.sessionId = sessionId;\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 activeCatalog.sessionId = 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 { DOOM_MCP_STATUS_SERVICE, readDoomMcpStatus } from '@agimon-ai/doompi-extension-contracts/mcp-status';\nimport {\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 { removeContextDetail, writeContextDetail } from '../../adapters/contextDetailStore.ts';\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 * The bound session, which the detail store is keyed by.\n *\n * The server launches the agent with `--session-id`, so this is the same id\n * the cockpit and the session API know the session by, and a browser asking\n * for a row's detail looks under the file this session wrote.\n */\n sessionId?: string;\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\n/**\n * The minor modes that are actually on, for the composition panel.\n *\n * Read from the bound catalog at publish time rather than passed in, because a\n * mode switching on is one of the reasons a publish happens at all, and a\n * remembered list would describe the composition before the switch.\n */\nfunction activeMinorModes(binding: CatalogBinding): { id: string; label: string }[] {\n const snapshot = binding.current?.getSnapshot();\n if (!snapshot) return [];\n return snapshot.modes\n .filter((record) => record.state.activation === 'active')\n .map((record) => ({ id: record.descriptor.id, label: record.descriptor.label }));\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 // Turns still refresh active-tool costs, including for older pull-only MCP providers.\n // Identical compositions are skipped rather than journaled again.\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 readMinorModes: () => activeMinorModes(activeCatalog),\n readSessionId: () => activeCatalog.sessionId,\n writeDetail: (sessionId, revision, items) => void writeContextDetail(sessionId, revision, items),\n removeDetail: removeContextDetail,\n });\n cordis.inject([DOOM_MCP_STATUS_SERVICE], (mcpContext) => {\n const publish = () => void contextBinding.publisher?.publish();\n const unsubscribe = readDoomMcpStatus(mcpContext)?.onChange?.(publish);\n // Subscribe first, then read: discovery may already have finished before binding.\n publish();\n return unsubscribe;\n });\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 activeCatalog.sessionId = sessionId;\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 activeCatalog.sessionId = undefined;\n catalog.dispose();\n };\n });\n}\n\nexport default modeCatalogExtension;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agimon-ai/doompi",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.58",
|
|
4
4
|
"description": "Opinionated, composable Pi distribution for scoped agent tools, skills, MCP servers, and developer workflows.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -320,17 +320,17 @@
|
|
|
320
320
|
"rolldown": "1.2.6",
|
|
321
321
|
"typebox": "1.3.19",
|
|
322
322
|
"yaml": "2.9.0",
|
|
323
|
-
"@agimon-ai/doompi-autostop": "0.0.1-alpha.
|
|
324
|
-
"@agimon-ai/doompi-
|
|
325
|
-
"@agimon-ai/doompi-
|
|
326
|
-
"@agimon-ai/doompi-domain": "0.0.1-alpha.
|
|
327
|
-
"@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.
|
|
328
|
-
"@agimon-ai/doompi-major-mode": "0.0.1-alpha.
|
|
329
|
-
"@agimon-ai/doompi-
|
|
330
|
-
"@agimon-ai/doompi-
|
|
331
|
-
"@agimon-ai/doompi-skill": "0.0.1-alpha.
|
|
332
|
-
"@agimon-ai/doompi-telemetry": "0.0.1-alpha.
|
|
333
|
-
"@agimon-ai/doompi-ui": "0.0.1-alpha.
|
|
323
|
+
"@agimon-ai/doompi-autostop": "0.0.1-alpha.34",
|
|
324
|
+
"@agimon-ai/doompi-cache": "0.0.1-alpha.23",
|
|
325
|
+
"@agimon-ai/doompi-config": "0.0.1-alpha.56",
|
|
326
|
+
"@agimon-ai/doompi-domain": "0.0.1-alpha.35",
|
|
327
|
+
"@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.56",
|
|
328
|
+
"@agimon-ai/doompi-major-mode": "0.0.1-alpha.35",
|
|
329
|
+
"@agimon-ai/doompi-notification": "0.0.1-alpha.34",
|
|
330
|
+
"@agimon-ai/doompi-profile": "0.0.1-alpha.35",
|
|
331
|
+
"@agimon-ai/doompi-skill": "0.0.1-alpha.35",
|
|
332
|
+
"@agimon-ai/doompi-telemetry": "0.0.1-alpha.56",
|
|
333
|
+
"@agimon-ai/doompi-ui": "0.0.1-alpha.57"
|
|
334
334
|
},
|
|
335
335
|
"devDependencies": {
|
|
336
336
|
"@earendil-works/pi-ai": "0.85.0",
|
|
@@ -340,7 +340,7 @@
|
|
|
340
340
|
"@vitest/coverage-v8": "4.1.11",
|
|
341
341
|
"typescript": "7.0.2",
|
|
342
342
|
"vitest": "4.1.11",
|
|
343
|
-
"@agimon-ai/doompi-runner": "0.0.1-alpha.
|
|
343
|
+
"@agimon-ai/doompi-runner": "0.0.1-alpha.57"
|
|
344
344
|
},
|
|
345
345
|
"peerDependencies": {
|
|
346
346
|
"@earendil-works/pi-tui": "0.85.0"
|