@agimon-ai/doompi-task 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 (36) hide show
  1. package/README.md +2 -2
  2. package/dist/adapters/pi/extension.cjs +2 -2
  3. package/dist/adapters/pi/extension.cjs.map +1 -1
  4. package/dist/adapters/pi/extension.d.cts +1 -1
  5. package/dist/adapters/pi/extension.d.cts.map +1 -1
  6. package/dist/adapters/pi/extension.d.mts +2 -2
  7. package/dist/adapters/pi/extension.d.mts.map +1 -1
  8. package/dist/adapters/pi/extension.mjs +2 -2
  9. package/dist/adapters/pi/extension.mjs.map +1 -1
  10. package/dist/commands/index.cjs +1 -1
  11. package/dist/commands/index.cjs.map +1 -1
  12. package/dist/commands/index.d.cts +2 -2
  13. package/dist/commands/index.d.cts.map +1 -1
  14. package/dist/commands/index.d.mts +2 -2
  15. package/dist/commands/index.d.mts.map +1 -1
  16. package/dist/commands/index.mjs +1 -1
  17. package/dist/commands/index.mjs.map +1 -1
  18. package/dist/commands/task/taskTool.cjs +1 -1
  19. package/dist/commands/task/taskTool.cjs.map +1 -1
  20. package/dist/commands/task/taskTool.d.cts +2 -1
  21. package/dist/commands/task/taskTool.d.cts.map +1 -1
  22. package/dist/commands/task/taskTool.d.mts +2 -1
  23. package/dist/commands/task/taskTool.d.mts.map +1 -1
  24. package/dist/commands/task/taskTool.mjs +1 -1
  25. package/dist/commands/task/taskTool.mjs.map +1 -1
  26. package/dist/services/delegation/manager.cjs +3 -3
  27. package/dist/services/delegation/manager.cjs.map +1 -1
  28. package/dist/services/delegation/manager.d.cts +15 -11
  29. package/dist/services/delegation/manager.d.cts.map +1 -1
  30. package/dist/services/delegation/manager.d.mts +15 -11
  31. package/dist/services/delegation/manager.d.mts.map +1 -1
  32. package/dist/services/delegation/manager.mjs +3 -3
  33. package/dist/services/delegation/manager.mjs.map +1 -1
  34. package/dist/services/narration/taskNarration.cjs.map +1 -1
  35. package/dist/services/narration/taskNarration.mjs.map +1 -1
  36. package/package.json +4 -4
package/README.md CHANGED
@@ -4,7 +4,7 @@ A persistent, dependency-aware task graph for Pi, with an optional delegation br
4
4
 
5
5
  Part of the [DoomPi distribution](https://www.npmjs.com/package/@agimon-ai/doompi).
6
6
 
7
- Task owns task records and `tasks.json`. Team owns agents and runs. Loading both lets Task delegate pending work through Team's protocol; it does not merge their persistence.
7
+ Task owns task records and `tasks.json`. Team owns agents and runs. Loading both lets Task delegate pending work through Team's session-bound `doom/delegation` Cordis service; it does not merge their persistence.
8
8
 
9
9
  > **Alpha:** task and delegation contracts may change between releases.
10
10
 
@@ -92,7 +92,7 @@ Startup/reconciliation sweeps expired stores and repairs delegation records whos
92
92
 
93
93
  ## Task and Team together
94
94
 
95
- Task sends a delegation request and records the resulting lifecycle on the task. Team discovers the selected agent, applies model/tool policy, owns the run, and returns completion or failure. Intercom and Team membership remain Team state; `tasks.json` remains Task state.
95
+ Task injects Team's delegation service and records its lifecycle events on the task. It also contributes pending assignments through `doom/background-work`. Team discovers the selected agent, applies model/tool policy, owns the run, and returns completion or failure. Losing or replacing Team unloads and rebinds both consumers without leaving a process-global registration. Intercom and Team membership remain Team state; `tasks.json` remains Task state.
96
96
 
97
97
  ## Public API
98
98
 
@@ -1,3 +1,3 @@
1
- const e=require("../../schemas/task.cjs"),t=require("../../types/telemetry.cjs"),n=require("../../services/delegation/manager.cjs"),r=require("../../commands/index.cjs"),i=require("../../types/config.cjs"),a=require("../../commands/task/taskTool.cjs"),o=require("../../services/narration/taskNarration.cjs"),s=require("../store/paths.cjs"),c=require("../store/taskStore.cjs"),l=require("../../tui/taskOverlay2.cjs"),u=require("../node/delegationPlatform.cjs"),d=require("../telemetry/logSinkTelemetry.cjs");let f=require("@earendil-works/pi-tui"),p=require("@agimon-ai/doompi-extension-contracts/protocol"),m=require("@agimon-ai/doompi-extension-contracts/background-work"),h=require("@agimon-ai/doompi-extension-contracts/narration"),g=require("@agimon-ai/doompi-ui/leader"),_=require("@deepseek-ai/cordis");const v=`@agimon-ai/doompi-task`,y={narrate:()=>void 0};function b(_,b){let x=d.createTaskErrorReporter(),S=d.toFailureReporter(x),C=!0,w=0,T=y,E,D,O,k,A,j,M,N=()=>{k?.(),k=void 0,A?.dispose(),A=void 0,D?.dispose(),O?.dispose(),T=y,M=void 0};_.effect(()=>async()=>{C=!1,w+=1;try{N(),j?.(),j=void 0,E?.dispose()}finally{await x.shutdown()}},v);let P=new c.TaskStore({report:S,onCommitted:(e,t)=>o.narrateTaskCommit(T,e,t)});E=P;let F=()=>{C&&(O?.update(),A?.update())},I=new n.DelegationManager({events:b.events,store:P,cwd:process.cwd(),platform:u.createNodeDelegationPlatform(),notify:(e,t)=>b.sendMessage(e,t),getSessionId:()=>M,onChange:F,runTimeoutMs:i.getDelegationTimeoutMs(),report:S,onNotifyError:(e,t)=>{x.recordNotificationError(e,t)}});D=I;let L=new l.TaskOverlay({getTasks:()=>P.snapshot.tasks,delegation:I});O=L,a.registerTaskTool(b,{store:P,delegation:I,maxTasks:i.getMaxTasks(),onChange:F,report:S}),r.registerTasksCommand(b,P),j=(0,g.registerDoomLeaderContribution)(b,{source:v,bindings:[{id:`tasks.open`,path:[{key:`t`,label:`tasks`,order:65},{key:`t`,label:`tasks`}],command:{name:e.COMMAND_NAME}}]}),b.registerMessageRenderer(n.NOTIFY_CUSTOM_TYPE,(e,t,n)=>{let r=typeof e.content==`string`?e.content:``;return new f.Text(n.fg(`muted`,r),0,0)});let R=i.resolveCollapseKey();R!==`off`&&b.registerShortcut(R,{description:`Collapse or expand the task overlay`,handler:e=>{!C||!e.hasUI||!L.isRegistered()||L.toggleCollapse()}}),b.on(`session_start`,async(e,r)=>{if(!C)return;let a=++w;M!==void 0&&N();let o=()=>C&&a===w;try{let e=r,a=e.sessionManager?.getSessionId();if(!a)throw Error(`doom-task requires a session id`);M=a,T=(0,h.createNarrationRequester)({bus:b.events,source:v,sessionId:a}),A=e.hasUI?void 0:(0,m.registerBackgroundWorkProvider)((0,p.createProtocolRuntime)({bus:b.events,source:v,sessionId:a}),{provider:n.BACKGROUND_WORK_PROVIDER,listActiveWork:()=>I.listActiveWork()}),P.configureSession(s.resolveSessionKey(a));let c=await s.removeLegacyStoreDirectoryAsync(P.storePath);if(!o())return;let l=s.hasStorePathOverride()?{removed:[],errors:[]}:await s.sweepStoreFilesAsync(P.storePath,i.getStoreTtlMs());if(!o())return;let u=[...c.errors,...l.errors];for(let e of u)S.warn(t.TASK_EVENT.storeSweepFailed,Error(e));if(u.length>0&&e.hasUI&&e.ui.notify(u.join(`
2
- `),`warning`),e.hasUI&&L.setUICtx(e.ui),await P.readAsync(o),!o()||(k=P.onExternalChange(F),I.start(),await I.reconcile(o),!o()))return;F()}catch(e){if(!o())return;throw N(),S.error(t.TASK_EVENT.sessionStartFailed,e),e}}),b.on(`session_compact`,F),b.on(`session_tree`,F),b.on(`tool_execution_end`,e=>{C&&e.toolName===`task`&&F()})}async function x(e){let t=new _.Context,n,r=()=>(n??=t.fiber.dispose(),n);try{b(t,e)}catch(e){throw await r(),e}e.on(`session_shutdown`,r)}exports.default=x,exports.taskExtension=x,exports.installTaskRuntime=b;
1
+ const e=require("../../schemas/task.cjs"),t=require("../../types/telemetry.cjs"),n=require("../../services/delegation/manager.cjs"),r=require("../../commands/index.cjs"),i=require("../../types/config.cjs"),a=require("../../commands/task/taskTool.cjs"),o=require("../../services/narration/taskNarration.cjs"),s=require("../store/paths.cjs"),c=require("../store/taskStore.cjs"),l=require("../../tui/taskOverlay2.cjs"),u=require("../node/delegationPlatform.cjs"),d=require("../telemetry/logSinkTelemetry.cjs");let f=require("@earendil-works/pi-tui"),p=require("@agimon-ai/doompi-extension-contracts/delegation"),m=require("@agimon-ai/doompi-extension-contracts/background-work"),h=require("@agimon-ai/doompi-extension-contracts/cordis-host"),g=require("@agimon-ai/doompi-extension-contracts/narration"),_=require("@agimon-ai/doompi-extension-contracts/readiness"),v=require("@agimon-ai/doompi-extension-contracts/ui-hub");const y=`@agimon-ai/doompi-task`;function b(h,b){let x=d.createTaskErrorReporter(),S=d.toFailureReporter(x),C=!0,w=0,T,E,D,O,k,A,j=!1,M,N,P,F=e=>{x.recordWarning(`doom_task.narration_failed`,e).catch(e=>{process.emitWarning(`Doom-task could not record a narration failure: ${String(e)}`)})},I={narrate(e){let t=T,n=(0,g.createNarrationRequest)(e);if(!(!t||!n))try{Promise.resolve(t.request(n)).catch(F)}catch(e){F(e)}}};h.inject([g.DOOM_NARRATION_SERVICE],e=>{let t=(0,g.requireDoomNarrationService)(e);return T=t,()=>{T===t&&(T=void 0)}});let L=async(e,t)=>{t?.throwIfAborted();let n=P;if(!n)throw Error(`doom-task session initialization has not started`);if(n.sessionManager!==e.sessionManager)throw Error(`doom-task readiness belongs to a stale Pi session`);if(await n.operation,t?.throwIfAborted(),!C||n!==P||!N)throw Error(`doom-task readiness belongs to a stale extension generation`)},R=()=>{k?.(),k=void 0,j=!1,A?.update(),D?.reset(),O?.dispose(),N=void 0};h.effect(()=>async()=>{C=!1,w+=1;let e=P?.operation;P=void 0;try{e&&await Promise.allSettled([e]),R(),D?.dispose(),M?.(),M=void 0,E?.dispose()}finally{await x.shutdown()}},y);let z=new c.TaskStore({report:S,onCommitted:(e,t)=>o.narrateTaskCommit(I,e,t)});E=z;let B=()=>{C&&(O?.update(),A?.update())},V=new n.DelegationManager({store:z,cwd:process.cwd(),platform:u.createNodeDelegationPlatform(),notify:(e,t)=>b.sendMessage(e,t),getSessionId:()=>N,onChange:B,runTimeoutMs:i.getDelegationTimeoutMs(),report:S,onNotifyError:(e,t)=>{x.recordNotificationError(e,t)}});D=V,h.inject([p.DOOM_DELEGATION_SERVICE],e=>{let t=(0,p.readDoomDelegationService)(e);if(t)return V.bind(e,t)}),h.inject([m.DOOM_BACKGROUND_WORK_SERVICE],e=>{let t=(0,m.readDoomBackgroundWorkService)(e);if(!t)return;let r=t.register({provider:n.BACKGROUND_WORK_PROVIDER,listActiveWork:()=>j?V.listActiveWork():[]});return A=r,()=>{r.dispose(),A===r&&(A=void 0)}});let H=new l.TaskOverlay({getTasks:()=>z.snapshot.tasks,delegation:V});O=H,a.registerTaskTool(b,{store:z,delegation:V,maxTasks:i.getMaxTasks(),onChange:B,report:S,waitUntilReady:L}),r.registerTasksCommand(b,z,L),h.inject([v.DOOM_UI_HUB_SERVICE],t=>{let n=(0,v.requireDoomUiHub)(t).registerLeader({source:y,bindings:[{id:`tasks.open`,path:[{key:`t`,label:`tasks`,order:65},{key:`t`,label:`tasks`}],command:{name:e.COMMAND_NAME}}]}),r=()=>n.dispose();return M=r,()=>{r(),M===r&&(M=void 0)}}),b.registerMessageRenderer(n.NOTIFY_CUSTOM_TYPE,(e,t,n)=>{let r=typeof e.content==`string`?e.content:``;return new f.Text(n.fg(`muted`,r),0,0)});let U=i.resolveCollapseKey();U!==`off`&&b.registerShortcut(U,{description:`Collapse or expand the task overlay`,handler:async e=>{!C||!e.hasUI||(await L(e),!(!C||!H.isRegistered())&&H.toggleCollapse())}}),b.on(`session_start`,async(e,n)=>{if(!C)return;let r=++w;N!==void 0&&R();let a=n,o=async e=>{let n=()=>!e?.aborted&&C&&r===w;try{let e=a.sessionManager?.getSessionId();if(!e)throw Error(`doom-task requires a session id`);N=e,j=!a.hasUI,A?.update(),z.configureSession(s.resolveSessionKey(e));let r=await s.removeLegacyStoreDirectoryAsync(z.storePath);if(!n())return;let o=s.hasStorePathOverride()?{removed:[],errors:[]}:await s.sweepStoreFilesAsync(z.storePath,i.getStoreTtlMs());if(!n())return;let c=[...r.errors,...o.errors];for(let e of c)S.warn(t.TASK_EVENT.storeSweepFailed,Error(e));if(c.length>0&&a.hasUI&&a.ui.notify(c.join(`
2
+ `),`warning`),a.hasUI&&H.setUICtx(a.ui),await z.readAsync(n),!n()||(k=z.onExternalChange(B),await V.reconcile(n),!n()))return;B()}catch(e){if(!n())return;throw R(),S.error(t.TASK_EVENT.sessionStartFailed,e),e}},c=(0,_.readDoomReadinessCoordinator)(h);if(!c){let e=o();return P={sessionManager:n.sessionManager,operation:e},e}let l=P?.operation,u=(async()=>{l&&await Promise.allSettled([l]),!(!C||r!==w)&&await c.start(y,`${n.sessionManager.getSessionId()}:${r}`,async e=>(await o(e),{value:void 0})).wait()})();P={sessionManager:n.sessionManager,operation:u},Promise.allSettled([u])}),b.on(`session_compact`,B),b.on(`session_tree`,B),b.on(`tool_execution_end`,e=>{C&&e.toolName===`task`&&B()})}async function x(e){let t=await(0,h.connectDoomCordisHost)(e,y),n=t.root.plugin(S,{pi:e});try{await n}catch(e){try{await n.dispose()}finally{await t.dispose()}throw e}let r;e.on(`session_shutdown`,()=>r??=(async()=>{try{await n.dispose()}finally{await t.dispose()}})())}function S(e,t){b(e,t.pi)}exports.default=x,exports.taskExtension=x,exports.installTaskRuntime=b;
3
3
  //# sourceMappingURL=extension.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.cjs","names":["createTaskErrorReporter","toFailureReporter","TaskStore","narrateTaskCommit","DelegationManager","createNodeDelegationPlatform","getDelegationTimeoutMs","TaskOverlay","getMaxTasks","registerDoomLeaderContribution","COMMAND_NAME","NOTIFY_CUSTOM_TYPE","Text","resolveCollapseKey","createNarrationRequester","registerBackgroundWorkProvider","createProtocolRuntime","BACKGROUND_WORK_PROVIDER","resolveSessionKey","removeLegacyStoreDirectoryAsync","hasStorePathOverride","sweepStoreFilesAsync","getStoreTtlMs","TASK_EVENT","Context"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import {\n type BackgroundWorkProviderHandle,\n registerBackgroundWorkProvider,\n} from '@agimon-ai/doompi-extension-contracts/background-work';\nimport { createNarrationRequester, type NarrationRequester } from '@agimon-ai/doompi-extension-contracts/narration';\nimport { createProtocolRuntime } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport { registerDoomLeaderContribution } from '@agimon-ai/doompi-ui/leader';\nimport { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport type { KeyId } from '@earendil-works/pi-tui';\nimport { Text } from '@earendil-works/pi-tui';\nimport { registerTasksCommand } from '../../commands/index.ts';\nimport { registerTaskTool } from '../../commands/task/taskTool.ts';\nimport { COMMAND_NAME, TOOL_NAME } from '../../schemas/task.ts';\nimport { BACKGROUND_WORK_PROVIDER, DelegationManager, NOTIFY_CUSTOM_TYPE } from '../../services/delegation/manager.ts';\nimport { narrateTaskCommit } from '../../services/narration/taskNarration.ts';\nimport {\n hasStorePathOverride,\n removeLegacyStoreDirectoryAsync,\n resolveSessionKey,\n sweepStoreFilesAsync,\n} from '../../adapters/store/paths';\nimport { TaskStore } from '../../adapters/store/taskStore';\nimport { TaskOverlay } from '../../tui/taskOverlay.ts';\nimport {\n COLLAPSE_KEY_OFF,\n getDelegationTimeoutMs,\n getMaxTasks,\n getStoreTtlMs,\n resolveCollapseKey,\n} from '../../types/config.ts';\nimport { createNodeDelegationPlatform } from '../node/delegationPlatform.ts';\nimport { createTaskErrorReporter, TASK_EVENT, toFailureReporter } from '../telemetry/logSinkTelemetry.ts';\n\ninterface SessionContextLike {\n hasUI: boolean;\n ui: Parameters<TaskOverlay['setUICtx']>[0];\n sessionManager?: { getSessionId(): string };\n}\n\nconst LEADER_SOURCE = '@agimon-ai/doompi-task';\nconst SILENT_NARRATION_REQUESTER: NarrationRequester = { narrate: () => undefined };\n/** Between doom-plan's 60 and the core help group's 70, so `t` sits after `p`. */\nconst LEADER_GROUP_ORDER = 65;\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_COMPACT_EVENT = 'session_compact';\nconst SESSION_TREE_EVENT = 'session_tree';\nconst TOOL_EXECUTION_END_EVENT = 'tool_execution_end';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\n\n/** Install Task state and external resources into one package-local Cordis root. */\nexport function installTaskRuntime(cordis: Context, pi: ExtensionAPI): void {\n const errorReporter = createTaskErrorReporter();\n const report = toFailureReporter(errorReporter);\n let active = true;\n let sessionGeneration = 0;\n let narrationRequester = SILENT_NARRATION_REQUESTER;\n let store: TaskStore | undefined;\n let delegation: DelegationManager | undefined;\n let overlay: TaskOverlay | undefined;\n let unwatch: (() => void) | undefined;\n let backgroundWork: BackgroundWorkProviderHandle | undefined;\n let disposeLeader: (() => void) | undefined;\n let sessionId: string | undefined;\n\n const clearSessionResources = (): void => {\n unwatch?.();\n unwatch = undefined;\n backgroundWork?.dispose();\n backgroundWork = undefined;\n delegation?.dispose();\n overlay?.dispose();\n narrationRequester = SILENT_NARRATION_REQUESTER;\n sessionId = undefined;\n };\n\n cordis.effect(\n () => async () => {\n active = false;\n sessionGeneration += 1;\n try {\n clearSessionResources();\n disposeLeader?.();\n disposeLeader = undefined;\n store?.dispose();\n } finally {\n await errorReporter.shutdown();\n }\n },\n LEADER_SOURCE,\n );\n\n const taskStore = new TaskStore({\n report,\n onCommitted: (previous, committed) => narrateTaskCommit(narrationRequester, previous, committed),\n });\n store = taskStore;\n\n const refresh = (): void => {\n if (!active) return;\n overlay?.update();\n backgroundWork?.update();\n };\n\n const delegationManager = new DelegationManager({\n events: pi.events,\n store: taskStore,\n cwd: process.cwd(),\n platform: createNodeDelegationPlatform(),\n notify: (message, options) => pi.sendMessage(message, options),\n getSessionId: () => sessionId,\n onChange: refresh,\n runTimeoutMs: getDelegationTimeoutMs(),\n report,\n onNotifyError: (error, taskId) => {\n void errorReporter.recordNotificationError(error, taskId);\n },\n });\n delegation = delegationManager;\n\n const taskOverlay = new TaskOverlay({ getTasks: () => taskStore.snapshot.tasks, delegation: delegationManager });\n overlay = taskOverlay;\n\n registerTaskTool(pi, {\n store: taskStore,\n delegation: delegationManager,\n maxTasks: getMaxTasks(),\n onChange: refresh,\n report,\n });\n registerTasksCommand(pi, taskStore);\n\n disposeLeader = registerDoomLeaderContribution(pi, {\n source: LEADER_SOURCE,\n bindings: [\n {\n id: 'tasks.open',\n path: [\n { key: 't', label: 'tasks', order: LEADER_GROUP_ORDER },\n { key: 't', label: 'tasks' },\n ],\n command: { name: COMMAND_NAME },\n },\n ],\n });\n\n pi.registerMessageRenderer(NOTIFY_CUSTOM_TYPE, (message, _options, theme) => {\n const content = typeof message.content === 'string' ? message.content : '';\n return new Text(theme.fg('muted', content), 0, 0);\n });\n\n const collapseKey = resolveCollapseKey();\n if (collapseKey !== COLLAPSE_KEY_OFF) {\n pi.registerShortcut(collapseKey as KeyId, {\n description: 'Collapse or expand the task overlay',\n handler: (ctx) => {\n if (!active || !ctx.hasUI || !taskOverlay.isRegistered()) return;\n taskOverlay.toggleCollapse();\n },\n });\n }\n\n pi.on(SESSION_START_EVENT, async (_event, ctx) => {\n if (!active) return;\n const ownGeneration = ++sessionGeneration;\n if (sessionId !== undefined) clearSessionResources();\n const isCurrent = (): boolean => active && ownGeneration === sessionGeneration;\n try {\n const context = ctx as unknown as SessionContextLike;\n const currentSessionId = context.sessionManager?.getSessionId();\n if (!currentSessionId) throw new Error('doom-task requires a session id');\n sessionId = currentSessionId;\n narrationRequester = createNarrationRequester({\n bus: pi.events,\n source: LEADER_SOURCE,\n sessionId: currentSessionId,\n });\n backgroundWork = context.hasUI\n ? undefined\n : registerBackgroundWorkProvider(\n createProtocolRuntime({\n bus: pi.events,\n source: LEADER_SOURCE,\n sessionId: currentSessionId,\n }),\n {\n provider: BACKGROUND_WORK_PROVIDER,\n listActiveWork: () => delegationManager.listActiveWork(),\n },\n );\n taskStore.configureSession(resolveSessionKey(currentSessionId));\n const cleanup = await removeLegacyStoreDirectoryAsync(taskStore.storePath);\n if (!isCurrent()) return;\n const sweep = hasStorePathOverride()\n ? { removed: [], errors: [] }\n : await sweepStoreFilesAsync(taskStore.storePath, getStoreTtlMs());\n if (!isCurrent()) return;\n const storeErrors = [...cleanup.errors, ...sweep.errors];\n for (const failure of storeErrors) report.warn(TASK_EVENT.storeSweepFailed, new Error(failure));\n if (storeErrors.length > 0 && context.hasUI) context.ui.notify(storeErrors.join('\\n'), 'warning');\n if (context.hasUI) taskOverlay.setUICtx(context.ui);\n await taskStore.readAsync(isCurrent);\n if (!isCurrent()) return;\n unwatch = taskStore.onExternalChange(refresh);\n delegationManager.start();\n await delegationManager.reconcile(isCurrent);\n if (!isCurrent()) return;\n refresh();\n } catch (error) {\n if (!isCurrent()) return;\n clearSessionResources();\n report.error(TASK_EVENT.sessionStartFailed, error);\n throw error;\n }\n });\n\n pi.on(SESSION_COMPACT_EVENT, refresh);\n pi.on(SESSION_TREE_EVENT, refresh);\n pi.on(TOOL_EXECUTION_END_EVENT, (event) => {\n if (active && event.toolName === TOOL_NAME) refresh();\n });\n}\n\n/** The package's single standard Pi factory. */\nexport async function taskExtension(pi: ExtensionAPI): Promise<void> {\n const cordis = new Context();\n let disposal: Promise<void> | undefined;\n const dispose = (): Promise<void> => {\n disposal ??= cordis.fiber.dispose();\n return disposal;\n };\n\n try {\n installTaskRuntime(cordis, pi);\n } catch (error) {\n await dispose();\n throw error;\n }\n\n pi.on(SESSION_SHUTDOWN_EVENT, dispose);\n}\n\nexport default taskExtension;\n"],"mappings":"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"}
1
+ {"version":3,"file":"extension.cjs","names":["createTaskErrorReporter","toFailureReporter","createNarrationRequest","DOOM_NARRATION_SERVICE","requireDoomNarrationService","TaskStore","narrateTaskCommit","DelegationManager","createNodeDelegationPlatform","getDelegationTimeoutMs","DOOM_DELEGATION_SERVICE","readDoomDelegationService","DOOM_BACKGROUND_WORK_SERVICE","readDoomBackgroundWorkService","BACKGROUND_WORK_PROVIDER","TaskOverlay","getMaxTasks","DOOM_UI_HUB_SERVICE","requireDoomUiHub","COMMAND_NAME","NOTIFY_CUSTOM_TYPE","Text","resolveCollapseKey","resolveSessionKey","removeLegacyStoreDirectoryAsync","hasStorePathOverride","sweepStoreFilesAsync","getStoreTtlMs","TASK_EVENT","readDoomReadinessCoordinator","connectDoomCordisHost"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import {\n DOOM_BACKGROUND_WORK_SERVICE,\n type BackgroundWorkProviderHandle,\n readDoomBackgroundWorkService,\n} from '@agimon-ai/doompi-extension-contracts/background-work';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_DELEGATION_SERVICE, readDoomDelegationService } from '@agimon-ai/doompi-extension-contracts/delegation';\nimport {\n createNarrationRequest,\n DOOM_NARRATION_SERVICE,\n type DoomNarrationService,\n requireDoomNarrationService,\n} from '@agimon-ai/doompi-extension-contracts/narration';\nimport { readDoomReadinessCoordinator } from '@agimon-ai/doompi-extension-contracts/readiness';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport type { KeyId } from '@earendil-works/pi-tui';\nimport { Text } from '@earendil-works/pi-tui';\nimport { registerTasksCommand } from '../../commands/index.ts';\nimport { registerTaskTool } from '../../commands/task/taskTool.ts';\nimport { COMMAND_NAME, TOOL_NAME } from '../../schemas/task.ts';\nimport { BACKGROUND_WORK_PROVIDER, DelegationManager, NOTIFY_CUSTOM_TYPE } from '../../services/delegation/manager.ts';\nimport { narrateTaskCommit, type TaskNarrationSink } from '../../services/narration/taskNarration.ts';\nimport {\n hasStorePathOverride,\n removeLegacyStoreDirectoryAsync,\n resolveSessionKey,\n sweepStoreFilesAsync,\n} from '../../adapters/store/paths';\nimport { TaskStore } from '../../adapters/store/taskStore';\nimport { TaskOverlay } from '../../tui/taskOverlay.ts';\nimport {\n COLLAPSE_KEY_OFF,\n getDelegationTimeoutMs,\n getMaxTasks,\n getStoreTtlMs,\n resolveCollapseKey,\n} from '../../types/config.ts';\nimport { createNodeDelegationPlatform } from '../node/delegationPlatform.ts';\nimport { createTaskErrorReporter, TASK_EVENT, toFailureReporter } from '../telemetry/logSinkTelemetry.ts';\n\ninterface SessionContextLike {\n hasUI: boolean;\n ui: Parameters<TaskOverlay['setUICtx']>[0];\n sessionManager?: { getSessionId(): string };\n}\n\nconst LEADER_SOURCE = '@agimon-ai/doompi-task';\nconst NARRATION_FAILED_EVENT = 'doom_task.narration_failed';\n/** Between doom-plan's 60 and the core help group's 70, so `t` sits after `p`. */\nconst LEADER_GROUP_ORDER = 65;\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_COMPACT_EVENT = 'session_compact';\nconst SESSION_TREE_EVENT = 'session_tree';\nconst TOOL_EXECUTION_END_EVENT = 'tool_execution_end';\n\n/** Install Task state and external resources into its host-owned Cordis plugin fiber. */\nexport function installTaskRuntime(cordis: Context, pi: ExtensionAPI): void {\n const errorReporter = createTaskErrorReporter();\n const report = toFailureReporter(errorReporter);\n let active = true;\n let sessionGeneration = 0;\n let narrationService: DoomNarrationService | undefined;\n let store: TaskStore | undefined;\n let delegation: DelegationManager | undefined;\n let overlay: TaskOverlay | undefined;\n let unwatch: (() => void) | undefined;\n let backgroundWork: BackgroundWorkProviderHandle | undefined;\n let backgroundWorkEnabled = false;\n let disposeLeader: (() => void) | undefined;\n let sessionId: string | undefined;\n let sessionInitialization:\n | {\n readonly sessionManager: object;\n readonly operation: Promise<void>;\n }\n | undefined;\n\n const reportNarrationFailure = (error: unknown): void => {\n void errorReporter.recordWarning(NARRATION_FAILED_EVENT, error).catch((telemetryError: unknown) => {\n process.emitWarning(`Doom-task could not record a narration failure: ${String(telemetryError)}`);\n });\n };\n const narrationSink: TaskNarrationSink = {\n narrate(text) {\n const service = narrationService;\n const request = createNarrationRequest(text);\n if (!service || !request) return;\n try {\n void Promise.resolve(service.request(request)).catch(reportNarrationFailure);\n } catch (error) {\n reportNarrationFailure(error);\n }\n },\n };\n\n cordis.inject([DOOM_NARRATION_SERVICE], (serviceContext) => {\n const service = requireDoomNarrationService(serviceContext);\n narrationService = service;\n return () => {\n if (narrationService === service) narrationService = undefined;\n };\n });\n\n const waitForSessionReadiness = async (\n context: { readonly sessionManager: object },\n signal?: AbortSignal,\n ): Promise<void> => {\n signal?.throwIfAborted();\n const current = sessionInitialization;\n if (!current) throw new Error('doom-task session initialization has not started');\n if (current.sessionManager !== context.sessionManager) {\n throw new Error('doom-task readiness belongs to a stale Pi session');\n }\n await current.operation;\n signal?.throwIfAborted();\n if (!active || current !== sessionInitialization || !sessionId) {\n throw new Error('doom-task readiness belongs to a stale extension generation');\n }\n };\n\n const clearSessionResources = (): void => {\n unwatch?.();\n unwatch = undefined;\n backgroundWorkEnabled = false;\n backgroundWork?.update();\n delegation?.reset();\n overlay?.dispose();\n sessionId = undefined;\n };\n\n cordis.effect(\n () => async () => {\n active = false;\n sessionGeneration += 1;\n const pendingInitialization = sessionInitialization?.operation;\n sessionInitialization = undefined;\n try {\n if (pendingInitialization) await Promise.allSettled([pendingInitialization]);\n clearSessionResources();\n delegation?.dispose();\n disposeLeader?.();\n disposeLeader = undefined;\n store?.dispose();\n } finally {\n await errorReporter.shutdown();\n }\n },\n LEADER_SOURCE,\n );\n\n const taskStore = new TaskStore({\n report,\n onCommitted: (previous, committed) => narrateTaskCommit(narrationSink, previous, committed),\n });\n store = taskStore;\n\n const refresh = (): void => {\n if (!active) return;\n overlay?.update();\n backgroundWork?.update();\n };\n\n const delegationManager = new DelegationManager({\n store: taskStore,\n cwd: process.cwd(),\n platform: createNodeDelegationPlatform(),\n notify: (message, options) => pi.sendMessage(message, options),\n getSessionId: () => sessionId,\n onChange: refresh,\n runTimeoutMs: getDelegationTimeoutMs(),\n report,\n onNotifyError: (error, taskId) => {\n void errorReporter.recordNotificationError(error, taskId);\n },\n });\n delegation = delegationManager;\n\n cordis.inject([DOOM_DELEGATION_SERVICE], (serviceContext) => {\n const service = readDoomDelegationService(serviceContext);\n if (!service) return undefined;\n return delegationManager.bind(serviceContext, service);\n });\n\n cordis.inject([DOOM_BACKGROUND_WORK_SERVICE], (serviceContext) => {\n const service = readDoomBackgroundWorkService(serviceContext);\n if (!service) return undefined;\n const handle = service.register({\n provider: BACKGROUND_WORK_PROVIDER,\n listActiveWork: () => (backgroundWorkEnabled ? delegationManager.listActiveWork() : []),\n });\n backgroundWork = handle;\n return () => {\n handle.dispose();\n if (backgroundWork === handle) backgroundWork = undefined;\n };\n });\n\n const taskOverlay = new TaskOverlay({ getTasks: () => taskStore.snapshot.tasks, delegation: delegationManager });\n overlay = taskOverlay;\n\n registerTaskTool(pi, {\n store: taskStore,\n delegation: delegationManager,\n maxTasks: getMaxTasks(),\n onChange: refresh,\n report,\n waitUntilReady: waitForSessionReadiness,\n });\n registerTasksCommand(pi, taskStore, waitForSessionReadiness);\n\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n const contribution = requireDoomUiHub(uiContext).registerLeader({\n source: LEADER_SOURCE,\n bindings: [\n {\n id: 'tasks.open',\n path: [\n { key: 't', label: 'tasks', order: LEADER_GROUP_ORDER },\n { key: 't', label: 'tasks' },\n ],\n command: { name: COMMAND_NAME },\n },\n ],\n });\n const dispose = (): void => contribution.dispose();\n disposeLeader = dispose;\n return () => {\n dispose();\n if (disposeLeader === dispose) disposeLeader = undefined;\n };\n });\n\n pi.registerMessageRenderer(NOTIFY_CUSTOM_TYPE, (message, _options, theme) => {\n const content = typeof message.content === 'string' ? message.content : '';\n return new Text(theme.fg('muted', content), 0, 0);\n });\n\n const collapseKey = resolveCollapseKey();\n if (collapseKey !== COLLAPSE_KEY_OFF) {\n pi.registerShortcut(collapseKey as KeyId, {\n description: 'Collapse or expand the task overlay',\n handler: async (ctx) => {\n if (!active || !ctx.hasUI) return;\n await waitForSessionReadiness(ctx);\n if (!active || !taskOverlay.isRegistered()) return;\n taskOverlay.toggleCollapse();\n },\n });\n }\n\n pi.on(SESSION_START_EVENT, async (_event, ctx) => {\n if (!active) return;\n const ownGeneration = ++sessionGeneration;\n if (sessionId !== undefined) clearSessionResources();\n const context = ctx as unknown as SessionContextLike;\n const initialize = async (signal?: AbortSignal): Promise<void> => {\n const isCurrent = (): boolean => !signal?.aborted && active && ownGeneration === sessionGeneration;\n try {\n const currentSessionId = context.sessionManager?.getSessionId();\n if (!currentSessionId) throw new Error('doom-task requires a session id');\n sessionId = currentSessionId;\n backgroundWorkEnabled = !context.hasUI;\n backgroundWork?.update();\n taskStore.configureSession(resolveSessionKey(currentSessionId));\n const cleanup = await removeLegacyStoreDirectoryAsync(taskStore.storePath);\n if (!isCurrent()) return;\n const sweep = hasStorePathOverride()\n ? { removed: [], errors: [] }\n : await sweepStoreFilesAsync(taskStore.storePath, getStoreTtlMs());\n if (!isCurrent()) return;\n const storeErrors = [...cleanup.errors, ...sweep.errors];\n for (const failure of storeErrors) report.warn(TASK_EVENT.storeSweepFailed, new Error(failure));\n if (storeErrors.length > 0 && context.hasUI) context.ui.notify(storeErrors.join('\\n'), 'warning');\n if (context.hasUI) taskOverlay.setUICtx(context.ui);\n await taskStore.readAsync(isCurrent);\n if (!isCurrent()) return;\n unwatch = taskStore.onExternalChange(refresh);\n await delegationManager.reconcile(isCurrent);\n if (!isCurrent()) return;\n refresh();\n } catch (error) {\n if (!isCurrent()) return;\n clearSessionResources();\n report.error(TASK_EVENT.sessionStartFailed, error);\n throw error;\n }\n };\n\n const coordinator = readDoomReadinessCoordinator(cordis);\n if (!coordinator) {\n const operation = initialize();\n sessionInitialization = { sessionManager: ctx.sessionManager, operation };\n return operation;\n }\n\n const previous = sessionInitialization?.operation;\n const operation = (async (): Promise<void> => {\n if (previous) await Promise.allSettled([previous]);\n if (!active || ownGeneration !== sessionGeneration) return;\n const handle = coordinator.start(\n LEADER_SOURCE,\n `${ctx.sessionManager.getSessionId()}:${ownGeneration}`,\n async (signal) => {\n await initialize(signal);\n return { value: undefined };\n },\n );\n await handle.wait();\n })();\n sessionInitialization = { sessionManager: ctx.sessionManager, operation };\n // Config's coordinator owns the single failure notification. This detached\n // observer only keeps a failed background generation from going unhandled.\n void Promise.allSettled([operation]);\n return undefined;\n });\n\n pi.on(SESSION_COMPACT_EVENT, refresh);\n pi.on(SESSION_TREE_EVENT, refresh);\n pi.on(TOOL_EXECUTION_END_EVENT, (event) => {\n if (active && event.toolName === TOOL_NAME) refresh();\n });\n}\n\n/** The package's single standard Pi factory. */\nexport async function taskExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, LEADER_SOURCE);\n const fiber = connection.root.plugin(taskPlugin, { pi });\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 let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\ninterface TaskPluginConfig {\n readonly pi: ExtensionAPI;\n}\n\nfunction taskPlugin(cordis: Context, config: TaskPluginConfig): void {\n installTaskRuntime(cordis, config.pi);\n}\n\nexport default taskExtension;\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import { Context } from "@deepseek-ai/cordis";
3
3
  //#region src/adapters/pi/extension.d.ts
4
- /** Install Task state and external resources into one package-local Cordis root. */
4
+ /** Install Task state and external resources into its host-owned Cordis plugin fiber. */
5
5
  declare function installTaskRuntime(cordis: Context, pi: ExtensionAPI): void;
6
6
  /** The package's single standard Pi factory. */
7
7
  declare function taskExtension(pi: ExtensionAPI): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAmDgB,mBAAmB,QAAQ,SAAS,IAAI;;iBA6KlC,cAAc,IAAI,eAAe"}
1
+ {"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBA0DgB,mBAAmB,QAAQ,SAAS,IAAI;;iBA4QlC,cAAc,IAAI,eAAe"}
@@ -1,7 +1,7 @@
1
- import { Context } from "@deepseek-ai/cordis";
2
1
  import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { Context } from "@deepseek-ai/cordis";
3
3
  //#region src/adapters/pi/extension.d.ts
4
- /** Install Task state and external resources into one package-local Cordis root. */
4
+ /** Install Task state and external resources into its host-owned Cordis plugin fiber. */
5
5
  declare function installTaskRuntime(cordis: Context, pi: ExtensionAPI): void;
6
6
  /** The package's single standard Pi factory. */
7
7
  declare function taskExtension(pi: ExtensionAPI): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAmDgB,mBAAmB,QAAQ,SAAS,IAAI;;iBA6KlC,cAAc,IAAI,eAAe"}
1
+ {"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBA0DgB,mBAAmB,QAAQ,SAAS,IAAI;;iBA4QlC,cAAc,IAAI,eAAe"}
@@ -1,3 +1,3 @@
1
- import{COMMAND_NAME as e}from"../../schemas/task.mjs";import{TASK_EVENT as t}from"../../types/telemetry.mjs";import{BACKGROUND_WORK_PROVIDER as n,DelegationManager as r,NOTIFY_CUSTOM_TYPE as i}from"../../services/delegation/manager.mjs";import{registerTasksCommand as a}from"../../commands/index.mjs";import{getDelegationTimeoutMs as o,getMaxTasks as s,getStoreTtlMs as c,resolveCollapseKey as l}from"../../types/config.mjs";import{registerTaskTool as u}from"../../commands/task/taskTool.mjs";import{narrateTaskCommit as d}from"../../services/narration/taskNarration.mjs";import{hasStorePathOverride as f,removeLegacyStoreDirectoryAsync as p,resolveSessionKey as m,sweepStoreFilesAsync as h}from"../store/paths.mjs";import{TaskStore as g}from"../store/taskStore.mjs";import{TaskOverlay as _}from"../../tui/taskOverlay2.mjs";import{createNodeDelegationPlatform as v}from"../node/delegationPlatform.mjs";import{createTaskErrorReporter as y,toFailureReporter as b}from"../telemetry/logSinkTelemetry.mjs";import{Text as x}from"@earendil-works/pi-tui";import{createProtocolRuntime as S}from"@agimon-ai/doompi-extension-contracts/protocol";import{registerBackgroundWorkProvider as C}from"@agimon-ai/doompi-extension-contracts/background-work";import{createNarrationRequester as w}from"@agimon-ai/doompi-extension-contracts/narration";import{registerDoomLeaderContribution as T}from"@agimon-ai/doompi-ui/leader";import{Context as E}from"@deepseek-ai/cordis";const D=`@agimon-ai/doompi-task`,O={narrate:()=>void 0};function k(E,k){let A=y(),j=b(A),M=!0,N=0,P=O,F,I,L,R,z,B,V,H=()=>{R?.(),R=void 0,z?.dispose(),z=void 0,I?.dispose(),L?.dispose(),P=O,V=void 0};E.effect(()=>async()=>{M=!1,N+=1;try{H(),B?.(),B=void 0,F?.dispose()}finally{await A.shutdown()}},D);let U=new g({report:j,onCommitted:(e,t)=>d(P,e,t)});F=U;let W=()=>{M&&(L?.update(),z?.update())},G=new r({events:k.events,store:U,cwd:process.cwd(),platform:v(),notify:(e,t)=>k.sendMessage(e,t),getSessionId:()=>V,onChange:W,runTimeoutMs:o(),report:j,onNotifyError:(e,t)=>{A.recordNotificationError(e,t)}});I=G;let K=new _({getTasks:()=>U.snapshot.tasks,delegation:G});L=K,u(k,{store:U,delegation:G,maxTasks:s(),onChange:W,report:j}),a(k,U),B=T(k,{source:D,bindings:[{id:`tasks.open`,path:[{key:`t`,label:`tasks`,order:65},{key:`t`,label:`tasks`}],command:{name:e}}]}),k.registerMessageRenderer(i,(e,t,n)=>{let r=typeof e.content==`string`?e.content:``;return new x(n.fg(`muted`,r),0,0)});let q=l();q!==`off`&&k.registerShortcut(q,{description:`Collapse or expand the task overlay`,handler:e=>{!M||!e.hasUI||!K.isRegistered()||K.toggleCollapse()}}),k.on(`session_start`,async(e,r)=>{if(!M)return;let i=++N;V!==void 0&&H();let a=()=>M&&i===N;try{let e=r,i=e.sessionManager?.getSessionId();if(!i)throw Error(`doom-task requires a session id`);V=i,P=w({bus:k.events,source:D,sessionId:i}),z=e.hasUI?void 0:C(S({bus:k.events,source:D,sessionId:i}),{provider:n,listActiveWork:()=>G.listActiveWork()}),U.configureSession(m(i));let o=await p(U.storePath);if(!a())return;let s=f()?{removed:[],errors:[]}:await h(U.storePath,c());if(!a())return;let l=[...o.errors,...s.errors];for(let e of l)j.warn(t.storeSweepFailed,Error(e));if(l.length>0&&e.hasUI&&e.ui.notify(l.join(`
2
- `),`warning`),e.hasUI&&K.setUICtx(e.ui),await U.readAsync(a),!a()||(R=U.onExternalChange(W),G.start(),await G.reconcile(a),!a()))return;W()}catch(e){if(!a())return;throw H(),j.error(t.sessionStartFailed,e),e}}),k.on(`session_compact`,W),k.on(`session_tree`,W),k.on(`tool_execution_end`,e=>{M&&e.toolName===`task`&&W()})}async function A(e){let t=new E,n,r=()=>(n??=t.fiber.dispose(),n);try{k(t,e)}catch(e){throw await r(),e}e.on(`session_shutdown`,r)}export{A as default,A as taskExtension,k as installTaskRuntime};
1
+ import{COMMAND_NAME as e}from"../../schemas/task.mjs";import{TASK_EVENT as t}from"../../types/telemetry.mjs";import{BACKGROUND_WORK_PROVIDER as n,DelegationManager as r,NOTIFY_CUSTOM_TYPE as i}from"../../services/delegation/manager.mjs";import{registerTasksCommand as a}from"../../commands/index.mjs";import{getDelegationTimeoutMs as o,getMaxTasks as s,getStoreTtlMs as c,resolveCollapseKey as l}from"../../types/config.mjs";import{registerTaskTool as u}from"../../commands/task/taskTool.mjs";import{narrateTaskCommit as d}from"../../services/narration/taskNarration.mjs";import{hasStorePathOverride as f,removeLegacyStoreDirectoryAsync as p,resolveSessionKey as m,sweepStoreFilesAsync as h}from"../store/paths.mjs";import{TaskStore as g}from"../store/taskStore.mjs";import{TaskOverlay as _}from"../../tui/taskOverlay2.mjs";import{createNodeDelegationPlatform as v}from"../node/delegationPlatform.mjs";import{createTaskErrorReporter as y,toFailureReporter as b}from"../telemetry/logSinkTelemetry.mjs";import{Text as x}from"@earendil-works/pi-tui";import{DOOM_DELEGATION_SERVICE as S,readDoomDelegationService as C}from"@agimon-ai/doompi-extension-contracts/delegation";import{DOOM_BACKGROUND_WORK_SERVICE as w,readDoomBackgroundWorkService as T}from"@agimon-ai/doompi-extension-contracts/background-work";import{connectDoomCordisHost as E}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{DOOM_NARRATION_SERVICE as D,createNarrationRequest as ee,requireDoomNarrationService as te}from"@agimon-ai/doompi-extension-contracts/narration";import{readDoomReadinessCoordinator as ne}from"@agimon-ai/doompi-extension-contracts/readiness";import{DOOM_UI_HUB_SERVICE as re,requireDoomUiHub as O}from"@agimon-ai/doompi-extension-contracts/ui-hub";const k=`@agimon-ai/doompi-task`;function A(E,A){let j=y(),M=b(j),N=!0,P=0,F,I,L,R,z,B,V=!1,H,U,W,G=e=>{j.recordWarning(`doom_task.narration_failed`,e).catch(e=>{process.emitWarning(`Doom-task could not record a narration failure: ${String(e)}`)})},K={narrate(e){let t=F,n=ee(e);if(!(!t||!n))try{Promise.resolve(t.request(n)).catch(G)}catch(e){G(e)}}};E.inject([D],e=>{let t=te(e);return F=t,()=>{F===t&&(F=void 0)}});let q=async(e,t)=>{t?.throwIfAborted();let n=W;if(!n)throw Error(`doom-task session initialization has not started`);if(n.sessionManager!==e.sessionManager)throw Error(`doom-task readiness belongs to a stale Pi session`);if(await n.operation,t?.throwIfAborted(),!N||n!==W||!U)throw Error(`doom-task readiness belongs to a stale extension generation`)},J=()=>{z?.(),z=void 0,V=!1,B?.update(),L?.reset(),R?.dispose(),U=void 0};E.effect(()=>async()=>{N=!1,P+=1;let e=W?.operation;W=void 0;try{e&&await Promise.allSettled([e]),J(),L?.dispose(),H?.(),H=void 0,I?.dispose()}finally{await j.shutdown()}},k);let Y=new g({report:M,onCommitted:(e,t)=>d(K,e,t)});I=Y;let X=()=>{N&&(R?.update(),B?.update())},Z=new r({store:Y,cwd:process.cwd(),platform:v(),notify:(e,t)=>A.sendMessage(e,t),getSessionId:()=>U,onChange:X,runTimeoutMs:o(),report:M,onNotifyError:(e,t)=>{j.recordNotificationError(e,t)}});L=Z,E.inject([S],e=>{let t=C(e);if(t)return Z.bind(e,t)}),E.inject([w],e=>{let t=T(e);if(!t)return;let r=t.register({provider:n,listActiveWork:()=>V?Z.listActiveWork():[]});return B=r,()=>{r.dispose(),B===r&&(B=void 0)}});let Q=new _({getTasks:()=>Y.snapshot.tasks,delegation:Z});R=Q,u(A,{store:Y,delegation:Z,maxTasks:s(),onChange:X,report:M,waitUntilReady:q}),a(A,Y,q),E.inject([re],t=>{let n=O(t).registerLeader({source:k,bindings:[{id:`tasks.open`,path:[{key:`t`,label:`tasks`,order:65},{key:`t`,label:`tasks`}],command:{name:e}}]}),r=()=>n.dispose();return H=r,()=>{r(),H===r&&(H=void 0)}}),A.registerMessageRenderer(i,(e,t,n)=>{let r=typeof e.content==`string`?e.content:``;return new x(n.fg(`muted`,r),0,0)});let $=l();$!==`off`&&A.registerShortcut($,{description:`Collapse or expand the task overlay`,handler:async e=>{!N||!e.hasUI||(await q(e),!(!N||!Q.isRegistered())&&Q.toggleCollapse())}}),A.on(`session_start`,async(e,n)=>{if(!N)return;let r=++P;U!==void 0&&J();let i=n,a=async e=>{let n=()=>!e?.aborted&&N&&r===P;try{let e=i.sessionManager?.getSessionId();if(!e)throw Error(`doom-task requires a session id`);U=e,V=!i.hasUI,B?.update(),Y.configureSession(m(e));let r=await p(Y.storePath);if(!n())return;let a=f()?{removed:[],errors:[]}:await h(Y.storePath,c());if(!n())return;let o=[...r.errors,...a.errors];for(let e of o)M.warn(t.storeSweepFailed,Error(e));if(o.length>0&&i.hasUI&&i.ui.notify(o.join(`
2
+ `),`warning`),i.hasUI&&Q.setUICtx(i.ui),await Y.readAsync(n),!n()||(z=Y.onExternalChange(X),await Z.reconcile(n),!n()))return;X()}catch(e){if(!n())return;throw J(),M.error(t.sessionStartFailed,e),e}},o=ne(E);if(!o){let e=a();return W={sessionManager:n.sessionManager,operation:e},e}let s=W?.operation,l=(async()=>{s&&await Promise.allSettled([s]),!(!N||r!==P)&&await o.start(k,`${n.sessionManager.getSessionId()}:${r}`,async e=>(await a(e),{value:void 0})).wait()})();W={sessionManager:n.sessionManager,operation:l},Promise.allSettled([l])}),A.on(`session_compact`,X),A.on(`session_tree`,X),A.on(`tool_execution_end`,e=>{N&&e.toolName===`task`&&X()})}async function j(e){let t=await E(e,k),n=t.root.plugin(M,{pi:e});try{await n}catch(e){try{await n.dispose()}finally{await t.dispose()}throw e}let r;e.on(`session_shutdown`,()=>r??=(async()=>{try{await n.dispose()}finally{await t.dispose()}})())}function M(e,t){A(e,t.pi)}export{j as default,j as taskExtension,A as installTaskRuntime};
3
3
  //# sourceMappingURL=extension.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import {\n type BackgroundWorkProviderHandle,\n registerBackgroundWorkProvider,\n} from '@agimon-ai/doompi-extension-contracts/background-work';\nimport { createNarrationRequester, type NarrationRequester } from '@agimon-ai/doompi-extension-contracts/narration';\nimport { createProtocolRuntime } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport { registerDoomLeaderContribution } from '@agimon-ai/doompi-ui/leader';\nimport { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport type { KeyId } from '@earendil-works/pi-tui';\nimport { Text } from '@earendil-works/pi-tui';\nimport { registerTasksCommand } from '../../commands/index.ts';\nimport { registerTaskTool } from '../../commands/task/taskTool.ts';\nimport { COMMAND_NAME, TOOL_NAME } from '../../schemas/task.ts';\nimport { BACKGROUND_WORK_PROVIDER, DelegationManager, NOTIFY_CUSTOM_TYPE } from '../../services/delegation/manager.ts';\nimport { narrateTaskCommit } from '../../services/narration/taskNarration.ts';\nimport {\n hasStorePathOverride,\n removeLegacyStoreDirectoryAsync,\n resolveSessionKey,\n sweepStoreFilesAsync,\n} from '../../adapters/store/paths';\nimport { TaskStore } from '../../adapters/store/taskStore';\nimport { TaskOverlay } from '../../tui/taskOverlay.ts';\nimport {\n COLLAPSE_KEY_OFF,\n getDelegationTimeoutMs,\n getMaxTasks,\n getStoreTtlMs,\n resolveCollapseKey,\n} from '../../types/config.ts';\nimport { createNodeDelegationPlatform } from '../node/delegationPlatform.ts';\nimport { createTaskErrorReporter, TASK_EVENT, toFailureReporter } from '../telemetry/logSinkTelemetry.ts';\n\ninterface SessionContextLike {\n hasUI: boolean;\n ui: Parameters<TaskOverlay['setUICtx']>[0];\n sessionManager?: { getSessionId(): string };\n}\n\nconst LEADER_SOURCE = '@agimon-ai/doompi-task';\nconst SILENT_NARRATION_REQUESTER: NarrationRequester = { narrate: () => undefined };\n/** Between doom-plan's 60 and the core help group's 70, so `t` sits after `p`. */\nconst LEADER_GROUP_ORDER = 65;\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_COMPACT_EVENT = 'session_compact';\nconst SESSION_TREE_EVENT = 'session_tree';\nconst TOOL_EXECUTION_END_EVENT = 'tool_execution_end';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\n\n/** Install Task state and external resources into one package-local Cordis root. */\nexport function installTaskRuntime(cordis: Context, pi: ExtensionAPI): void {\n const errorReporter = createTaskErrorReporter();\n const report = toFailureReporter(errorReporter);\n let active = true;\n let sessionGeneration = 0;\n let narrationRequester = SILENT_NARRATION_REQUESTER;\n let store: TaskStore | undefined;\n let delegation: DelegationManager | undefined;\n let overlay: TaskOverlay | undefined;\n let unwatch: (() => void) | undefined;\n let backgroundWork: BackgroundWorkProviderHandle | undefined;\n let disposeLeader: (() => void) | undefined;\n let sessionId: string | undefined;\n\n const clearSessionResources = (): void => {\n unwatch?.();\n unwatch = undefined;\n backgroundWork?.dispose();\n backgroundWork = undefined;\n delegation?.dispose();\n overlay?.dispose();\n narrationRequester = SILENT_NARRATION_REQUESTER;\n sessionId = undefined;\n };\n\n cordis.effect(\n () => async () => {\n active = false;\n sessionGeneration += 1;\n try {\n clearSessionResources();\n disposeLeader?.();\n disposeLeader = undefined;\n store?.dispose();\n } finally {\n await errorReporter.shutdown();\n }\n },\n LEADER_SOURCE,\n );\n\n const taskStore = new TaskStore({\n report,\n onCommitted: (previous, committed) => narrateTaskCommit(narrationRequester, previous, committed),\n });\n store = taskStore;\n\n const refresh = (): void => {\n if (!active) return;\n overlay?.update();\n backgroundWork?.update();\n };\n\n const delegationManager = new DelegationManager({\n events: pi.events,\n store: taskStore,\n cwd: process.cwd(),\n platform: createNodeDelegationPlatform(),\n notify: (message, options) => pi.sendMessage(message, options),\n getSessionId: () => sessionId,\n onChange: refresh,\n runTimeoutMs: getDelegationTimeoutMs(),\n report,\n onNotifyError: (error, taskId) => {\n void errorReporter.recordNotificationError(error, taskId);\n },\n });\n delegation = delegationManager;\n\n const taskOverlay = new TaskOverlay({ getTasks: () => taskStore.snapshot.tasks, delegation: delegationManager });\n overlay = taskOverlay;\n\n registerTaskTool(pi, {\n store: taskStore,\n delegation: delegationManager,\n maxTasks: getMaxTasks(),\n onChange: refresh,\n report,\n });\n registerTasksCommand(pi, taskStore);\n\n disposeLeader = registerDoomLeaderContribution(pi, {\n source: LEADER_SOURCE,\n bindings: [\n {\n id: 'tasks.open',\n path: [\n { key: 't', label: 'tasks', order: LEADER_GROUP_ORDER },\n { key: 't', label: 'tasks' },\n ],\n command: { name: COMMAND_NAME },\n },\n ],\n });\n\n pi.registerMessageRenderer(NOTIFY_CUSTOM_TYPE, (message, _options, theme) => {\n const content = typeof message.content === 'string' ? message.content : '';\n return new Text(theme.fg('muted', content), 0, 0);\n });\n\n const collapseKey = resolveCollapseKey();\n if (collapseKey !== COLLAPSE_KEY_OFF) {\n pi.registerShortcut(collapseKey as KeyId, {\n description: 'Collapse or expand the task overlay',\n handler: (ctx) => {\n if (!active || !ctx.hasUI || !taskOverlay.isRegistered()) return;\n taskOverlay.toggleCollapse();\n },\n });\n }\n\n pi.on(SESSION_START_EVENT, async (_event, ctx) => {\n if (!active) return;\n const ownGeneration = ++sessionGeneration;\n if (sessionId !== undefined) clearSessionResources();\n const isCurrent = (): boolean => active && ownGeneration === sessionGeneration;\n try {\n const context = ctx as unknown as SessionContextLike;\n const currentSessionId = context.sessionManager?.getSessionId();\n if (!currentSessionId) throw new Error('doom-task requires a session id');\n sessionId = currentSessionId;\n narrationRequester = createNarrationRequester({\n bus: pi.events,\n source: LEADER_SOURCE,\n sessionId: currentSessionId,\n });\n backgroundWork = context.hasUI\n ? undefined\n : registerBackgroundWorkProvider(\n createProtocolRuntime({\n bus: pi.events,\n source: LEADER_SOURCE,\n sessionId: currentSessionId,\n }),\n {\n provider: BACKGROUND_WORK_PROVIDER,\n listActiveWork: () => delegationManager.listActiveWork(),\n },\n );\n taskStore.configureSession(resolveSessionKey(currentSessionId));\n const cleanup = await removeLegacyStoreDirectoryAsync(taskStore.storePath);\n if (!isCurrent()) return;\n const sweep = hasStorePathOverride()\n ? { removed: [], errors: [] }\n : await sweepStoreFilesAsync(taskStore.storePath, getStoreTtlMs());\n if (!isCurrent()) return;\n const storeErrors = [...cleanup.errors, ...sweep.errors];\n for (const failure of storeErrors) report.warn(TASK_EVENT.storeSweepFailed, new Error(failure));\n if (storeErrors.length > 0 && context.hasUI) context.ui.notify(storeErrors.join('\\n'), 'warning');\n if (context.hasUI) taskOverlay.setUICtx(context.ui);\n await taskStore.readAsync(isCurrent);\n if (!isCurrent()) return;\n unwatch = taskStore.onExternalChange(refresh);\n delegationManager.start();\n await delegationManager.reconcile(isCurrent);\n if (!isCurrent()) return;\n refresh();\n } catch (error) {\n if (!isCurrent()) return;\n clearSessionResources();\n report.error(TASK_EVENT.sessionStartFailed, error);\n throw error;\n }\n });\n\n pi.on(SESSION_COMPACT_EVENT, refresh);\n pi.on(SESSION_TREE_EVENT, refresh);\n pi.on(TOOL_EXECUTION_END_EVENT, (event) => {\n if (active && event.toolName === TOOL_NAME) refresh();\n });\n}\n\n/** The package's single standard Pi factory. */\nexport async function taskExtension(pi: ExtensionAPI): Promise<void> {\n const cordis = new Context();\n let disposal: Promise<void> | undefined;\n const dispose = (): Promise<void> => {\n disposal ??= cordis.fiber.dispose();\n return disposal;\n };\n\n try {\n installTaskRuntime(cordis, pi);\n } catch (error) {\n await dispose();\n throw error;\n }\n\n pi.on(SESSION_SHUTDOWN_EVENT, dispose);\n}\n\nexport default taskExtension;\n"],"mappings":"26CAwCA,MAAM,EAAgB,yBAChB,EAAiD,CAAE,YAAe,IAAA,EAAU,EAUlF,SAAgB,EAAmB,EAAiB,EAAwB,CAC1E,IAAM,EAAgB,EAAwB,EACxC,EAAS,EAAkB,CAAa,EAC1C,EAAS,GACT,EAAoB,EACpB,EAAqB,EACrB,EACA,EACA,EACA,EACA,EACA,EACA,EAEE,MAAoC,CACxC,IAAU,EACV,EAAU,IAAA,GACV,GAAgB,QAAQ,EACxB,EAAiB,IAAA,GACjB,GAAY,QAAQ,EACpB,GAAS,QAAQ,EACjB,EAAqB,EACrB,EAAY,IAAA,EACd,EAEA,EAAO,WACC,SAAY,CAChB,EAAS,GACT,GAAqB,EACrB,GAAI,CACF,EAAsB,EACtB,IAAgB,EAChB,EAAgB,IAAA,GAChB,GAAO,QAAQ,CACjB,QAAU,CACR,MAAM,EAAc,SAAS,CAC/B,CACF,EACA,CACF,EAEA,IAAM,EAAY,IAAI,EAAU,CAC9B,SACA,aAAc,EAAU,IAAc,EAAkB,EAAoB,EAAU,CAAS,CACjG,CAAC,EACD,EAAQ,EAER,IAAM,MAAsB,CACrB,IACL,GAAS,OAAO,EAChB,GAAgB,OAAO,EACzB,EAEM,EAAoB,IAAI,EAAkB,CAC9C,OAAQ,EAAG,OACX,MAAO,EACP,IAAK,QAAQ,IAAI,EACjB,SAAU,EAA6B,EACvC,QAAS,EAAS,IAAY,EAAG,YAAY,EAAS,CAAO,EAC7D,iBAAoB,EACpB,SAAU,EACV,aAAc,EAAuB,EACrC,SACA,eAAgB,EAAO,IAAW,CAChC,EAAmB,wBAAwB,EAAO,CAAM,CAC1D,CACF,CAAC,EACD,EAAa,EAEb,IAAM,EAAc,IAAI,EAAY,CAAE,aAAgB,EAAU,SAAS,MAAO,WAAY,CAAkB,CAAC,EAC/G,EAAU,EAEV,EAAiB,EAAI,CACnB,MAAO,EACP,WAAY,EACZ,SAAU,EAAY,EACtB,SAAU,EACV,QACF,CAAC,EACD,EAAqB,EAAI,CAAS,EAElC,EAAgB,EAA+B,EAAI,CACjD,OAAQ,EACR,SAAU,CACR,CACE,GAAI,aACJ,KAAM,CACJ,CAAE,IAAK,IAAK,MAAO,QAAS,MAAO,EAAmB,EACtD,CAAE,IAAK,IAAK,MAAO,OAAQ,CAC7B,EACA,QAAS,CAAE,KAAM,CAAa,CAChC,CACF,CACF,CAAC,EAED,EAAG,wBAAwB,GAAqB,EAAS,EAAU,IAAU,CAC3E,IAAM,EAAU,OAAO,EAAQ,SAAY,SAAW,EAAQ,QAAU,GACxE,OAAO,IAAI,EAAK,EAAM,GAAG,QAAS,CAAO,EAAG,EAAG,CAAC,CAClD,CAAC,EAED,IAAM,EAAc,EAAmB,EACnC,IAAA,OACF,EAAG,iBAAiB,EAAsB,CACxC,YAAa,sCACb,QAAU,GAAQ,CACZ,CAAC,GAAU,CAAC,EAAI,OAAS,CAAC,EAAY,aAAa,GACvD,EAAY,eAAe,CAC7B,CACF,CAAC,EAGH,EAAG,GAAG,gBAAqB,MAAO,EAAQ,IAAQ,CAChD,GAAI,CAAC,EAAQ,OACb,IAAM,EAAgB,EAAE,EACpB,IAAc,IAAA,IAAW,EAAsB,EACnD,IAAM,MAA2B,GAAU,IAAkB,EAC7D,GAAI,CACF,IAAM,EAAU,EACV,EAAmB,EAAQ,gBAAgB,aAAa,EAC9D,GAAI,CAAC,EAAkB,MAAU,MAAM,iCAAiC,EACxE,EAAY,EACZ,EAAqB,EAAyB,CAC5C,IAAK,EAAG,OACR,OAAQ,EACR,UAAW,CACb,CAAC,EACD,EAAiB,EAAQ,MACrB,IAAA,GACA,EACE,EAAsB,CACpB,IAAK,EAAG,OACR,OAAQ,EACR,UAAW,CACb,CAAC,EACD,CACE,SAAU,EACV,mBAAsB,EAAkB,eAAe,CACzD,CACF,EACJ,EAAU,iBAAiB,EAAkB,CAAgB,CAAC,EAC9D,IAAM,EAAU,MAAM,EAAgC,EAAU,SAAS,EACzE,GAAI,CAAC,EAAU,EAAG,OAClB,IAAM,EAAQ,EAAqB,EAC/B,CAAE,QAAS,CAAC,EAAG,OAAQ,CAAC,CAAE,EAC1B,MAAM,EAAqB,EAAU,UAAW,EAAc,CAAC,EACnE,GAAI,CAAC,EAAU,EAAG,OAClB,IAAM,EAAc,CAAC,GAAG,EAAQ,OAAQ,GAAG,EAAM,MAAM,EACvD,IAAK,IAAM,KAAW,EAAa,EAAO,KAAK,EAAW,iBAAsB,MAAM,CAAO,CAAC,EAQ9F,GAPI,EAAY,OAAS,GAAK,EAAQ,OAAO,EAAQ,GAAG,OAAO,EAAY,KAAK;CAAI,EAAG,SAAS,EAC5F,EAAQ,OAAO,EAAY,SAAS,EAAQ,EAAE,EAClD,MAAM,EAAU,UAAU,CAAS,EAC/B,CAAC,EAAU,IACf,EAAU,EAAU,iBAAiB,CAAO,EAC5C,EAAkB,MAAM,EACxB,MAAM,EAAkB,UAAU,CAAS,EACvC,CAAC,EAAU,GAAG,OAClB,EAAQ,CACV,OAAS,EAAO,CACd,GAAI,CAAC,EAAU,EAAG,OAGlB,MAFA,EAAsB,EACtB,EAAO,MAAM,EAAW,mBAAoB,CAAK,EAC3C,CACR,CACF,CAAC,EAED,EAAG,GAAG,kBAAuB,CAAO,EACpC,EAAG,GAAG,eAAoB,CAAO,EACjC,EAAG,GAAG,qBAA2B,GAAU,CACrC,GAAU,EAAM,WAAA,QAAwB,EAAQ,CACtD,CAAC,CACH,CAGA,eAAsB,EAAc,EAAiC,CACnE,IAAM,EAAS,IAAI,EACf,EACE,OACJ,IAAa,EAAO,MAAM,QAAQ,EAC3B,GAGT,GAAI,CACF,EAAmB,EAAQ,CAAE,CAC/B,OAAS,EAAO,CAEd,MADA,MAAM,EAAQ,EACR,CACR,CAEA,EAAG,GAAG,mBAAwB,CAAO,CACvC"}
1
+ {"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import {\n DOOM_BACKGROUND_WORK_SERVICE,\n type BackgroundWorkProviderHandle,\n readDoomBackgroundWorkService,\n} from '@agimon-ai/doompi-extension-contracts/background-work';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_DELEGATION_SERVICE, readDoomDelegationService } from '@agimon-ai/doompi-extension-contracts/delegation';\nimport {\n createNarrationRequest,\n DOOM_NARRATION_SERVICE,\n type DoomNarrationService,\n requireDoomNarrationService,\n} from '@agimon-ai/doompi-extension-contracts/narration';\nimport { readDoomReadinessCoordinator } from '@agimon-ai/doompi-extension-contracts/readiness';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport type { KeyId } from '@earendil-works/pi-tui';\nimport { Text } from '@earendil-works/pi-tui';\nimport { registerTasksCommand } from '../../commands/index.ts';\nimport { registerTaskTool } from '../../commands/task/taskTool.ts';\nimport { COMMAND_NAME, TOOL_NAME } from '../../schemas/task.ts';\nimport { BACKGROUND_WORK_PROVIDER, DelegationManager, NOTIFY_CUSTOM_TYPE } from '../../services/delegation/manager.ts';\nimport { narrateTaskCommit, type TaskNarrationSink } from '../../services/narration/taskNarration.ts';\nimport {\n hasStorePathOverride,\n removeLegacyStoreDirectoryAsync,\n resolveSessionKey,\n sweepStoreFilesAsync,\n} from '../../adapters/store/paths';\nimport { TaskStore } from '../../adapters/store/taskStore';\nimport { TaskOverlay } from '../../tui/taskOverlay.ts';\nimport {\n COLLAPSE_KEY_OFF,\n getDelegationTimeoutMs,\n getMaxTasks,\n getStoreTtlMs,\n resolveCollapseKey,\n} from '../../types/config.ts';\nimport { createNodeDelegationPlatform } from '../node/delegationPlatform.ts';\nimport { createTaskErrorReporter, TASK_EVENT, toFailureReporter } from '../telemetry/logSinkTelemetry.ts';\n\ninterface SessionContextLike {\n hasUI: boolean;\n ui: Parameters<TaskOverlay['setUICtx']>[0];\n sessionManager?: { getSessionId(): string };\n}\n\nconst LEADER_SOURCE = '@agimon-ai/doompi-task';\nconst NARRATION_FAILED_EVENT = 'doom_task.narration_failed';\n/** Between doom-plan's 60 and the core help group's 70, so `t` sits after `p`. */\nconst LEADER_GROUP_ORDER = 65;\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_COMPACT_EVENT = 'session_compact';\nconst SESSION_TREE_EVENT = 'session_tree';\nconst TOOL_EXECUTION_END_EVENT = 'tool_execution_end';\n\n/** Install Task state and external resources into its host-owned Cordis plugin fiber. */\nexport function installTaskRuntime(cordis: Context, pi: ExtensionAPI): void {\n const errorReporter = createTaskErrorReporter();\n const report = toFailureReporter(errorReporter);\n let active = true;\n let sessionGeneration = 0;\n let narrationService: DoomNarrationService | undefined;\n let store: TaskStore | undefined;\n let delegation: DelegationManager | undefined;\n let overlay: TaskOverlay | undefined;\n let unwatch: (() => void) | undefined;\n let backgroundWork: BackgroundWorkProviderHandle | undefined;\n let backgroundWorkEnabled = false;\n let disposeLeader: (() => void) | undefined;\n let sessionId: string | undefined;\n let sessionInitialization:\n | {\n readonly sessionManager: object;\n readonly operation: Promise<void>;\n }\n | undefined;\n\n const reportNarrationFailure = (error: unknown): void => {\n void errorReporter.recordWarning(NARRATION_FAILED_EVENT, error).catch((telemetryError: unknown) => {\n process.emitWarning(`Doom-task could not record a narration failure: ${String(telemetryError)}`);\n });\n };\n const narrationSink: TaskNarrationSink = {\n narrate(text) {\n const service = narrationService;\n const request = createNarrationRequest(text);\n if (!service || !request) return;\n try {\n void Promise.resolve(service.request(request)).catch(reportNarrationFailure);\n } catch (error) {\n reportNarrationFailure(error);\n }\n },\n };\n\n cordis.inject([DOOM_NARRATION_SERVICE], (serviceContext) => {\n const service = requireDoomNarrationService(serviceContext);\n narrationService = service;\n return () => {\n if (narrationService === service) narrationService = undefined;\n };\n });\n\n const waitForSessionReadiness = async (\n context: { readonly sessionManager: object },\n signal?: AbortSignal,\n ): Promise<void> => {\n signal?.throwIfAborted();\n const current = sessionInitialization;\n if (!current) throw new Error('doom-task session initialization has not started');\n if (current.sessionManager !== context.sessionManager) {\n throw new Error('doom-task readiness belongs to a stale Pi session');\n }\n await current.operation;\n signal?.throwIfAborted();\n if (!active || current !== sessionInitialization || !sessionId) {\n throw new Error('doom-task readiness belongs to a stale extension generation');\n }\n };\n\n const clearSessionResources = (): void => {\n unwatch?.();\n unwatch = undefined;\n backgroundWorkEnabled = false;\n backgroundWork?.update();\n delegation?.reset();\n overlay?.dispose();\n sessionId = undefined;\n };\n\n cordis.effect(\n () => async () => {\n active = false;\n sessionGeneration += 1;\n const pendingInitialization = sessionInitialization?.operation;\n sessionInitialization = undefined;\n try {\n if (pendingInitialization) await Promise.allSettled([pendingInitialization]);\n clearSessionResources();\n delegation?.dispose();\n disposeLeader?.();\n disposeLeader = undefined;\n store?.dispose();\n } finally {\n await errorReporter.shutdown();\n }\n },\n LEADER_SOURCE,\n );\n\n const taskStore = new TaskStore({\n report,\n onCommitted: (previous, committed) => narrateTaskCommit(narrationSink, previous, committed),\n });\n store = taskStore;\n\n const refresh = (): void => {\n if (!active) return;\n overlay?.update();\n backgroundWork?.update();\n };\n\n const delegationManager = new DelegationManager({\n store: taskStore,\n cwd: process.cwd(),\n platform: createNodeDelegationPlatform(),\n notify: (message, options) => pi.sendMessage(message, options),\n getSessionId: () => sessionId,\n onChange: refresh,\n runTimeoutMs: getDelegationTimeoutMs(),\n report,\n onNotifyError: (error, taskId) => {\n void errorReporter.recordNotificationError(error, taskId);\n },\n });\n delegation = delegationManager;\n\n cordis.inject([DOOM_DELEGATION_SERVICE], (serviceContext) => {\n const service = readDoomDelegationService(serviceContext);\n if (!service) return undefined;\n return delegationManager.bind(serviceContext, service);\n });\n\n cordis.inject([DOOM_BACKGROUND_WORK_SERVICE], (serviceContext) => {\n const service = readDoomBackgroundWorkService(serviceContext);\n if (!service) return undefined;\n const handle = service.register({\n provider: BACKGROUND_WORK_PROVIDER,\n listActiveWork: () => (backgroundWorkEnabled ? delegationManager.listActiveWork() : []),\n });\n backgroundWork = handle;\n return () => {\n handle.dispose();\n if (backgroundWork === handle) backgroundWork = undefined;\n };\n });\n\n const taskOverlay = new TaskOverlay({ getTasks: () => taskStore.snapshot.tasks, delegation: delegationManager });\n overlay = taskOverlay;\n\n registerTaskTool(pi, {\n store: taskStore,\n delegation: delegationManager,\n maxTasks: getMaxTasks(),\n onChange: refresh,\n report,\n waitUntilReady: waitForSessionReadiness,\n });\n registerTasksCommand(pi, taskStore, waitForSessionReadiness);\n\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n const contribution = requireDoomUiHub(uiContext).registerLeader({\n source: LEADER_SOURCE,\n bindings: [\n {\n id: 'tasks.open',\n path: [\n { key: 't', label: 'tasks', order: LEADER_GROUP_ORDER },\n { key: 't', label: 'tasks' },\n ],\n command: { name: COMMAND_NAME },\n },\n ],\n });\n const dispose = (): void => contribution.dispose();\n disposeLeader = dispose;\n return () => {\n dispose();\n if (disposeLeader === dispose) disposeLeader = undefined;\n };\n });\n\n pi.registerMessageRenderer(NOTIFY_CUSTOM_TYPE, (message, _options, theme) => {\n const content = typeof message.content === 'string' ? message.content : '';\n return new Text(theme.fg('muted', content), 0, 0);\n });\n\n const collapseKey = resolveCollapseKey();\n if (collapseKey !== COLLAPSE_KEY_OFF) {\n pi.registerShortcut(collapseKey as KeyId, {\n description: 'Collapse or expand the task overlay',\n handler: async (ctx) => {\n if (!active || !ctx.hasUI) return;\n await waitForSessionReadiness(ctx);\n if (!active || !taskOverlay.isRegistered()) return;\n taskOverlay.toggleCollapse();\n },\n });\n }\n\n pi.on(SESSION_START_EVENT, async (_event, ctx) => {\n if (!active) return;\n const ownGeneration = ++sessionGeneration;\n if (sessionId !== undefined) clearSessionResources();\n const context = ctx as unknown as SessionContextLike;\n const initialize = async (signal?: AbortSignal): Promise<void> => {\n const isCurrent = (): boolean => !signal?.aborted && active && ownGeneration === sessionGeneration;\n try {\n const currentSessionId = context.sessionManager?.getSessionId();\n if (!currentSessionId) throw new Error('doom-task requires a session id');\n sessionId = currentSessionId;\n backgroundWorkEnabled = !context.hasUI;\n backgroundWork?.update();\n taskStore.configureSession(resolveSessionKey(currentSessionId));\n const cleanup = await removeLegacyStoreDirectoryAsync(taskStore.storePath);\n if (!isCurrent()) return;\n const sweep = hasStorePathOverride()\n ? { removed: [], errors: [] }\n : await sweepStoreFilesAsync(taskStore.storePath, getStoreTtlMs());\n if (!isCurrent()) return;\n const storeErrors = [...cleanup.errors, ...sweep.errors];\n for (const failure of storeErrors) report.warn(TASK_EVENT.storeSweepFailed, new Error(failure));\n if (storeErrors.length > 0 && context.hasUI) context.ui.notify(storeErrors.join('\\n'), 'warning');\n if (context.hasUI) taskOverlay.setUICtx(context.ui);\n await taskStore.readAsync(isCurrent);\n if (!isCurrent()) return;\n unwatch = taskStore.onExternalChange(refresh);\n await delegationManager.reconcile(isCurrent);\n if (!isCurrent()) return;\n refresh();\n } catch (error) {\n if (!isCurrent()) return;\n clearSessionResources();\n report.error(TASK_EVENT.sessionStartFailed, error);\n throw error;\n }\n };\n\n const coordinator = readDoomReadinessCoordinator(cordis);\n if (!coordinator) {\n const operation = initialize();\n sessionInitialization = { sessionManager: ctx.sessionManager, operation };\n return operation;\n }\n\n const previous = sessionInitialization?.operation;\n const operation = (async (): Promise<void> => {\n if (previous) await Promise.allSettled([previous]);\n if (!active || ownGeneration !== sessionGeneration) return;\n const handle = coordinator.start(\n LEADER_SOURCE,\n `${ctx.sessionManager.getSessionId()}:${ownGeneration}`,\n async (signal) => {\n await initialize(signal);\n return { value: undefined };\n },\n );\n await handle.wait();\n })();\n sessionInitialization = { sessionManager: ctx.sessionManager, operation };\n // Config's coordinator owns the single failure notification. This detached\n // observer only keeps a failed background generation from going unhandled.\n void Promise.allSettled([operation]);\n return undefined;\n });\n\n pi.on(SESSION_COMPACT_EVENT, refresh);\n pi.on(SESSION_TREE_EVENT, refresh);\n pi.on(TOOL_EXECUTION_END_EVENT, (event) => {\n if (active && event.toolName === TOOL_NAME) refresh();\n });\n}\n\n/** The package's single standard Pi factory. */\nexport async function taskExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, LEADER_SOURCE);\n const fiber = connection.root.plugin(taskPlugin, { pi });\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 let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\ninterface TaskPluginConfig {\n readonly pi: ExtensionAPI;\n}\n\nfunction taskPlugin(cordis: Context, config: TaskPluginConfig): void {\n installTaskRuntime(cordis, config.pi);\n}\n\nexport default taskExtension;\n"],"mappings":"qtDAgDA,MAAM,EAAgB,yBAUtB,SAAgB,EAAmB,EAAiB,EAAwB,CAC1E,IAAM,EAAgB,EAAwB,EACxC,EAAS,EAAkB,CAAa,EAC1C,EAAS,GACT,EAAoB,EACpB,EACA,EACA,EACA,EACA,EACA,EACA,EAAwB,GACxB,EACA,EACA,EAOE,EAA0B,GAAyB,CACvD,EAAmB,cAAc,6BAAwB,CAAK,CAAC,CAAC,MAAO,GAA4B,CACjG,QAAQ,YAAY,mDAAmD,OAAO,CAAc,GAAG,CACjG,CAAC,CACH,EACM,EAAmC,CACvC,QAAQ,EAAM,CACZ,IAAM,EAAU,EACV,EAAU,GAAuB,CAAI,EACvC,MAAC,GAAW,CAAC,GACjB,GAAI,CACF,QAAa,QAAQ,EAAQ,QAAQ,CAAO,CAAC,CAAC,CAAC,MAAM,CAAsB,CAC7E,OAAS,EAAO,CACd,EAAuB,CAAK,CAC9B,CACF,CACF,EAEA,EAAO,OAAO,CAAC,CAAsB,EAAI,GAAmB,CAC1D,IAAM,EAAU,GAA4B,CAAc,EAE1D,MADA,GAAmB,MACN,CACP,IAAqB,IAAS,EAAmB,IAAA,GACvD,CACF,CAAC,EAED,IAAM,EAA0B,MAC9B,EACA,IACkB,CAClB,GAAQ,eAAe,EACvB,IAAM,EAAU,EAChB,GAAI,CAAC,EAAS,MAAU,MAAM,kDAAkD,EAChF,GAAI,EAAQ,iBAAmB,EAAQ,eACrC,MAAU,MAAM,mDAAmD,EAIrE,GAFA,MAAM,EAAQ,UACd,GAAQ,eAAe,EACnB,CAAC,GAAU,IAAY,GAAyB,CAAC,EACnD,MAAU,MAAM,6DAA6D,CAEjF,EAEM,MAAoC,CACxC,IAAU,EACV,EAAU,IAAA,GACV,EAAwB,GACxB,GAAgB,OAAO,EACvB,GAAY,MAAM,EAClB,GAAS,QAAQ,EACjB,EAAY,IAAA,EACd,EAEA,EAAO,WACC,SAAY,CAChB,EAAS,GACT,GAAqB,EACrB,IAAM,EAAwB,GAAuB,UACrD,EAAwB,IAAA,GACxB,GAAI,CACE,GAAuB,MAAM,QAAQ,WAAW,CAAC,CAAqB,CAAC,EAC3E,EAAsB,EACtB,GAAY,QAAQ,EACpB,IAAgB,EAChB,EAAgB,IAAA,GAChB,GAAO,QAAQ,CACjB,QAAU,CACR,MAAM,EAAc,SAAS,CAC/B,CACF,EACA,CACF,EAEA,IAAM,EAAY,IAAI,EAAU,CAC9B,SACA,aAAc,EAAU,IAAc,EAAkB,EAAe,EAAU,CAAS,CAC5F,CAAC,EACD,EAAQ,EAER,IAAM,MAAsB,CACrB,IACL,GAAS,OAAO,EAChB,GAAgB,OAAO,EACzB,EAEM,EAAoB,IAAI,EAAkB,CAC9C,MAAO,EACP,IAAK,QAAQ,IAAI,EACjB,SAAU,EAA6B,EACvC,QAAS,EAAS,IAAY,EAAG,YAAY,EAAS,CAAO,EAC7D,iBAAoB,EACpB,SAAU,EACV,aAAc,EAAuB,EACrC,SACA,eAAgB,EAAO,IAAW,CAChC,EAAmB,wBAAwB,EAAO,CAAM,CAC1D,CACF,CAAC,EACD,EAAa,EAEb,EAAO,OAAO,CAAC,CAAuB,EAAI,GAAmB,CAC3D,IAAM,EAAU,EAA0B,CAAc,EACnD,KACL,OAAO,EAAkB,KAAK,EAAgB,CAAO,CACvD,CAAC,EAED,EAAO,OAAO,CAAC,CAA4B,EAAI,GAAmB,CAChE,IAAM,EAAU,EAA8B,CAAc,EAC5D,GAAI,CAAC,EAAS,OACd,IAAM,EAAS,EAAQ,SAAS,CAC9B,SAAU,EACV,mBAAuB,EAAwB,EAAkB,eAAe,EAAI,CAAC,CACvF,CAAC,EAED,MADA,GAAiB,MACJ,CACX,EAAO,QAAQ,EACX,IAAmB,IAAQ,EAAiB,IAAA,GAClD,CACF,CAAC,EAED,IAAM,EAAc,IAAI,EAAY,CAAE,aAAgB,EAAU,SAAS,MAAO,WAAY,CAAkB,CAAC,EAC/G,EAAU,EAEV,EAAiB,EAAI,CACnB,MAAO,EACP,WAAY,EACZ,SAAU,EAAY,EACtB,SAAU,EACV,SACA,eAAgB,CAClB,CAAC,EACD,EAAqB,EAAI,EAAW,CAAuB,EAE3D,EAAO,OAAO,CAAC,EAAmB,EAAI,GAAc,CAClD,IAAM,EAAe,EAAiB,CAAS,CAAC,CAAC,eAAe,CAC9D,OAAQ,EACR,SAAU,CACR,CACE,GAAI,aACJ,KAAM,CACJ,CAAE,IAAK,IAAK,MAAO,QAAS,MAAO,EAAmB,EACtD,CAAE,IAAK,IAAK,MAAO,OAAQ,CAC7B,EACA,QAAS,CAAE,KAAM,CAAa,CAChC,CACF,CACF,CAAC,EACK,MAAsB,EAAa,QAAQ,EAEjD,MADA,GAAgB,MACH,CACX,EAAQ,EACJ,IAAkB,IAAS,EAAgB,IAAA,GACjD,CACF,CAAC,EAED,EAAG,wBAAwB,GAAqB,EAAS,EAAU,IAAU,CAC3E,IAAM,EAAU,OAAO,EAAQ,SAAY,SAAW,EAAQ,QAAU,GACxE,OAAO,IAAI,EAAK,EAAM,GAAG,QAAS,CAAO,EAAG,EAAG,CAAC,CAClD,CAAC,EAED,IAAM,EAAc,EAAmB,EACnC,IAAA,OACF,EAAG,iBAAiB,EAAsB,CACxC,YAAa,sCACb,QAAS,KAAO,IAAQ,CAClB,CAAC,GAAU,CAAC,EAAI,QACpB,MAAM,EAAwB,CAAG,EAC7B,GAAC,GAAU,CAAC,EAAY,aAAa,IACzC,EAAY,eAAe,EAC7B,CACF,CAAC,EAGH,EAAG,GAAG,gBAAqB,MAAO,EAAQ,IAAQ,CAChD,GAAI,CAAC,EAAQ,OACb,IAAM,EAAgB,EAAE,EACpB,IAAc,IAAA,IAAW,EAAsB,EACnD,IAAM,EAAU,EACV,EAAa,KAAO,IAAwC,CAChE,IAAM,MAA2B,CAAC,GAAQ,SAAW,GAAU,IAAkB,EACjF,GAAI,CACF,IAAM,EAAmB,EAAQ,gBAAgB,aAAa,EAC9D,GAAI,CAAC,EAAkB,MAAU,MAAM,iCAAiC,EACxE,EAAY,EACZ,EAAwB,CAAC,EAAQ,MACjC,GAAgB,OAAO,EACvB,EAAU,iBAAiB,EAAkB,CAAgB,CAAC,EAC9D,IAAM,EAAU,MAAM,EAAgC,EAAU,SAAS,EACzE,GAAI,CAAC,EAAU,EAAG,OAClB,IAAM,EAAQ,EAAqB,EAC/B,CAAE,QAAS,CAAC,EAAG,OAAQ,CAAC,CAAE,EAC1B,MAAM,EAAqB,EAAU,UAAW,EAAc,CAAC,EACnE,GAAI,CAAC,EAAU,EAAG,OAClB,IAAM,EAAc,CAAC,GAAG,EAAQ,OAAQ,GAAG,EAAM,MAAM,EACvD,IAAK,IAAM,KAAW,EAAa,EAAO,KAAK,EAAW,iBAAsB,MAAM,CAAO,CAAC,EAO9F,GANI,EAAY,OAAS,GAAK,EAAQ,OAAO,EAAQ,GAAG,OAAO,EAAY,KAAK;CAAI,EAAG,SAAS,EAC5F,EAAQ,OAAO,EAAY,SAAS,EAAQ,EAAE,EAClD,MAAM,EAAU,UAAU,CAAS,EAC/B,CAAC,EAAU,IACf,EAAU,EAAU,iBAAiB,CAAO,EAC5C,MAAM,EAAkB,UAAU,CAAS,EACvC,CAAC,EAAU,GAAG,OAClB,EAAQ,CACV,OAAS,EAAO,CACd,GAAI,CAAC,EAAU,EAAG,OAGlB,MAFA,EAAsB,EACtB,EAAO,MAAM,EAAW,mBAAoB,CAAK,EAC3C,CACR,CACF,EAEM,EAAc,GAA6B,CAAM,EACvD,GAAI,CAAC,EAAa,CAChB,IAAM,EAAY,EAAW,EAE7B,MADA,GAAwB,CAAE,eAAgB,EAAI,eAAgB,WAAU,EACjE,CACT,CAEA,IAAM,EAAW,GAAuB,UAClC,GAAa,SAA2B,CACxC,GAAU,MAAM,QAAQ,WAAW,CAAC,CAAQ,CAAC,EAC7C,GAAC,GAAU,IAAkB,IASjC,MARe,EAAY,MACzB,EACA,GAAG,EAAI,eAAe,aAAa,EAAE,GAAG,IACxC,KAAO,KACL,MAAM,EAAW,CAAM,EAChB,CAAE,MAAO,IAAA,EAAU,EAGnB,CAAC,CAAC,KAAK,CACpB,EAAA,CAAG,EACH,EAAwB,CAAE,eAAgB,EAAI,eAAgB,WAAU,EAGxE,QAAa,WAAW,CAAC,CAAS,CAAC,CAErC,CAAC,EAED,EAAG,GAAG,kBAAuB,CAAO,EACpC,EAAG,GAAG,eAAoB,CAAO,EACjC,EAAG,GAAG,qBAA2B,GAAU,CACrC,GAAU,EAAM,WAAA,QAAwB,EAAQ,CACtD,CAAC,CACH,CAGA,eAAsB,EAAc,EAAiC,CACnE,IAAM,EAAa,MAAM,EAAsB,EAAI,CAAa,EAC1D,EAAQ,EAAW,KAAK,OAAO,EAAY,CAAE,IAAG,CAAC,EACvD,GAAI,CACF,MAAM,CACR,OAAS,EAAO,CACd,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACA,MAAM,CACR,CACA,IAAI,EACJ,EAAG,GACD,uBAEG,KAAc,SAAY,CACzB,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACF,EAAA,CAAG,CACP,CACF,CAMA,SAAS,EAAW,EAAiB,EAAgC,CACnE,EAAmB,EAAQ,EAAO,EAAE,CACtC"}
@@ -1,2 +1,2 @@
1
- const e=require("../schemas/task.cjs"),t=require("../tui/taskSpace2.cjs");function n(n,r){n.registerCommand(e.COMMAND_NAME,{description:`Open Task Space for this session tree`,handler:async(n,i)=>{if(!i.hasUI){i.ui.notify(e.ERR_REQUIRES_INTERACTIVE,`error`);return}r.read(),await t.openTaskSpace(i,{store:r})}})}exports.registerTasksCommand=n;
1
+ const e=require("../schemas/task.cjs"),t=require("../tui/taskSpace2.cjs");function n(n,r,i){n.registerCommand(e.COMMAND_NAME,{description:`Open Task Space for this session tree`,handler:async(n,a)=>{if(!a.hasUI){a.ui.notify(e.ERR_REQUIRES_INTERACTIVE,`error`);return}await i?.(a),r.read(),await t.openTaskSpace(a,{store:r})}})}exports.registerTasksCommand=n;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["COMMAND_NAME","ERR_REQUIRES_INTERACTIVE","openTaskSpace"],"sources":["../../src/commands/index.ts"],"sourcesContent":["import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { COMMAND_NAME, ERR_REQUIRES_INTERACTIVE } from '../schemas/task.ts';\nimport type { TaskStore } from '../adapters/store/taskStore';\nimport { openTaskSpace } from '../tui/taskSpace.ts';\n\n/**\n * `/tasks`, reachable from the leader palette as `SPC t t`.\n *\n * The command opens the Task Space overlay rather than printing a listing: the\n * overlay is the readable surface and it can edit, while a transcript dump could\n * only be read.\n */\nexport function registerTasksCommand(pi: ExtensionAPI, store: TaskStore): void {\n pi.registerCommand(COMMAND_NAME, {\n description: 'Open Task Space for this session tree',\n handler: async (_args, ctx) => {\n if (!ctx.hasUI) {\n ctx.ui.notify(ERR_REQUIRES_INTERACTIVE, 'error');\n return;\n }\n\n store.read();\n await openTaskSpace(ctx, { store });\n },\n });\n}\n"],"mappings":"0EAYA,SAAgB,EAAqB,EAAkB,EAAwB,CAC7E,EAAG,gBAAgBA,EAAAA,aAAc,CAC/B,YAAa,wCACb,QAAS,MAAO,EAAO,IAAQ,CAC7B,GAAI,CAAC,EAAI,MAAO,CACd,EAAI,GAAG,OAAOC,EAAAA,yBAA0B,OAAO,EAC/C,MACF,CAEA,EAAM,KAAK,EACX,MAAMC,EAAAA,cAAc,EAAK,CAAE,OAAM,CAAC,CACpC,CACF,CAAC,CACH"}
1
+ {"version":3,"file":"index.cjs","names":["COMMAND_NAME","ERR_REQUIRES_INTERACTIVE","openTaskSpace"],"sources":["../../src/commands/index.ts"],"sourcesContent":["import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { COMMAND_NAME, ERR_REQUIRES_INTERACTIVE } from '../schemas/task.ts';\nimport type { TaskStore } from '../adapters/store/taskStore';\nimport { openTaskSpace } from '../tui/taskSpace.ts';\n\n/**\n * `/tasks`, reachable from the leader palette as `SPC t t`.\n *\n * The command opens the Task Space overlay rather than printing a listing: the\n * overlay is the readable surface and it can edit, while a transcript dump could\n * only be read.\n */\nexport function registerTasksCommand(\n pi: ExtensionAPI,\n store: TaskStore,\n waitUntilReady?: (context: ExtensionContext) => Promise<void>,\n): void {\n pi.registerCommand(COMMAND_NAME, {\n description: 'Open Task Space for this session tree',\n handler: async (_args, ctx) => {\n if (!ctx.hasUI) {\n ctx.ui.notify(ERR_REQUIRES_INTERACTIVE, 'error');\n return;\n }\n\n await waitUntilReady?.(ctx);\n store.read();\n await openTaskSpace(ctx, { store });\n },\n });\n}\n"],"mappings":"0EAYA,SAAgB,EACd,EACA,EACA,EACM,CACN,EAAG,gBAAgBA,EAAAA,aAAc,CAC/B,YAAa,wCACb,QAAS,MAAO,EAAO,IAAQ,CAC7B,GAAI,CAAC,EAAI,MAAO,CACd,EAAI,GAAG,OAAOC,EAAAA,yBAA0B,OAAO,EAC/C,MACF,CAEA,MAAM,IAAiB,CAAG,EAC1B,EAAM,KAAK,EACX,MAAMC,EAAAA,cAAc,EAAK,CAAE,OAAM,CAAC,CACpC,CACF,CAAC,CACH"}
@@ -1,5 +1,5 @@
1
1
  import { TaskStore } from "../adapters/store/taskStore.cjs";
2
- import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
3
3
  //#region src/commands/index.d.ts
4
4
  /**
5
5
  * `/tasks`, reachable from the leader palette as `SPC t t`.
@@ -8,7 +8,7 @@ import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
8
8
  * overlay is the readable surface and it can edit, while a transcript dump could
9
9
  * only be read.
10
10
  */
11
- declare function registerTasksCommand(pi: ExtensionAPI, store: TaskStore): void;
11
+ declare function registerTasksCommand(pi: ExtensionAPI, store: TaskStore, waitUntilReady?: (context: ExtensionContext) => Promise<void>): void;
12
12
  //#endregion
13
13
  export { registerTasksCommand };
14
14
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/commands/index.ts"],"mappings":";;;;;;;;;;iBAYgB,qBAAqB,IAAI,cAAc,OAAO"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/commands/index.ts"],"mappings":";;;;;;;;;;iBAYgB,qBACd,IAAI,cACJ,OAAO,WACP,kBAAkB,SAAS,qBAAqB"}
@@ -1,5 +1,5 @@
1
1
  import { TaskStore } from "../adapters/store/taskStore.mjs";
2
- import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
3
3
  //#region src/commands/index.d.ts
4
4
  /**
5
5
  * `/tasks`, reachable from the leader palette as `SPC t t`.
@@ -8,7 +8,7 @@ import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
8
8
  * overlay is the readable surface and it can edit, while a transcript dump could
9
9
  * only be read.
10
10
  */
11
- declare function registerTasksCommand(pi: ExtensionAPI, store: TaskStore): void;
11
+ declare function registerTasksCommand(pi: ExtensionAPI, store: TaskStore, waitUntilReady?: (context: ExtensionContext) => Promise<void>): void;
12
12
  //#endregion
13
13
  export { registerTasksCommand };
14
14
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/commands/index.ts"],"mappings":";;;;;;;;;;iBAYgB,qBAAqB,IAAI,cAAc,OAAO"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/commands/index.ts"],"mappings":";;;;;;;;;;iBAYgB,qBACd,IAAI,cACJ,OAAO,WACP,kBAAkB,SAAS,qBAAqB"}
@@ -1,2 +1,2 @@
1
- import{COMMAND_NAME as e,ERR_REQUIRES_INTERACTIVE as t}from"../schemas/task.mjs";import{openTaskSpace as n}from"../tui/taskSpace2.mjs";function r(r,i){r.registerCommand(e,{description:`Open Task Space for this session tree`,handler:async(e,r)=>{if(!r.hasUI){r.ui.notify(t,`error`);return}i.read(),await n(r,{store:i})}})}export{r as registerTasksCommand};
1
+ import{COMMAND_NAME as e,ERR_REQUIRES_INTERACTIVE as t}from"../schemas/task.mjs";import{openTaskSpace as n}from"../tui/taskSpace2.mjs";function r(r,i,a){r.registerCommand(e,{description:`Open Task Space for this session tree`,handler:async(e,r)=>{if(!r.hasUI){r.ui.notify(t,`error`);return}await a?.(r),i.read(),await n(r,{store:i})}})}export{r as registerTasksCommand};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/commands/index.ts"],"sourcesContent":["import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { COMMAND_NAME, ERR_REQUIRES_INTERACTIVE } from '../schemas/task.ts';\nimport type { TaskStore } from '../adapters/store/taskStore';\nimport { openTaskSpace } from '../tui/taskSpace.ts';\n\n/**\n * `/tasks`, reachable from the leader palette as `SPC t t`.\n *\n * The command opens the Task Space overlay rather than printing a listing: the\n * overlay is the readable surface and it can edit, while a transcript dump could\n * only be read.\n */\nexport function registerTasksCommand(pi: ExtensionAPI, store: TaskStore): void {\n pi.registerCommand(COMMAND_NAME, {\n description: 'Open Task Space for this session tree',\n handler: async (_args, ctx) => {\n if (!ctx.hasUI) {\n ctx.ui.notify(ERR_REQUIRES_INTERACTIVE, 'error');\n return;\n }\n\n store.read();\n await openTaskSpace(ctx, { store });\n },\n });\n}\n"],"mappings":"uIAYA,SAAgB,EAAqB,EAAkB,EAAwB,CAC7E,EAAG,gBAAgB,EAAc,CAC/B,YAAa,wCACb,QAAS,MAAO,EAAO,IAAQ,CAC7B,GAAI,CAAC,EAAI,MAAO,CACd,EAAI,GAAG,OAAO,EAA0B,OAAO,EAC/C,MACF,CAEA,EAAM,KAAK,EACX,MAAM,EAAc,EAAK,CAAE,OAAM,CAAC,CACpC,CACF,CAAC,CACH"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/commands/index.ts"],"sourcesContent":["import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { COMMAND_NAME, ERR_REQUIRES_INTERACTIVE } from '../schemas/task.ts';\nimport type { TaskStore } from '../adapters/store/taskStore';\nimport { openTaskSpace } from '../tui/taskSpace.ts';\n\n/**\n * `/tasks`, reachable from the leader palette as `SPC t t`.\n *\n * The command opens the Task Space overlay rather than printing a listing: the\n * overlay is the readable surface and it can edit, while a transcript dump could\n * only be read.\n */\nexport function registerTasksCommand(\n pi: ExtensionAPI,\n store: TaskStore,\n waitUntilReady?: (context: ExtensionContext) => Promise<void>,\n): void {\n pi.registerCommand(COMMAND_NAME, {\n description: 'Open Task Space for this session tree',\n handler: async (_args, ctx) => {\n if (!ctx.hasUI) {\n ctx.ui.notify(ERR_REQUIRES_INTERACTIVE, 'error');\n return;\n }\n\n await waitUntilReady?.(ctx);\n store.read();\n await openTaskSpace(ctx, { store });\n },\n });\n}\n"],"mappings":"uIAYA,SAAgB,EACd,EACA,EACA,EACM,CACN,EAAG,gBAAgB,EAAc,CAC/B,YAAa,wCACb,QAAS,MAAO,EAAO,IAAQ,CAC7B,GAAI,CAAC,EAAI,MAAO,CACd,EAAI,GAAG,OAAO,EAA0B,OAAO,EAC/C,MACF,CAEA,MAAM,IAAiB,CAAG,EAC1B,EAAM,KAAK,EACX,MAAM,EAAc,EAAK,CAAE,OAAM,CAAC,CACpC,CACF,CAAC,CACH"}
@@ -1,3 +1,3 @@
1
1
  const e=require("../../schemas/task.cjs"),t=require("../../services/store/reducer.cjs"),n=require("../../types/telemetry.cjs"),r=require("../../tui/format2.cjs");require("../../types/config.cjs");const i=require("./promptGuidelines.cjs"),a=require("./responseEnvelope.cjs"),o=`Manage a shared task list to track multi-step progress, and delegate tasks to subagents`,s=`tool.action`,c=`task.id`,l=new Set([`upsert`,`list`,`get`,`delete`,`clear`]);var u=class extends Error{};function d(e,t){return new u([`Task ${e} failed: ${t}`,``,`Options:`,`- List the task board and inspect the current ids, states, and blockers.`,`- Correct the arguments or state conflict, then retry once.`,`- Ask the user before cancelling work or changing dependencies to recover.`].join(`
2
- `))}function f(t,n){let r=Object.keys(n).filter(r=>n[r]!==void 0&&!e.taskActionAcceptsField(t,r));if(r.length===0)return;let i=t===`upsert`?` ${e.MSG_UPSERT_FIELD_MISPLACED}`:``;throw d(t,`${t} does not accept ${r.join(`, `)}.${i}`)}function p(e){let t=e.assignments;if(!t||t.length===0)throw d(`assign`,`assign requires a non-empty assignments[] array`);return t}function m(e,t){return{agent:e.agent,inlineAgent:e.inlineAgent,instructions:e.instructions,relevantFiles:e.relevantFiles,priorFindings:e.priorFindings,model:e.model,context:e.context,signal:t}}async function h(e,t,r,i){let a=[];for(let[o,l]of t.entries()){let t;try{t=await e.assign(l.id,m(l,r))}catch(e){i?.error(n.TASK_EVENT.toolFailed,e,{[s]:`assign`,[c]:l.id}),t={ok:!1,message:e instanceof Error?e.message:String(e)}}a.push({index:o,id:l.id,agent:l.agent,...t})}return a}async function g(e,n,r,i){let{document:o,value:s}=await e.mutate(e=>{let a=t.applyTaskMutation(e,n,r,void 0,i);return{...t.isCommittingOp(a.op)?{document:a.document}:{},value:a}});if(s.op.kind===`error`)throw d(n,s.op.message);if(s.op.kind===`upsert`&&s.op.applied===0)throw d(n,a.formatUpsertFailureText(s.op));return a.buildToolResult(n,r,o,s.op)}function _(t,m){let{store:_,delegation:v,maxTasks:y=15}=m;t.registerTool({name:e.TOOL_NAME,label:e.TOOL_LABEL,description:`Manage a shared task list for tracking multi-step progress, and delegate tasks to subagents. Actions: upsert (write tasks — a tasks[] array where an entry with an id changes that task and an entry without an id creates one, so one call can capture a whole plan), list, get, delete (tombstone), clear (close/reset the list), assign (hand one or more tasks through assignments[] to named subagents that work in the background), cancel (stop a delegated run). upsert and assign apply entries independently: successes remain committed or delegated and failures are reported by array index. Batch a plan and independent assignments, but report progress one task at a time. Status: pending → in_progress → completed, plus failed and a deleted tombstone. The list is shared within the current session tree, including delegated subagents, while unrelated sessions start empty. Session stores persist until retention cleanup.`,promptSnippet:o,promptGuidelines:i.DEFAULT_PROMPT_GUIDELINES,parameters:e.TaskParamsSchema,renderShell:`self`,async execute(e,t,r,i,o){let b=t.action,x=t;try{if(f(b,x),l.has(b)){let e=await g(_,b,x,y);return m.onChange?.(),e}if(b===`assign`){let e=p(x),t=e[0],n=e.length===1&&t?`Delegating task #${t.id}...`:`Delegating ${e.length} tasks...`;i?.(a.buildTextResult(b,x,_.snapshot,n));let o=await h(v,e,r,m.report);m.onChange?.();let s=a.formatAssignmentResults(o),c=o.flatMap(e=>e.ok?[e.id]:[]);if(c.length===0)throw d(b,s);return a.buildAssignmentResult(x,_.snapshot,s,{assigned:c,failed:o.length-c.length})}i?.(a.buildTextResult(b,x,_.snapshot,`Requesting cancellation for task #${x.id??`unknown`}...`));let e=await v.cancel(x.id??NaN);if(m.onChange?.(),!e.ok)throw d(b,e.message);return a.buildTextResult(b,x,_.snapshot,e.message,void 0)}catch(e){throw m.report?.error(n.TASK_EVENT.toolFailed,e,{[s]:b,...x.id===void 0?{}:{[c]:x.id}}),e instanceof u?e:d(b,e instanceof Error?e.message:String(e))}},renderCall(e,t,n){return r.renderTaskCall(e,t,_.snapshot.tasks)},renderResult(e,t,n,i){return r.renderTaskResult(e,t,n)}})}exports.DEFAULT_PROMPT_GUIDELINES=i.DEFAULT_PROMPT_GUIDELINES,exports.DEFAULT_PROMPT_SNIPPET=o,exports.registerTaskTool=_;
2
+ `))}function f(t,n){let r=Object.keys(n).filter(r=>n[r]!==void 0&&!e.taskActionAcceptsField(t,r));if(r.length===0)return;let i=t===`upsert`?` ${e.MSG_UPSERT_FIELD_MISPLACED}`:``;throw d(t,`${t} does not accept ${r.join(`, `)}.${i}`)}function p(e){let t=e.assignments;if(!t||t.length===0)throw d(`assign`,`assign requires a non-empty assignments[] array`);return t}function m(e,t){return{agent:e.agent,inlineAgent:e.inlineAgent,instructions:e.instructions,relevantFiles:e.relevantFiles,priorFindings:e.priorFindings,model:e.model,context:e.context,signal:t}}async function h(e,t,r,i){let a=[];for(let[o,l]of t.entries()){let t;try{t=await e.assign(l.id,m(l,r))}catch(e){i?.error(n.TASK_EVENT.toolFailed,e,{[s]:`assign`,[c]:l.id}),t={ok:!1,message:e instanceof Error?e.message:String(e)}}a.push({index:o,id:l.id,agent:l.agent,...t})}return a}async function g(e,n,r,i){let{document:o,value:s}=await e.mutate(e=>{let a=t.applyTaskMutation(e,n,r,void 0,i);return{...t.isCommittingOp(a.op)?{document:a.document}:{},value:a}});if(s.op.kind===`error`)throw d(n,s.op.message);if(s.op.kind===`upsert`&&s.op.applied===0)throw d(n,a.formatUpsertFailureText(s.op));return a.buildToolResult(n,r,o,s.op)}function _(t,m){let{store:_,delegation:v,maxTasks:y=15}=m;t.registerTool({name:e.TOOL_NAME,label:e.TOOL_LABEL,description:`Manage a shared task list for tracking multi-step progress, and delegate tasks to subagents. Actions: upsert (write tasks — a tasks[] array where an entry with an id changes that task and an entry without an id creates one, so one call can capture a whole plan), list, get, delete (tombstone), clear (close/reset the list), assign (hand one or more tasks through assignments[] to named subagents that work in the background), cancel (stop a delegated run). upsert and assign apply entries independently: successes remain committed or delegated and failures are reported by array index. Batch a plan and independent assignments, but report progress one task at a time. Status: pending → in_progress → completed, plus failed and a deleted tombstone. The list is shared within the current session tree, including delegated subagents, while unrelated sessions start empty. Session stores persist until retention cleanup.`,promptSnippet:o,promptGuidelines:i.DEFAULT_PROMPT_GUIDELINES,parameters:e.TaskParamsSchema,renderShell:`self`,async execute(e,t,r,i,o){let b=t.action,x=t;try{if(await m.waitUntilReady?.(o,r),f(b,x),l.has(b)){let e=await g(_,b,x,y);return m.onChange?.(),e}if(b===`assign`){let e=p(x),t=e[0],n=e.length===1&&t?`Delegating task #${t.id}...`:`Delegating ${e.length} tasks...`;i?.(a.buildTextResult(b,x,_.snapshot,n));let o=await h(v,e,r,m.report);m.onChange?.();let s=a.formatAssignmentResults(o),c=o.flatMap(e=>e.ok?[e.id]:[]);if(c.length===0)throw d(b,s);return a.buildAssignmentResult(x,_.snapshot,s,{assigned:c,failed:o.length-c.length})}i?.(a.buildTextResult(b,x,_.snapshot,`Requesting cancellation for task #${x.id??`unknown`}...`));let e=await v.cancel(x.id??NaN);if(m.onChange?.(),!e.ok)throw d(b,e.message);return a.buildTextResult(b,x,_.snapshot,e.message,void 0)}catch(e){throw m.report?.error(n.TASK_EVENT.toolFailed,e,{[s]:b,...x.id===void 0?{}:{[c]:x.id}}),e instanceof u?e:d(b,e instanceof Error?e.message:String(e))}},renderCall(e,t,n){return r.renderTaskCall(e,t,_.snapshot.tasks)},renderResult(e,t,n,i){return r.renderTaskResult(e,t,n)}})}exports.DEFAULT_PROMPT_GUIDELINES=i.DEFAULT_PROMPT_GUIDELINES,exports.DEFAULT_PROMPT_SNIPPET=o,exports.registerTaskTool=_;
3
3
  //# sourceMappingURL=taskTool.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"taskTool.cjs","names":["taskActionAcceptsField","MSG_UPSERT_FIELD_MISPLACED","TASK_EVENT","applyTaskMutation","isCommittingOp","formatUpsertFailureText","buildToolResult","TOOL_NAME","TOOL_LABEL","DEFAULT_PROMPT_GUIDELINES","TaskParamsSchema","buildTextResult","formatAssignmentResults","buildAssignmentResult","renderTaskCall","renderTaskResult"],"sources":["../../../src/commands/task/taskTool.ts"],"sourcesContent":["import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport {\n MSG_UPSERT_FIELD_MISPLACED,\n TaskParamsSchema,\n TOOL_LABEL,\n TOOL_NAME,\n taskActionAcceptsField,\n} from '../../schemas/task.ts';\nimport type { AssignOptions, DelegationManager, DelegationOutcome } from '../../services/delegation/manager.ts';\nimport { applyTaskMutation, isCommittingOp, type ReducerAction } from '../../services/store/reducer.ts';\nimport type { TaskStore } from '../../adapters/store/taskStore';\nimport type { TaskAction, TaskAssignment, TaskMutationParams } from '../../services/store/types.ts';\nimport { renderTaskCall, renderTaskResult } from '../../tui/format.ts';\nimport { DEFAULT_MAX_TASKS } from '../../types/config.ts';\nimport { TASK_EVENT, type TaskFailureReporter } from '../../types/telemetry.ts';\nimport { DEFAULT_PROMPT_GUIDELINES } from './promptGuidelines.ts';\nimport {\n type AssignmentItemResult,\n buildAssignmentResult,\n buildTextResult,\n buildToolResult,\n formatAssignmentResults,\n formatUpsertFailureText,\n type ToolResult,\n} from './responseEnvelope.ts';\n\nexport { DEFAULT_PROMPT_GUIDELINES } from './promptGuidelines.ts';\n\nexport const DEFAULT_PROMPT_SNIPPET =\n 'Manage a shared task list to track multi-step progress, and delegate tasks to subagents';\n\nexport interface TaskToolDependencies {\n store: TaskStore;\n delegation: DelegationManager;\n maxTasks?: number;\n onChange?: () => void;\n report?: TaskFailureReporter;\n}\n\nconst ACTION_ATTRIBUTE = 'tool.action';\nconst TASK_ID_ATTRIBUTE = 'task.id';\nconst REDUCER_ACTIONS = new Set<TaskAction>(['upsert', 'list', 'get', 'delete', 'clear']);\n\nclass TaskToolExecutionError extends Error {}\n\nfunction actionableTaskError(action: TaskAction, message: string): TaskToolExecutionError {\n return new TaskToolExecutionError(\n [\n `Task ${action} failed: ${message}`,\n '',\n 'Options:',\n '- List the task board and inspect the current ids, states, and blockers.',\n '- Correct the arguments or state conflict, then retry once.',\n '- Ask the user before cancelling work or changing dependencies to recover.',\n ].join('\\n'),\n );\n}\n\n/**\n * Reject a field that belongs to a different action.\n *\n * The params schema is flat and shared across every action, so this is the only\n * place `{\"action\":\"upsert\",\"id\":3}` can be caught — and it must be, because\n * the entry it carries has no id and would silently create a duplicate task.\n */\nfunction rejectStrayFields(action: TaskAction, params: TaskMutationParams): void {\n const stray = Object.keys(params).filter((key) => params[key] !== undefined && !taskActionAcceptsField(action, key));\n if (stray.length === 0) return;\n const hint = action === 'upsert' ? ` ${MSG_UPSERT_FIELD_MISPLACED}` : '';\n throw actionableTaskError(action, `${action} does not accept ${stray.join(', ')}.${hint}`);\n}\n\n/** assignments[] is the only assign contract, even when it contains one task. */\nfunction resolveAssignments(params: TaskMutationParams): TaskAssignment[] {\n const assignments = params.assignments;\n if (!assignments || assignments.length === 0) {\n throw actionableTaskError('assign', 'assign requires a non-empty assignments[] array');\n }\n return assignments;\n}\n\nfunction assignOptions(request: TaskAssignment, signal: AbortSignal | undefined): AssignOptions {\n return {\n agent: request.agent,\n inlineAgent: request.inlineAgent,\n instructions: request.instructions,\n relevantFiles: request.relevantFiles,\n priorFindings: request.priorFindings,\n model: request.model,\n context: request.context,\n signal,\n };\n}\n\nasync function executeAssignmentBatch(\n delegation: DelegationManager,\n assignments: readonly TaskAssignment[],\n signal: AbortSignal | undefined,\n report: TaskFailureReporter | undefined,\n): Promise<AssignmentItemResult[]> {\n const results: AssignmentItemResult[] = [];\n for (const [index, assignment] of assignments.entries()) {\n let outcome: DelegationOutcome;\n try {\n outcome = await delegation.assign(assignment.id, assignOptions(assignment, signal));\n } catch (error) {\n report?.error(TASK_EVENT.toolFailed, error, {\n [ACTION_ATTRIBUTE]: 'assign',\n [TASK_ID_ATTRIBUTE]: assignment.id,\n });\n outcome = { ok: false, message: error instanceof Error ? error.message : String(error) };\n }\n results.push({ index, id: assignment.id, agent: assignment.agent, ...outcome });\n }\n return results;\n}\n\n/** Run an action through the reducer, persisting only when it produced a change. */\nasync function executeReducerAction(\n store: TaskStore,\n action: ReducerAction,\n params: TaskMutationParams,\n maxTasks: number,\n): Promise<ToolResult> {\n const { document, value } = await store.mutate((current) => {\n const result = applyTaskMutation(current, action, params, undefined, maxTasks);\n return {\n ...(isCommittingOp(result.op) ? { document: result.document } : {}),\n value: result,\n };\n });\n if (value.op.kind === 'error') throw actionableTaskError(action, value.op.message);\n // An upsert that applied nothing is a failed call: it wrote nothing and left\n // `rev` alone, so it must not read to the model as a success. A batch where\n // some entries landed returns normally — that is what partial apply means.\n if (value.op.kind === 'upsert' && value.op.applied === 0) {\n throw actionableTaskError(action, formatUpsertFailureText(value.op));\n }\n // `document` is the committed document, so `details.rev` matches what landed\n // on disk; `value.document` is the pre-write copy and lags by one.\n return buildToolResult(action, params, document, value.op);\n}\n\nexport function registerTaskTool(pi: ExtensionAPI, dependencies: TaskToolDependencies): void {\n const { store, delegation, maxTasks = DEFAULT_MAX_TASKS } = dependencies;\n\n pi.registerTool({\n name: TOOL_NAME,\n label: TOOL_LABEL,\n description:\n 'Manage a shared task list for tracking multi-step progress, and delegate tasks to subagents. Actions: upsert (write tasks — a tasks[] array where an entry with an id changes that task and an entry without an id creates one, so one call can capture a whole plan), list, get, delete (tombstone), clear (close/reset the list), assign (hand one or more tasks through assignments[] to named subagents that work in the background), cancel (stop a delegated run). upsert and assign apply entries independently: successes remain committed or delegated and failures are reported by array index. Batch a plan and independent assignments, but report progress one task at a time. Status: pending → in_progress → completed, plus failed and a deleted tombstone. The list is shared within the current session tree, including delegated subagents, while unrelated sessions start empty. Session stores persist until retention cleanup.',\n promptSnippet: DEFAULT_PROMPT_SNIPPET,\n promptGuidelines: DEFAULT_PROMPT_GUIDELINES,\n parameters: TaskParamsSchema,\n // Task rows carry their own status colors. Owning the shell prevents Pi's\n // pending/success/error background fill from obscuring those row states.\n renderShell: 'self',\n\n async execute(_toolCallId, params, signal, onUpdate, _ctx) {\n const action = params.action as TaskAction;\n const mutationParams = params as TaskMutationParams;\n\n try {\n rejectStrayFields(action, mutationParams);\n if (REDUCER_ACTIONS.has(action)) {\n const result = await executeReducerAction(store, action as ReducerAction, mutationParams, maxTasks);\n dependencies.onChange?.();\n return result;\n }\n\n if (action === 'assign') {\n const assignments = resolveAssignments(mutationParams);\n const first = assignments[0];\n const progress =\n assignments.length === 1 && first\n ? `Delegating task #${first.id}...`\n : `Delegating ${assignments.length} tasks...`;\n onUpdate?.(buildTextResult(action, mutationParams, store.snapshot, progress));\n const results = await executeAssignmentBatch(delegation, assignments, signal, dependencies.report);\n dependencies.onChange?.();\n const text = formatAssignmentResults(results);\n const assigned = results.flatMap((item) => (item.ok ? [item.id] : []));\n if (assigned.length === 0) throw actionableTaskError(action, text);\n return buildAssignmentResult(mutationParams, store.snapshot, text, {\n assigned,\n failed: results.length - assigned.length,\n });\n }\n\n onUpdate?.(\n buildTextResult(\n action,\n mutationParams,\n store.snapshot,\n `Requesting cancellation for task #${mutationParams.id ?? 'unknown'}...`,\n ),\n );\n const outcome = await delegation.cancel(mutationParams.id ?? Number.NaN);\n dependencies.onChange?.();\n if (!outcome.ok) throw actionableTaskError(action, outcome.message);\n return buildTextResult(action, mutationParams, store.snapshot, outcome.message, undefined);\n } catch (error) {\n // Rethrown so pi still renders the failure to the model; recorded\n // because this is where a store fault becomes visible to the user.\n dependencies.report?.error(TASK_EVENT.toolFailed, error, {\n [ACTION_ATTRIBUTE]: action,\n ...(mutationParams.id === undefined ? {} : { [TASK_ID_ATTRIBUTE]: mutationParams.id }),\n });\n if (error instanceof TaskToolExecutionError) throw error;\n throw actionableTaskError(action, error instanceof Error ? error.message : String(error));\n }\n },\n\n // Render hooks receive no session identity, so they read the store snapshot\n // that the executing session last loaded. That is the foreground session's\n // own view, which is exactly what its transcript should show.\n renderCall(args, theme, _context) {\n return renderTaskCall(args as never, theme, store.snapshot.tasks);\n },\n\n renderResult(result, options, theme, _context) {\n return renderTaskResult(result, options, theme);\n },\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"taskTool.cjs","names":["taskActionAcceptsField","MSG_UPSERT_FIELD_MISPLACED","TASK_EVENT","applyTaskMutation","isCommittingOp","formatUpsertFailureText","buildToolResult","TOOL_NAME","TOOL_LABEL","DEFAULT_PROMPT_GUIDELINES","TaskParamsSchema","buildTextResult","formatAssignmentResults","buildAssignmentResult","renderTaskCall","renderTaskResult"],"sources":["../../../src/commands/task/taskTool.ts"],"sourcesContent":["import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport {\n MSG_UPSERT_FIELD_MISPLACED,\n TaskParamsSchema,\n TOOL_LABEL,\n TOOL_NAME,\n taskActionAcceptsField,\n} from '../../schemas/task.ts';\nimport type { AssignOptions, DelegationManager, DelegationOutcome } from '../../services/delegation/manager.ts';\nimport { applyTaskMutation, isCommittingOp, type ReducerAction } from '../../services/store/reducer.ts';\nimport type { TaskStore } from '../../adapters/store/taskStore';\nimport type { TaskAction, TaskAssignment, TaskMutationParams } from '../../services/store/types.ts';\nimport { renderTaskCall, renderTaskResult } from '../../tui/format.ts';\nimport { DEFAULT_MAX_TASKS } from '../../types/config.ts';\nimport { TASK_EVENT, type TaskFailureReporter } from '../../types/telemetry.ts';\nimport { DEFAULT_PROMPT_GUIDELINES } from './promptGuidelines.ts';\nimport {\n type AssignmentItemResult,\n buildAssignmentResult,\n buildTextResult,\n buildToolResult,\n formatAssignmentResults,\n formatUpsertFailureText,\n type ToolResult,\n} from './responseEnvelope.ts';\n\nexport { DEFAULT_PROMPT_GUIDELINES } from './promptGuidelines.ts';\n\nexport const DEFAULT_PROMPT_SNIPPET =\n 'Manage a shared task list to track multi-step progress, and delegate tasks to subagents';\n\nexport interface TaskToolDependencies {\n store: TaskStore;\n delegation: DelegationManager;\n maxTasks?: number;\n onChange?: () => void;\n report?: TaskFailureReporter;\n waitUntilReady?: (context: ExtensionContext, signal?: AbortSignal) => Promise<void>;\n}\n\nconst ACTION_ATTRIBUTE = 'tool.action';\nconst TASK_ID_ATTRIBUTE = 'task.id';\nconst REDUCER_ACTIONS = new Set<TaskAction>(['upsert', 'list', 'get', 'delete', 'clear']);\n\nclass TaskToolExecutionError extends Error {}\n\nfunction actionableTaskError(action: TaskAction, message: string): TaskToolExecutionError {\n return new TaskToolExecutionError(\n [\n `Task ${action} failed: ${message}`,\n '',\n 'Options:',\n '- List the task board and inspect the current ids, states, and blockers.',\n '- Correct the arguments or state conflict, then retry once.',\n '- Ask the user before cancelling work or changing dependencies to recover.',\n ].join('\\n'),\n );\n}\n\n/**\n * Reject a field that belongs to a different action.\n *\n * The params schema is flat and shared across every action, so this is the only\n * place `{\"action\":\"upsert\",\"id\":3}` can be caught — and it must be, because\n * the entry it carries has no id and would silently create a duplicate task.\n */\nfunction rejectStrayFields(action: TaskAction, params: TaskMutationParams): void {\n const stray = Object.keys(params).filter((key) => params[key] !== undefined && !taskActionAcceptsField(action, key));\n if (stray.length === 0) return;\n const hint = action === 'upsert' ? ` ${MSG_UPSERT_FIELD_MISPLACED}` : '';\n throw actionableTaskError(action, `${action} does not accept ${stray.join(', ')}.${hint}`);\n}\n\n/** assignments[] is the only assign contract, even when it contains one task. */\nfunction resolveAssignments(params: TaskMutationParams): TaskAssignment[] {\n const assignments = params.assignments;\n if (!assignments || assignments.length === 0) {\n throw actionableTaskError('assign', 'assign requires a non-empty assignments[] array');\n }\n return assignments;\n}\n\nfunction assignOptions(request: TaskAssignment, signal: AbortSignal | undefined): AssignOptions {\n return {\n agent: request.agent,\n inlineAgent: request.inlineAgent,\n instructions: request.instructions,\n relevantFiles: request.relevantFiles,\n priorFindings: request.priorFindings,\n model: request.model,\n context: request.context,\n signal,\n };\n}\n\nasync function executeAssignmentBatch(\n delegation: DelegationManager,\n assignments: readonly TaskAssignment[],\n signal: AbortSignal | undefined,\n report: TaskFailureReporter | undefined,\n): Promise<AssignmentItemResult[]> {\n const results: AssignmentItemResult[] = [];\n for (const [index, assignment] of assignments.entries()) {\n let outcome: DelegationOutcome;\n try {\n outcome = await delegation.assign(assignment.id, assignOptions(assignment, signal));\n } catch (error) {\n report?.error(TASK_EVENT.toolFailed, error, {\n [ACTION_ATTRIBUTE]: 'assign',\n [TASK_ID_ATTRIBUTE]: assignment.id,\n });\n outcome = { ok: false, message: error instanceof Error ? error.message : String(error) };\n }\n results.push({ index, id: assignment.id, agent: assignment.agent, ...outcome });\n }\n return results;\n}\n\n/** Run an action through the reducer, persisting only when it produced a change. */\nasync function executeReducerAction(\n store: TaskStore,\n action: ReducerAction,\n params: TaskMutationParams,\n maxTasks: number,\n): Promise<ToolResult> {\n const { document, value } = await store.mutate((current) => {\n const result = applyTaskMutation(current, action, params, undefined, maxTasks);\n return {\n ...(isCommittingOp(result.op) ? { document: result.document } : {}),\n value: result,\n };\n });\n if (value.op.kind === 'error') throw actionableTaskError(action, value.op.message);\n // An upsert that applied nothing is a failed call: it wrote nothing and left\n // `rev` alone, so it must not read to the model as a success. A batch where\n // some entries landed returns normally — that is what partial apply means.\n if (value.op.kind === 'upsert' && value.op.applied === 0) {\n throw actionableTaskError(action, formatUpsertFailureText(value.op));\n }\n // `document` is the committed document, so `details.rev` matches what landed\n // on disk; `value.document` is the pre-write copy and lags by one.\n return buildToolResult(action, params, document, value.op);\n}\n\nexport function registerTaskTool(pi: ExtensionAPI, dependencies: TaskToolDependencies): void {\n const { store, delegation, maxTasks = DEFAULT_MAX_TASKS } = dependencies;\n\n pi.registerTool({\n name: TOOL_NAME,\n label: TOOL_LABEL,\n description:\n 'Manage a shared task list for tracking multi-step progress, and delegate tasks to subagents. Actions: upsert (write tasks — a tasks[] array where an entry with an id changes that task and an entry without an id creates one, so one call can capture a whole plan), list, get, delete (tombstone), clear (close/reset the list), assign (hand one or more tasks through assignments[] to named subagents that work in the background), cancel (stop a delegated run). upsert and assign apply entries independently: successes remain committed or delegated and failures are reported by array index. Batch a plan and independent assignments, but report progress one task at a time. Status: pending → in_progress → completed, plus failed and a deleted tombstone. The list is shared within the current session tree, including delegated subagents, while unrelated sessions start empty. Session stores persist until retention cleanup.',\n promptSnippet: DEFAULT_PROMPT_SNIPPET,\n promptGuidelines: DEFAULT_PROMPT_GUIDELINES,\n parameters: TaskParamsSchema,\n // Task rows carry their own status colors. Owning the shell prevents Pi's\n // pending/success/error background fill from obscuring those row states.\n renderShell: 'self',\n\n async execute(_toolCallId, params, signal, onUpdate, ctx) {\n const action = params.action as TaskAction;\n const mutationParams = params as TaskMutationParams;\n\n try {\n await dependencies.waitUntilReady?.(ctx, signal);\n rejectStrayFields(action, mutationParams);\n if (REDUCER_ACTIONS.has(action)) {\n const result = await executeReducerAction(store, action as ReducerAction, mutationParams, maxTasks);\n dependencies.onChange?.();\n return result;\n }\n\n if (action === 'assign') {\n const assignments = resolveAssignments(mutationParams);\n const first = assignments[0];\n const progress =\n assignments.length === 1 && first\n ? `Delegating task #${first.id}...`\n : `Delegating ${assignments.length} tasks...`;\n onUpdate?.(buildTextResult(action, mutationParams, store.snapshot, progress));\n const results = await executeAssignmentBatch(delegation, assignments, signal, dependencies.report);\n dependencies.onChange?.();\n const text = formatAssignmentResults(results);\n const assigned = results.flatMap((item) => (item.ok ? [item.id] : []));\n if (assigned.length === 0) throw actionableTaskError(action, text);\n return buildAssignmentResult(mutationParams, store.snapshot, text, {\n assigned,\n failed: results.length - assigned.length,\n });\n }\n\n onUpdate?.(\n buildTextResult(\n action,\n mutationParams,\n store.snapshot,\n `Requesting cancellation for task #${mutationParams.id ?? 'unknown'}...`,\n ),\n );\n const outcome = await delegation.cancel(mutationParams.id ?? Number.NaN);\n dependencies.onChange?.();\n if (!outcome.ok) throw actionableTaskError(action, outcome.message);\n return buildTextResult(action, mutationParams, store.snapshot, outcome.message, undefined);\n } catch (error) {\n // Rethrown so pi still renders the failure to the model; recorded\n // because this is where a store fault becomes visible to the user.\n dependencies.report?.error(TASK_EVENT.toolFailed, error, {\n [ACTION_ATTRIBUTE]: action,\n ...(mutationParams.id === undefined ? {} : { [TASK_ID_ATTRIBUTE]: mutationParams.id }),\n });\n if (error instanceof TaskToolExecutionError) throw error;\n throw actionableTaskError(action, error instanceof Error ? error.message : String(error));\n }\n },\n\n // Render hooks receive no session identity, so they read the store snapshot\n // that the executing session last loaded. That is the foreground session's\n // own view, which is exactly what its transcript should show.\n renderCall(args, theme, _context) {\n return renderTaskCall(args as never, theme, store.snapshot.tasks);\n },\n\n renderResult(result, options, theme, _context) {\n return renderTaskResult(result, options, theme);\n },\n });\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { TaskFailureReporter } from "../../types/telemetry.cjs";
2
2
  import { TaskStore } from "../../adapters/store/taskStore.cjs";
3
3
  import { DelegationManager } from "../../services/delegation/manager.cjs";
4
4
  import { DEFAULT_PROMPT_GUIDELINES } from "./promptGuidelines.cjs";
5
- import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
5
+ import { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
6
6
  //#region src/commands/task/taskTool.d.ts
7
7
  declare const DEFAULT_PROMPT_SNIPPET = "Manage a shared task list to track multi-step progress, and delegate tasks to subagents";
8
8
  interface TaskToolDependencies {
@@ -11,6 +11,7 @@ interface TaskToolDependencies {
11
11
  maxTasks?: number;
12
12
  onChange?: () => void;
13
13
  report?: TaskFailureReporter;
14
+ waitUntilReady?: (context: ExtensionContext, signal?: AbortSignal) => Promise<void>;
14
15
  }
15
16
  declare function registerTaskTool(pi: ExtensionAPI, dependencies: TaskToolDependencies): void;
16
17
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"taskTool.d.cts","names":[],"sources":["../../../src/commands/task/taskTool.ts"],"mappings":";;;;;;cA4Ba;UAGI;EACf,OAAO;EACP,YAAY;EACZ;EACA;EACA,SAAS;;iBA2GK,iBAAiB,IAAI,cAAc,cAAc"}
1
+ {"version":3,"file":"taskTool.d.cts","names":[],"sources":["../../../src/commands/task/taskTool.ts"],"mappings":";;;;;;cA4Ba;UAGI;EACf,OAAO;EACP,YAAY;EACZ;EACA;EACA,SAAS;EACT,kBAAkB,SAAS,kBAAkB,SAAS,gBAAgB;;iBA2GxD,iBAAiB,IAAI,cAAc,cAAc"}
@@ -2,7 +2,7 @@ import { TaskFailureReporter } from "../../types/telemetry.mjs";
2
2
  import { TaskStore } from "../../adapters/store/taskStore.mjs";
3
3
  import { DelegationManager } from "../../services/delegation/manager.mjs";
4
4
  import { DEFAULT_PROMPT_GUIDELINES } from "./promptGuidelines.mjs";
5
- import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
5
+ import { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
6
6
  //#region src/commands/task/taskTool.d.ts
7
7
  declare const DEFAULT_PROMPT_SNIPPET = "Manage a shared task list to track multi-step progress, and delegate tasks to subagents";
8
8
  interface TaskToolDependencies {
@@ -11,6 +11,7 @@ interface TaskToolDependencies {
11
11
  maxTasks?: number;
12
12
  onChange?: () => void;
13
13
  report?: TaskFailureReporter;
14
+ waitUntilReady?: (context: ExtensionContext, signal?: AbortSignal) => Promise<void>;
14
15
  }
15
16
  declare function registerTaskTool(pi: ExtensionAPI, dependencies: TaskToolDependencies): void;
16
17
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"taskTool.d.mts","names":[],"sources":["../../../src/commands/task/taskTool.ts"],"mappings":";;;;;;cA4Ba;UAGI;EACf,OAAO;EACP,YAAY;EACZ;EACA;EACA,SAAS;;iBA2GK,iBAAiB,IAAI,cAAc,cAAc"}
1
+ {"version":3,"file":"taskTool.d.mts","names":[],"sources":["../../../src/commands/task/taskTool.ts"],"mappings":";;;;;;cA4Ba;UAGI;EACf,OAAO;EACP,YAAY;EACZ;EACA;EACA,SAAS;EACT,kBAAkB,SAAS,kBAAkB,SAAS,gBAAgB;;iBA2GxD,iBAAiB,IAAI,cAAc,cAAc"}
@@ -1,3 +1,3 @@
1
1
  import{MSG_UPSERT_FIELD_MISPLACED as e,TOOL_LABEL as t,TOOL_NAME as n,TaskParamsSchema as r,taskActionAcceptsField as i}from"../../schemas/task.mjs";import{applyTaskMutation as a,isCommittingOp as o}from"../../services/store/reducer.mjs";import{TASK_EVENT as s}from"../../types/telemetry.mjs";import{renderTaskCall as c,renderTaskResult as l}from"../../tui/format2.mjs";import"../../types/config.mjs";import{DEFAULT_PROMPT_GUIDELINES as u}from"./promptGuidelines.mjs";import{buildAssignmentResult as d,buildTextResult as f,buildToolResult as p,formatAssignmentResults as m,formatUpsertFailureText as h}from"./responseEnvelope.mjs";const g=`Manage a shared task list to track multi-step progress, and delegate tasks to subagents`,_=`tool.action`,v=`task.id`,y=new Set([`upsert`,`list`,`get`,`delete`,`clear`]);var b=class extends Error{};function x(e,t){return new b([`Task ${e} failed: ${t}`,``,`Options:`,`- List the task board and inspect the current ids, states, and blockers.`,`- Correct the arguments or state conflict, then retry once.`,`- Ask the user before cancelling work or changing dependencies to recover.`].join(`
2
- `))}function S(t,n){let r=Object.keys(n).filter(e=>n[e]!==void 0&&!i(t,e));if(r.length===0)return;let a=t===`upsert`?` ${e}`:``;throw x(t,`${t} does not accept ${r.join(`, `)}.${a}`)}function C(e){let t=e.assignments;if(!t||t.length===0)throw x(`assign`,`assign requires a non-empty assignments[] array`);return t}function w(e,t){return{agent:e.agent,inlineAgent:e.inlineAgent,instructions:e.instructions,relevantFiles:e.relevantFiles,priorFindings:e.priorFindings,model:e.model,context:e.context,signal:t}}async function T(e,t,n,r){let i=[];for(let[a,o]of t.entries()){let t;try{t=await e.assign(o.id,w(o,n))}catch(e){r?.error(s.toolFailed,e,{[_]:`assign`,[v]:o.id}),t={ok:!1,message:e instanceof Error?e.message:String(e)}}i.push({index:a,id:o.id,agent:o.agent,...t})}return i}async function E(e,t,n,r){let{document:i,value:s}=await e.mutate(e=>{let i=a(e,t,n,void 0,r);return{...o(i.op)?{document:i.document}:{},value:i}});if(s.op.kind===`error`)throw x(t,s.op.message);if(s.op.kind===`upsert`&&s.op.applied===0)throw x(t,h(s.op));return p(t,n,i,s.op)}function D(e,i){let{store:a,delegation:o,maxTasks:p=15}=i;e.registerTool({name:n,label:t,description:`Manage a shared task list for tracking multi-step progress, and delegate tasks to subagents. Actions: upsert (write tasks — a tasks[] array where an entry with an id changes that task and an entry without an id creates one, so one call can capture a whole plan), list, get, delete (tombstone), clear (close/reset the list), assign (hand one or more tasks through assignments[] to named subagents that work in the background), cancel (stop a delegated run). upsert and assign apply entries independently: successes remain committed or delegated and failures are reported by array index. Batch a plan and independent assignments, but report progress one task at a time. Status: pending → in_progress → completed, plus failed and a deleted tombstone. The list is shared within the current session tree, including delegated subagents, while unrelated sessions start empty. Session stores persist until retention cleanup.`,promptSnippet:g,promptGuidelines:u,parameters:r,renderShell:`self`,async execute(e,t,n,r,c){let l=t.action,u=t;try{if(S(l,u),y.has(l)){let e=await E(a,l,u,p);return i.onChange?.(),e}if(l===`assign`){let e=C(u),t=e[0],s=e.length===1&&t?`Delegating task #${t.id}...`:`Delegating ${e.length} tasks...`;r?.(f(l,u,a.snapshot,s));let c=await T(o,e,n,i.report);i.onChange?.();let p=m(c),h=c.flatMap(e=>e.ok?[e.id]:[]);if(h.length===0)throw x(l,p);return d(u,a.snapshot,p,{assigned:h,failed:c.length-h.length})}r?.(f(l,u,a.snapshot,`Requesting cancellation for task #${u.id??`unknown`}...`));let e=await o.cancel(u.id??NaN);if(i.onChange?.(),!e.ok)throw x(l,e.message);return f(l,u,a.snapshot,e.message,void 0)}catch(e){throw i.report?.error(s.toolFailed,e,{[_]:l,...u.id===void 0?{}:{[v]:u.id}}),e instanceof b?e:x(l,e instanceof Error?e.message:String(e))}},renderCall(e,t,n){return c(e,t,a.snapshot.tasks)},renderResult(e,t,n,r){return l(e,t,n)}})}export{u as DEFAULT_PROMPT_GUIDELINES,g as DEFAULT_PROMPT_SNIPPET,D as registerTaskTool};
2
+ `))}function S(t,n){let r=Object.keys(n).filter(e=>n[e]!==void 0&&!i(t,e));if(r.length===0)return;let a=t===`upsert`?` ${e}`:``;throw x(t,`${t} does not accept ${r.join(`, `)}.${a}`)}function C(e){let t=e.assignments;if(!t||t.length===0)throw x(`assign`,`assign requires a non-empty assignments[] array`);return t}function w(e,t){return{agent:e.agent,inlineAgent:e.inlineAgent,instructions:e.instructions,relevantFiles:e.relevantFiles,priorFindings:e.priorFindings,model:e.model,context:e.context,signal:t}}async function T(e,t,n,r){let i=[];for(let[a,o]of t.entries()){let t;try{t=await e.assign(o.id,w(o,n))}catch(e){r?.error(s.toolFailed,e,{[_]:`assign`,[v]:o.id}),t={ok:!1,message:e instanceof Error?e.message:String(e)}}i.push({index:a,id:o.id,agent:o.agent,...t})}return i}async function E(e,t,n,r){let{document:i,value:s}=await e.mutate(e=>{let i=a(e,t,n,void 0,r);return{...o(i.op)?{document:i.document}:{},value:i}});if(s.op.kind===`error`)throw x(t,s.op.message);if(s.op.kind===`upsert`&&s.op.applied===0)throw x(t,h(s.op));return p(t,n,i,s.op)}function D(e,i){let{store:a,delegation:o,maxTasks:p=15}=i;e.registerTool({name:n,label:t,description:`Manage a shared task list for tracking multi-step progress, and delegate tasks to subagents. Actions: upsert (write tasks — a tasks[] array where an entry with an id changes that task and an entry without an id creates one, so one call can capture a whole plan), list, get, delete (tombstone), clear (close/reset the list), assign (hand one or more tasks through assignments[] to named subagents that work in the background), cancel (stop a delegated run). upsert and assign apply entries independently: successes remain committed or delegated and failures are reported by array index. Batch a plan and independent assignments, but report progress one task at a time. Status: pending → in_progress → completed, plus failed and a deleted tombstone. The list is shared within the current session tree, including delegated subagents, while unrelated sessions start empty. Session stores persist until retention cleanup.`,promptSnippet:g,promptGuidelines:u,parameters:r,renderShell:`self`,async execute(e,t,n,r,c){let l=t.action,u=t;try{if(await i.waitUntilReady?.(c,n),S(l,u),y.has(l)){let e=await E(a,l,u,p);return i.onChange?.(),e}if(l===`assign`){let e=C(u),t=e[0],s=e.length===1&&t?`Delegating task #${t.id}...`:`Delegating ${e.length} tasks...`;r?.(f(l,u,a.snapshot,s));let c=await T(o,e,n,i.report);i.onChange?.();let p=m(c),h=c.flatMap(e=>e.ok?[e.id]:[]);if(h.length===0)throw x(l,p);return d(u,a.snapshot,p,{assigned:h,failed:c.length-h.length})}r?.(f(l,u,a.snapshot,`Requesting cancellation for task #${u.id??`unknown`}...`));let e=await o.cancel(u.id??NaN);if(i.onChange?.(),!e.ok)throw x(l,e.message);return f(l,u,a.snapshot,e.message,void 0)}catch(e){throw i.report?.error(s.toolFailed,e,{[_]:l,...u.id===void 0?{}:{[v]:u.id}}),e instanceof b?e:x(l,e instanceof Error?e.message:String(e))}},renderCall(e,t,n){return c(e,t,a.snapshot.tasks)},renderResult(e,t,n,r){return l(e,t,n)}})}export{u as DEFAULT_PROMPT_GUIDELINES,g as DEFAULT_PROMPT_SNIPPET,D as registerTaskTool};
3
3
  //# sourceMappingURL=taskTool.mjs.map