@agimon-ai/doompi-ui 0.0.1-alpha.24 → 0.0.1-alpha.26

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.
Files changed (58) hide show
  1. package/README.md +19 -16
  2. package/dist/adapters/pi/extension.cjs +1 -1
  3. package/dist/adapters/pi/extension.cjs.map +1 -1
  4. package/dist/adapters/pi/extension.d.cts +2 -1
  5. package/dist/adapters/pi/extension.d.cts.map +1 -1
  6. package/dist/adapters/pi/extension.d.mts +2 -1
  7. package/dist/adapters/pi/extension.d.mts.map +1 -1
  8. package/dist/adapters/pi/extension.mjs +1 -1
  9. package/dist/adapters/pi/extension.mjs.map +1 -1
  10. package/dist/adapters/pi/extensionName.cjs +1 -1
  11. package/dist/adapters/pi/extensionName.cjs.map +1 -1
  12. package/dist/adapters/pi/extensionName.d.cts +1 -1
  13. package/dist/adapters/pi/extensionName.d.cts.map +1 -1
  14. package/dist/adapters/pi/extensionName.d.mts +1 -1
  15. package/dist/adapters/pi/extensionName.d.mts.map +1 -1
  16. package/dist/adapters/pi/extensionName.mjs +1 -1
  17. package/dist/adapters/pi/extensionName.mjs.map +1 -1
  18. package/dist/components/configOverlay.d.cts +2 -2
  19. package/dist/components/configOverlay.d.mts +2 -2
  20. package/dist/components/doomFooter.d.cts +2 -2
  21. package/dist/components/doomFooter.d.mts +2 -2
  22. package/dist/config.cjs +1 -1
  23. package/dist/config.d.cts +2 -2
  24. package/dist/config.d.mts +2 -2
  25. package/dist/config.mjs +1 -1
  26. package/dist/footer.cjs +1 -1
  27. package/dist/footer.d.cts +2 -2
  28. package/dist/footer.d.mts +2 -2
  29. package/dist/footer.mjs +1 -1
  30. package/dist/index.cjs +1 -1
  31. package/dist/index.d.cts +5 -4
  32. package/dist/index.d.mts +5 -4
  33. package/dist/index.mjs +1 -1
  34. package/dist/leader.cjs +0 -1
  35. package/dist/leader.d.cts +2 -2
  36. package/dist/leader.d.mts +2 -2
  37. package/dist/leader.mjs +1 -1
  38. package/dist/services/hub/uiHub.cjs +2 -0
  39. package/dist/services/hub/uiHub.cjs.map +1 -0
  40. package/dist/services/hub/uiHub.mjs +2 -0
  41. package/dist/services/hub/uiHub.mjs.map +1 -0
  42. package/dist/skills.cjs +1 -1
  43. package/dist/skills.d.cts +2 -2
  44. package/dist/skills.d.mts +2 -2
  45. package/dist/skills.mjs +1 -1
  46. package/dist/tui/configOverlay.cjs.map +1 -1
  47. package/dist/tui/configOverlay.d.cts +0 -0
  48. package/dist/tui/configOverlay.d.cts.map +1 -1
  49. package/dist/tui/configOverlay.d.mts +0 -0
  50. package/dist/tui/configOverlay.d.mts.map +1 -1
  51. package/dist/tui/configOverlay.mjs.map +1 -1
  52. package/dist/tui/doomFooter.cjs.map +1 -1
  53. package/dist/tui/doomFooter.d.cts +16 -3
  54. package/dist/tui/doomFooter.d.cts.map +1 -1
  55. package/dist/tui/doomFooter.d.mts +16 -3
  56. package/dist/tui/doomFooter.d.mts.map +1 -1
  57. package/dist/tui/doomFooter.mjs.map +1 -1
  58. package/package.json +4 -3
package/README.md CHANGED
@@ -36,24 +36,27 @@ The registry rejects or diagnoses conflicting Leader contributions instead of si
36
36
  ## Contribute to Leader Space
37
37
 
38
38
  ```ts
39
- import { registerDoomLeaderContribution } from '@agimon-ai/doompi-ui/leader';
40
- import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
41
-
42
- export function registerReviewLeader(pi: ExtensionAPI): () => void {
43
- return registerDoomLeaderContribution(pi, {
44
- source: '@example/review-extension',
45
- bindings: [
46
- {
47
- id: 'review.open',
48
- path: [{ key: 'r', label: 'review', detail: 'open review tools' }],
49
- command: { name: 'review' },
50
- },
51
- ],
39
+ import { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-extension-contracts/ui-hub';
40
+ import type { Context } from '@deepseek-ai/cordis';
41
+
42
+ export function reviewPlugin(ctx: Context): void {
43
+ ctx.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {
44
+ const contribution = requireDoomUiHub(uiContext).registerLeader({
45
+ source: '@example/review-extension',
46
+ bindings: [
47
+ {
48
+ id: 'review.open',
49
+ path: [{ key: 'r', label: 'review', detail: 'open review tools' }],
50
+ command: { name: 'review' },
51
+ },
52
+ ],
53
+ });
54
+ return () => contribution.dispose();
52
55
  });
53
56
  }
54
57
  ```
55
58
 
56
- Dispose the returned registration during shutdown so reloads cannot retain stale bindings.
59
+ Mount this plugin beneath the shared Doom Cordis host. Cordis retracts the registration when either the contributor or UI provider disappears, so reloads cannot retain stale bindings.
57
60
 
58
61
  ## TUI and headless sessions
59
62
 
@@ -65,10 +68,10 @@ The package publishes `@agimon-ai/doompi-ui/themes/doom-pi-dark.json`. DoomPi sy
65
68
 
66
69
  ## Public API
67
70
 
68
- Declared exports cover Leader registration, UI state, rendering, tool chrome, header/footer/editor components, configuration and tools overlays, telemetry integration, and theme helpers. Use these exports rather than importing generated `dist` paths.
71
+ Declared exports cover UI state, rendering, tool chrome, header/footer/editor components, configuration and tools overlays, telemetry integration, and theme helpers. Contribution schemas and the direct UI hub service live in extension contracts. Use these exports rather than importing generated `dist` paths.
69
72
 
70
73
  ```ts
71
- import { registerDoomLeaderContribution } from '@agimon-ai/doompi-ui/leader';
74
+ import { DOOM_UI_HUB_SERVICE } from '@agimon-ai/doompi-extension-contracts/ui-hub';
72
75
  import { DEFAULT_THEME_NAME } from '@agimon-ai/doompi-ui/theme';
73
76
  ```
74
77
 
@@ -1,2 +1,2 @@
1
- const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../services/leader/leaderRegistry.cjs"),n=require("../../services/state/uiState.cjs"),r=require("../../services/tools/toolInventory.cjs"),i=require("../../tui/configOverlay.cjs"),a=require("../../tui/doomEditor.cjs"),o=require("../../tui/doomFooter.cjs"),s=require("../../tui/doomHeader.cjs"),c=require("../../tui/leaderHints.cjs");require("../../tui/theme.cjs");const l=require("../../tui/toolsOverlay.cjs"),u=require("../telemetry/logSinkTelemetry.cjs"),d=require("./extensionName.cjs"),f=require("./toolOverrides.cjs");let p=require("@agimon-ai/doompi-extension-contracts/config"),m=require("node:path");m=e.__toESM(m,1);let h=require("@agimon-ai/doompi-extension-contracts/footer"),g=require("@agimon-ai/doompi-extension-contracts/leader"),_=require("@agimon-ai/doompi-extension-contracts/mcp-status"),v=require("@agimon-ai/doompi-extension-contracts/mode"),y=require("@agimon-ai/doompi-extension-contracts/protocol");const b=`doom-pi-leader`,x=`belowEditor`,S=`warning`,C=`doom-pi`,w=new Set([`hotkeys`]);function T(e,t){let n=e.trim().replace(/\s+/g,` `);if(!n)return;let r=n.slice(0,64).trimEnd();return`${C} · ${r} · ${m.default.basename(t)||t}`}function E(e,E=u.createUiTelemetry()){f.registerBuiltinToolUi(e,process.cwd());let D=new n.DoomUiState,O=new h.DoomFooterStatusRegistry,k=(0,v.createMinorModeCatalogClient)(),A=new p.DoomConfigRegistry,j=new t.DoomLeaderRegistry,M=new Set,N=new Map,P,F,I,L,R,z,B,V,H=new Map,U=0,W=0,G=!1,K,q,J=async()=>{if(K)try{return(await K.request(_.McpStatusQueryProtocol,{},{timeoutMs:250})).servers}catch{return}};e.registerCommand(`tools`,{description:`Browse the tools available in this session`,handler:async(t,n)=>{let i=await J(),a=r.buildToolSources({tools:e.getAllTools(),activeTools:e.getActiveTools(),...i?{mcpServers:i}:{},resolveExtensionName:d.extensionName,resolveExtensionToolSource:d.extensionToolSource});await l.openToolsOverlay(n,a)}}),e.registerCommand(`config`,{description:`Browse and change the settings extensions contribute`,handler:async(e,t)=>{await i.openConfigOverlay(t,A)}});let Y=e=>{for(let t of e){let e=t.bindingId?` (${t.bindingId})`:``,n=`Leader contribution from ${t.source}${e}: ${t.message}`;M.has(n)||(M.add(n),E.recordWarning(u.UI_EVENT.leaderContributionRejected,t.message,{"leader.source":t.source,...t.bindingId?{"leader.binding.id":t.bindingId}:{}}),F?.mode===`tui`&&F.ui.notify(n,S))}},X=(e,t)=>{let n=Symbol(e.source),r=t?e=>j.registerDeferred(e):e=>j.register(e),i=r(e);if(Y(i.diagnostics),!i.accepted)return{update:()=>void 0,dispose:()=>void 0};N.set(e.source,n);let a=!1;return{update(t){a||N.get(e.source)!==n||Y(r({source:e.source,bindings:t}).diagnostics)},dispose(){a||(a=!0,N.get(e.source)===n&&(N.delete(e.source),r({source:e.source,bindings:[]})))}}},Z=Object.freeze({register(e){let t=X(e,!1);return()=>t.dispose()}});q=(0,g.installDoomLeaderBootstrapHost)({register:e=>X(e,!0)}),e.on(`session_start`,(t,r)=>{F=r;let i=++W,l=(0,y.createProtocolRuntime)({bus:e.events,source:`@agimon-ai/doompi-ui`,sessionId:r.sessionManager.getSessionId()});if(K=l,Y(j.flush()),I?.(),O.reset(),I=O.bind(l),L?.(),L=k.bind(l),z?.(),A.reset(),z=A.bind(l),B?.(),V?.(),B=l.provide(g.LeaderRegistrationProtocol,({contribution:e,generation:t},n)=>{if(n.source!==e.source)throw Error(`Leader contribution source does not match the registration envelope source.`);let r=`${n.source}:${t}:${++U}`,i={source:e.source,bindings:e.bindings.map(e=>{let[t,...n]=e.path;if(!t)throw Error(`Leader binding '${e.id}' has no path.`);return{...e,path:[t,...n]}})};return H.set(r,Z.register(i)),{handleId:r}}),V=l.provide(g.LeaderUnregistrationProtocol,({handleId:e})=>{let t=H.get(e);return t?(H.delete(e),t(),{removed:!0}):{removed:!1}}),G=r.sessionManager.getEntries().some(e=>e.type===`message`),r.mode!==`tui`)return;for(let e of M)r.ui.notify(e,S);let d=process.env.DOOMPI_THEME||`doom-pi-dark`,f=r.ui.setTheme(d);f.success||(r.ui.notify(`Could not apply Doom Pi theme: ${f.error}`,S),E.recordWarning(u.UI_EVENT.themeApplyFailed,f.error??`Unknown theme error`,{"ui.theme":d})),R?.(),R=k.subscribe(()=>D.setModes(n.projectMinorModeRecords(k.list()))),D.setModes(n.projectMinorModeRecords(k.list())),r.ui.setTitle(`${C} · ${m.default.basename(r.cwd)||r.cwd} · pi/coding`),r.ui.setHeader((e,t)=>new s.DoomHeader(t,r.cwd,void 0,r,()=>e.terminal.rows)),r.ui.setFooter((e,t,n)=>(P=n,new o.DoomFooter(e,t,r,n,O,D))),r.ui.setEditorComponent((t,n,o)=>new a.DoomEditor(t,n,o,D,e=>{if(!e.active){r.ui.setWidget(b,void 0,{placement:x});return}r.ui.setWidget(b,(t,n)=>new c.LeaderHints(n,e,r,P,D.getModes()),{placement:x})},void 0,r.ui.theme,{registry:j,isCommandAvailable:t=>w.has(t)||e.getCommands().some(e=>e.name===t),onLeaderAction:(e,t)=>{if(F!==r||W!==i){r.ui.notify(`Leader action ${t} is unavailable.`,S);return}l.notify(g.LeaderActionInvoked,{source:e,action:t})},onUnavailableCommand:e=>{E.recordWarning(u.UI_EVENT.leaderCommandUnavailable,`Leader command /${e} is unavailable.`,{"ui.kind":`command`}),r.ui.notify(`Leader command /${e} is unavailable.`,S)},onUnavailableAction:e=>{E.recordWarning(u.UI_EVENT.leaderActionUnavailable,`Leader action ${e} is unavailable.`,{"ui.kind":`action`}),r.ui.notify(`Leader action ${e} is unavailable.`,S)}})),E.recordEvent(u.UI_EVENT.shellInstalled,{"ui.theme":d,"ui.theme.applied":f.success,"ui.leader.group.count":j.getGroup([])?.options.length??0})}),e.on(`input`,(e,t)=>{if(t.mode!==`tui`||e.source!==`interactive`||G)return;G=!0;let n=T(e.text,t.cwd);n&&t.ui.setTitle(n)}),e.on(`session_shutdown`,async(e,t)=>{++W,q?.(),q=void 0;for(let e of H.values())e();H.clear(),F=void 0,P=void 0,I?.(),I=void 0,O.reset(),L?.(),L=void 0,R?.(),R=void 0,k.reset(),z?.(),z=void 0,B?.(),B=void 0,V?.(),V=void 0,A.reset(),D.reset(),K=void 0,t.mode===`tui`&&t.ui.setWidget(b,void 0,{placement:x}),await E.shutdown()})}exports.doomPiUiExtension=E;
1
+ const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../services/leader/leaderRegistry.cjs"),n=require("../../services/hub/uiHub.cjs"),r=require("../../services/state/uiState.cjs"),i=require("../../services/tools/toolInventory.cjs"),a=require("../../tui/configOverlay.cjs"),o=require("../../tui/doomEditor.cjs"),s=require("../../tui/doomFooter.cjs"),c=require("../../tui/doomHeader.cjs"),l=require("../../tui/leaderHints.cjs");require("../../tui/theme.cjs");const u=require("../../tui/toolsOverlay.cjs"),d=require("../telemetry/logSinkTelemetry.cjs"),f=require("./extensionName.cjs"),p=require("./toolOverrides.cjs");let m=require("node:path");m=e.__toESM(m,1);let h=require("@agimon-ai/doompi-extension-contracts/cordis-host"),g=require("@agimon-ai/doompi-extension-contracts/mcp-status"),_=require("@agimon-ai/doompi-extension-contracts/mode"),v=require("@agimon-ai/doompi-extension-contracts/ui-hub");const y=`doom-pi-leader`,b=`belowEditor`,x=`warning`,S=`doom-pi`,C=new Set([`hotkeys`]),w=`@agimon-ai/doompi-ui`;function T(e,t){let n=e.trim().replace(/\s+/g,` `);if(!n)return;let r=n.slice(0,64).trimEnd();return`${S} · ${r} · ${m.default.basename(t)||t}`}function E(e,{pi:h,telemetry:E}){p.registerBuiltinToolUi(h,process.cwd());let D=new r.DoomUiState,O=new t.DoomLeaderRegistry,k=new Set,A,j,M=0,N=!1,P=()=>(0,g.readDoomMcpStatus)(e)?.getSnapshot().servers;h.registerCommand(`tools`,{description:`Browse the tools available in this session`,handler:async(e,t)=>{let n=P(),r=i.buildToolSources({tools:h.getAllTools(),activeTools:h.getActiveTools(),...n?{mcpServers:n}:{},resolveExtensionName:f.extensionName,resolveExtensionToolSource:e=>f.extensionToolSource(h,e)});await u.openToolsOverlay(t,r)}}),h.registerCommand(`config`,{description:`Browse and change the settings extensions contribute`,handler:async(e,t)=>{await a.openConfigOverlay(t,I.config)}});let F=e=>{for(let t of e){let e=t.bindingId?` (${t.bindingId})`:``,n=`Leader contribution from ${t.source}${e}: ${t.message}`;k.has(n)||(k.add(n),E.recordWarning(d.UI_EVENT.leaderContributionRejected,t.message,{"leader.source":t.source,...t.bindingId?{"leader.binding.id":t.bindingId}:{}}),j?.mode===`tui`&&j.ui.notify(n,x))}},I=n.createDoomUiHub({leaderRegistry:O,reportDiagnostics:F});e.provide(v.DOOM_UI_HUB_SERVICE,I),e.inject([_.DOOM_MINOR_MODE_CATALOG_SERVICE],e=>{let t=(0,_.createMinorModeCatalogClient)((0,_.requireMinorModeCatalog)(e)),n=()=>D.setModes(r.projectMinorModeRecords(t.list())),i=t.subscribe(n);return n(),()=>{i(),D.setModes([])}}),h.on(`session_start`,(e,t)=>{j=t,I.setContext(t);let n=++M;if(F(O.flush()),N=t.sessionManager.getEntries().some(e=>e.type===`message`),t.mode!==`tui`)return;for(let e of k)t.ui.notify(e,x);let r=process.env.DOOMPI_THEME||`doom-pi-dark`,i=t.ui.setTheme(r);i.success||(t.ui.notify(`Could not apply Doom Pi theme: ${i.error}`,x),E.recordWarning(d.UI_EVENT.themeApplyFailed,i.error??`Unknown theme error`,{"ui.theme":r})),t.ui.setTitle(`${S} · ${m.default.basename(t.cwd)||t.cwd} · pi/coding`),t.ui.setHeader((e,n)=>new c.DoomHeader(n,t.cwd,void 0,t,()=>e.terminal.rows)),t.ui.setFooter((e,n,r)=>(A=r,new s.DoomFooter(e,n,t,r,I.footer,D))),t.ui.setEditorComponent((e,r,i)=>new o.DoomEditor(e,r,i,D,e=>{if(!e.active){t.ui.setWidget(y,void 0,{placement:b});return}t.ui.setWidget(y,(n,r)=>new l.LeaderHints(r,e,t,A,D.getModes()),{placement:b})},void 0,t.ui.theme,{registry:O,isCommandAvailable:e=>C.has(e)||h.getCommands().some(t=>t.name===e),onLeaderAction:(e,r)=>{if(j!==t||M!==n){t.ui.notify(`Leader action ${r} is unavailable.`,x);return}I.invokeLeaderAction(e,r)},onUnavailableCommand:e=>{E.recordWarning(d.UI_EVENT.leaderCommandUnavailable,`Leader command /${e} is unavailable.`,{"ui.kind":`command`}),t.ui.notify(`Leader command /${e} is unavailable.`,x)},onUnavailableAction:e=>{E.recordWarning(d.UI_EVENT.leaderActionUnavailable,`Leader action ${e} is unavailable.`,{"ui.kind":`action`}),t.ui.notify(`Leader action ${e} is unavailable.`,x)}})),E.recordEvent(d.UI_EVENT.shellInstalled,{"ui.theme":r,"ui.theme.applied":i.success,"ui.leader.group.count":O.getGroup([])?.options.length??0})}),h.on(`input`,(e,t)=>{if(t.mode!==`tui`||e.source!==`interactive`||N)return;N=!0;let n=T(e.text,t.cwd);n&&t.ui.setTitle(n)}),e.effect(()=>async()=>{let e=j;++M,j=void 0,I.setContext(void 0),A=void 0,I.dispose(),D.reset(),e?.mode===`tui`&&e.ui.setWidget(y,void 0,{placement:b}),await E.shutdown()},w)}async function D(e,t=d.createUiTelemetry()){let n=await(0,h.connectDoomCordisHost)(e,w),r=n.root.plugin(E,{pi:e,telemetry:t});try{await r}catch(e){try{await r.dispose()}finally{await n.dispose()}throw e}let i;e.on(`session_shutdown`,()=>i??=(async()=>{try{await r.dispose()}finally{await n.dispose()}})())}exports.doomPiUiExtension=D;
2
2
  //# sourceMappingURL=extension.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.cjs","names":["path","createUiTelemetry","DoomUiState","DoomFooterStatusRegistry","createMinorModeCatalogClient","DoomConfigRegistry","DoomLeaderRegistry","McpStatusQueryProtocol","buildToolSources","extensionName","extensionToolSource","openToolsOverlay","openConfigOverlay","UI_EVENT","installDoomLeaderBootstrapHost","createProtocolRuntime","LeaderRegistrationProtocol","LeaderUnregistrationProtocol","projectMinorModeRecords","DoomHeader","DoomFooter","DoomEditor","LeaderHints","LeaderActionInvoked"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import path from 'node:path';\nimport { DoomConfigRegistry } from '@agimon-ai/doompi-extension-contracts/config';\nimport { DoomFooterStatusRegistry } from '@agimon-ai/doompi-extension-contracts/footer';\nimport {\n installDoomLeaderBootstrapHost,\n LeaderActionInvoked,\n type LeaderContribution,\n LeaderRegistrationProtocol,\n LeaderUnregistrationProtocol,\n} from '@agimon-ai/doompi-extension-contracts/leader';\nimport { McpStatusQueryProtocol } from '@agimon-ai/doompi-extension-contracts/mcp-status';\nimport { createMinorModeCatalogClient } from '@agimon-ai/doompi-extension-contracts/mode';\nimport { createProtocolRuntime, type ProtocolRuntime } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport type { ExtensionAPI, ExtensionContext, ReadonlyFooterDataProvider } from '@earendil-works/pi-coding-agent';\nimport { type DoomLeaderDiagnostic, DoomLeaderRegistry } from '../../services/leader/leaderRegistry.ts';\nimport { DoomUiState, type LeaderSnapshot, projectMinorModeRecords } from '../../services/state/uiState.ts';\nimport { buildToolSources, type McpServerStatus } from '../../services/tools/toolInventory.ts';\nimport { openConfigOverlay } from '../../tui/configOverlay.ts';\nimport { DoomEditor } from '../../tui/doomEditor.ts';\nimport { DoomFooter } from '../../tui/doomFooter.ts';\nimport { DoomHeader } from '../../tui/doomHeader.ts';\nimport { LeaderHints } from '../../tui/leaderHints.ts';\nimport { DEFAULT_THEME_NAME } from '../../tui/theme.ts';\nimport { openToolsOverlay } from '../../tui/toolsOverlay.ts';\nimport { createUiTelemetry, UI_EVENT, type UiTelemetry } from '../telemetry/logSinkTelemetry.ts';\nimport { extensionName, extensionToolSource } from './extensionName.ts';\nimport { registerBuiltinToolUi } from './toolOverrides.ts';\n\nconst LEADER_WIDGET_KEY = 'doom-pi-leader';\nconst TUI_MODE = 'tui';\nconst WIDGET_PLACEMENT = 'belowEditor';\nconst WARNING_STYLE = 'warning';\nconst THEME_ENVIRONMENT_KEY = 'DOOMPI_THEME';\nconst HOTKEYS_COMMAND = 'hotkeys';\nconst TOOLS_COMMAND = 'tools';\nconst CONFIG_COMMAND = 'config';\n/** Short: `/tools` must open promptly whether or not an MCP extension answers. */\nconst MCP_STATUS_TIMEOUT_MS = 250;\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_MESSAGE_ENTRY = 'message';\nconst INPUT_EVENT = 'input';\nconst INTERACTIVE_INPUT_SOURCE = 'interactive';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\nconst TITLE_MESSAGE_MAX_LENGTH = 64;\nconst TITLE_PREFIX = 'doom-pi';\nconst BUILTIN_LEADER_COMMANDS = new Set([HOTKEYS_COMMAND]);\n\nfunction createMessageTitle(message: string, cwd: string): string | undefined {\n const normalizedMessage = message.trim().replace(/\\s+/g, ' ');\n if (!normalizedMessage) return undefined;\n const messageTitle = normalizedMessage.slice(0, TITLE_MESSAGE_MAX_LENGTH).trimEnd();\n return `${TITLE_PREFIX} · ${messageTitle} · ${path.basename(cwd) || cwd}`;\n}\n\nexport function doomPiUiExtension(pi: ExtensionAPI, telemetry: UiTelemetry = createUiTelemetry()): void {\n registerBuiltinToolUi(pi, process.cwd());\n const uiState = new DoomUiState();\n const footerStatusRegistry = new DoomFooterStatusRegistry();\n const modeCatalog = createMinorModeCatalogClient();\n const configRegistry = new DoomConfigRegistry();\n const leaderRegistry = new DoomLeaderRegistry();\n const pendingDiagnostics = new Set<string>();\n const contributionGenerations = new Map<string, symbol>();\n let footerData: ReadonlyFooterDataProvider | undefined;\n let activeContext: ExtensionContext | undefined;\n let disposeFooterStatuses: (() => void) | undefined;\n let disposeModeCatalogBinding: (() => void) | undefined;\n let disposeModeSubscription: (() => void) | undefined;\n let disposeConfigContributions: (() => void) | undefined;\n let disposeLeaderRegistration: (() => void) | undefined;\n let disposeLeaderUnregistration: (() => void) | undefined;\n const protocolContributions = new Map<string, () => void>();\n let nextProtocolHandle = 0;\n let sessionGeneration = 0;\n let hasSessionMessage = false;\n let sessionProtocol: ProtocolRuntime | undefined;\n let disposeLeaderBootstrap: (() => void) | undefined;\n\n /**\n * Asks the MCP extension what it is currently connected to.\n *\n * No answer is a normal session: `--no-mcp` leaves nobody providing the query,\n * and the panel simply lists MCP tools under the extension that registered them.\n */\n const readMcpServers = async (): Promise<readonly McpServerStatus[] | undefined> => {\n if (!sessionProtocol) return undefined;\n try {\n const snapshot = await sessionProtocol.request(McpStatusQueryProtocol, {}, { timeoutMs: MCP_STATUS_TIMEOUT_MS });\n return snapshot.servers;\n } catch {\n return undefined;\n }\n };\n\n pi.registerCommand(TOOLS_COMMAND, {\n description: 'Browse the tools available in this session',\n handler: async (_args, ctx) => {\n // Read at open time so a reconnected server or a plan-mode tool swap shows\n // up without restarting the session.\n const mcpServers = await readMcpServers();\n const sources = buildToolSources({\n tools: pi.getAllTools(),\n activeTools: pi.getActiveTools(),\n ...(mcpServers ? { mcpServers } : {}),\n resolveExtensionName: extensionName,\n resolveExtensionToolSource: extensionToolSource,\n });\n await openToolsOverlay(ctx, sources);\n },\n });\n\n pi.registerCommand(CONFIG_COMMAND, {\n description: 'Browse and change the settings extensions contribute',\n handler: async (_args, ctx) => {\n // The registry is passed live rather than snapshotted: a contributor can be\n // fetching or installing something while the panel is open, and that\n // progress is meant to land in it.\n await openConfigOverlay(ctx, configRegistry);\n },\n });\n\n const reportDiagnostics = (diagnostics: readonly DoomLeaderDiagnostic[]): void => {\n for (const diagnostic of diagnostics) {\n const binding = diagnostic.bindingId ? ` (${diagnostic.bindingId})` : '';\n const message = `Leader contribution from ${diagnostic.source}${binding}: ${diagnostic.message}`;\n if (pendingDiagnostics.has(message)) continue;\n pendingDiagnostics.add(message);\n // A rejected contribution silently drops another extension's keybindings,\n // and the notice below only reaches a run that has a TUI attached.\n void telemetry.recordWarning(UI_EVENT.leaderContributionRejected, diagnostic.message, {\n 'leader.source': diagnostic.source,\n ...(diagnostic.bindingId ? { 'leader.binding.id': diagnostic.bindingId } : {}),\n });\n if (activeContext?.mode === TUI_MODE) activeContext.ui.notify(message, WARNING_STYLE);\n }\n };\n\n const registerLeaderContribution = (contribution: LeaderContribution, deferred: boolean) => {\n const generation = Symbol(contribution.source);\n const register = deferred\n ? (value: LeaderContribution) => leaderRegistry.registerDeferred(value)\n : (value: LeaderContribution) => leaderRegistry.register(value);\n const result = register(contribution);\n reportDiagnostics(result.diagnostics);\n if (!result.accepted) return { update: () => undefined, dispose: () => undefined };\n contributionGenerations.set(contribution.source, generation);\n let disposed = false;\n return {\n update(bindings: LeaderContribution['bindings']) {\n if (disposed || contributionGenerations.get(contribution.source) !== generation) return;\n reportDiagnostics(register({ source: contribution.source, bindings }).diagnostics);\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n if (contributionGenerations.get(contribution.source) !== generation) return;\n contributionGenerations.delete(contribution.source);\n register({ source: contribution.source, bindings: [] });\n },\n };\n };\n\n const leaderContext = Object.freeze({\n register(contribution: LeaderContribution) {\n const handle = registerLeaderContribution(contribution, false);\n return () => handle.dispose();\n },\n });\n // Installed during the UI factory, before the remaining Doom factories run.\n // Their registrations are validated immediately and rebuilt as one batch at\n // session_start, so the first editor always receives the complete keyspace.\n disposeLeaderBootstrap = installDoomLeaderBootstrapHost({\n register: (contribution) => registerLeaderContribution(contribution, true),\n });\n pi.on(SESSION_START_EVENT, (_event, ctx) => {\n activeContext = ctx;\n const activeGeneration = ++sessionGeneration;\n const protocol = createProtocolRuntime({\n bus: pi.events,\n source: '@agimon-ai/doompi-ui',\n sessionId: ctx.sessionManager.getSessionId(),\n });\n sessionProtocol = protocol;\n reportDiagnostics(leaderRegistry.flush());\n disposeFooterStatuses?.();\n footerStatusRegistry.reset();\n disposeFooterStatuses = footerStatusRegistry.bind(protocol);\n disposeModeCatalogBinding?.();\n disposeModeCatalogBinding = modeCatalog.bind(protocol);\n // Bound above the TUI-mode guard below, like footer and mode: a headless run\n // still accepts contributions, it just never draws them.\n disposeConfigContributions?.();\n configRegistry.reset();\n disposeConfigContributions = configRegistry.bind(protocol);\n disposeLeaderRegistration?.();\n disposeLeaderUnregistration?.();\n disposeLeaderRegistration = protocol.provide(\n LeaderRegistrationProtocol,\n ({ contribution, generation }, identity) => {\n if (identity.source !== contribution.source) {\n throw new Error('Leader contribution source does not match the registration envelope source.');\n }\n const handleId = `${identity.source}:${generation}:${++nextProtocolHandle}`;\n const typedContribution: LeaderContribution = {\n source: contribution.source,\n bindings: contribution.bindings.map((binding) => {\n const [first, ...rest] = binding.path;\n if (!first) throw new Error(`Leader binding '${binding.id}' has no path.`);\n return { ...binding, path: [first, ...rest] };\n }),\n };\n protocolContributions.set(handleId, leaderContext.register(typedContribution));\n return { handleId };\n },\n );\n disposeLeaderUnregistration = protocol.provide(LeaderUnregistrationProtocol, ({ handleId }) => {\n const dispose = protocolContributions.get(handleId);\n if (!dispose) return { removed: false };\n protocolContributions.delete(handleId);\n dispose();\n return { removed: true };\n });\n hasSessionMessage = ctx.sessionManager.getEntries().some((entry) => entry.type === SESSION_MESSAGE_ENTRY);\n if (ctx.mode !== TUI_MODE) return;\n for (const message of pendingDiagnostics) ctx.ui.notify(message, WARNING_STYLE);\n\n const themeName = process.env[THEME_ENVIRONMENT_KEY] || DEFAULT_THEME_NAME;\n const themeResult = ctx.ui.setTheme(themeName);\n if (!themeResult.success) {\n ctx.ui.notify(`Could not apply Doom Pi theme: ${themeResult.error}`, WARNING_STYLE);\n void telemetry.recordWarning(UI_EVENT.themeApplyFailed, themeResult.error ?? 'Unknown theme error', {\n 'ui.theme': themeName,\n });\n }\n\n // The modes go into shared state rather than a widget of their own: the\n // editor prints their names beside its badge and the leader panel prints\n // them with their detail, so there is no third surface to paint.\n disposeModeSubscription?.();\n disposeModeSubscription = modeCatalog.subscribe(() =>\n uiState.setModes(projectMinorModeRecords(modeCatalog.list())),\n );\n uiState.setModes(projectMinorModeRecords(modeCatalog.list()));\n\n ctx.ui.setTitle(`${TITLE_PREFIX} · ${path.basename(ctx.cwd) || ctx.cwd} · pi/coding`);\n ctx.ui.setHeader((tui, theme) => new DoomHeader(theme, ctx.cwd, undefined, ctx, () => tui.terminal.rows));\n ctx.ui.setFooter((tui, theme, data) => {\n footerData = data;\n return new DoomFooter(tui, theme, ctx, data, footerStatusRegistry, uiState);\n });\n ctx.ui.setEditorComponent(\n (tui, editorTheme, keybindings) =>\n new DoomEditor(\n tui,\n editorTheme,\n keybindings,\n uiState,\n (snapshot: LeaderSnapshot) => {\n if (!snapshot.active) {\n ctx.ui.setWidget(LEADER_WIDGET_KEY, undefined, { placement: WIDGET_PLACEMENT });\n return;\n }\n ctx.ui.setWidget(\n LEADER_WIDGET_KEY,\n (_widgetTui, widgetTheme) => new LeaderHints(widgetTheme, snapshot, ctx, footerData, uiState.getModes()),\n { placement: WIDGET_PLACEMENT },\n );\n },\n undefined,\n ctx.ui.theme,\n {\n registry: leaderRegistry,\n isCommandAvailable: (commandName) =>\n BUILTIN_LEADER_COMMANDS.has(commandName) ||\n pi.getCommands().some((command) => command.name === commandName),\n onLeaderAction: (source, action) => {\n if (activeContext !== ctx || sessionGeneration !== activeGeneration) {\n ctx.ui.notify(`Leader action ${action} is unavailable.`, WARNING_STYLE);\n return;\n }\n protocol.notify(LeaderActionInvoked, { source, action });\n },\n onUnavailableCommand: (commandName) => {\n void telemetry.recordWarning(\n UI_EVENT.leaderCommandUnavailable,\n `Leader command /${commandName} is unavailable.`,\n { 'ui.kind': 'command' },\n );\n ctx.ui.notify(`Leader command /${commandName} is unavailable.`, WARNING_STYLE);\n },\n onUnavailableAction: (action) => {\n void telemetry.recordWarning(\n UI_EVENT.leaderActionUnavailable,\n `Leader action ${action} is unavailable.`,\n {\n 'ui.kind': 'action',\n },\n );\n ctx.ui.notify(`Leader action ${action} is unavailable.`, WARNING_STYLE);\n },\n },\n ),\n );\n\n void telemetry.recordEvent(UI_EVENT.shellInstalled, {\n 'ui.theme': themeName,\n 'ui.theme.applied': themeResult.success,\n 'ui.leader.group.count': leaderRegistry.getGroup([])?.options.length ?? 0,\n });\n });\n\n pi.on(INPUT_EVENT, (event, ctx) => {\n if (ctx.mode !== TUI_MODE || event.source !== INTERACTIVE_INPUT_SOURCE || hasSessionMessage) return;\n hasSessionMessage = true;\n const title = createMessageTitle(event.text, ctx.cwd);\n if (title) ctx.ui.setTitle(title);\n });\n\n pi.on(SESSION_SHUTDOWN_EVENT, async (_event, ctx) => {\n ++sessionGeneration;\n disposeLeaderBootstrap?.();\n disposeLeaderBootstrap = undefined;\n for (const dispose of protocolContributions.values()) dispose();\n protocolContributions.clear();\n activeContext = undefined;\n footerData = undefined;\n disposeFooterStatuses?.();\n disposeFooterStatuses = undefined;\n footerStatusRegistry.reset();\n disposeModeCatalogBinding?.();\n disposeModeCatalogBinding = undefined;\n disposeModeSubscription?.();\n disposeModeSubscription = undefined;\n modeCatalog.reset();\n disposeConfigContributions?.();\n disposeConfigContributions = undefined;\n disposeLeaderRegistration?.();\n disposeLeaderRegistration = undefined;\n disposeLeaderUnregistration?.();\n disposeLeaderUnregistration = undefined;\n configRegistry.reset();\n uiState.reset();\n sessionProtocol = undefined;\n if (ctx.mode === TUI_MODE) ctx.ui.setWidget(LEADER_WIDGET_KEY, undefined, { placement: WIDGET_PLACEMENT });\n await telemetry.shutdown();\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"extension.cjs","names":["path","DoomUiState","DoomLeaderRegistry","readDoomMcpStatus","buildToolSources","extensionName","extensionToolSource","openToolsOverlay","openConfigOverlay","UI_EVENT","createDoomUiHub","DOOM_UI_HUB_SERVICE","DOOM_MINOR_MODE_CATALOG_SERVICE","createMinorModeCatalogClient","requireMinorModeCatalog","projectMinorModeRecords","DoomHeader","DoomFooter","DoomEditor","LeaderHints","createUiTelemetry","connectDoomCordisHost"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import path from 'node:path';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { readDoomMcpStatus } from '@agimon-ai/doompi-extension-contracts/mcp-status';\nimport {\n DOOM_MINOR_MODE_CATALOG_SERVICE,\n createMinorModeCatalogClient,\n requireMinorModeCatalog,\n} from '@agimon-ai/doompi-extension-contracts/mode';\nimport { DOOM_UI_HUB_SERVICE } from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext, ReadonlyFooterDataProvider } from '@earendil-works/pi-coding-agent';\nimport { type DoomLeaderDiagnostic, DoomLeaderRegistry } from '../../services/leader/leaderRegistry.ts';\nimport { createDoomUiHub } from '../../services/hub/uiHub.ts';\nimport { DoomUiState, type LeaderSnapshot, projectMinorModeRecords } from '../../services/state/uiState.ts';\nimport { buildToolSources, type McpServerStatus } from '../../services/tools/toolInventory.ts';\nimport { openConfigOverlay } from '../../tui/configOverlay.ts';\nimport { DoomEditor } from '../../tui/doomEditor.ts';\nimport { DoomFooter } from '../../tui/doomFooter.ts';\nimport { DoomHeader } from '../../tui/doomHeader.ts';\nimport { LeaderHints } from '../../tui/leaderHints.ts';\nimport { DEFAULT_THEME_NAME } from '../../tui/theme.ts';\nimport { openToolsOverlay } from '../../tui/toolsOverlay.ts';\nimport { createUiTelemetry, UI_EVENT, type UiTelemetry } from '../telemetry/logSinkTelemetry.ts';\nimport { extensionName, extensionToolSource } from './extensionName.ts';\nimport { registerBuiltinToolUi } from './toolOverrides.ts';\n\nconst LEADER_WIDGET_KEY = 'doom-pi-leader';\nconst TUI_MODE = 'tui';\nconst WIDGET_PLACEMENT = 'belowEditor';\nconst WARNING_STYLE = 'warning';\nconst THEME_ENVIRONMENT_KEY = 'DOOMPI_THEME';\nconst HOTKEYS_COMMAND = 'hotkeys';\nconst TOOLS_COMMAND = 'tools';\nconst CONFIG_COMMAND = 'config';\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_MESSAGE_ENTRY = 'message';\nconst INPUT_EVENT = 'input';\nconst INTERACTIVE_INPUT_SOURCE = 'interactive';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\nconst TITLE_MESSAGE_MAX_LENGTH = 64;\nconst TITLE_PREFIX = 'doom-pi';\nconst BUILTIN_LEADER_COMMANDS = new Set([HOTKEYS_COMMAND]);\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-ui';\n\nfunction createMessageTitle(message: string, cwd: string): string | undefined {\n const normalizedMessage = message.trim().replace(/\\s+/g, ' ');\n if (!normalizedMessage) return undefined;\n const messageTitle = normalizedMessage.slice(0, TITLE_MESSAGE_MAX_LENGTH).trimEnd();\n return `${TITLE_PREFIX} · ${messageTitle} · ${path.basename(cwd) || cwd}`;\n}\n\ninterface UiPluginOptions {\n readonly pi: ExtensionAPI;\n readonly telemetry: UiTelemetry;\n}\n\nfunction doomPiUiPlugin(cordis: Context, { pi, telemetry }: UiPluginOptions): void {\n registerBuiltinToolUi(pi, process.cwd());\n const uiState = new DoomUiState();\n const leaderRegistry = new DoomLeaderRegistry();\n const pendingDiagnostics = new Set<string>();\n let footerData: ReadonlyFooterDataProvider | undefined;\n let activeContext: ExtensionContext | undefined;\n let sessionGeneration = 0;\n let hasSessionMessage = false;\n\n /**\n * Asks the MCP extension what it is currently connected to.\n *\n * No answer is a normal session: `--no-mcp` leaves nobody providing the query,\n * and the panel simply lists MCP tools under the extension that registered them.\n */\n const readMcpServers = (): readonly McpServerStatus[] | undefined => readDoomMcpStatus(cordis)?.getSnapshot().servers;\n\n pi.registerCommand(TOOLS_COMMAND, {\n description: 'Browse the tools available in this session',\n handler: async (_args, ctx) => {\n // Read at open time so a reconnected server or a plan-mode tool swap shows\n // up without restarting the session.\n const mcpServers = readMcpServers();\n const sources = buildToolSources({\n tools: pi.getAllTools(),\n activeTools: pi.getActiveTools(),\n ...(mcpServers ? { mcpServers } : {}),\n resolveExtensionName: extensionName,\n resolveExtensionToolSource: (toolName) => extensionToolSource(pi, toolName),\n });\n await openToolsOverlay(ctx, sources);\n },\n });\n\n pi.registerCommand(CONFIG_COMMAND, {\n description: 'Browse and change the settings extensions contribute',\n handler: async (_args, ctx) => {\n // The registry is passed live rather than snapshotted: a contributor can be\n // fetching or installing something while the panel is open, and that\n // progress is meant to land in it.\n await openConfigOverlay(ctx, hub.config);\n },\n });\n\n const reportDiagnostics = (diagnostics: readonly DoomLeaderDiagnostic[]): void => {\n for (const diagnostic of diagnostics) {\n const binding = diagnostic.bindingId ? ` (${diagnostic.bindingId})` : '';\n const message = `Leader contribution from ${diagnostic.source}${binding}: ${diagnostic.message}`;\n if (pendingDiagnostics.has(message)) continue;\n pendingDiagnostics.add(message);\n // A rejected contribution silently drops another extension's keybindings,\n // and the notice below only reaches a run that has a TUI attached.\n void telemetry.recordWarning(UI_EVENT.leaderContributionRejected, diagnostic.message, {\n 'leader.source': diagnostic.source,\n ...(diagnostic.bindingId ? { 'leader.binding.id': diagnostic.bindingId } : {}),\n });\n if (activeContext?.mode === TUI_MODE) activeContext.ui.notify(message, WARNING_STYLE);\n }\n };\n\n const hub = createDoomUiHub({ leaderRegistry, reportDiagnostics });\n cordis.provide(DOOM_UI_HUB_SERVICE, hub);\n cordis.inject([DOOM_MINOR_MODE_CATALOG_SERVICE], (modeContext) => {\n const catalog = createMinorModeCatalogClient(requireMinorModeCatalog(modeContext));\n const update = (): void => uiState.setModes(projectMinorModeRecords(catalog.list()));\n const dispose = catalog.subscribe(update);\n update();\n return () => {\n dispose();\n uiState.setModes([]);\n };\n });\n\n pi.on(SESSION_START_EVENT, (_event, ctx) => {\n activeContext = ctx;\n hub.setContext(ctx);\n const activeGeneration = ++sessionGeneration;\n reportDiagnostics(leaderRegistry.flush());\n hasSessionMessage = ctx.sessionManager.getEntries().some((entry) => entry.type === SESSION_MESSAGE_ENTRY);\n if (ctx.mode !== TUI_MODE) return;\n for (const message of pendingDiagnostics) ctx.ui.notify(message, WARNING_STYLE);\n\n const themeName = process.env[THEME_ENVIRONMENT_KEY] || DEFAULT_THEME_NAME;\n const themeResult = ctx.ui.setTheme(themeName);\n if (!themeResult.success) {\n ctx.ui.notify(`Could not apply Doom Pi theme: ${themeResult.error}`, WARNING_STYLE);\n void telemetry.recordWarning(UI_EVENT.themeApplyFailed, themeResult.error ?? 'Unknown theme error', {\n 'ui.theme': themeName,\n });\n }\n\n ctx.ui.setTitle(`${TITLE_PREFIX} · ${path.basename(ctx.cwd) || ctx.cwd} · pi/coding`);\n ctx.ui.setHeader((tui, theme) => new DoomHeader(theme, ctx.cwd, undefined, ctx, () => tui.terminal.rows));\n ctx.ui.setFooter((tui, theme, data) => {\n footerData = data;\n return new DoomFooter(tui, theme, ctx, data, hub.footer, uiState);\n });\n ctx.ui.setEditorComponent(\n (tui, editorTheme, keybindings) =>\n new DoomEditor(\n tui,\n editorTheme,\n keybindings,\n uiState,\n (snapshot: LeaderSnapshot) => {\n if (!snapshot.active) {\n ctx.ui.setWidget(LEADER_WIDGET_KEY, undefined, { placement: WIDGET_PLACEMENT });\n return;\n }\n ctx.ui.setWidget(\n LEADER_WIDGET_KEY,\n (_widgetTui, widgetTheme) => new LeaderHints(widgetTheme, snapshot, ctx, footerData, uiState.getModes()),\n { placement: WIDGET_PLACEMENT },\n );\n },\n undefined,\n ctx.ui.theme,\n {\n registry: leaderRegistry,\n isCommandAvailable: (commandName) =>\n BUILTIN_LEADER_COMMANDS.has(commandName) ||\n pi.getCommands().some((command) => command.name === commandName),\n onLeaderAction: (source, action) => {\n if (activeContext !== ctx || sessionGeneration !== activeGeneration) {\n ctx.ui.notify(`Leader action ${action} is unavailable.`, WARNING_STYLE);\n return;\n }\n hub.invokeLeaderAction(source, action);\n },\n onUnavailableCommand: (commandName) => {\n void telemetry.recordWarning(\n UI_EVENT.leaderCommandUnavailable,\n `Leader command /${commandName} is unavailable.`,\n { 'ui.kind': 'command' },\n );\n ctx.ui.notify(`Leader command /${commandName} is unavailable.`, WARNING_STYLE);\n },\n onUnavailableAction: (action) => {\n void telemetry.recordWarning(\n UI_EVENT.leaderActionUnavailable,\n `Leader action ${action} is unavailable.`,\n {\n 'ui.kind': 'action',\n },\n );\n ctx.ui.notify(`Leader action ${action} is unavailable.`, WARNING_STYLE);\n },\n },\n ),\n );\n\n void telemetry.recordEvent(UI_EVENT.shellInstalled, {\n 'ui.theme': themeName,\n 'ui.theme.applied': themeResult.success,\n 'ui.leader.group.count': leaderRegistry.getGroup([])?.options.length ?? 0,\n });\n });\n\n pi.on(INPUT_EVENT, (event, ctx) => {\n if (ctx.mode !== TUI_MODE || event.source !== INTERACTIVE_INPUT_SOURCE || hasSessionMessage) return;\n hasSessionMessage = true;\n const title = createMessageTitle(event.text, ctx.cwd);\n if (title) ctx.ui.setTitle(title);\n });\n\n cordis.effect(\n () => async () => {\n const context = activeContext;\n ++sessionGeneration;\n activeContext = undefined;\n hub.setContext(undefined);\n footerData = undefined;\n hub.dispose();\n uiState.reset();\n if (context?.mode === TUI_MODE) {\n context.ui.setWidget(LEADER_WIDGET_KEY, undefined, { placement: WIDGET_PLACEMENT });\n }\n await telemetry.shutdown();\n },\n PACKAGE_SOURCE,\n );\n}\n\n/** The package's standard Pi factory, mounted under the session Cordis host. */\nexport async function doomPiUiExtension(pi: ExtensionAPI, telemetry: UiTelemetry = createUiTelemetry()): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(doomPiUiPlugin, { pi, telemetry });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n\n let disposal: Promise<void> | undefined;\n pi.on(\n SESSION_SHUTDOWN_EVENT,\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n"],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  import { UiTelemetry } from "../telemetry/logSinkTelemetry.cjs";
2
2
  import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
3
  //#region src/adapters/pi/extension.d.ts
4
- declare function doomPiUiExtension(pi: ExtensionAPI, telemetry?: UiTelemetry): void;
4
+ /** The package's standard Pi factory, mounted under the session Cordis host. */
5
+ declare function doomPiUiExtension(pi: ExtensionAPI, telemetry?: UiTelemetry): Promise<void>;
5
6
  //#endregion
6
7
  export { doomPiUiExtension };
7
8
  //# sourceMappingURL=extension.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;iBAsDgB,kBAAkB,IAAI,cAAc,YAAW"}
1
+ {"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAiPsB,kBAAkB,IAAI,cAAc,YAAW,cAAoC"}
@@ -1,7 +1,8 @@
1
1
  import { UiTelemetry } from "../telemetry/logSinkTelemetry.mjs";
2
2
  import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
3
  //#region src/adapters/pi/extension.d.ts
4
- declare function doomPiUiExtension(pi: ExtensionAPI, telemetry?: UiTelemetry): void;
4
+ /** The package's standard Pi factory, mounted under the session Cordis host. */
5
+ declare function doomPiUiExtension(pi: ExtensionAPI, telemetry?: UiTelemetry): Promise<void>;
5
6
  //#endregion
6
7
  export { doomPiUiExtension };
7
8
  //# sourceMappingURL=extension.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;iBAsDgB,kBAAkB,IAAI,cAAc,YAAW"}
1
+ {"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAiPsB,kBAAkB,IAAI,cAAc,YAAW,cAAoC"}
@@ -1,2 +1,2 @@
1
- import{DoomLeaderRegistry as e}from"../../services/leader/leaderRegistry.mjs";import{DoomUiState as t,projectMinorModeRecords as n}from"../../services/state/uiState.mjs";import{buildToolSources as r}from"../../services/tools/toolInventory.mjs";import{openConfigOverlay as i}from"../../tui/configOverlay.mjs";import{DoomEditor as a}from"../../tui/doomEditor.mjs";import{DoomFooter as o}from"../../tui/doomFooter.mjs";import{DoomHeader as s}from"../../tui/doomHeader.mjs";import{LeaderHints as c}from"../../tui/leaderHints.mjs";import"../../tui/theme.mjs";import{openToolsOverlay as l}from"../../tui/toolsOverlay.mjs";import{UI_EVENT as u,createUiTelemetry as d}from"../telemetry/logSinkTelemetry.mjs";import{extensionName as f,extensionToolSource as p}from"./extensionName.mjs";import{registerBuiltinToolUi as m}from"./toolOverrides.mjs";import{DoomConfigRegistry as ee}from"@agimon-ai/doompi-extension-contracts/config";import h from"node:path";import{DoomFooterStatusRegistry as te}from"@agimon-ai/doompi-extension-contracts/footer";import{LeaderActionInvoked as g,LeaderRegistrationProtocol as _,LeaderUnregistrationProtocol as v,installDoomLeaderBootstrapHost as y}from"@agimon-ai/doompi-extension-contracts/leader";import{McpStatusQueryProtocol as b}from"@agimon-ai/doompi-extension-contracts/mcp-status";import{createMinorModeCatalogClient as x}from"@agimon-ai/doompi-extension-contracts/mode";import{createProtocolRuntime as S}from"@agimon-ai/doompi-extension-contracts/protocol";const C=`doom-pi-leader`,w=`belowEditor`,T=`warning`,E=`doom-pi`,D=new Set([`hotkeys`]);function O(e,t){let n=e.trim().replace(/\s+/g,` `);if(!n)return;let r=n.slice(0,64).trimEnd();return`${E} · ${r} · ${h.basename(t)||t}`}function k(k,A=d()){m(k,process.cwd());let j=new t,M=new te,N=x(),P=new ee,F=new e,I=new Set,L=new Map,R,z,B,V,H,U,W,G,K=new Map,q=0,J=0,Y=!1,X,Z,ne=async()=>{if(X)try{return(await X.request(b,{},{timeoutMs:250})).servers}catch{return}};k.registerCommand(`tools`,{description:`Browse the tools available in this session`,handler:async(e,t)=>{let n=await ne(),i=r({tools:k.getAllTools(),activeTools:k.getActiveTools(),...n?{mcpServers:n}:{},resolveExtensionName:f,resolveExtensionToolSource:p});await l(t,i)}}),k.registerCommand(`config`,{description:`Browse and change the settings extensions contribute`,handler:async(e,t)=>{await i(t,P)}});let Q=e=>{for(let t of e){let e=t.bindingId?` (${t.bindingId})`:``,n=`Leader contribution from ${t.source}${e}: ${t.message}`;I.has(n)||(I.add(n),A.recordWarning(u.leaderContributionRejected,t.message,{"leader.source":t.source,...t.bindingId?{"leader.binding.id":t.bindingId}:{}}),z?.mode===`tui`&&z.ui.notify(n,T))}},$=(e,t)=>{let n=Symbol(e.source),r=t?e=>F.registerDeferred(e):e=>F.register(e),i=r(e);if(Q(i.diagnostics),!i.accepted)return{update:()=>void 0,dispose:()=>void 0};L.set(e.source,n);let a=!1;return{update(t){a||L.get(e.source)!==n||Q(r({source:e.source,bindings:t}).diagnostics)},dispose(){a||(a=!0,L.get(e.source)===n&&(L.delete(e.source),r({source:e.source,bindings:[]})))}}},re=Object.freeze({register(e){let t=$(e,!1);return()=>t.dispose()}});Z=y({register:e=>$(e,!0)}),k.on(`session_start`,(e,t)=>{z=t;let r=++J,i=S({bus:k.events,source:`@agimon-ai/doompi-ui`,sessionId:t.sessionManager.getSessionId()});if(X=i,Q(F.flush()),B?.(),M.reset(),B=M.bind(i),V?.(),V=N.bind(i),U?.(),P.reset(),U=P.bind(i),W?.(),G?.(),W=i.provide(_,({contribution:e,generation:t},n)=>{if(n.source!==e.source)throw Error(`Leader contribution source does not match the registration envelope source.`);let r=`${n.source}:${t}:${++q}`,i={source:e.source,bindings:e.bindings.map(e=>{let[t,...n]=e.path;if(!t)throw Error(`Leader binding '${e.id}' has no path.`);return{...e,path:[t,...n]}})};return K.set(r,re.register(i)),{handleId:r}}),G=i.provide(v,({handleId:e})=>{let t=K.get(e);return t?(K.delete(e),t(),{removed:!0}):{removed:!1}}),Y=t.sessionManager.getEntries().some(e=>e.type===`message`),t.mode!==`tui`)return;for(let e of I)t.ui.notify(e,T);let l=process.env.DOOMPI_THEME||`doom-pi-dark`,d=t.ui.setTheme(l);d.success||(t.ui.notify(`Could not apply Doom Pi theme: ${d.error}`,T),A.recordWarning(u.themeApplyFailed,d.error??`Unknown theme error`,{"ui.theme":l})),H?.(),H=N.subscribe(()=>j.setModes(n(N.list()))),j.setModes(n(N.list())),t.ui.setTitle(`${E} · ${h.basename(t.cwd)||t.cwd} · pi/coding`),t.ui.setHeader((e,n)=>new s(n,t.cwd,void 0,t,()=>e.terminal.rows)),t.ui.setFooter((e,n,r)=>(R=r,new o(e,n,t,r,M,j))),t.ui.setEditorComponent((e,n,o)=>new a(e,n,o,j,e=>{if(!e.active){t.ui.setWidget(C,void 0,{placement:w});return}t.ui.setWidget(C,(n,r)=>new c(r,e,t,R,j.getModes()),{placement:w})},void 0,t.ui.theme,{registry:F,isCommandAvailable:e=>D.has(e)||k.getCommands().some(t=>t.name===e),onLeaderAction:(e,n)=>{if(z!==t||J!==r){t.ui.notify(`Leader action ${n} is unavailable.`,T);return}i.notify(g,{source:e,action:n})},onUnavailableCommand:e=>{A.recordWarning(u.leaderCommandUnavailable,`Leader command /${e} is unavailable.`,{"ui.kind":`command`}),t.ui.notify(`Leader command /${e} is unavailable.`,T)},onUnavailableAction:e=>{A.recordWarning(u.leaderActionUnavailable,`Leader action ${e} is unavailable.`,{"ui.kind":`action`}),t.ui.notify(`Leader action ${e} is unavailable.`,T)}})),A.recordEvent(u.shellInstalled,{"ui.theme":l,"ui.theme.applied":d.success,"ui.leader.group.count":F.getGroup([])?.options.length??0})}),k.on(`input`,(e,t)=>{if(t.mode!==`tui`||e.source!==`interactive`||Y)return;Y=!0;let n=O(e.text,t.cwd);n&&t.ui.setTitle(n)}),k.on(`session_shutdown`,async(e,t)=>{++J,Z?.(),Z=void 0;for(let e of K.values())e();K.clear(),z=void 0,R=void 0,B?.(),B=void 0,M.reset(),V?.(),V=void 0,H?.(),H=void 0,N.reset(),U?.(),U=void 0,W?.(),W=void 0,G?.(),G=void 0,P.reset(),j.reset(),X=void 0,t.mode===`tui`&&t.ui.setWidget(C,void 0,{placement:w}),await A.shutdown()})}export{k as doomPiUiExtension};
1
+ import{DoomLeaderRegistry as e}from"../../services/leader/leaderRegistry.mjs";import{createDoomUiHub as t}from"../../services/hub/uiHub.mjs";import{DoomUiState as n,projectMinorModeRecords as r}from"../../services/state/uiState.mjs";import{buildToolSources as i}from"../../services/tools/toolInventory.mjs";import{openConfigOverlay as a}from"../../tui/configOverlay.mjs";import{DoomEditor as o}from"../../tui/doomEditor.mjs";import{DoomFooter as s}from"../../tui/doomFooter.mjs";import{DoomHeader as c}from"../../tui/doomHeader.mjs";import{LeaderHints as l}from"../../tui/leaderHints.mjs";import"../../tui/theme.mjs";import{openToolsOverlay as u}from"../../tui/toolsOverlay.mjs";import{UI_EVENT as d,createUiTelemetry as f}from"../telemetry/logSinkTelemetry.mjs";import{extensionName as p,extensionToolSource as m}from"./extensionName.mjs";import{registerBuiltinToolUi as h}from"./toolOverrides.mjs";import g from"node:path";import{connectDoomCordisHost as _}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{readDoomMcpStatus as v}from"@agimon-ai/doompi-extension-contracts/mcp-status";import{DOOM_MINOR_MODE_CATALOG_SERVICE as y,createMinorModeCatalogClient as b,requireMinorModeCatalog as x}from"@agimon-ai/doompi-extension-contracts/mode";import{DOOM_UI_HUB_SERVICE as S}from"@agimon-ai/doompi-extension-contracts/ui-hub";const C=`doom-pi-leader`,w=`belowEditor`,T=`warning`,E=`doom-pi`,D=new Set([`hotkeys`]),O=`@agimon-ai/doompi-ui`;function k(e,t){let n=e.trim().replace(/\s+/g,` `);if(!n)return;let r=n.slice(0,64).trimEnd();return`${E} · ${r} · ${g.basename(t)||t}`}function A(f,{pi:_,telemetry:A}){h(_,process.cwd());let j=new n,M=new e,N=new Set,P,F,I=0,L=!1,R=()=>v(f)?.getSnapshot().servers;_.registerCommand(`tools`,{description:`Browse the tools available in this session`,handler:async(e,t)=>{let n=R(),r=i({tools:_.getAllTools(),activeTools:_.getActiveTools(),...n?{mcpServers:n}:{},resolveExtensionName:p,resolveExtensionToolSource:e=>m(_,e)});await u(t,r)}}),_.registerCommand(`config`,{description:`Browse and change the settings extensions contribute`,handler:async(e,t)=>{await a(t,B.config)}});let z=e=>{for(let t of e){let e=t.bindingId?` (${t.bindingId})`:``,n=`Leader contribution from ${t.source}${e}: ${t.message}`;N.has(n)||(N.add(n),A.recordWarning(d.leaderContributionRejected,t.message,{"leader.source":t.source,...t.bindingId?{"leader.binding.id":t.bindingId}:{}}),F?.mode===`tui`&&F.ui.notify(n,T))}},B=t({leaderRegistry:M,reportDiagnostics:z});f.provide(S,B),f.inject([y],e=>{let t=b(x(e)),n=()=>j.setModes(r(t.list())),i=t.subscribe(n);return n(),()=>{i(),j.setModes([])}}),_.on(`session_start`,(e,t)=>{F=t,B.setContext(t);let n=++I;if(z(M.flush()),L=t.sessionManager.getEntries().some(e=>e.type===`message`),t.mode!==`tui`)return;for(let e of N)t.ui.notify(e,T);let r=process.env.DOOMPI_THEME||`doom-pi-dark`,i=t.ui.setTheme(r);i.success||(t.ui.notify(`Could not apply Doom Pi theme: ${i.error}`,T),A.recordWarning(d.themeApplyFailed,i.error??`Unknown theme error`,{"ui.theme":r})),t.ui.setTitle(`${E} · ${g.basename(t.cwd)||t.cwd} · pi/coding`),t.ui.setHeader((e,n)=>new c(n,t.cwd,void 0,t,()=>e.terminal.rows)),t.ui.setFooter((e,n,r)=>(P=r,new s(e,n,t,r,B.footer,j))),t.ui.setEditorComponent((e,r,i)=>new o(e,r,i,j,e=>{if(!e.active){t.ui.setWidget(C,void 0,{placement:w});return}t.ui.setWidget(C,(n,r)=>new l(r,e,t,P,j.getModes()),{placement:w})},void 0,t.ui.theme,{registry:M,isCommandAvailable:e=>D.has(e)||_.getCommands().some(t=>t.name===e),onLeaderAction:(e,r)=>{if(F!==t||I!==n){t.ui.notify(`Leader action ${r} is unavailable.`,T);return}B.invokeLeaderAction(e,r)},onUnavailableCommand:e=>{A.recordWarning(d.leaderCommandUnavailable,`Leader command /${e} is unavailable.`,{"ui.kind":`command`}),t.ui.notify(`Leader command /${e} is unavailable.`,T)},onUnavailableAction:e=>{A.recordWarning(d.leaderActionUnavailable,`Leader action ${e} is unavailable.`,{"ui.kind":`action`}),t.ui.notify(`Leader action ${e} is unavailable.`,T)}})),A.recordEvent(d.shellInstalled,{"ui.theme":r,"ui.theme.applied":i.success,"ui.leader.group.count":M.getGroup([])?.options.length??0})}),_.on(`input`,(e,t)=>{if(t.mode!==`tui`||e.source!==`interactive`||L)return;L=!0;let n=k(e.text,t.cwd);n&&t.ui.setTitle(n)}),f.effect(()=>async()=>{let e=F;++I,F=void 0,B.setContext(void 0),P=void 0,B.dispose(),j.reset(),e?.mode===`tui`&&e.ui.setWidget(C,void 0,{placement:w}),await A.shutdown()},O)}async function j(e,t=f()){let n=await _(e,O),r=n.root.plugin(A,{pi:e,telemetry:t});try{await r}catch(e){try{await r.dispose()}finally{await n.dispose()}throw e}let i;e.on(`session_shutdown`,()=>i??=(async()=>{try{await r.dispose()}finally{await n.dispose()}})())}export{j as doomPiUiExtension};
2
2
  //# sourceMappingURL=extension.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import path from 'node:path';\nimport { DoomConfigRegistry } from '@agimon-ai/doompi-extension-contracts/config';\nimport { DoomFooterStatusRegistry } from '@agimon-ai/doompi-extension-contracts/footer';\nimport {\n installDoomLeaderBootstrapHost,\n LeaderActionInvoked,\n type LeaderContribution,\n LeaderRegistrationProtocol,\n LeaderUnregistrationProtocol,\n} from '@agimon-ai/doompi-extension-contracts/leader';\nimport { McpStatusQueryProtocol } from '@agimon-ai/doompi-extension-contracts/mcp-status';\nimport { createMinorModeCatalogClient } from '@agimon-ai/doompi-extension-contracts/mode';\nimport { createProtocolRuntime, type ProtocolRuntime } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport type { ExtensionAPI, ExtensionContext, ReadonlyFooterDataProvider } from '@earendil-works/pi-coding-agent';\nimport { type DoomLeaderDiagnostic, DoomLeaderRegistry } from '../../services/leader/leaderRegistry.ts';\nimport { DoomUiState, type LeaderSnapshot, projectMinorModeRecords } from '../../services/state/uiState.ts';\nimport { buildToolSources, type McpServerStatus } from '../../services/tools/toolInventory.ts';\nimport { openConfigOverlay } from '../../tui/configOverlay.ts';\nimport { DoomEditor } from '../../tui/doomEditor.ts';\nimport { DoomFooter } from '../../tui/doomFooter.ts';\nimport { DoomHeader } from '../../tui/doomHeader.ts';\nimport { LeaderHints } from '../../tui/leaderHints.ts';\nimport { DEFAULT_THEME_NAME } from '../../tui/theme.ts';\nimport { openToolsOverlay } from '../../tui/toolsOverlay.ts';\nimport { createUiTelemetry, UI_EVENT, type UiTelemetry } from '../telemetry/logSinkTelemetry.ts';\nimport { extensionName, extensionToolSource } from './extensionName.ts';\nimport { registerBuiltinToolUi } from './toolOverrides.ts';\n\nconst LEADER_WIDGET_KEY = 'doom-pi-leader';\nconst TUI_MODE = 'tui';\nconst WIDGET_PLACEMENT = 'belowEditor';\nconst WARNING_STYLE = 'warning';\nconst THEME_ENVIRONMENT_KEY = 'DOOMPI_THEME';\nconst HOTKEYS_COMMAND = 'hotkeys';\nconst TOOLS_COMMAND = 'tools';\nconst CONFIG_COMMAND = 'config';\n/** Short: `/tools` must open promptly whether or not an MCP extension answers. */\nconst MCP_STATUS_TIMEOUT_MS = 250;\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_MESSAGE_ENTRY = 'message';\nconst INPUT_EVENT = 'input';\nconst INTERACTIVE_INPUT_SOURCE = 'interactive';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\nconst TITLE_MESSAGE_MAX_LENGTH = 64;\nconst TITLE_PREFIX = 'doom-pi';\nconst BUILTIN_LEADER_COMMANDS = new Set([HOTKEYS_COMMAND]);\n\nfunction createMessageTitle(message: string, cwd: string): string | undefined {\n const normalizedMessage = message.trim().replace(/\\s+/g, ' ');\n if (!normalizedMessage) return undefined;\n const messageTitle = normalizedMessage.slice(0, TITLE_MESSAGE_MAX_LENGTH).trimEnd();\n return `${TITLE_PREFIX} · ${messageTitle} · ${path.basename(cwd) || cwd}`;\n}\n\nexport function doomPiUiExtension(pi: ExtensionAPI, telemetry: UiTelemetry = createUiTelemetry()): void {\n registerBuiltinToolUi(pi, process.cwd());\n const uiState = new DoomUiState();\n const footerStatusRegistry = new DoomFooterStatusRegistry();\n const modeCatalog = createMinorModeCatalogClient();\n const configRegistry = new DoomConfigRegistry();\n const leaderRegistry = new DoomLeaderRegistry();\n const pendingDiagnostics = new Set<string>();\n const contributionGenerations = new Map<string, symbol>();\n let footerData: ReadonlyFooterDataProvider | undefined;\n let activeContext: ExtensionContext | undefined;\n let disposeFooterStatuses: (() => void) | undefined;\n let disposeModeCatalogBinding: (() => void) | undefined;\n let disposeModeSubscription: (() => void) | undefined;\n let disposeConfigContributions: (() => void) | undefined;\n let disposeLeaderRegistration: (() => void) | undefined;\n let disposeLeaderUnregistration: (() => void) | undefined;\n const protocolContributions = new Map<string, () => void>();\n let nextProtocolHandle = 0;\n let sessionGeneration = 0;\n let hasSessionMessage = false;\n let sessionProtocol: ProtocolRuntime | undefined;\n let disposeLeaderBootstrap: (() => void) | undefined;\n\n /**\n * Asks the MCP extension what it is currently connected to.\n *\n * No answer is a normal session: `--no-mcp` leaves nobody providing the query,\n * and the panel simply lists MCP tools under the extension that registered them.\n */\n const readMcpServers = async (): Promise<readonly McpServerStatus[] | undefined> => {\n if (!sessionProtocol) return undefined;\n try {\n const snapshot = await sessionProtocol.request(McpStatusQueryProtocol, {}, { timeoutMs: MCP_STATUS_TIMEOUT_MS });\n return snapshot.servers;\n } catch {\n return undefined;\n }\n };\n\n pi.registerCommand(TOOLS_COMMAND, {\n description: 'Browse the tools available in this session',\n handler: async (_args, ctx) => {\n // Read at open time so a reconnected server or a plan-mode tool swap shows\n // up without restarting the session.\n const mcpServers = await readMcpServers();\n const sources = buildToolSources({\n tools: pi.getAllTools(),\n activeTools: pi.getActiveTools(),\n ...(mcpServers ? { mcpServers } : {}),\n resolveExtensionName: extensionName,\n resolveExtensionToolSource: extensionToolSource,\n });\n await openToolsOverlay(ctx, sources);\n },\n });\n\n pi.registerCommand(CONFIG_COMMAND, {\n description: 'Browse and change the settings extensions contribute',\n handler: async (_args, ctx) => {\n // The registry is passed live rather than snapshotted: a contributor can be\n // fetching or installing something while the panel is open, and that\n // progress is meant to land in it.\n await openConfigOverlay(ctx, configRegistry);\n },\n });\n\n const reportDiagnostics = (diagnostics: readonly DoomLeaderDiagnostic[]): void => {\n for (const diagnostic of diagnostics) {\n const binding = diagnostic.bindingId ? ` (${diagnostic.bindingId})` : '';\n const message = `Leader contribution from ${diagnostic.source}${binding}: ${diagnostic.message}`;\n if (pendingDiagnostics.has(message)) continue;\n pendingDiagnostics.add(message);\n // A rejected contribution silently drops another extension's keybindings,\n // and the notice below only reaches a run that has a TUI attached.\n void telemetry.recordWarning(UI_EVENT.leaderContributionRejected, diagnostic.message, {\n 'leader.source': diagnostic.source,\n ...(diagnostic.bindingId ? { 'leader.binding.id': diagnostic.bindingId } : {}),\n });\n if (activeContext?.mode === TUI_MODE) activeContext.ui.notify(message, WARNING_STYLE);\n }\n };\n\n const registerLeaderContribution = (contribution: LeaderContribution, deferred: boolean) => {\n const generation = Symbol(contribution.source);\n const register = deferred\n ? (value: LeaderContribution) => leaderRegistry.registerDeferred(value)\n : (value: LeaderContribution) => leaderRegistry.register(value);\n const result = register(contribution);\n reportDiagnostics(result.diagnostics);\n if (!result.accepted) return { update: () => undefined, dispose: () => undefined };\n contributionGenerations.set(contribution.source, generation);\n let disposed = false;\n return {\n update(bindings: LeaderContribution['bindings']) {\n if (disposed || contributionGenerations.get(contribution.source) !== generation) return;\n reportDiagnostics(register({ source: contribution.source, bindings }).diagnostics);\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n if (contributionGenerations.get(contribution.source) !== generation) return;\n contributionGenerations.delete(contribution.source);\n register({ source: contribution.source, bindings: [] });\n },\n };\n };\n\n const leaderContext = Object.freeze({\n register(contribution: LeaderContribution) {\n const handle = registerLeaderContribution(contribution, false);\n return () => handle.dispose();\n },\n });\n // Installed during the UI factory, before the remaining Doom factories run.\n // Their registrations are validated immediately and rebuilt as one batch at\n // session_start, so the first editor always receives the complete keyspace.\n disposeLeaderBootstrap = installDoomLeaderBootstrapHost({\n register: (contribution) => registerLeaderContribution(contribution, true),\n });\n pi.on(SESSION_START_EVENT, (_event, ctx) => {\n activeContext = ctx;\n const activeGeneration = ++sessionGeneration;\n const protocol = createProtocolRuntime({\n bus: pi.events,\n source: '@agimon-ai/doompi-ui',\n sessionId: ctx.sessionManager.getSessionId(),\n });\n sessionProtocol = protocol;\n reportDiagnostics(leaderRegistry.flush());\n disposeFooterStatuses?.();\n footerStatusRegistry.reset();\n disposeFooterStatuses = footerStatusRegistry.bind(protocol);\n disposeModeCatalogBinding?.();\n disposeModeCatalogBinding = modeCatalog.bind(protocol);\n // Bound above the TUI-mode guard below, like footer and mode: a headless run\n // still accepts contributions, it just never draws them.\n disposeConfigContributions?.();\n configRegistry.reset();\n disposeConfigContributions = configRegistry.bind(protocol);\n disposeLeaderRegistration?.();\n disposeLeaderUnregistration?.();\n disposeLeaderRegistration = protocol.provide(\n LeaderRegistrationProtocol,\n ({ contribution, generation }, identity) => {\n if (identity.source !== contribution.source) {\n throw new Error('Leader contribution source does not match the registration envelope source.');\n }\n const handleId = `${identity.source}:${generation}:${++nextProtocolHandle}`;\n const typedContribution: LeaderContribution = {\n source: contribution.source,\n bindings: contribution.bindings.map((binding) => {\n const [first, ...rest] = binding.path;\n if (!first) throw new Error(`Leader binding '${binding.id}' has no path.`);\n return { ...binding, path: [first, ...rest] };\n }),\n };\n protocolContributions.set(handleId, leaderContext.register(typedContribution));\n return { handleId };\n },\n );\n disposeLeaderUnregistration = protocol.provide(LeaderUnregistrationProtocol, ({ handleId }) => {\n const dispose = protocolContributions.get(handleId);\n if (!dispose) return { removed: false };\n protocolContributions.delete(handleId);\n dispose();\n return { removed: true };\n });\n hasSessionMessage = ctx.sessionManager.getEntries().some((entry) => entry.type === SESSION_MESSAGE_ENTRY);\n if (ctx.mode !== TUI_MODE) return;\n for (const message of pendingDiagnostics) ctx.ui.notify(message, WARNING_STYLE);\n\n const themeName = process.env[THEME_ENVIRONMENT_KEY] || DEFAULT_THEME_NAME;\n const themeResult = ctx.ui.setTheme(themeName);\n if (!themeResult.success) {\n ctx.ui.notify(`Could not apply Doom Pi theme: ${themeResult.error}`, WARNING_STYLE);\n void telemetry.recordWarning(UI_EVENT.themeApplyFailed, themeResult.error ?? 'Unknown theme error', {\n 'ui.theme': themeName,\n });\n }\n\n // The modes go into shared state rather than a widget of their own: the\n // editor prints their names beside its badge and the leader panel prints\n // them with their detail, so there is no third surface to paint.\n disposeModeSubscription?.();\n disposeModeSubscription = modeCatalog.subscribe(() =>\n uiState.setModes(projectMinorModeRecords(modeCatalog.list())),\n );\n uiState.setModes(projectMinorModeRecords(modeCatalog.list()));\n\n ctx.ui.setTitle(`${TITLE_PREFIX} · ${path.basename(ctx.cwd) || ctx.cwd} · pi/coding`);\n ctx.ui.setHeader((tui, theme) => new DoomHeader(theme, ctx.cwd, undefined, ctx, () => tui.terminal.rows));\n ctx.ui.setFooter((tui, theme, data) => {\n footerData = data;\n return new DoomFooter(tui, theme, ctx, data, footerStatusRegistry, uiState);\n });\n ctx.ui.setEditorComponent(\n (tui, editorTheme, keybindings) =>\n new DoomEditor(\n tui,\n editorTheme,\n keybindings,\n uiState,\n (snapshot: LeaderSnapshot) => {\n if (!snapshot.active) {\n ctx.ui.setWidget(LEADER_WIDGET_KEY, undefined, { placement: WIDGET_PLACEMENT });\n return;\n }\n ctx.ui.setWidget(\n LEADER_WIDGET_KEY,\n (_widgetTui, widgetTheme) => new LeaderHints(widgetTheme, snapshot, ctx, footerData, uiState.getModes()),\n { placement: WIDGET_PLACEMENT },\n );\n },\n undefined,\n ctx.ui.theme,\n {\n registry: leaderRegistry,\n isCommandAvailable: (commandName) =>\n BUILTIN_LEADER_COMMANDS.has(commandName) ||\n pi.getCommands().some((command) => command.name === commandName),\n onLeaderAction: (source, action) => {\n if (activeContext !== ctx || sessionGeneration !== activeGeneration) {\n ctx.ui.notify(`Leader action ${action} is unavailable.`, WARNING_STYLE);\n return;\n }\n protocol.notify(LeaderActionInvoked, { source, action });\n },\n onUnavailableCommand: (commandName) => {\n void telemetry.recordWarning(\n UI_EVENT.leaderCommandUnavailable,\n `Leader command /${commandName} is unavailable.`,\n { 'ui.kind': 'command' },\n );\n ctx.ui.notify(`Leader command /${commandName} is unavailable.`, WARNING_STYLE);\n },\n onUnavailableAction: (action) => {\n void telemetry.recordWarning(\n UI_EVENT.leaderActionUnavailable,\n `Leader action ${action} is unavailable.`,\n {\n 'ui.kind': 'action',\n },\n );\n ctx.ui.notify(`Leader action ${action} is unavailable.`, WARNING_STYLE);\n },\n },\n ),\n );\n\n void telemetry.recordEvent(UI_EVENT.shellInstalled, {\n 'ui.theme': themeName,\n 'ui.theme.applied': themeResult.success,\n 'ui.leader.group.count': leaderRegistry.getGroup([])?.options.length ?? 0,\n });\n });\n\n pi.on(INPUT_EVENT, (event, ctx) => {\n if (ctx.mode !== TUI_MODE || event.source !== INTERACTIVE_INPUT_SOURCE || hasSessionMessage) return;\n hasSessionMessage = true;\n const title = createMessageTitle(event.text, ctx.cwd);\n if (title) ctx.ui.setTitle(title);\n });\n\n pi.on(SESSION_SHUTDOWN_EVENT, async (_event, ctx) => {\n ++sessionGeneration;\n disposeLeaderBootstrap?.();\n disposeLeaderBootstrap = undefined;\n for (const dispose of protocolContributions.values()) dispose();\n protocolContributions.clear();\n activeContext = undefined;\n footerData = undefined;\n disposeFooterStatuses?.();\n disposeFooterStatuses = undefined;\n footerStatusRegistry.reset();\n disposeModeCatalogBinding?.();\n disposeModeCatalogBinding = undefined;\n disposeModeSubscription?.();\n disposeModeSubscription = undefined;\n modeCatalog.reset();\n disposeConfigContributions?.();\n disposeConfigContributions = undefined;\n disposeLeaderRegistration?.();\n disposeLeaderRegistration = undefined;\n disposeLeaderUnregistration?.();\n disposeLeaderUnregistration = undefined;\n configRegistry.reset();\n uiState.reset();\n sessionProtocol = undefined;\n if (ctx.mode === TUI_MODE) ctx.ui.setWidget(LEADER_WIDGET_KEY, undefined, { placement: WIDGET_PLACEMENT });\n await telemetry.shutdown();\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import path from 'node:path';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { readDoomMcpStatus } from '@agimon-ai/doompi-extension-contracts/mcp-status';\nimport {\n DOOM_MINOR_MODE_CATALOG_SERVICE,\n createMinorModeCatalogClient,\n requireMinorModeCatalog,\n} from '@agimon-ai/doompi-extension-contracts/mode';\nimport { DOOM_UI_HUB_SERVICE } from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext, ReadonlyFooterDataProvider } from '@earendil-works/pi-coding-agent';\nimport { type DoomLeaderDiagnostic, DoomLeaderRegistry } from '../../services/leader/leaderRegistry.ts';\nimport { createDoomUiHub } from '../../services/hub/uiHub.ts';\nimport { DoomUiState, type LeaderSnapshot, projectMinorModeRecords } from '../../services/state/uiState.ts';\nimport { buildToolSources, type McpServerStatus } from '../../services/tools/toolInventory.ts';\nimport { openConfigOverlay } from '../../tui/configOverlay.ts';\nimport { DoomEditor } from '../../tui/doomEditor.ts';\nimport { DoomFooter } from '../../tui/doomFooter.ts';\nimport { DoomHeader } from '../../tui/doomHeader.ts';\nimport { LeaderHints } from '../../tui/leaderHints.ts';\nimport { DEFAULT_THEME_NAME } from '../../tui/theme.ts';\nimport { openToolsOverlay } from '../../tui/toolsOverlay.ts';\nimport { createUiTelemetry, UI_EVENT, type UiTelemetry } from '../telemetry/logSinkTelemetry.ts';\nimport { extensionName, extensionToolSource } from './extensionName.ts';\nimport { registerBuiltinToolUi } from './toolOverrides.ts';\n\nconst LEADER_WIDGET_KEY = 'doom-pi-leader';\nconst TUI_MODE = 'tui';\nconst WIDGET_PLACEMENT = 'belowEditor';\nconst WARNING_STYLE = 'warning';\nconst THEME_ENVIRONMENT_KEY = 'DOOMPI_THEME';\nconst HOTKEYS_COMMAND = 'hotkeys';\nconst TOOLS_COMMAND = 'tools';\nconst CONFIG_COMMAND = 'config';\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_MESSAGE_ENTRY = 'message';\nconst INPUT_EVENT = 'input';\nconst INTERACTIVE_INPUT_SOURCE = 'interactive';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\nconst TITLE_MESSAGE_MAX_LENGTH = 64;\nconst TITLE_PREFIX = 'doom-pi';\nconst BUILTIN_LEADER_COMMANDS = new Set([HOTKEYS_COMMAND]);\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-ui';\n\nfunction createMessageTitle(message: string, cwd: string): string | undefined {\n const normalizedMessage = message.trim().replace(/\\s+/g, ' ');\n if (!normalizedMessage) return undefined;\n const messageTitle = normalizedMessage.slice(0, TITLE_MESSAGE_MAX_LENGTH).trimEnd();\n return `${TITLE_PREFIX} · ${messageTitle} · ${path.basename(cwd) || cwd}`;\n}\n\ninterface UiPluginOptions {\n readonly pi: ExtensionAPI;\n readonly telemetry: UiTelemetry;\n}\n\nfunction doomPiUiPlugin(cordis: Context, { pi, telemetry }: UiPluginOptions): void {\n registerBuiltinToolUi(pi, process.cwd());\n const uiState = new DoomUiState();\n const leaderRegistry = new DoomLeaderRegistry();\n const pendingDiagnostics = new Set<string>();\n let footerData: ReadonlyFooterDataProvider | undefined;\n let activeContext: ExtensionContext | undefined;\n let sessionGeneration = 0;\n let hasSessionMessage = false;\n\n /**\n * Asks the MCP extension what it is currently connected to.\n *\n * No answer is a normal session: `--no-mcp` leaves nobody providing the query,\n * and the panel simply lists MCP tools under the extension that registered them.\n */\n const readMcpServers = (): readonly McpServerStatus[] | undefined => readDoomMcpStatus(cordis)?.getSnapshot().servers;\n\n pi.registerCommand(TOOLS_COMMAND, {\n description: 'Browse the tools available in this session',\n handler: async (_args, ctx) => {\n // Read at open time so a reconnected server or a plan-mode tool swap shows\n // up without restarting the session.\n const mcpServers = readMcpServers();\n const sources = buildToolSources({\n tools: pi.getAllTools(),\n activeTools: pi.getActiveTools(),\n ...(mcpServers ? { mcpServers } : {}),\n resolveExtensionName: extensionName,\n resolveExtensionToolSource: (toolName) => extensionToolSource(pi, toolName),\n });\n await openToolsOverlay(ctx, sources);\n },\n });\n\n pi.registerCommand(CONFIG_COMMAND, {\n description: 'Browse and change the settings extensions contribute',\n handler: async (_args, ctx) => {\n // The registry is passed live rather than snapshotted: a contributor can be\n // fetching or installing something while the panel is open, and that\n // progress is meant to land in it.\n await openConfigOverlay(ctx, hub.config);\n },\n });\n\n const reportDiagnostics = (diagnostics: readonly DoomLeaderDiagnostic[]): void => {\n for (const diagnostic of diagnostics) {\n const binding = diagnostic.bindingId ? ` (${diagnostic.bindingId})` : '';\n const message = `Leader contribution from ${diagnostic.source}${binding}: ${diagnostic.message}`;\n if (pendingDiagnostics.has(message)) continue;\n pendingDiagnostics.add(message);\n // A rejected contribution silently drops another extension's keybindings,\n // and the notice below only reaches a run that has a TUI attached.\n void telemetry.recordWarning(UI_EVENT.leaderContributionRejected, diagnostic.message, {\n 'leader.source': diagnostic.source,\n ...(diagnostic.bindingId ? { 'leader.binding.id': diagnostic.bindingId } : {}),\n });\n if (activeContext?.mode === TUI_MODE) activeContext.ui.notify(message, WARNING_STYLE);\n }\n };\n\n const hub = createDoomUiHub({ leaderRegistry, reportDiagnostics });\n cordis.provide(DOOM_UI_HUB_SERVICE, hub);\n cordis.inject([DOOM_MINOR_MODE_CATALOG_SERVICE], (modeContext) => {\n const catalog = createMinorModeCatalogClient(requireMinorModeCatalog(modeContext));\n const update = (): void => uiState.setModes(projectMinorModeRecords(catalog.list()));\n const dispose = catalog.subscribe(update);\n update();\n return () => {\n dispose();\n uiState.setModes([]);\n };\n });\n\n pi.on(SESSION_START_EVENT, (_event, ctx) => {\n activeContext = ctx;\n hub.setContext(ctx);\n const activeGeneration = ++sessionGeneration;\n reportDiagnostics(leaderRegistry.flush());\n hasSessionMessage = ctx.sessionManager.getEntries().some((entry) => entry.type === SESSION_MESSAGE_ENTRY);\n if (ctx.mode !== TUI_MODE) return;\n for (const message of pendingDiagnostics) ctx.ui.notify(message, WARNING_STYLE);\n\n const themeName = process.env[THEME_ENVIRONMENT_KEY] || DEFAULT_THEME_NAME;\n const themeResult = ctx.ui.setTheme(themeName);\n if (!themeResult.success) {\n ctx.ui.notify(`Could not apply Doom Pi theme: ${themeResult.error}`, WARNING_STYLE);\n void telemetry.recordWarning(UI_EVENT.themeApplyFailed, themeResult.error ?? 'Unknown theme error', {\n 'ui.theme': themeName,\n });\n }\n\n ctx.ui.setTitle(`${TITLE_PREFIX} · ${path.basename(ctx.cwd) || ctx.cwd} · pi/coding`);\n ctx.ui.setHeader((tui, theme) => new DoomHeader(theme, ctx.cwd, undefined, ctx, () => tui.terminal.rows));\n ctx.ui.setFooter((tui, theme, data) => {\n footerData = data;\n return new DoomFooter(tui, theme, ctx, data, hub.footer, uiState);\n });\n ctx.ui.setEditorComponent(\n (tui, editorTheme, keybindings) =>\n new DoomEditor(\n tui,\n editorTheme,\n keybindings,\n uiState,\n (snapshot: LeaderSnapshot) => {\n if (!snapshot.active) {\n ctx.ui.setWidget(LEADER_WIDGET_KEY, undefined, { placement: WIDGET_PLACEMENT });\n return;\n }\n ctx.ui.setWidget(\n LEADER_WIDGET_KEY,\n (_widgetTui, widgetTheme) => new LeaderHints(widgetTheme, snapshot, ctx, footerData, uiState.getModes()),\n { placement: WIDGET_PLACEMENT },\n );\n },\n undefined,\n ctx.ui.theme,\n {\n registry: leaderRegistry,\n isCommandAvailable: (commandName) =>\n BUILTIN_LEADER_COMMANDS.has(commandName) ||\n pi.getCommands().some((command) => command.name === commandName),\n onLeaderAction: (source, action) => {\n if (activeContext !== ctx || sessionGeneration !== activeGeneration) {\n ctx.ui.notify(`Leader action ${action} is unavailable.`, WARNING_STYLE);\n return;\n }\n hub.invokeLeaderAction(source, action);\n },\n onUnavailableCommand: (commandName) => {\n void telemetry.recordWarning(\n UI_EVENT.leaderCommandUnavailable,\n `Leader command /${commandName} is unavailable.`,\n { 'ui.kind': 'command' },\n );\n ctx.ui.notify(`Leader command /${commandName} is unavailable.`, WARNING_STYLE);\n },\n onUnavailableAction: (action) => {\n void telemetry.recordWarning(\n UI_EVENT.leaderActionUnavailable,\n `Leader action ${action} is unavailable.`,\n {\n 'ui.kind': 'action',\n },\n );\n ctx.ui.notify(`Leader action ${action} is unavailable.`, WARNING_STYLE);\n },\n },\n ),\n );\n\n void telemetry.recordEvent(UI_EVENT.shellInstalled, {\n 'ui.theme': themeName,\n 'ui.theme.applied': themeResult.success,\n 'ui.leader.group.count': leaderRegistry.getGroup([])?.options.length ?? 0,\n });\n });\n\n pi.on(INPUT_EVENT, (event, ctx) => {\n if (ctx.mode !== TUI_MODE || event.source !== INTERACTIVE_INPUT_SOURCE || hasSessionMessage) return;\n hasSessionMessage = true;\n const title = createMessageTitle(event.text, ctx.cwd);\n if (title) ctx.ui.setTitle(title);\n });\n\n cordis.effect(\n () => async () => {\n const context = activeContext;\n ++sessionGeneration;\n activeContext = undefined;\n hub.setContext(undefined);\n footerData = undefined;\n hub.dispose();\n uiState.reset();\n if (context?.mode === TUI_MODE) {\n context.ui.setWidget(LEADER_WIDGET_KEY, undefined, { placement: WIDGET_PLACEMENT });\n }\n await telemetry.shutdown();\n },\n PACKAGE_SOURCE,\n );\n}\n\n/** The package's standard Pi factory, mounted under the session Cordis host. */\nexport async function doomPiUiExtension(pi: ExtensionAPI, telemetry: UiTelemetry = createUiTelemetry()): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(doomPiUiPlugin, { pi, telemetry });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n\n let disposal: Promise<void> | undefined;\n pi.on(\n SESSION_SHUTDOWN_EVENT,\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require("../../_virtual/_rolldown/runtime.cjs");let t=require("node:path");t=e.__toESM(t,1);let n=require("node:fs");n=e.__toESM(n,1);const r=new Map,i=`__doompiExtensionToolSources__`;function a(){let e=globalThis,t=e[i];if(t)return t;let n=new Map;return e[i]=n,n}function o(e,t){let n=Reflect.get(e,t,e);return typeof n==`function`?n.bind(e):n}function s(e,t){return new Proxy(e,{get(e,n){return n===`registerTool`?n=>{e.registerTool(n),a().set(n.name,t)}:o(e,n)}})}function c(e){return a().get(e)}function l(e){let r=e;for(;;){try{let e=JSON.parse(n.default.readFileSync(t.default.join(r,`package.json`),`utf8`));if(typeof e.name==`string`&&e.name.length>0)return e.name}catch{}let e=t.default.dirname(r);if(e===r)return;r=e}}function u(e){let n=r.get(e);if(n!==void 0)return n;let i=l(t.default.dirname(e)),a=i?i.split(`/`).pop()??i:t.default.basename(e,t.default.extname(e));return r.set(e,a),a}exports.extensionName=u,exports.extensionToolSource=c,exports.withExtensionSource=s;
1
+ const e=require("../../_virtual/_rolldown/runtime.cjs");let t=require("node:path");t=e.__toESM(t,1);let n=require("node:fs");n=e.__toESM(n,1);const r=new Map,i=`__doompiExtensionToolSources__`;function a(e){let t=e,n=t[i];if(n)return n;let r=new Map;return Object.defineProperty(t,i,{configurable:!1,enumerable:!1,value:r,writable:!1}),r}function o(e,t){let n=Reflect.get(e,t,e);return typeof n==`function`?n.bind(e):n}function s(e,t){return new Proxy(e,{get(e,n){return n===`registerTool`?n=>{e.registerTool(n),a(e).set(n.name,Object.freeze({entryPath:t}))}:o(e,n)}})}function c(e,t){return a(e).get(t)?.entryPath}function l(e){let r=e;for(;;){try{let e=JSON.parse(n.default.readFileSync(t.default.join(r,`package.json`),`utf8`));if(typeof e.name==`string`&&e.name.length>0)return e.name}catch{}let e=t.default.dirname(r);if(e===r)return;r=e}}function u(e){let n=r.get(e);if(n!==void 0)return n;let i=l(t.default.dirname(e)),a=i?i.split(`/`).pop()??i:t.default.basename(e,t.default.extname(e));return r.set(e,a),a}exports.extensionName=u,exports.extensionToolSource=c,exports.withExtensionSource=s;
2
2
  //# sourceMappingURL=extensionName.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extensionName.cjs","names":["fs","path"],"sources":["../../../src/adapters/pi/extensionName.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\n\n/**\n * Display name for an extension that Pi could not attribute to a package.\n *\n * Pi stamps every `--extension <path>` argument with the literal source `cli`,\n * and doom-pi launches all of its extensions that way, so the only surviving\n * identity is the entry path. The nearest `package.json` above it names the\n * package that registered the tools.\n */\n\n/** Results are stable for the life of a session, and every source hits the same few dirs. */\nconst cache = new Map<string, string>();\nconst TOOL_SOURCE_REGISTRY_KEY = '__doompiExtensionToolSources__' as const;\n\ntype RegisteredTool = Parameters<ExtensionAPI['registerTool']>[0];\ntype RegistryHost = typeof globalThis & { [TOOL_SOURCE_REGISTRY_KEY]?: Map<string, string> };\n\n/** Shared through `globalThis` so compiled and separately loaded modules see one registry. */\nfunction toolSourceRegistry(): Map<string, string> {\n const host = globalThis as RegistryHost;\n const existing = host[TOOL_SOURCE_REGISTRY_KEY];\n if (existing) return existing;\n const registry = new Map<string, string>();\n host[TOOL_SOURCE_REGISTRY_KEY] = registry;\n return registry;\n}\n\nfunction boundValue(target: object, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\n/**\n * Gives one composed extension a Pi API that remembers which tools it registers.\n *\n * Pi attributes every factory inside a compiled Doom bundle to the outer bundle.\n * The compiler still knows each original entry path, so it calls factories through\n * this boundary and preserves that identity before the information is lost.\n */\nexport function withExtensionSource(pi: ExtensionAPI, entryPath: string): ExtensionAPI {\n return new Proxy(pi, {\n get(target, property) {\n if (property !== 'registerTool') return boundValue(target, property);\n return (tool: RegisteredTool): void => {\n target.registerTool(tool);\n toolSourceRegistry().set(tool.name, entryPath);\n };\n },\n });\n}\n\n/** Original extension entry that registered a tool inside a composed bundle. */\nexport function extensionToolSource(toolName: string): string | undefined {\n return toolSourceRegistry().get(toolName);\n}\n\nfunction packageName(directory: string): string | undefined {\n let current = directory;\n for (;;) {\n try {\n const manifest = JSON.parse(fs.readFileSync(path.join(current, 'package.json'), 'utf8')) as { name?: unknown };\n if (typeof manifest.name === 'string' && manifest.name.length > 0) return manifest.name;\n } catch {\n // No manifest here, or an unreadable one; keep walking up.\n }\n const parent = path.dirname(current);\n if (parent === current) return undefined;\n current = parent;\n }\n}\n\nexport function extensionName(entryPath: string): string {\n const cached = cache.get(entryPath);\n if (cached !== undefined) return cached;\n const name = packageName(path.dirname(entryPath));\n // `@agimon-ai/doompi-task` reads as `doom-task`; the scope is noise in a tree.\n const resolved = name ? (name.split('/').pop() ?? name) : path.basename(entryPath, path.extname(entryPath));\n cache.set(entryPath, resolved);\n return resolved;\n}\n"],"mappings":"8IAcA,MAAM,EAAQ,IAAI,IACZ,EAA2B,iCAMjC,SAAS,GAA0C,CACjD,IAAM,EAAO,WACP,EAAW,EAAK,GACtB,GAAI,EAAU,OAAO,EACrB,IAAM,EAAW,IAAI,IAErB,MADA,GAAK,GAA4B,EAC1B,CACT,CAEA,SAAS,EAAW,EAAgB,EAAgC,CAClE,IAAM,EAAQ,QAAQ,IAAI,EAAQ,EAAU,CAAM,EAClD,OAAO,OAAO,GAAU,WAAa,EAAM,KAAK,CAAM,EAAI,CAC5D,CASA,SAAgB,EAAoB,EAAkB,EAAiC,CACrF,OAAO,IAAI,MAAM,EAAI,CACnB,IAAI,EAAQ,EAAU,CAEpB,OADI,IAAa,eACT,GAA+B,CACrC,EAAO,aAAa,CAAI,EACxB,EAAmB,CAAC,CAAC,IAAI,EAAK,KAAM,CAAS,CAC/C,EAJwC,EAAW,EAAQ,CAAQ,CAKrE,CACF,CAAC,CACH,CAGA,SAAgB,EAAoB,EAAsC,CACxE,OAAO,EAAmB,CAAC,CAAC,IAAI,CAAQ,CAC1C,CAEA,SAAS,EAAY,EAAuC,CAC1D,IAAI,EAAU,EACd,OAAS,CACP,GAAI,CACF,IAAM,EAAW,KAAK,MAAMA,EAAAA,QAAG,aAAaC,EAAAA,QAAK,KAAK,EAAS,cAAc,EAAG,MAAM,CAAC,EACvF,GAAI,OAAO,EAAS,MAAS,UAAY,EAAS,KAAK,OAAS,EAAG,OAAO,EAAS,IACrF,MAAQ,CAER,CACA,IAAM,EAASA,EAAAA,QAAK,QAAQ,CAAO,EACnC,GAAI,IAAW,EAAS,OACxB,EAAU,CACZ,CACF,CAEA,SAAgB,EAAc,EAA2B,CACvD,IAAM,EAAS,EAAM,IAAI,CAAS,EAClC,GAAI,IAAW,IAAA,GAAW,OAAO,EACjC,IAAM,EAAO,EAAYA,EAAAA,QAAK,QAAQ,CAAS,CAAC,EAE1C,EAAW,EAAQ,EAAK,MAAM,GAAG,CAAC,CAAC,IAAI,GAAK,EAAQA,EAAAA,QAAK,SAAS,EAAWA,EAAAA,QAAK,QAAQ,CAAS,CAAC,EAE1G,OADA,EAAM,IAAI,EAAW,CAAQ,EACtB,CACT"}
1
+ {"version":3,"file":"extensionName.cjs","names":["fs","path"],"sources":["../../../src/adapters/pi/extensionName.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\n\n/**\n * Display name for an extension that Pi could not attribute to a package.\n *\n * Pi stamps every `--extension <path>` argument with the literal source `cli`,\n * and doom-pi launches all of its extensions that way, so the only surviving\n * identity is the entry path. The nearest `package.json` above it names the\n * package that registered the tools.\n */\n\n/** Results are stable for the life of a session, and every source hits the same few dirs. */\nconst cache = new Map<string, string>();\nconst TOOL_SOURCE_REGISTRY_KEY = '__doompiExtensionToolSources__' as const;\n\ntype RegisteredTool = Parameters<ExtensionAPI['registerTool']>[0];\ninterface ToolSourceMetadata {\n readonly entryPath: string;\n}\ntype RegistryHost = ExtensionAPI & { [TOOL_SOURCE_REGISTRY_KEY]?: Map<string, ToolSourceMetadata> };\n\n/** Session-local provenance attached to Pi's API rather than process-global state. */\nfunction toolSourceRegistry(pi: ExtensionAPI): Map<string, ToolSourceMetadata> {\n const host = pi as RegistryHost;\n const existing = host[TOOL_SOURCE_REGISTRY_KEY];\n if (existing) return existing;\n const registry = new Map<string, ToolSourceMetadata>();\n Object.defineProperty(host, TOOL_SOURCE_REGISTRY_KEY, {\n configurable: false,\n enumerable: false,\n value: registry,\n writable: false,\n });\n return registry;\n}\n\nfunction boundValue(target: object, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\n/**\n * Gives one composed extension a Pi API that remembers which tools it registers.\n *\n * Pi attributes every factory inside a compiled Doom bundle to the outer bundle.\n * The compiler still knows each original entry path, so it calls factories through\n * this boundary and preserves that identity before the information is lost.\n */\nexport function withExtensionSource(pi: ExtensionAPI, entryPath: string): ExtensionAPI {\n return new Proxy(pi, {\n get(target, property) {\n if (property !== 'registerTool') return boundValue(target, property);\n return (tool: RegisteredTool): void => {\n target.registerTool(tool);\n toolSourceRegistry(target).set(tool.name, Object.freeze({ entryPath }));\n };\n },\n });\n}\n\n/** Original extension entry that registered a tool inside a composed bundle. */\nexport function extensionToolSource(pi: ExtensionAPI, toolName: string): string | undefined {\n return toolSourceRegistry(pi).get(toolName)?.entryPath;\n}\n\nfunction packageName(directory: string): string | undefined {\n let current = directory;\n for (;;) {\n try {\n const manifest = JSON.parse(fs.readFileSync(path.join(current, 'package.json'), 'utf8')) as { name?: unknown };\n if (typeof manifest.name === 'string' && manifest.name.length > 0) return manifest.name;\n } catch {\n // No manifest here, or an unreadable one; keep walking up.\n }\n const parent = path.dirname(current);\n if (parent === current) return undefined;\n current = parent;\n }\n}\n\nexport function extensionName(entryPath: string): string {\n const cached = cache.get(entryPath);\n if (cached !== undefined) return cached;\n const name = packageName(path.dirname(entryPath));\n // `@agimon-ai/doompi-task` reads as `doom-task`; the scope is noise in a tree.\n const resolved = name ? (name.split('/').pop() ?? name) : path.basename(entryPath, path.extname(entryPath));\n cache.set(entryPath, resolved);\n return resolved;\n}\n"],"mappings":"8IAcA,MAAM,EAAQ,IAAI,IACZ,EAA2B,iCASjC,SAAS,EAAmB,EAAmD,CAC7E,IAAM,EAAO,EACP,EAAW,EAAK,GACtB,GAAI,EAAU,OAAO,EACrB,IAAM,EAAW,IAAI,IAOrB,OANA,OAAO,eAAe,EAAM,EAA0B,CACpD,aAAc,GACd,WAAY,GACZ,MAAO,EACP,SAAU,EACZ,CAAC,EACM,CACT,CAEA,SAAS,EAAW,EAAgB,EAAgC,CAClE,IAAM,EAAQ,QAAQ,IAAI,EAAQ,EAAU,CAAM,EAClD,OAAO,OAAO,GAAU,WAAa,EAAM,KAAK,CAAM,EAAI,CAC5D,CASA,SAAgB,EAAoB,EAAkB,EAAiC,CACrF,OAAO,IAAI,MAAM,EAAI,CACnB,IAAI,EAAQ,EAAU,CAEpB,OADI,IAAa,eACT,GAA+B,CACrC,EAAO,aAAa,CAAI,EACxB,EAAmB,CAAM,CAAC,CAAC,IAAI,EAAK,KAAM,OAAO,OAAO,CAAE,WAAU,CAAC,CAAC,CACxE,EAJwC,EAAW,EAAQ,CAAQ,CAKrE,CACF,CAAC,CACH,CAGA,SAAgB,EAAoB,EAAkB,EAAsC,CAC1F,OAAO,EAAmB,CAAE,CAAC,CAAC,IAAI,CAAQ,CAAC,EAAE,SAC/C,CAEA,SAAS,EAAY,EAAuC,CAC1D,IAAI,EAAU,EACd,OAAS,CACP,GAAI,CACF,IAAM,EAAW,KAAK,MAAMA,EAAAA,QAAG,aAAaC,EAAAA,QAAK,KAAK,EAAS,cAAc,EAAG,MAAM,CAAC,EACvF,GAAI,OAAO,EAAS,MAAS,UAAY,EAAS,KAAK,OAAS,EAAG,OAAO,EAAS,IACrF,MAAQ,CAER,CACA,IAAM,EAASA,EAAAA,QAAK,QAAQ,CAAO,EACnC,GAAI,IAAW,EAAS,OACxB,EAAU,CACZ,CACF,CAEA,SAAgB,EAAc,EAA2B,CACvD,IAAM,EAAS,EAAM,IAAI,CAAS,EAClC,GAAI,IAAW,IAAA,GAAW,OAAO,EACjC,IAAM,EAAO,EAAYA,EAAAA,QAAK,QAAQ,CAAS,CAAC,EAE1C,EAAW,EAAQ,EAAK,MAAM,GAAG,CAAC,CAAC,IAAI,GAAK,EAAQA,EAAAA,QAAK,SAAS,EAAWA,EAAAA,QAAK,QAAQ,CAAS,CAAC,EAE1G,OADA,EAAM,IAAI,EAAW,CAAQ,EACtB,CACT"}
@@ -9,7 +9,7 @@ import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
9
9
  */
10
10
  declare function withExtensionSource(pi: ExtensionAPI, entryPath: string): ExtensionAPI;
11
11
  /** Original extension entry that registered a tool inside a composed bundle. */
12
- declare function extensionToolSource(toolName: string): string | undefined;
12
+ declare function extensionToolSource(pi: ExtensionAPI, toolName: string): string | undefined;
13
13
  declare function extensionName(entryPath: string): string;
14
14
  //#endregion
15
15
  export { extensionName, extensionToolSource, withExtensionSource };
@@ -1 +1 @@
1
- {"version":3,"file":"extensionName.d.cts","names":[],"sources":["../../../src/adapters/pi/extensionName.ts"],"mappings":";;;;;;;;;iBA0CgB,oBAAoB,IAAI,cAAc,oBAAoB;;iBAa1D,oBAAoB;iBAmBpB,cAAc"}
1
+ {"version":3,"file":"extensionName.d.cts","names":[],"sources":["../../../src/adapters/pi/extensionName.ts"],"mappings":";;;;;;;;;iBAkDgB,oBAAoB,IAAI,cAAc,oBAAoB;;iBAa1D,oBAAoB,IAAI,cAAc;iBAmBtC,cAAc"}
@@ -9,7 +9,7 @@ import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
9
9
  */
10
10
  declare function withExtensionSource(pi: ExtensionAPI, entryPath: string): ExtensionAPI;
11
11
  /** Original extension entry that registered a tool inside a composed bundle. */
12
- declare function extensionToolSource(toolName: string): string | undefined;
12
+ declare function extensionToolSource(pi: ExtensionAPI, toolName: string): string | undefined;
13
13
  declare function extensionName(entryPath: string): string;
14
14
  //#endregion
15
15
  export { extensionName, extensionToolSource, withExtensionSource };
@@ -1 +1 @@
1
- {"version":3,"file":"extensionName.d.mts","names":[],"sources":["../../../src/adapters/pi/extensionName.ts"],"mappings":";;;;;;;;;iBA0CgB,oBAAoB,IAAI,cAAc,oBAAoB;;iBAa1D,oBAAoB;iBAmBpB,cAAc"}
1
+ {"version":3,"file":"extensionName.d.mts","names":[],"sources":["../../../src/adapters/pi/extensionName.ts"],"mappings":";;;;;;;;;iBAkDgB,oBAAoB,IAAI,cAAc,oBAAoB;;iBAa1D,oBAAoB,IAAI,cAAc;iBAmBtC,cAAc"}
@@ -1,2 +1,2 @@
1
- import e from"node:path";import t from"node:fs";const n=new Map,r=`__doompiExtensionToolSources__`;function i(){let e=globalThis,t=e[r];if(t)return t;let n=new Map;return e[r]=n,n}function a(e,t){let n=Reflect.get(e,t,e);return typeof n==`function`?n.bind(e):n}function o(e,t){return new Proxy(e,{get(e,n){return n===`registerTool`?n=>{e.registerTool(n),i().set(n.name,t)}:a(e,n)}})}function s(e){return i().get(e)}function c(n){let r=n;for(;;){try{let n=JSON.parse(t.readFileSync(e.join(r,`package.json`),`utf8`));if(typeof n.name==`string`&&n.name.length>0)return n.name}catch{}let n=e.dirname(r);if(n===r)return;r=n}}function l(t){let r=n.get(t);if(r!==void 0)return r;let i=c(e.dirname(t)),a=i?i.split(`/`).pop()??i:e.basename(t,e.extname(t));return n.set(t,a),a}export{l as extensionName,s as extensionToolSource,o as withExtensionSource};
1
+ import e from"node:path";import t from"node:fs";const n=new Map,r=`__doompiExtensionToolSources__`;function i(e){let t=e,n=t[r];if(n)return n;let i=new Map;return Object.defineProperty(t,r,{configurable:!1,enumerable:!1,value:i,writable:!1}),i}function a(e,t){let n=Reflect.get(e,t,e);return typeof n==`function`?n.bind(e):n}function o(e,t){return new Proxy(e,{get(e,n){return n===`registerTool`?n=>{e.registerTool(n),i(e).set(n.name,Object.freeze({entryPath:t}))}:a(e,n)}})}function s(e,t){return i(e).get(t)?.entryPath}function c(n){let r=n;for(;;){try{let n=JSON.parse(t.readFileSync(e.join(r,`package.json`),`utf8`));if(typeof n.name==`string`&&n.name.length>0)return n.name}catch{}let n=e.dirname(r);if(n===r)return;r=n}}function l(t){let r=n.get(t);if(r!==void 0)return r;let i=c(e.dirname(t)),a=i?i.split(`/`).pop()??i:e.basename(t,e.extname(t));return n.set(t,a),a}export{l as extensionName,s as extensionToolSource,o as withExtensionSource};
2
2
  //# sourceMappingURL=extensionName.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extensionName.mjs","names":[],"sources":["../../../src/adapters/pi/extensionName.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\n\n/**\n * Display name for an extension that Pi could not attribute to a package.\n *\n * Pi stamps every `--extension <path>` argument with the literal source `cli`,\n * and doom-pi launches all of its extensions that way, so the only surviving\n * identity is the entry path. The nearest `package.json` above it names the\n * package that registered the tools.\n */\n\n/** Results are stable for the life of a session, and every source hits the same few dirs. */\nconst cache = new Map<string, string>();\nconst TOOL_SOURCE_REGISTRY_KEY = '__doompiExtensionToolSources__' as const;\n\ntype RegisteredTool = Parameters<ExtensionAPI['registerTool']>[0];\ntype RegistryHost = typeof globalThis & { [TOOL_SOURCE_REGISTRY_KEY]?: Map<string, string> };\n\n/** Shared through `globalThis` so compiled and separately loaded modules see one registry. */\nfunction toolSourceRegistry(): Map<string, string> {\n const host = globalThis as RegistryHost;\n const existing = host[TOOL_SOURCE_REGISTRY_KEY];\n if (existing) return existing;\n const registry = new Map<string, string>();\n host[TOOL_SOURCE_REGISTRY_KEY] = registry;\n return registry;\n}\n\nfunction boundValue(target: object, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\n/**\n * Gives one composed extension a Pi API that remembers which tools it registers.\n *\n * Pi attributes every factory inside a compiled Doom bundle to the outer bundle.\n * The compiler still knows each original entry path, so it calls factories through\n * this boundary and preserves that identity before the information is lost.\n */\nexport function withExtensionSource(pi: ExtensionAPI, entryPath: string): ExtensionAPI {\n return new Proxy(pi, {\n get(target, property) {\n if (property !== 'registerTool') return boundValue(target, property);\n return (tool: RegisteredTool): void => {\n target.registerTool(tool);\n toolSourceRegistry().set(tool.name, entryPath);\n };\n },\n });\n}\n\n/** Original extension entry that registered a tool inside a composed bundle. */\nexport function extensionToolSource(toolName: string): string | undefined {\n return toolSourceRegistry().get(toolName);\n}\n\nfunction packageName(directory: string): string | undefined {\n let current = directory;\n for (;;) {\n try {\n const manifest = JSON.parse(fs.readFileSync(path.join(current, 'package.json'), 'utf8')) as { name?: unknown };\n if (typeof manifest.name === 'string' && manifest.name.length > 0) return manifest.name;\n } catch {\n // No manifest here, or an unreadable one; keep walking up.\n }\n const parent = path.dirname(current);\n if (parent === current) return undefined;\n current = parent;\n }\n}\n\nexport function extensionName(entryPath: string): string {\n const cached = cache.get(entryPath);\n if (cached !== undefined) return cached;\n const name = packageName(path.dirname(entryPath));\n // `@agimon-ai/doompi-task` reads as `doom-task`; the scope is noise in a tree.\n const resolved = name ? (name.split('/').pop() ?? name) : path.basename(entryPath, path.extname(entryPath));\n cache.set(entryPath, resolved);\n return resolved;\n}\n"],"mappings":"gDAcA,MAAM,EAAQ,IAAI,IACZ,EAA2B,iCAMjC,SAAS,GAA0C,CACjD,IAAM,EAAO,WACP,EAAW,EAAK,GACtB,GAAI,EAAU,OAAO,EACrB,IAAM,EAAW,IAAI,IAErB,MADA,GAAK,GAA4B,EAC1B,CACT,CAEA,SAAS,EAAW,EAAgB,EAAgC,CAClE,IAAM,EAAQ,QAAQ,IAAI,EAAQ,EAAU,CAAM,EAClD,OAAO,OAAO,GAAU,WAAa,EAAM,KAAK,CAAM,EAAI,CAC5D,CASA,SAAgB,EAAoB,EAAkB,EAAiC,CACrF,OAAO,IAAI,MAAM,EAAI,CACnB,IAAI,EAAQ,EAAU,CAEpB,OADI,IAAa,eACT,GAA+B,CACrC,EAAO,aAAa,CAAI,EACxB,EAAmB,CAAC,CAAC,IAAI,EAAK,KAAM,CAAS,CAC/C,EAJwC,EAAW,EAAQ,CAAQ,CAKrE,CACF,CAAC,CACH,CAGA,SAAgB,EAAoB,EAAsC,CACxE,OAAO,EAAmB,CAAC,CAAC,IAAI,CAAQ,CAC1C,CAEA,SAAS,EAAY,EAAuC,CAC1D,IAAI,EAAU,EACd,OAAS,CACP,GAAI,CACF,IAAM,EAAW,KAAK,MAAM,EAAG,aAAa,EAAK,KAAK,EAAS,cAAc,EAAG,MAAM,CAAC,EACvF,GAAI,OAAO,EAAS,MAAS,UAAY,EAAS,KAAK,OAAS,EAAG,OAAO,EAAS,IACrF,MAAQ,CAER,CACA,IAAM,EAAS,EAAK,QAAQ,CAAO,EACnC,GAAI,IAAW,EAAS,OACxB,EAAU,CACZ,CACF,CAEA,SAAgB,EAAc,EAA2B,CACvD,IAAM,EAAS,EAAM,IAAI,CAAS,EAClC,GAAI,IAAW,IAAA,GAAW,OAAO,EACjC,IAAM,EAAO,EAAY,EAAK,QAAQ,CAAS,CAAC,EAE1C,EAAW,EAAQ,EAAK,MAAM,GAAG,CAAC,CAAC,IAAI,GAAK,EAAQ,EAAK,SAAS,EAAW,EAAK,QAAQ,CAAS,CAAC,EAE1G,OADA,EAAM,IAAI,EAAW,CAAQ,EACtB,CACT"}
1
+ {"version":3,"file":"extensionName.mjs","names":[],"sources":["../../../src/adapters/pi/extensionName.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\n\n/**\n * Display name for an extension that Pi could not attribute to a package.\n *\n * Pi stamps every `--extension <path>` argument with the literal source `cli`,\n * and doom-pi launches all of its extensions that way, so the only surviving\n * identity is the entry path. The nearest `package.json` above it names the\n * package that registered the tools.\n */\n\n/** Results are stable for the life of a session, and every source hits the same few dirs. */\nconst cache = new Map<string, string>();\nconst TOOL_SOURCE_REGISTRY_KEY = '__doompiExtensionToolSources__' as const;\n\ntype RegisteredTool = Parameters<ExtensionAPI['registerTool']>[0];\ninterface ToolSourceMetadata {\n readonly entryPath: string;\n}\ntype RegistryHost = ExtensionAPI & { [TOOL_SOURCE_REGISTRY_KEY]?: Map<string, ToolSourceMetadata> };\n\n/** Session-local provenance attached to Pi's API rather than process-global state. */\nfunction toolSourceRegistry(pi: ExtensionAPI): Map<string, ToolSourceMetadata> {\n const host = pi as RegistryHost;\n const existing = host[TOOL_SOURCE_REGISTRY_KEY];\n if (existing) return existing;\n const registry = new Map<string, ToolSourceMetadata>();\n Object.defineProperty(host, TOOL_SOURCE_REGISTRY_KEY, {\n configurable: false,\n enumerable: false,\n value: registry,\n writable: false,\n });\n return registry;\n}\n\nfunction boundValue(target: object, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\n/**\n * Gives one composed extension a Pi API that remembers which tools it registers.\n *\n * Pi attributes every factory inside a compiled Doom bundle to the outer bundle.\n * The compiler still knows each original entry path, so it calls factories through\n * this boundary and preserves that identity before the information is lost.\n */\nexport function withExtensionSource(pi: ExtensionAPI, entryPath: string): ExtensionAPI {\n return new Proxy(pi, {\n get(target, property) {\n if (property !== 'registerTool') return boundValue(target, property);\n return (tool: RegisteredTool): void => {\n target.registerTool(tool);\n toolSourceRegistry(target).set(tool.name, Object.freeze({ entryPath }));\n };\n },\n });\n}\n\n/** Original extension entry that registered a tool inside a composed bundle. */\nexport function extensionToolSource(pi: ExtensionAPI, toolName: string): string | undefined {\n return toolSourceRegistry(pi).get(toolName)?.entryPath;\n}\n\nfunction packageName(directory: string): string | undefined {\n let current = directory;\n for (;;) {\n try {\n const manifest = JSON.parse(fs.readFileSync(path.join(current, 'package.json'), 'utf8')) as { name?: unknown };\n if (typeof manifest.name === 'string' && manifest.name.length > 0) return manifest.name;\n } catch {\n // No manifest here, or an unreadable one; keep walking up.\n }\n const parent = path.dirname(current);\n if (parent === current) return undefined;\n current = parent;\n }\n}\n\nexport function extensionName(entryPath: string): string {\n const cached = cache.get(entryPath);\n if (cached !== undefined) return cached;\n const name = packageName(path.dirname(entryPath));\n // `@agimon-ai/doompi-task` reads as `doom-task`; the scope is noise in a tree.\n const resolved = name ? (name.split('/').pop() ?? name) : path.basename(entryPath, path.extname(entryPath));\n cache.set(entryPath, resolved);\n return resolved;\n}\n"],"mappings":"gDAcA,MAAM,EAAQ,IAAI,IACZ,EAA2B,iCASjC,SAAS,EAAmB,EAAmD,CAC7E,IAAM,EAAO,EACP,EAAW,EAAK,GACtB,GAAI,EAAU,OAAO,EACrB,IAAM,EAAW,IAAI,IAOrB,OANA,OAAO,eAAe,EAAM,EAA0B,CACpD,aAAc,GACd,WAAY,GACZ,MAAO,EACP,SAAU,EACZ,CAAC,EACM,CACT,CAEA,SAAS,EAAW,EAAgB,EAAgC,CAClE,IAAM,EAAQ,QAAQ,IAAI,EAAQ,EAAU,CAAM,EAClD,OAAO,OAAO,GAAU,WAAa,EAAM,KAAK,CAAM,EAAI,CAC5D,CASA,SAAgB,EAAoB,EAAkB,EAAiC,CACrF,OAAO,IAAI,MAAM,EAAI,CACnB,IAAI,EAAQ,EAAU,CAEpB,OADI,IAAa,eACT,GAA+B,CACrC,EAAO,aAAa,CAAI,EACxB,EAAmB,CAAM,CAAC,CAAC,IAAI,EAAK,KAAM,OAAO,OAAO,CAAE,WAAU,CAAC,CAAC,CACxE,EAJwC,EAAW,EAAQ,CAAQ,CAKrE,CACF,CAAC,CACH,CAGA,SAAgB,EAAoB,EAAkB,EAAsC,CAC1F,OAAO,EAAmB,CAAE,CAAC,CAAC,IAAI,CAAQ,CAAC,EAAE,SAC/C,CAEA,SAAS,EAAY,EAAuC,CAC1D,IAAI,EAAU,EACd,OAAS,CACP,GAAI,CACF,IAAM,EAAW,KAAK,MAAM,EAAG,aAAa,EAAK,KAAK,EAAS,cAAc,EAAG,MAAM,CAAC,EACvF,GAAI,OAAO,EAAS,MAAS,UAAY,EAAS,KAAK,OAAS,EAAG,OAAO,EAAS,IACrF,MAAQ,CAER,CACA,IAAM,EAAS,EAAK,QAAQ,CAAO,EACnC,GAAI,IAAW,EAAS,OACxB,EAAU,CACZ,CACF,CAEA,SAAgB,EAAc,EAA2B,CACvD,IAAM,EAAS,EAAM,IAAI,CAAS,EAClC,GAAI,IAAW,IAAA,GAAW,OAAO,EACjC,IAAM,EAAO,EAAY,EAAK,QAAQ,CAAS,CAAC,EAE1C,EAAW,EAAQ,EAAK,MAAM,GAAG,CAAC,CAAC,IAAI,GAAK,EAAQ,EAAK,SAAS,EAAW,EAAK,QAAQ,CAAS,CAAC,EAE1G,OADA,EAAM,IAAI,EAAW,CAAQ,EACtB,CACT"}
@@ -1,2 +1,2 @@
1
- import { ConfigOverlayComponent, openConfigOverlay } from "../tui/configOverlay.cjs";
2
- export { ConfigOverlayComponent, openConfigOverlay };
1
+ import { ConfigOverlayComponent, DoomConfigStoreView, openConfigOverlay } from "../tui/configOverlay.cjs";
2
+ export { ConfigOverlayComponent, type DoomConfigStoreView, openConfigOverlay };
@@ -1,2 +1,2 @@
1
- import { ConfigOverlayComponent, openConfigOverlay } from "../tui/configOverlay.mjs";
2
- export { ConfigOverlayComponent, openConfigOverlay };
1
+ import { ConfigOverlayComponent, DoomConfigStoreView, openConfigOverlay } from "../tui/configOverlay.mjs";
2
+ export { ConfigOverlayComponent, type DoomConfigStoreView, openConfigOverlay };
@@ -1,2 +1,2 @@
1
- import { DoomFooter } from "../tui/doomFooter.cjs";
2
- export { DoomFooter };
1
+ import { DoomFooter, DoomFooterStatusView } from "../tui/doomFooter.cjs";
2
+ export { DoomFooter, type DoomFooterStatusView };
@@ -1,2 +1,2 @@
1
- import { DoomFooter } from "../tui/doomFooter.mjs";
2
- export { DoomFooter };
1
+ import { DoomFooter, DoomFooterStatusView } from "../tui/doomFooter.mjs";
2
+ export { DoomFooter, type DoomFooterStatusView };
package/dist/config.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@agimon-ai/doompi-extension-contracts/config");Object.defineProperty(exports,"CONFIG_ACTION",{enumerable:!0,get:function(){return e.CONFIG_ACTION}}),Object.defineProperty(exports,"ConfigActionSchema",{enumerable:!0,get:function(){return e.ConfigActionSchema}}),Object.defineProperty(exports,"ConfigChanged",{enumerable:!0,get:function(){return e.ConfigChanged}}),Object.defineProperty(exports,"ConfigChoiceSchema",{enumerable:!0,get:function(){return e.ConfigChoiceSchema}}),Object.defineProperty(exports,"ConfigDiscovery",{enumerable:!0,get:function(){return e.ConfigDiscovery}}),Object.defineProperty(exports,"ConfigFieldKindSchema",{enumerable:!0,get:function(){return e.ConfigFieldKindSchema}}),Object.defineProperty(exports,"ConfigFieldSchema",{enumerable:!0,get:function(){return e.ConfigFieldSchema}}),Object.defineProperty(exports,"ConfigInvoked",{enumerable:!0,get:function(){return e.ConfigInvoked}}),Object.defineProperty(exports,"ConfigProgressSchema",{enumerable:!0,get:function(){return e.ConfigProgressSchema}}),Object.defineProperty(exports,"ConfigRegistration",{enumerable:!0,get:function(){return e.ConfigRegistration}}),Object.defineProperty(exports,"ConfigSectionSchema",{enumerable:!0,get:function(){return e.ConfigSectionSchema}}),Object.defineProperty(exports,"ConfigSourceSchema",{enumerable:!0,get:function(){return e.ConfigSourceSchema}}),Object.defineProperty(exports,"ConfigStatusSchema",{enumerable:!0,get:function(){return e.ConfigStatusSchema}}),Object.defineProperty(exports,"ConfigStepSchema",{enumerable:!0,get:function(){return e.ConfigStepSchema}}),Object.defineProperty(exports,"ConfigUnregistration",{enumerable:!0,get:function(){return e.ConfigUnregistration}}),Object.defineProperty(exports,"DoomConfigRegistry",{enumerable:!0,get:function(){return e.DoomConfigRegistry}}),Object.defineProperty(exports,"registerConfigProvider",{enumerable:!0,get:function(){return e.registerConfigProvider}}),Object.defineProperty(exports,"registerDoomConfigContribution",{enumerable:!0,get:function(){return e.registerDoomConfigContribution}});
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@agimon-ai/doompi-extension-contracts/config");Object.defineProperty(exports,"CONFIG_ACTION",{enumerable:!0,get:function(){return e.CONFIG_ACTION}}),Object.defineProperty(exports,"ConfigActionSchema",{enumerable:!0,get:function(){return e.ConfigActionSchema}}),Object.defineProperty(exports,"ConfigChoiceSchema",{enumerable:!0,get:function(){return e.ConfigChoiceSchema}}),Object.defineProperty(exports,"ConfigFieldKindSchema",{enumerable:!0,get:function(){return e.ConfigFieldKindSchema}}),Object.defineProperty(exports,"ConfigFieldSchema",{enumerable:!0,get:function(){return e.ConfigFieldSchema}}),Object.defineProperty(exports,"ConfigProgressSchema",{enumerable:!0,get:function(){return e.ConfigProgressSchema}}),Object.defineProperty(exports,"ConfigSectionSchema",{enumerable:!0,get:function(){return e.ConfigSectionSchema}}),Object.defineProperty(exports,"ConfigSourceSchema",{enumerable:!0,get:function(){return e.ConfigSourceSchema}}),Object.defineProperty(exports,"ConfigStatusSchema",{enumerable:!0,get:function(){return e.ConfigStatusSchema}}),Object.defineProperty(exports,"ConfigStepSchema",{enumerable:!0,get:function(){return e.ConfigStepSchema}});
package/dist/config.d.cts CHANGED
@@ -1,2 +1,2 @@
1
- import { CONFIG_ACTION, ConfigAction, ConfigActionSchema, ConfigChanged, ConfigChoice, ConfigChoiceSchema, ConfigDiscovery, ConfigField, ConfigFieldKind, ConfigFieldKindSchema, ConfigFieldSchema, ConfigInvoked, ConfigProgress, ConfigProgressSchema, ConfigProvider, ConfigProviderHandle, ConfigRegistration, ConfigSection, ConfigSectionSchema, ConfigSnapshot, ConfigSourceRef, ConfigSourceSchema, ConfigStatus, ConfigStatusSchema, ConfigStep, ConfigStepSchema, ConfigUnregistration, DoomConfigActionInput, DoomConfigContributionHandle, DoomConfigContributionOptions, DoomConfigInvocation, DoomConfigRegistry, DoomConfigSectionView, DoomExtensionContext, DoomExtensionHost, registerConfigProvider, registerDoomConfigContribution } from "@agimon-ai/doompi-extension-contracts/config";
2
- export { CONFIG_ACTION, type ConfigAction, ConfigActionSchema, ConfigChanged, type ConfigChoice, ConfigChoiceSchema, ConfigDiscovery, type ConfigField, type ConfigFieldKind, ConfigFieldKindSchema, ConfigFieldSchema, ConfigInvoked, type ConfigProgress, ConfigProgressSchema, type ConfigProvider, type ConfigProviderHandle, ConfigRegistration, type ConfigSection, ConfigSectionSchema, type ConfigSnapshot, type ConfigSourceRef, ConfigSourceSchema, type ConfigStatus, ConfigStatusSchema, type ConfigStep, ConfigStepSchema, ConfigUnregistration, type DoomConfigActionInput, type DoomConfigContributionHandle, type DoomConfigContributionOptions, type DoomConfigInvocation, DoomConfigRegistry, type DoomConfigSectionView, type DoomExtensionContext, type DoomExtensionHost, registerConfigProvider, registerDoomConfigContribution };
1
+ import { CONFIG_ACTION, ConfigAction, ConfigActionSchema, ConfigChoice, ConfigChoiceSchema, ConfigField, ConfigFieldKind, ConfigFieldKindSchema, ConfigFieldSchema, ConfigProgress, ConfigProgressSchema, ConfigSection, ConfigSectionSchema, ConfigSnapshot, ConfigSourceRef, ConfigSourceSchema, ConfigStatus, ConfigStatusSchema, ConfigStep, ConfigStepSchema, DoomConfigActionInput, DoomConfigContributionHandle, DoomConfigContributionOptions, DoomConfigInvocation, DoomConfigSectionView, DoomExtensionContext } from "@agimon-ai/doompi-extension-contracts/config";
2
+ export { CONFIG_ACTION, type ConfigAction, ConfigActionSchema, type ConfigChoice, ConfigChoiceSchema, type ConfigField, type ConfigFieldKind, ConfigFieldKindSchema, ConfigFieldSchema, type ConfigProgress, ConfigProgressSchema, type ConfigSection, ConfigSectionSchema, type ConfigSnapshot, type ConfigSourceRef, ConfigSourceSchema, type ConfigStatus, ConfigStatusSchema, type ConfigStep, ConfigStepSchema, type DoomConfigActionInput, type DoomConfigContributionHandle, type DoomConfigContributionOptions, type DoomConfigInvocation, type DoomConfigSectionView, type DoomExtensionContext };
package/dist/config.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { CONFIG_ACTION, ConfigAction, ConfigActionSchema, ConfigChanged, ConfigChoice, ConfigChoiceSchema, ConfigDiscovery, ConfigField, ConfigFieldKind, ConfigFieldKindSchema, ConfigFieldSchema, ConfigInvoked, ConfigProgress, ConfigProgressSchema, ConfigProvider, ConfigProviderHandle, ConfigRegistration, ConfigSection, ConfigSectionSchema, ConfigSnapshot, ConfigSourceRef, ConfigSourceSchema, ConfigStatus, ConfigStatusSchema, ConfigStep, ConfigStepSchema, ConfigUnregistration, DoomConfigActionInput, DoomConfigContributionHandle, DoomConfigContributionOptions, DoomConfigInvocation, DoomConfigRegistry, DoomConfigSectionView, DoomExtensionContext, DoomExtensionHost, registerConfigProvider, registerDoomConfigContribution } from "@agimon-ai/doompi-extension-contracts/config";
2
- export { CONFIG_ACTION, type ConfigAction, ConfigActionSchema, ConfigChanged, type ConfigChoice, ConfigChoiceSchema, ConfigDiscovery, type ConfigField, type ConfigFieldKind, ConfigFieldKindSchema, ConfigFieldSchema, ConfigInvoked, type ConfigProgress, ConfigProgressSchema, type ConfigProvider, type ConfigProviderHandle, ConfigRegistration, type ConfigSection, ConfigSectionSchema, type ConfigSnapshot, type ConfigSourceRef, ConfigSourceSchema, type ConfigStatus, ConfigStatusSchema, type ConfigStep, ConfigStepSchema, ConfigUnregistration, type DoomConfigActionInput, type DoomConfigContributionHandle, type DoomConfigContributionOptions, type DoomConfigInvocation, DoomConfigRegistry, type DoomConfigSectionView, type DoomExtensionContext, type DoomExtensionHost, registerConfigProvider, registerDoomConfigContribution };
1
+ import { CONFIG_ACTION, ConfigAction, ConfigActionSchema, ConfigChoice, ConfigChoiceSchema, ConfigField, ConfigFieldKind, ConfigFieldKindSchema, ConfigFieldSchema, ConfigProgress, ConfigProgressSchema, ConfigSection, ConfigSectionSchema, ConfigSnapshot, ConfigSourceRef, ConfigSourceSchema, ConfigStatus, ConfigStatusSchema, ConfigStep, ConfigStepSchema, DoomConfigActionInput, DoomConfigContributionHandle, DoomConfigContributionOptions, DoomConfigInvocation, DoomConfigSectionView, DoomExtensionContext } from "@agimon-ai/doompi-extension-contracts/config";
2
+ export { CONFIG_ACTION, type ConfigAction, ConfigActionSchema, type ConfigChoice, ConfigChoiceSchema, type ConfigField, type ConfigFieldKind, ConfigFieldKindSchema, ConfigFieldSchema, type ConfigProgress, ConfigProgressSchema, type ConfigSection, ConfigSectionSchema, type ConfigSnapshot, type ConfigSourceRef, ConfigSourceSchema, type ConfigStatus, ConfigStatusSchema, type ConfigStep, ConfigStepSchema, type DoomConfigActionInput, type DoomConfigContributionHandle, type DoomConfigContributionOptions, type DoomConfigInvocation, type DoomConfigSectionView, type DoomExtensionContext };
package/dist/config.mjs CHANGED
@@ -1 +1 @@
1
- import{CONFIG_ACTION as e,ConfigActionSchema as t,ConfigChanged as n,ConfigChoiceSchema as r,ConfigDiscovery as i,ConfigFieldKindSchema as a,ConfigFieldSchema as o,ConfigInvoked as s,ConfigProgressSchema as c,ConfigRegistration as l,ConfigSectionSchema as u,ConfigSourceSchema as d,ConfigStatusSchema as f,ConfigStepSchema as p,ConfigUnregistration as m,DoomConfigRegistry as h,registerConfigProvider as g,registerDoomConfigContribution as _}from"@agimon-ai/doompi-extension-contracts/config";export{e as CONFIG_ACTION,t as ConfigActionSchema,n as ConfigChanged,r as ConfigChoiceSchema,i as ConfigDiscovery,a as ConfigFieldKindSchema,o as ConfigFieldSchema,s as ConfigInvoked,c as ConfigProgressSchema,l as ConfigRegistration,u as ConfigSectionSchema,d as ConfigSourceSchema,f as ConfigStatusSchema,p as ConfigStepSchema,m as ConfigUnregistration,h as DoomConfigRegistry,g as registerConfigProvider,_ as registerDoomConfigContribution};
1
+ import{CONFIG_ACTION as e,ConfigActionSchema as t,ConfigChoiceSchema as n,ConfigFieldKindSchema as r,ConfigFieldSchema as i,ConfigProgressSchema as a,ConfigSectionSchema as o,ConfigSourceSchema as s,ConfigStatusSchema as c,ConfigStepSchema as l}from"@agimon-ai/doompi-extension-contracts/config";export{e as CONFIG_ACTION,t as ConfigActionSchema,n as ConfigChoiceSchema,r as ConfigFieldKindSchema,i as ConfigFieldSchema,a as ConfigProgressSchema,o as ConfigSectionSchema,s as ConfigSourceSchema,c as ConfigStatusSchema,l as ConfigStepSchema};
package/dist/footer.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@agimon-ai/doompi-extension-contracts/footer");Object.defineProperty(exports,"DoomFooterStatusRegistry",{enumerable:!0,get:function(){return e.DoomFooterStatusRegistry}}),Object.defineProperty(exports,"FooterStatusChanged",{enumerable:!0,get:function(){return e.FooterStatusChanged}}),Object.defineProperty(exports,"FooterStatusDiscovery",{enumerable:!0,get:function(){return e.FooterStatusDiscovery}}),Object.defineProperty(exports,"FooterStatusItemSchema",{enumerable:!0,get:function(){return e.FooterStatusItemSchema}}),Object.defineProperty(exports,"FooterStatusPlacementSchema",{enumerable:!0,get:function(){return e.FooterStatusPlacementSchema}}),Object.defineProperty(exports,"FooterStatusRegistration",{enumerable:!0,get:function(){return e.FooterStatusRegistration}}),Object.defineProperty(exports,"FooterStatusUnregistration",{enumerable:!0,get:function(){return e.FooterStatusUnregistration}}),Object.defineProperty(exports,"FooterTextColorSchema",{enumerable:!0,get:function(){return e.FooterTextColorSchema}}),Object.defineProperty(exports,"FooterTextSegmentSchema",{enumerable:!0,get:function(){return e.FooterTextSegmentSchema}}),Object.defineProperty(exports,"registerDoomFooterContribution",{enumerable:!0,get:function(){return e.registerDoomFooterContribution}}),Object.defineProperty(exports,"registerFooterStatusProvider",{enumerable:!0,get:function(){return e.registerFooterStatusProvider}});
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@agimon-ai/doompi-extension-contracts/footer");Object.defineProperty(exports,"FooterStatusItemSchema",{enumerable:!0,get:function(){return e.FooterStatusItemSchema}}),Object.defineProperty(exports,"FooterStatusPlacementSchema",{enumerable:!0,get:function(){return e.FooterStatusPlacementSchema}}),Object.defineProperty(exports,"FooterTextColorSchema",{enumerable:!0,get:function(){return e.FooterTextColorSchema}}),Object.defineProperty(exports,"FooterTextSegmentSchema",{enumerable:!0,get:function(){return e.FooterTextSegmentSchema}});
package/dist/footer.d.cts CHANGED
@@ -1,2 +1,2 @@
1
- import { DoomFooterContributionDefinition, DoomFooterContributionHandle, DoomFooterContributionValue, DoomFooterStatus, DoomFooterStatusRegistry, FooterStatusChanged, FooterStatusDiscovery, FooterStatusItem, FooterStatusItemSchema, FooterStatusPlacement, FooterStatusPlacementSchema, FooterStatusProvider, FooterStatusProviderHandle, FooterStatusRegistration, FooterStatusSnapshot, FooterStatusSource, FooterStatusUnregistration, FooterTextColor, FooterTextColorSchema, FooterTextSegment, FooterTextSegmentSchema, registerDoomFooterContribution, registerFooterStatusProvider } from "@agimon-ai/doompi-extension-contracts/footer";
2
- export { type DoomFooterContributionDefinition, type DoomFooterContributionHandle, type DoomFooterContributionValue, type DoomFooterStatus, DoomFooterStatusRegistry, FooterStatusChanged, FooterStatusDiscovery, type FooterStatusItem, FooterStatusItemSchema, type FooterStatusPlacement, FooterStatusPlacementSchema, type FooterStatusProvider, type FooterStatusProviderHandle, FooterStatusRegistration, type FooterStatusSnapshot, type FooterStatusSource, FooterStatusUnregistration, type FooterTextColor, FooterTextColorSchema, type FooterTextSegment, FooterTextSegmentSchema, registerDoomFooterContribution, registerFooterStatusProvider };
1
+ import { DoomFooterContributionDefinition, DoomFooterContributionHandle, DoomFooterContributionValue, DoomFooterStatus, FooterStatusItem, FooterStatusItemSchema, FooterStatusPlacement, FooterStatusPlacementSchema, FooterTextColor, FooterTextColorSchema, FooterTextSegment, FooterTextSegmentSchema } from "@agimon-ai/doompi-extension-contracts/footer";
2
+ export { type DoomFooterContributionDefinition, type DoomFooterContributionHandle, type DoomFooterContributionValue, type DoomFooterStatus, type FooterStatusItem, FooterStatusItemSchema, type FooterStatusPlacement, FooterStatusPlacementSchema, type FooterTextColor, FooterTextColorSchema, type FooterTextSegment, FooterTextSegmentSchema };
package/dist/footer.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { DoomFooterContributionDefinition, DoomFooterContributionHandle, DoomFooterContributionValue, DoomFooterStatus, DoomFooterStatusRegistry, FooterStatusChanged, FooterStatusDiscovery, FooterStatusItem, FooterStatusItemSchema, FooterStatusPlacement, FooterStatusPlacementSchema, FooterStatusProvider, FooterStatusProviderHandle, FooterStatusRegistration, FooterStatusSnapshot, FooterStatusSource, FooterStatusUnregistration, FooterTextColor, FooterTextColorSchema, FooterTextSegment, FooterTextSegmentSchema, registerDoomFooterContribution, registerFooterStatusProvider } from "@agimon-ai/doompi-extension-contracts/footer";
2
- export { type DoomFooterContributionDefinition, type DoomFooterContributionHandle, type DoomFooterContributionValue, type DoomFooterStatus, DoomFooterStatusRegistry, FooterStatusChanged, FooterStatusDiscovery, type FooterStatusItem, FooterStatusItemSchema, type FooterStatusPlacement, FooterStatusPlacementSchema, type FooterStatusProvider, type FooterStatusProviderHandle, FooterStatusRegistration, type FooterStatusSnapshot, type FooterStatusSource, FooterStatusUnregistration, type FooterTextColor, FooterTextColorSchema, type FooterTextSegment, FooterTextSegmentSchema, registerDoomFooterContribution, registerFooterStatusProvider };
1
+ import { DoomFooterContributionDefinition, DoomFooterContributionHandle, DoomFooterContributionValue, DoomFooterStatus, FooterStatusItem, FooterStatusItemSchema, FooterStatusPlacement, FooterStatusPlacementSchema, FooterTextColor, FooterTextColorSchema, FooterTextSegment, FooterTextSegmentSchema } from "@agimon-ai/doompi-extension-contracts/footer";
2
+ export { type DoomFooterContributionDefinition, type DoomFooterContributionHandle, type DoomFooterContributionValue, type DoomFooterStatus, type FooterStatusItem, FooterStatusItemSchema, type FooterStatusPlacement, FooterStatusPlacementSchema, type FooterTextColor, FooterTextColorSchema, type FooterTextSegment, FooterTextSegmentSchema };
package/dist/footer.mjs CHANGED
@@ -1 +1 @@
1
- import{DoomFooterStatusRegistry as e,FooterStatusChanged as t,FooterStatusDiscovery as n,FooterStatusItemSchema as r,FooterStatusPlacementSchema as i,FooterStatusRegistration as a,FooterStatusUnregistration as o,FooterTextColorSchema as s,FooterTextSegmentSchema as c,registerDoomFooterContribution as l,registerFooterStatusProvider as u}from"@agimon-ai/doompi-extension-contracts/footer";export{e as DoomFooterStatusRegistry,t as FooterStatusChanged,n as FooterStatusDiscovery,r as FooterStatusItemSchema,i as FooterStatusPlacementSchema,a as FooterStatusRegistration,o as FooterStatusUnregistration,s as FooterTextColorSchema,c as FooterTextSegmentSchema,l as registerDoomFooterContribution,u as registerFooterStatusProvider};
1
+ import{FooterStatusItemSchema as e,FooterStatusPlacementSchema as t,FooterTextColorSchema as n,FooterTextSegmentSchema as r}from"@agimon-ai/doompi-extension-contracts/footer";export{e as FooterStatusItemSchema,t as FooterStatusPlacementSchema,n as FooterTextColorSchema,r as FooterTextSegmentSchema};