@agimon-ai/doompi-workflow 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.
package/README.md CHANGED
@@ -64,7 +64,7 @@ In the TUI, `SPC w w` launches, `SPC w l` manages runs, `SPC w r` opens recovery
64
64
 
65
65
  Registry data defaults to `$HOME/.workflow-mcp`; set `WORKFLOW_MCP_HOME` to relocate it. Persisted records contain workflow/run identity, job and step state, ownership, output locations, and recovery evidence. The default concurrency ceiling is five runs.
66
66
 
67
- Runs embedded directly in the Pi process end with that process. Runs launched through a terminal host can have a different lifetime and remain CLI-manageable. Reconciliation distinguishes stale registry records from live processes; do not assume every run outlives its parent session.
67
+ Runs embedded directly in the Pi process end with that process. Runs launched through a terminal host can have a different lifetime and remain CLI-manageable. Active session runs are contributed through Team's injected `doom/background-work` service; the contribution rebinds after provider replacement and retracts with Workflow. Reconciliation distinguishes stale registry records from live processes; do not assume every run outlives its parent session.
68
68
 
69
69
  Each workflow or repair step can launch commands and model-backed agents, consuming provider quota and repeating external side effects.
70
70
 
@@ -74,7 +74,7 @@ Recovery is available only for terminal failed records. A recovery claim atomica
74
74
 
75
75
  The package publishes `workflow-recovery` for active Workflow mode and contributes `workflow-help` while parent Help mode is active. Help deactivation logically hides the descriptor; cached files may remain.
76
76
 
77
- Every `extensions/pi` factory invocation owns a fresh package-local Cordis root. Pi owns reload and invokes `session_shutdown`; Workflow then fences retained callbacks, interrupts bounded inline work, unregisters protocol and UI resources, and awaits idempotent cleanup. Dispatcher children load this same factory, which detects their typed child-process context and limits them to workflow discovery and root-owned launch without an alternate extension entry.
77
+ Every `extensions/pi` factory invocation joins the runner-scoped Cordis host and mounts one Workflow plugin fiber. Pi owns reload and invokes `session_shutdown`; Workflow then fences retained callbacks, interrupts bounded inline work, releases Cordis service and UI registrations, disposes its plugin fiber, and finally releases its host lease. Dispatcher children load the same host/finalizer graph in their own process, then use this factory's typed child role without an alternate extension entry.
78
78
 
79
79
  ## Pi extension
80
80
 
@@ -1,2 +1,2 @@
1
- const e=require("./leader.cjs"),t=require("./workflow/piExtension.cjs");let n=require("node:async_hooks"),r=require("@agimon-ai/doompi-extension-contracts/child-process"),i=require("@agimon-ai/doompi-extension-contracts/help"),a=require("@agimon-ai/doompi-extension-contracts/protocol"),o=require("@agimon-ai/doompi-extension-contracts/workflow"),s=require("@deepseek-ai/cordis");const c=`@agimon-ai/doompi-workflow`,l=`${c}/dispatcher`,u=`agiflow-dispatcher`,d=`session_start`,f=`The workflow runtime is no longer active.`,p=Symbol(`doom-workflow-cleanup`),m=new Set([`list_workflows`,`launch_workflow`]),h=new Set([`launch_workflow`]);function g(e,t){let n=Reflect.get(e,t,e);return typeof n==`function`?n.bind(e):n}function _(e,t){let n=new Proxy(e.sessionManager,{get(e,n){return n===`getSessionId`?()=>t:g(e,n)}});return new Proxy(e,{get(e,t){return t===`sessionManager`?n:g(e,t)}})}function v(e,t,n=process.env){let i=t?(0,r.resolveRootSessionId)(t,n):void 0;return new Proxy(e,{get(e,t){return t===`setActiveTools`?t=>e.setActiveTools(t.filter(e=>e!==`workflow_run`)):t===`registerTool`?t=>{if(m.has(t.name)){if(!i||!h.has(t.name)){e.registerTool(t);return}e.registerTool({...t,execute:(e,n,r,a,o)=>t.execute(e,n,r,a,_(o,i))})}}:g(e,t)}})}function y(e){return(0,r.readChildProcessContext)(e)?.parentSessionId??(e[r.SUBAGENT_PARENT_SESSION_ENV]?.trim()||void 0)}function b(e){return(0,r.readChildProcessContext)(e)?.mode===u||e.PI_SUBAGENT_CHILD_AGENT===u&&!!e[r.SUBAGENT_PARENT_SESSION_ENV]?.trim()}function x(){return{content:[{type:`text`,text:f}],details:void 0}}function S(e){let t=new n.AsyncLocalStorage,r=!0,i=!1,a=0,o,s,c=new Set,l=()=>{if(!r)return!1;let e=t.getStore();return e===void 0||e===p||e===a},u=e=>{if(!r)return!1;let n=t.getStore();return n===p||e===a&&(n===void 0||n===e)},m=(e,t)=>{let n=new Proxy(e.ui,{get(e,n){let r=Reflect.get(e,n,e);return typeof r==`function`?(...i)=>{if(u(t))return Reflect.apply(r,e,i);if(n===`confirm`)return Promise.resolve(!1);if(n===`custom`||n===`editor`||n===`input`||n===`select`)return Promise.resolve(void 0)}:r}});return new Proxy(e,{get(e,t){return t===`ui`?n:g(e,t)}})},h={emit(t,n){l()&&e.events.emit(t,n)},on(n,i){if(!l())return()=>void 0;let o=t.getStore(),s=e.events.on(n,e=>{if(!r)return;let n=typeof o==`number`?o:a;(typeof o!=`number`||o===a)&&t.run(n,()=>i(e))}),u=!0,d=()=>{u&&(u=!1,c.delete(d),s())};return c.add(d),d}},_=n=>{l()&&e.registerTool({...n,execute:async(e,o,s,c,l)=>{let u=a;if(!r||i||s?.aborted)return x();let d=m(l,u),f=c?e=>{r&&u===a&&!s?.aborted&&c(e)}:void 0,p=await t.run(u,()=>n.execute(e,o,s,f,d));return r&&!i&&u===a?p:x()}})},v=(n,o)=>{l()&&e.registerCommand(n,{...o,handler:async(e,n)=>{let s=a;!r||i||await t.run(s,()=>o.handler(e,m(n,s)))}})},y=(n,o)=>{l()&&e.registerShortcut(n,{...o,handler:e=>{let n=a;if(!(!r||i))return t.run(n,()=>o.handler(m(e,n)))}})};return{pi:new Proxy(e,{get(e,n){return n===`events`?h:n===`on`?(n,c)=>{g(e,`on`)(n,(e,l)=>{if(!r||i)return;n===d&&(e!==o||l!==s)&&(a+=1,o=e,s=l);let u=a;return t.run(u,()=>c(e,m(l,u)))})}:n===`registerTool`?_:n===`registerCommand`?v:n===`registerShortcut`?y:n===`getActiveTools`?()=>l()?e.getActiveTools():[]:n===`setActiveTools`?t=>{l()&&e.setActiveTools(t)}:n===`sendMessage`?(...t)=>{l()&&e.sendMessage(...t)}:n===`sendUserMessage`?(...t)=>{l()&&e.sendUserMessage(...t)}:n===`exec`?(...t)=>l()?e.exec(...t):Promise.resolve({code:1,killed:!1,stderr:f,stdout:``}):g(e,n)}}),beginDisposal(){i||!r||(i=!0,a+=1)},disposeExternalSubscriptions(){let e=[];for(let t of c)try{t()}catch(t){e.push(t)}if(e.length>0)throw AggregateError(e,`Could not dispose workflow event subscriptions.`)},finishDisposal(){r=!1,i=!1,a+=1},isCurrentInvocation:l,runCleanup:e=>t.run(p,e)}}async function C(e,t){try{await t()}catch(t){process.emitWarning(`Doom-workflow cleanup could not ${e}: ${String(t)}`)}}function w(n,s,u,f=process.env){let p=b(f),m=p?y(f):void 0,h=m?(0,r.resolveRootSessionId)(m,f):void 0,g=p?v(s,m,f):s,_;if(n.effect(()=>()=>_?_.dispose():Promise.resolve(),`${c}/runtime`),p){_=t.installWorkflowPiRuntime({isActive:u})(g),s.on(d,(e,t)=>{let n=(0,r.resolveRootSessionId)(t.sessionManager.getSessionId());(0,a.createProtocolRuntime)({bus:s.events,source:l,sessionId:n}).notify(o.WorkflowModeChanged,{mode:`on`,...h?{parentSessionId:h}:{}})});return}let x=e.registerLeaderContribution(s);n.effect(()=>()=>C(`dispose the workflow leader contribution`,()=>x.dispose()),`${c}/leader`);let S=(0,i.registerDoomHelpContribution)(s,{source:c,moduleUrl:require("url").pathToFileURL(__filename).href,skills:[{name:`workflow-help`,description:`Use Doom Pi workflows, monitor long-running jobs, and recover failed runs safely.`}]});n.effect(()=>()=>C(`dispose the workflow help contribution`,()=>S.dispose()),`${c}/help`),_=t.installWorkflowPiRuntime({isActive:u,onModeChange:e=>x.setMode(e)})(g)}async function T(e){let t=new s.Context,n=S(e);t.effect(()=>()=>n.disposeExternalSubscriptions(),`${c}/event-subscriptions`);let r,i=()=>r||(n.beginDisposal(),r=n.runCleanup(async()=>{try{await t.fiber.dispose()}finally{n.finishDisposal()}}),r);try{w(t,n.pi,n.isCurrentInvocation),e.on(`session_shutdown`,i)}catch(e){throw await i(),e}}exports.createDispatcherBridge=v,exports.default=T,exports.workflowExtension=T,exports.installWorkflowRuntime=w,exports.isWorkflowDispatcherProcess=b,exports.resolveDispatcherParentSession=y;
1
+ const e=require("./leader.cjs"),t=require("./workflow/piExtension.cjs");let n=require("node:async_hooks"),r=require("node:fs"),i=require("node:path"),a=require("node:url"),o=require("@agimon-ai/doompi-extension-contracts/child-process"),s=require("@agimon-ai/doompi-extension-contracts/cordis-host"),c=require("@agimon-ai/doompi-extension-contracts/help"),l=require("@agimon-ai/doompi-extension-contracts/skills"),u=require("@agimon-ai/doompi-extension-contracts/ui-hub");const d=`@agimon-ai/doompi-workflow`,f=`agiflow-dispatcher`,p=`The workflow runtime is no longer active.`,m=Symbol(`doom-workflow-cleanup`),h=new Set([`list_workflows`,`launch_workflow`]),g=new Set([`launch_workflow`]);function _(e,t){let n=Reflect.get(e,t,e);return typeof n==`function`?n.bind(e):n}function v(e,t){let n=new Proxy(e.sessionManager,{get(e,n){return n===`getSessionId`?()=>t:_(e,n)}});return new Proxy(e,{get(e,t){return t===`sessionManager`?n:_(e,t)}})}function y(e,t,n=process.env){let r=t?(0,o.resolveRootSessionId)(t,n):void 0;return new Proxy(e,{get(e,t){return t===`setActiveTools`?t=>e.setActiveTools(t.filter(e=>e!==`workflow_run`)):t===`registerTool`?t=>{if(h.has(t.name)){if(!r||!g.has(t.name)){e.registerTool(t);return}e.registerTool({...t,execute:(e,n,i,a,o)=>t.execute(e,n,i,a,v(o,r))})}}:_(e,t)}})}function b(e){return(0,o.readChildProcessContext)(e)?.parentSessionId??(e[o.SUBAGENT_PARENT_SESSION_ENV]?.trim()||void 0)}function x(e){return(0,o.readChildProcessContext)(e)?.mode===f||e.PI_SUBAGENT_CHILD_AGENT===f&&!!e[o.SUBAGENT_PARENT_SESSION_ENV]?.trim()}function S(){return{content:[{type:`text`,text:p}],details:void 0}}function C(e){let t=new n.AsyncLocalStorage,r=!0,i=!1,a=0,o,s,c=()=>{if(!r)return!1;let e=t.getStore();return e===void 0||e===m||e===a},l=e=>{if(!r)return!1;let n=t.getStore();return n===m||e===a&&(n===void 0||n===e)},u=(e,t)=>{let n=new Proxy(e.ui,{get(e,n){let r=Reflect.get(e,n,e);return typeof r==`function`?(...i)=>{if(l(t))return Reflect.apply(r,e,i);if(n===`confirm`)return Promise.resolve(!1);if(n===`custom`||n===`editor`||n===`input`||n===`select`)return Promise.resolve(void 0)}:r}});return new Proxy(e,{get(e,t){return t===`ui`?n:_(e,t)}})},d=n=>{c()&&e.registerTool({...n,execute:async(e,o,s,c,l)=>{let d=a;if(!r||i||s?.aborted)return S();let f=u(l,d),p=c?e=>{r&&d===a&&!s?.aborted&&c(e)}:void 0,m=await t.run(d,()=>n.execute(e,o,s,p,f));return r&&!i&&d===a?m:S()}})},f=(n,o)=>{c()&&e.registerCommand(n,{...o,handler:async(e,n)=>{let s=a;!r||i||await t.run(s,()=>o.handler(e,u(n,s)))}})},h=(n,o)=>{c()&&e.registerShortcut(n,{...o,handler:e=>{let n=a;if(!(!r||i))return t.run(n,()=>o.handler(u(e,n)))}})};return{pi:new Proxy(e,{get(e,n){return n===`on`?(n,c)=>{_(e,`on`)(n,(e,l)=>{if(!r||i)return;n===`session_start`&&(e!==o||l!==s)&&(a+=1,o=e,s=l);let d=a;return t.run(d,()=>c(e,u(l,d)))})}:n===`registerTool`?d:n===`registerCommand`?f:n===`registerShortcut`?h:n===`getActiveTools`?()=>c()?e.getActiveTools():[]:n===`setActiveTools`?t=>{c()&&e.setActiveTools(t)}:n===`sendMessage`?(...t)=>{c()&&e.sendMessage(...t)}:n===`sendUserMessage`?(...t)=>{c()&&e.sendUserMessage(...t)}:n===`exec`?(...t)=>c()?e.exec(...t):Promise.resolve({code:1,killed:!1,stderr:p,stdout:``}):_(e,n)}}),beginDisposal(){i||!r||(i=!0,a+=1)},finishDisposal(){r=!1,i=!1,a+=1},isCurrentInvocation:c,runCleanup:e=>t.run(m,e)}}function w(n,o,s,f=process.env){let p=x(f),m=p?b(f):void 0,h=p?y(o,m,f):o,g;if(n.effect(()=>()=>g?g.dispose():Promise.resolve(),`${d}/runtime`),n.inject([l.DOOM_SKILL_SOURCES_SERVICE],e=>{let t=(0,i.resolve)((0,i.dirname)((0,a.fileURLToPath)(require("url").pathToFileURL(__filename).href)),`../../../skills`);if(!(0,r.existsSync)(t))return;let n=(0,l.requireDoomSkillSourcesService)(e).register({source:d,directories:[t]});return()=>n.dispose()}),p){g=t.installWorkflowPiRuntime({cordis:n,initialMode:!0,isActive:s})(h);return}let _=!1,v;n.inject([u.DOOM_UI_HUB_SERVICE],t=>{let n=e.registerLeaderContribution((0,u.requireDoomUiHub)(t),_);return v=n,()=>{n.dispose(),v===n&&(v=void 0)}}),n.inject([c.DOOM_HELP_SERVICE],e=>{let t=(0,c.requireDoomHelpService)(e).register({source:d,moduleUrl:require("url").pathToFileURL(__filename).href,skills:[{name:`workflow-help`,description:`Use Doom Pi workflows, monitor long-running jobs, and recover failed runs safely.`}]});return()=>t.dispose()}),g=t.installWorkflowPiRuntime({cordis:n,isActive:s,onModeChange:e=>{_=e,v?.setMode(e)}})(h)}function T(e,{fence:t,environment:n}){w(e,t.pi,t.isCurrentInvocation,n)}async function E(e){let t=await(0,s.connectDoomCordisHost)(e,d),n=C(e),r=t.root.plugin(T,{fence:n,environment:process.env}),i,a=()=>i||(n.beginDisposal(),i=n.runCleanup(async()=>{try{await r.dispose()}finally{try{n.finishDisposal()}finally{await t.dispose()}}}),i);try{await r}catch(e){throw await a(),e}e.on(`session_shutdown`,a)}exports.createDispatcherBridge=y,exports.default=E,exports.workflowExtension=E,exports.installWorkflowRuntime=w,exports.isWorkflowDispatcherProcess=x,exports.resolveDispatcherParentSession=b;
2
2
  //# sourceMappingURL=extension.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.cjs","names":["resolveRootSessionId","readChildProcessContext","SUBAGENT_PARENT_SESSION_ENV","AsyncLocalStorage","installWorkflowPiRuntime","WorkflowModeChanged","registerLeaderContribution","registerDoomHelpContribution","Context"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport {\n readChildProcessContext,\n resolveRootSessionId,\n SUBAGENT_PARENT_SESSION_ENV,\n} from '@agimon-ai/doompi-extension-contracts/child-process';\nimport { registerDoomHelpContribution } from '@agimon-ai/doompi-extension-contracts/help';\nimport { createProtocolRuntime, type EventBusLike } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport { WorkflowModeChanged } from '@agimon-ai/doompi-extension-contracts/workflow';\nimport { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { registerLeaderContribution } from './leader.ts';\nimport { installWorkflowPiRuntime, type WorkflowPiRuntime } from './workflow/piExtension.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-workflow';\nconst DISPATCHER_SOURCE = `${PACKAGE_SOURCE}/dispatcher`;\nconst DISPATCHER_AGENT_NAME = 'agiflow-dispatcher';\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\nconst INACTIVE_RUNTIME_MESSAGE = 'The workflow runtime is no longer active.';\nconst CLEANUP_SCOPE = Symbol('doom-workflow-cleanup');\n\nconst DISPATCHER_TOOL_NAMES = new Set(['list_workflows', 'launch_workflow']);\nconst ROOT_SCOPED_TOOL_NAMES = new Set(['launch_workflow']);\n\ntype RegisteredTool = Parameters<ExtensionAPI['registerTool']>[0];\ntype CommandOptions = Parameters<ExtensionAPI['registerCommand']>[1];\ntype ShortcutOptions = Parameters<ExtensionAPI['registerShortcut']>[1];\ntype RuntimeScope = number | typeof CLEANUP_SCOPE;\ntype LifecycleHandler = (event: unknown, context: ExtensionContext) => unknown;\n\ninterface WorkflowFence {\n readonly pi: ExtensionAPI;\n readonly beginDisposal: () => void;\n readonly disposeExternalSubscriptions: () => void;\n readonly finishDisposal: () => void;\n readonly isCurrentInvocation: () => boolean;\n readonly runCleanup: <T>(operation: () => T) => T;\n}\n\nfunction boundValue(target: object, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\nfunction withParentSession(ctx: ExtensionContext, parentSessionId: string): ExtensionContext {\n const sessionManager = new Proxy(ctx.sessionManager, {\n get(target, property) {\n if (property === 'getSessionId') return () => parentSessionId;\n return boundValue(target, property);\n },\n });\n return new Proxy(ctx, {\n get(target, property) {\n if (property === 'sessionManager') return sessionManager;\n return boundValue(target, property);\n },\n });\n}\n\n/** Restrict a dispatcher child to discovery and root-owned launch. */\nexport function createDispatcherBridge(\n pi: ExtensionAPI,\n parentSessionId: string | undefined,\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): ExtensionAPI {\n const rootSessionId = parentSessionId ? resolveRootSessionId(parentSessionId, environment) : undefined;\n return new Proxy(pi, {\n get(target, property) {\n if (property === 'setActiveTools') {\n return (names: string[]): void => target.setActiveTools(names.filter((name) => name !== 'workflow_run'));\n }\n if (property !== 'registerTool') return boundValue(target, property);\n return (tool: RegisteredTool): void => {\n if (!DISPATCHER_TOOL_NAMES.has(tool.name)) return;\n if (!rootSessionId || !ROOT_SCOPED_TOOL_NAMES.has(tool.name)) {\n target.registerTool(tool);\n return;\n }\n target.registerTool({\n ...tool,\n execute: (toolCallId, params, signal, onUpdate, ctx) =>\n tool.execute(toolCallId, params, signal, onUpdate, withParentSession(ctx, rootSessionId)),\n });\n };\n },\n });\n}\n\nexport function resolveDispatcherParentSession(\n environment: Readonly<Record<string, string | undefined>>,\n): string | undefined {\n const childContext = readChildProcessContext(environment);\n return childContext?.parentSessionId ?? (environment[SUBAGENT_PARENT_SESSION_ENV]?.trim() || undefined);\n}\n\nexport function isWorkflowDispatcherProcess(environment: Readonly<Record<string, string | undefined>>): boolean {\n const childContext = readChildProcessContext(environment);\n if (childContext?.mode === DISPATCHER_AGENT_NAME) return true;\n return (\n environment.PI_SUBAGENT_CHILD_AGENT === DISPATCHER_AGENT_NAME &&\n Boolean(environment[SUBAGENT_PARENT_SESSION_ENV]?.trim())\n );\n}\n\nfunction inactiveToolResult(): Awaited<ReturnType<RegisteredTool['execute']>> {\n return {\n content: [{ type: 'text', text: INACTIVE_RUNTIME_MESSAGE }],\n details: undefined,\n };\n}\n\n/** Fence every callback retained by Pi after this package root is replaced. */\nfunction createWorkflowFence(host: ExtensionAPI): WorkflowFence {\n const scope = new AsyncLocalStorage<RuntimeScope>();\n let active = true;\n let disposing = false;\n let generation = 0;\n let lastSessionStartEvent: unknown;\n let lastSessionStartContext: ExtensionContext | undefined;\n const eventUnsubscribers = new Set<() => void>();\n\n const isCurrentInvocation = (): boolean => {\n if (!active) return false;\n const currentScope = scope.getStore();\n return currentScope === undefined || currentScope === CLEANUP_SCOPE || currentScope === generation;\n };\n const ownsContext = (contextGeneration: number): boolean => {\n if (!active) return false;\n const currentScope = scope.getStore();\n return (\n currentScope === CLEANUP_SCOPE ||\n (contextGeneration === generation && (currentScope === undefined || currentScope === contextGeneration))\n );\n };\n\n const guardContext = <TContext extends ExtensionContext>(context: TContext, contextGeneration: number): TContext => {\n const guardedUi = new Proxy(context.ui, {\n get(target, property) {\n const value = Reflect.get(target, property, target);\n if (typeof value !== 'function') return value;\n return (...args: unknown[]): unknown => {\n if (ownsContext(contextGeneration)) return Reflect.apply(value, target, args);\n if (property === 'confirm') return Promise.resolve(false);\n if (property === 'custom' || property === 'editor' || property === 'input' || property === 'select') {\n return Promise.resolve(undefined);\n }\n return undefined;\n };\n },\n });\n return new Proxy(context, {\n get(target, property) {\n if (property === 'ui') return guardedUi;\n return boundValue(target, property);\n },\n }) as TContext;\n };\n\n const events: EventBusLike = {\n emit(channel, data) {\n if (isCurrentInvocation()) host.events.emit(channel, data);\n },\n on(channel, handler) {\n if (!isCurrentInvocation()) return () => undefined;\n const ownerScope = scope.getStore();\n const unsubscribe = host.events.on(channel, (data) => {\n if (!active) return;\n const callbackGeneration = typeof ownerScope === 'number' ? ownerScope : generation;\n if (typeof ownerScope === 'number' && ownerScope !== generation) return;\n scope.run(callbackGeneration, () => handler(data));\n });\n let subscribed = true;\n const disposeSubscription = (): void => {\n if (!subscribed) return;\n subscribed = false;\n eventUnsubscribers.delete(disposeSubscription);\n unsubscribe();\n };\n eventUnsubscribers.add(disposeSubscription);\n return disposeSubscription;\n },\n };\n\n const registerTool = (tool: RegisteredTool): void => {\n if (!isCurrentInvocation()) return;\n host.registerTool({\n ...tool,\n execute: async (toolCallId, params, signal, onUpdate, context) => {\n const executionGeneration = generation;\n if (!active || disposing || signal?.aborted) return inactiveToolResult();\n const guardedContext = guardContext(context, executionGeneration);\n const guardedUpdate = onUpdate\n ? (update: Parameters<NonNullable<typeof onUpdate>>[0]): void => {\n if (active && executionGeneration === generation && !signal?.aborted) onUpdate(update);\n }\n : undefined;\n const result = await scope.run(executionGeneration, () =>\n tool.execute(toolCallId, params, signal, guardedUpdate, guardedContext),\n );\n return active && !disposing && executionGeneration === generation ? result : inactiveToolResult();\n },\n });\n };\n\n const registerCommand = (name: string, options: CommandOptions): void => {\n if (!isCurrentInvocation()) return;\n host.registerCommand(name, {\n ...options,\n handler: async (args, context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n await scope.run(executionGeneration, () => options.handler(args, guardContext(context, executionGeneration)));\n },\n });\n };\n\n const registerShortcut = (\n shortcut: Parameters<ExtensionAPI['registerShortcut']>[0],\n options: ShortcutOptions,\n ): void => {\n if (!isCurrentInvocation()) return;\n host.registerShortcut(shortcut, {\n ...options,\n handler: (context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n return scope.run(executionGeneration, () => options.handler(guardContext(context, executionGeneration)));\n },\n });\n };\n\n const guardedPi = new Proxy(host, {\n get(target, property) {\n if (property === 'events') return events;\n if (property === 'on') {\n return (eventName: string, handler: LifecycleHandler): void => {\n const registerLifecycleHandler = boundValue(target, 'on') as (\n name: string,\n callback: LifecycleHandler,\n ) => void;\n registerLifecycleHandler(eventName, (event: unknown, context: ExtensionContext) => {\n if (!active || disposing) return undefined;\n if (\n eventName === SESSION_START_EVENT &&\n (event !== lastSessionStartEvent || context !== lastSessionStartContext)\n ) {\n generation += 1;\n lastSessionStartEvent = event;\n lastSessionStartContext = context;\n }\n const eventGeneration = generation;\n return scope.run(eventGeneration, () => handler(event, guardContext(context, eventGeneration)));\n });\n };\n }\n if (property === 'registerTool') return registerTool;\n if (property === 'registerCommand') return registerCommand;\n if (property === 'registerShortcut') return registerShortcut;\n if (property === 'getActiveTools') {\n return (): string[] => (isCurrentInvocation() ? target.getActiveTools() : []);\n }\n if (property === 'setActiveTools') {\n return (names: string[]): void => {\n if (isCurrentInvocation()) target.setActiveTools(names);\n };\n }\n if (property === 'sendMessage') {\n return (...args: Parameters<ExtensionAPI['sendMessage']>): void => {\n if (isCurrentInvocation()) target.sendMessage(...args);\n };\n }\n if (property === 'sendUserMessage') {\n return (...args: Parameters<ExtensionAPI['sendUserMessage']>): void => {\n if (isCurrentInvocation()) target.sendUserMessage(...args);\n };\n }\n if (property === 'exec') {\n return (...args: Parameters<ExtensionAPI['exec']>): ReturnType<ExtensionAPI['exec']> =>\n isCurrentInvocation()\n ? target.exec(...args)\n : Promise.resolve({ code: 1, killed: false, stderr: INACTIVE_RUNTIME_MESSAGE, stdout: '' });\n }\n return boundValue(target, property);\n },\n });\n\n return {\n pi: guardedPi,\n beginDisposal() {\n if (disposing || !active) return;\n disposing = true;\n generation += 1;\n },\n disposeExternalSubscriptions() {\n const errors: unknown[] = [];\n for (const unsubscribe of eventUnsubscribers) {\n try {\n unsubscribe();\n } catch (error) {\n errors.push(error);\n }\n }\n if (errors.length > 0) throw new AggregateError(errors, 'Could not dispose workflow event subscriptions.');\n },\n finishDisposal() {\n active = false;\n disposing = false;\n generation += 1;\n },\n isCurrentInvocation,\n runCleanup: (operation) => scope.run(CLEANUP_SCOPE, operation),\n };\n}\n\nasync function disposeSafely(label: string, cleanup: () => void | Promise<void>): Promise<void> {\n try {\n await cleanup();\n } catch (error) {\n process.emitWarning(`Doom-workflow cleanup could not ${label}: ${String(error)}`);\n }\n}\n\n/** Install one normal or dispatcher runtime into a package-local Cordis root. */\nexport function installWorkflowRuntime(\n cordis: Context,\n pi: ExtensionAPI,\n isCurrentInvocation: () => boolean,\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): void {\n const dispatcher = isWorkflowDispatcherProcess(environment);\n const parentSessionId = dispatcher ? resolveDispatcherParentSession(environment) : undefined;\n const rootSessionId = parentSessionId ? resolveRootSessionId(parentSessionId, environment) : undefined;\n const runtimePi = dispatcher ? createDispatcherBridge(pi, parentSessionId, environment) : pi;\n\n let runtime: WorkflowPiRuntime | undefined;\n cordis.effect(() => () => (runtime ? runtime.dispose() : Promise.resolve()), `${PACKAGE_SOURCE}/runtime`);\n\n if (dispatcher) {\n runtime = installWorkflowPiRuntime({ isActive: isCurrentInvocation })(runtimePi);\n pi.on(SESSION_START_EVENT, (_event, context) => {\n const sessionId = resolveRootSessionId(context.sessionManager.getSessionId());\n createProtocolRuntime({ bus: pi.events, source: DISPATCHER_SOURCE, sessionId }).notify(WorkflowModeChanged, {\n mode: 'on',\n ...(rootSessionId ? { parentSessionId: rootSessionId } : {}),\n });\n });\n return;\n }\n\n const leader = registerLeaderContribution(pi);\n cordis.effect(\n () => () => disposeSafely('dispose the workflow leader contribution', () => leader.dispose()),\n `${PACKAGE_SOURCE}/leader`,\n );\n const help = registerDoomHelpContribution(pi, {\n source: PACKAGE_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'workflow-help',\n description: 'Use Doom Pi workflows, monitor long-running jobs, and recover failed runs safely.',\n },\n ],\n });\n cordis.effect(\n () => () => disposeSafely('dispose the workflow help contribution', () => help.dispose()),\n `${PACKAGE_SOURCE}/help`,\n );\n runtime = installWorkflowPiRuntime({\n isActive: isCurrentInvocation,\n onModeChange: (enabled) => leader.setMode(enabled),\n })(runtimePi);\n}\n\n/** The package's sole Pi factory; Pi reloads it and Cordis owns all package resources. */\nexport async function workflowExtension(pi: ExtensionAPI): Promise<void> {\n const cordis = new Context();\n const fence = createWorkflowFence(pi);\n cordis.effect(() => () => fence.disposeExternalSubscriptions(), `${PACKAGE_SOURCE}/event-subscriptions`);\n let disposal: Promise<void> | undefined;\n const dispose = (): Promise<void> => {\n if (disposal) return disposal;\n fence.beginDisposal();\n disposal = fence.runCleanup(async () => {\n try {\n await cordis.fiber.dispose();\n } finally {\n fence.finishDisposal();\n }\n });\n return disposal;\n };\n\n try {\n installWorkflowRuntime(cordis, fence.pi, fence.isCurrentInvocation);\n pi.on(SESSION_SHUTDOWN_EVENT, dispose);\n } catch (error) {\n await dispose();\n throw error;\n }\n}\n\nexport default workflowExtension;\n"],"mappings":"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"}
1
+ {"version":3,"file":"extension.cjs","names":["resolveRootSessionId","readChildProcessContext","SUBAGENT_PARENT_SESSION_ENV","AsyncLocalStorage","DOOM_SKILL_SOURCES_SERVICE","resolve","dirname","fileURLToPath","existsSync","requireDoomSkillSourcesService","installWorkflowPiRuntime","DOOM_UI_HUB_SERVICE","registerLeaderContribution","requireDoomUiHub","DOOM_HELP_SERVICE","requireDoomHelpService","connectDoomCordisHost"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n readChildProcessContext,\n resolveRootSessionId,\n SUBAGENT_PARENT_SESSION_ENV,\n} from '@agimon-ai/doompi-extension-contracts/child-process';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_HELP_SERVICE, requireDoomHelpService } from '@agimon-ai/doompi-extension-contracts/help';\nimport {\n DOOM_SKILL_SOURCES_SERVICE,\n requireDoomSkillSourcesService,\n} from '@agimon-ai/doompi-extension-contracts/skills';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { registerLeaderContribution } from './leader.ts';\nimport { installWorkflowPiRuntime, type WorkflowPiRuntime } from './workflow/piExtension.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-workflow';\nconst SKILL_RELATIVE_PATH = '../../../skills';\nconst DISPATCHER_AGENT_NAME = 'agiflow-dispatcher';\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\nconst INACTIVE_RUNTIME_MESSAGE = 'The workflow runtime is no longer active.';\nconst CLEANUP_SCOPE = Symbol('doom-workflow-cleanup');\n\nconst DISPATCHER_TOOL_NAMES = new Set(['list_workflows', 'launch_workflow']);\nconst ROOT_SCOPED_TOOL_NAMES = new Set(['launch_workflow']);\n\ntype RegisteredTool = Parameters<ExtensionAPI['registerTool']>[0];\ntype CommandOptions = Parameters<ExtensionAPI['registerCommand']>[1];\ntype ShortcutOptions = Parameters<ExtensionAPI['registerShortcut']>[1];\ntype RuntimeScope = number | typeof CLEANUP_SCOPE;\ntype LifecycleHandler = (event: unknown, context: ExtensionContext) => unknown;\n\ninterface WorkflowFence {\n readonly pi: ExtensionAPI;\n readonly beginDisposal: () => void;\n readonly finishDisposal: () => void;\n readonly isCurrentInvocation: () => boolean;\n readonly runCleanup: <T>(operation: () => T) => T;\n}\n\nfunction boundValue(target: object, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\nfunction withParentSession(ctx: ExtensionContext, parentSessionId: string): ExtensionContext {\n const sessionManager = new Proxy(ctx.sessionManager, {\n get(target, property) {\n if (property === 'getSessionId') return () => parentSessionId;\n return boundValue(target, property);\n },\n });\n return new Proxy(ctx, {\n get(target, property) {\n if (property === 'sessionManager') return sessionManager;\n return boundValue(target, property);\n },\n });\n}\n\n/** Restrict a dispatcher child to discovery and root-owned launch. */\nexport function createDispatcherBridge(\n pi: ExtensionAPI,\n parentSessionId: string | undefined,\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): ExtensionAPI {\n const rootSessionId = parentSessionId ? resolveRootSessionId(parentSessionId, environment) : undefined;\n return new Proxy(pi, {\n get(target, property) {\n if (property === 'setActiveTools') {\n return (names: string[]): void => target.setActiveTools(names.filter((name) => name !== 'workflow_run'));\n }\n if (property !== 'registerTool') return boundValue(target, property);\n return (tool: RegisteredTool): void => {\n if (!DISPATCHER_TOOL_NAMES.has(tool.name)) return;\n if (!rootSessionId || !ROOT_SCOPED_TOOL_NAMES.has(tool.name)) {\n target.registerTool(tool);\n return;\n }\n target.registerTool({\n ...tool,\n execute: (toolCallId, params, signal, onUpdate, ctx) =>\n tool.execute(toolCallId, params, signal, onUpdate, withParentSession(ctx, rootSessionId)),\n });\n };\n },\n });\n}\n\nexport function resolveDispatcherParentSession(\n environment: Readonly<Record<string, string | undefined>>,\n): string | undefined {\n const childContext = readChildProcessContext(environment);\n return childContext?.parentSessionId ?? (environment[SUBAGENT_PARENT_SESSION_ENV]?.trim() || undefined);\n}\n\nexport function isWorkflowDispatcherProcess(environment: Readonly<Record<string, string | undefined>>): boolean {\n const childContext = readChildProcessContext(environment);\n if (childContext?.mode === DISPATCHER_AGENT_NAME) return true;\n return (\n environment.PI_SUBAGENT_CHILD_AGENT === DISPATCHER_AGENT_NAME &&\n Boolean(environment[SUBAGENT_PARENT_SESSION_ENV]?.trim())\n );\n}\n\nfunction inactiveToolResult(): Awaited<ReturnType<RegisteredTool['execute']>> {\n return {\n content: [{ type: 'text', text: INACTIVE_RUNTIME_MESSAGE }],\n details: undefined,\n };\n}\n\n/** Fence every callback retained by Pi after this package root is replaced. */\nfunction createWorkflowFence(host: ExtensionAPI): WorkflowFence {\n const scope = new AsyncLocalStorage<RuntimeScope>();\n let active = true;\n let disposing = false;\n let generation = 0;\n let lastSessionStartEvent: unknown;\n let lastSessionStartContext: ExtensionContext | undefined;\n\n const isCurrentInvocation = (): boolean => {\n if (!active) return false;\n const currentScope = scope.getStore();\n return currentScope === undefined || currentScope === CLEANUP_SCOPE || currentScope === generation;\n };\n const ownsContext = (contextGeneration: number): boolean => {\n if (!active) return false;\n const currentScope = scope.getStore();\n return (\n currentScope === CLEANUP_SCOPE ||\n (contextGeneration === generation && (currentScope === undefined || currentScope === contextGeneration))\n );\n };\n\n const guardContext = <TContext extends ExtensionContext>(context: TContext, contextGeneration: number): TContext => {\n const guardedUi = new Proxy(context.ui, {\n get(target, property) {\n const value = Reflect.get(target, property, target);\n if (typeof value !== 'function') return value;\n return (...args: unknown[]): unknown => {\n if (ownsContext(contextGeneration)) return Reflect.apply(value, target, args);\n if (property === 'confirm') return Promise.resolve(false);\n if (property === 'custom' || property === 'editor' || property === 'input' || property === 'select') {\n return Promise.resolve(undefined);\n }\n return undefined;\n };\n },\n });\n return new Proxy(context, {\n get(target, property) {\n if (property === 'ui') return guardedUi;\n return boundValue(target, property);\n },\n }) as TContext;\n };\n\n const registerTool = (tool: RegisteredTool): void => {\n if (!isCurrentInvocation()) return;\n host.registerTool({\n ...tool,\n execute: async (toolCallId, params, signal, onUpdate, context) => {\n const executionGeneration = generation;\n if (!active || disposing || signal?.aborted) return inactiveToolResult();\n const guardedContext = guardContext(context, executionGeneration);\n const guardedUpdate = onUpdate\n ? (update: Parameters<NonNullable<typeof onUpdate>>[0]): void => {\n if (active && executionGeneration === generation && !signal?.aborted) onUpdate(update);\n }\n : undefined;\n const result = await scope.run(executionGeneration, () =>\n tool.execute(toolCallId, params, signal, guardedUpdate, guardedContext),\n );\n return active && !disposing && executionGeneration === generation ? result : inactiveToolResult();\n },\n });\n };\n\n const registerCommand = (name: string, options: CommandOptions): void => {\n if (!isCurrentInvocation()) return;\n host.registerCommand(name, {\n ...options,\n handler: async (args, context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n await scope.run(executionGeneration, () => options.handler(args, guardContext(context, executionGeneration)));\n },\n });\n };\n\n const registerShortcut = (\n shortcut: Parameters<ExtensionAPI['registerShortcut']>[0],\n options: ShortcutOptions,\n ): void => {\n if (!isCurrentInvocation()) return;\n host.registerShortcut(shortcut, {\n ...options,\n handler: (context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n return scope.run(executionGeneration, () => options.handler(guardContext(context, executionGeneration)));\n },\n });\n };\n\n const guardedPi = new Proxy(host, {\n get(target, property) {\n if (property === 'on') {\n return (eventName: string, handler: LifecycleHandler): void => {\n const registerLifecycleHandler = boundValue(target, 'on') as (\n name: string,\n callback: LifecycleHandler,\n ) => void;\n registerLifecycleHandler(eventName, (event: unknown, context: ExtensionContext) => {\n if (!active || disposing) return undefined;\n if (\n eventName === SESSION_START_EVENT &&\n (event !== lastSessionStartEvent || context !== lastSessionStartContext)\n ) {\n generation += 1;\n lastSessionStartEvent = event;\n lastSessionStartContext = context;\n }\n const eventGeneration = generation;\n return scope.run(eventGeneration, () => handler(event, guardContext(context, eventGeneration)));\n });\n };\n }\n if (property === 'registerTool') return registerTool;\n if (property === 'registerCommand') return registerCommand;\n if (property === 'registerShortcut') return registerShortcut;\n if (property === 'getActiveTools') {\n return (): string[] => (isCurrentInvocation() ? target.getActiveTools() : []);\n }\n if (property === 'setActiveTools') {\n return (names: string[]): void => {\n if (isCurrentInvocation()) target.setActiveTools(names);\n };\n }\n if (property === 'sendMessage') {\n return (...args: Parameters<ExtensionAPI['sendMessage']>): void => {\n if (isCurrentInvocation()) target.sendMessage(...args);\n };\n }\n if (property === 'sendUserMessage') {\n return (...args: Parameters<ExtensionAPI['sendUserMessage']>): void => {\n if (isCurrentInvocation()) target.sendUserMessage(...args);\n };\n }\n if (property === 'exec') {\n return (...args: Parameters<ExtensionAPI['exec']>): ReturnType<ExtensionAPI['exec']> =>\n isCurrentInvocation()\n ? target.exec(...args)\n : Promise.resolve({ code: 1, killed: false, stderr: INACTIVE_RUNTIME_MESSAGE, stdout: '' });\n }\n return boundValue(target, property);\n },\n });\n\n return {\n pi: guardedPi,\n beginDisposal() {\n if (disposing || !active) return;\n disposing = true;\n generation += 1;\n },\n finishDisposal() {\n active = false;\n disposing = false;\n generation += 1;\n },\n isCurrentInvocation,\n runCleanup: (operation) => scope.run(CLEANUP_SCOPE, operation),\n };\n}\n\n/** Install one normal or dispatcher runtime into its host-owned Cordis plugin fiber. */\nexport function installWorkflowRuntime(\n cordis: Context,\n pi: ExtensionAPI,\n isCurrentInvocation: () => boolean,\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): void {\n const dispatcher = isWorkflowDispatcherProcess(environment);\n const parentSessionId = dispatcher ? resolveDispatcherParentSession(environment) : undefined;\n const runtimePi = dispatcher ? createDispatcherBridge(pi, parentSessionId, environment) : pi;\n\n let runtime: WorkflowPiRuntime | undefined;\n cordis.effect(() => () => (runtime ? runtime.dispose() : Promise.resolve()), `${PACKAGE_SOURCE}/runtime`);\n\n cordis.inject([DOOM_SKILL_SOURCES_SERVICE], (skillContext) => {\n const directory = resolve(dirname(fileURLToPath(import.meta.url)), SKILL_RELATIVE_PATH);\n if (!existsSync(directory)) return undefined;\n const contribution = requireDoomSkillSourcesService(skillContext).register({\n source: PACKAGE_SOURCE,\n directories: [directory],\n });\n return () => contribution.dispose();\n });\n\n if (dispatcher) {\n runtime = installWorkflowPiRuntime({ cordis, initialMode: true, isActive: isCurrentInvocation })(runtimePi);\n return;\n }\n\n let workflowMode = false;\n let leader: ReturnType<typeof registerLeaderContribution> | undefined;\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n const contribution = registerLeaderContribution(requireDoomUiHub(uiContext), workflowMode);\n leader = contribution;\n return () => {\n contribution.dispose();\n if (leader === contribution) leader = undefined;\n };\n });\n cordis.inject([DOOM_HELP_SERVICE], (helpContext) => {\n const help = requireDoomHelpService(helpContext).register({\n source: PACKAGE_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'workflow-help',\n description: 'Use Doom Pi workflows, monitor long-running jobs, and recover failed runs safely.',\n },\n ],\n });\n return () => help.dispose();\n });\n runtime = installWorkflowPiRuntime({\n cordis,\n isActive: isCurrentInvocation,\n onModeChange: (enabled) => {\n workflowMode = enabled;\n leader?.setMode(enabled);\n },\n })(runtimePi);\n}\n\ninterface WorkflowPluginConfig {\n readonly fence: WorkflowFence;\n readonly environment: Readonly<Record<string, string | undefined>>;\n}\n\nfunction workflowPlugin(cordis: Context, { fence, environment }: WorkflowPluginConfig): void {\n installWorkflowRuntime(cordis, fence.pi, fence.isCurrentInvocation, environment);\n}\n\n/** The package's sole Pi factory; Pi reloads it and Cordis owns all package resources. */\nexport async function workflowExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fence = createWorkflowFence(pi);\n const fiber = connection.root.plugin(workflowPlugin, { fence, environment: process.env });\n let disposal: Promise<void> | undefined;\n const dispose = (): Promise<void> => {\n if (disposal) return disposal;\n fence.beginDisposal();\n disposal = fence.runCleanup(async () => {\n try {\n await fiber.dispose();\n } finally {\n try {\n fence.finishDisposal();\n } finally {\n await connection.dispose();\n }\n }\n });\n return disposal;\n };\n\n try {\n await fiber;\n } catch (error) {\n await dispose();\n throw error;\n }\n pi.on(SESSION_SHUTDOWN_EVENT, dispose);\n}\n\nexport default workflowExtension;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAwXsB,kBAAkB,IAAI,eAAe"}
1
+ {"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAmWsB,kBAAkB,IAAI,eAAe"}
@@ -1,4 +1,4 @@
1
- import { Context } from "@deepseek-ai/cordis";
1
+ import "@deepseek-ai/cordis";
2
2
  import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
3
  //#region src/adapters/pi/extension.d.ts
4
4
  /** The package's sole Pi factory; Pi reloads it and Cordis owns all package resources. */
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAwXsB,kBAAkB,IAAI,eAAe"}
1
+ {"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAmWsB,kBAAkB,IAAI,eAAe"}
@@ -1,2 +1,2 @@
1
- import{registerLeaderContribution as e}from"./leader.mjs";import{installWorkflowPiRuntime as t}from"./workflow/piExtension.mjs";import{AsyncLocalStorage as n}from"node:async_hooks";import{SUBAGENT_PARENT_SESSION_ENV as r,readChildProcessContext as i,resolveRootSessionId as a}from"@agimon-ai/doompi-extension-contracts/child-process";import{registerDoomHelpContribution as o}from"@agimon-ai/doompi-extension-contracts/help";import{createProtocolRuntime as s}from"@agimon-ai/doompi-extension-contracts/protocol";import{WorkflowModeChanged as c}from"@agimon-ai/doompi-extension-contracts/workflow";import{Context as l}from"@deepseek-ai/cordis";const u=`@agimon-ai/doompi-workflow`,d=`${u}/dispatcher`,f=`agiflow-dispatcher`,p=`session_start`,m=`The workflow runtime is no longer active.`,h=Symbol(`doom-workflow-cleanup`),g=new Set([`list_workflows`,`launch_workflow`]),_=new Set([`launch_workflow`]);function v(e,t){let n=Reflect.get(e,t,e);return typeof n==`function`?n.bind(e):n}function y(e,t){let n=new Proxy(e.sessionManager,{get(e,n){return n===`getSessionId`?()=>t:v(e,n)}});return new Proxy(e,{get(e,t){return t===`sessionManager`?n:v(e,t)}})}function b(e,t,n=process.env){let r=t?a(t,n):void 0;return new Proxy(e,{get(e,t){return t===`setActiveTools`?t=>e.setActiveTools(t.filter(e=>e!==`workflow_run`)):t===`registerTool`?t=>{if(g.has(t.name)){if(!r||!_.has(t.name)){e.registerTool(t);return}e.registerTool({...t,execute:(e,n,i,a,o)=>t.execute(e,n,i,a,y(o,r))})}}:v(e,t)}})}function x(e){return i(e)?.parentSessionId??(e[r]?.trim()||void 0)}function S(e){return i(e)?.mode===f||e.PI_SUBAGENT_CHILD_AGENT===f&&!!e[r]?.trim()}function C(){return{content:[{type:`text`,text:m}],details:void 0}}function w(e){let t=new n,r=!0,i=!1,a=0,o,s,c=new Set,l=()=>{if(!r)return!1;let e=t.getStore();return e===void 0||e===h||e===a},u=e=>{if(!r)return!1;let n=t.getStore();return n===h||e===a&&(n===void 0||n===e)},d=(e,t)=>{let n=new Proxy(e.ui,{get(e,n){let r=Reflect.get(e,n,e);return typeof r==`function`?(...i)=>{if(u(t))return Reflect.apply(r,e,i);if(n===`confirm`)return Promise.resolve(!1);if(n===`custom`||n===`editor`||n===`input`||n===`select`)return Promise.resolve(void 0)}:r}});return new Proxy(e,{get(e,t){return t===`ui`?n:v(e,t)}})},f={emit(t,n){l()&&e.events.emit(t,n)},on(n,i){if(!l())return()=>void 0;let o=t.getStore(),s=e.events.on(n,e=>{if(!r)return;let n=typeof o==`number`?o:a;(typeof o!=`number`||o===a)&&t.run(n,()=>i(e))}),u=!0,d=()=>{u&&(u=!1,c.delete(d),s())};return c.add(d),d}},g=n=>{l()&&e.registerTool({...n,execute:async(e,o,s,c,l)=>{let u=a;if(!r||i||s?.aborted)return C();let f=d(l,u),p=c?e=>{r&&u===a&&!s?.aborted&&c(e)}:void 0,m=await t.run(u,()=>n.execute(e,o,s,p,f));return r&&!i&&u===a?m:C()}})},_=(n,o)=>{l()&&e.registerCommand(n,{...o,handler:async(e,n)=>{let s=a;!r||i||await t.run(s,()=>o.handler(e,d(n,s)))}})},y=(n,o)=>{l()&&e.registerShortcut(n,{...o,handler:e=>{let n=a;if(!(!r||i))return t.run(n,()=>o.handler(d(e,n)))}})};return{pi:new Proxy(e,{get(e,n){return n===`events`?f:n===`on`?(n,c)=>{v(e,`on`)(n,(e,l)=>{if(!r||i)return;n===p&&(e!==o||l!==s)&&(a+=1,o=e,s=l);let u=a;return t.run(u,()=>c(e,d(l,u)))})}:n===`registerTool`?g:n===`registerCommand`?_:n===`registerShortcut`?y:n===`getActiveTools`?()=>l()?e.getActiveTools():[]:n===`setActiveTools`?t=>{l()&&e.setActiveTools(t)}:n===`sendMessage`?(...t)=>{l()&&e.sendMessage(...t)}:n===`sendUserMessage`?(...t)=>{l()&&e.sendUserMessage(...t)}:n===`exec`?(...t)=>l()?e.exec(...t):Promise.resolve({code:1,killed:!1,stderr:m,stdout:``}):v(e,n)}}),beginDisposal(){i||!r||(i=!0,a+=1)},disposeExternalSubscriptions(){let e=[];for(let t of c)try{t()}catch(t){e.push(t)}if(e.length>0)throw AggregateError(e,`Could not dispose workflow event subscriptions.`)},finishDisposal(){r=!1,i=!1,a+=1},isCurrentInvocation:l,runCleanup:e=>t.run(h,e)}}async function T(e,t){try{await t()}catch(t){process.emitWarning(`Doom-workflow cleanup could not ${e}: ${String(t)}`)}}function E(n,r,i,l=process.env){let f=S(l),m=f?x(l):void 0,h=m?a(m,l):void 0,g=f?b(r,m,l):r,_;if(n.effect(()=>()=>_?_.dispose():Promise.resolve(),`${u}/runtime`),f){_=t({isActive:i})(g),r.on(p,(e,t)=>{let n=a(t.sessionManager.getSessionId());s({bus:r.events,source:d,sessionId:n}).notify(c,{mode:`on`,...h?{parentSessionId:h}:{}})});return}let v=e(r);n.effect(()=>()=>T(`dispose the workflow leader contribution`,()=>v.dispose()),`${u}/leader`);let y=o(r,{source:u,moduleUrl:import.meta.url,skills:[{name:`workflow-help`,description:`Use Doom Pi workflows, monitor long-running jobs, and recover failed runs safely.`}]});n.effect(()=>()=>T(`dispose the workflow help contribution`,()=>y.dispose()),`${u}/help`),_=t({isActive:i,onModeChange:e=>v.setMode(e)})(g)}async function D(e){let t=new l,n=w(e);t.effect(()=>()=>n.disposeExternalSubscriptions(),`${u}/event-subscriptions`);let r,i=()=>r||(n.beginDisposal(),r=n.runCleanup(async()=>{try{await t.fiber.dispose()}finally{n.finishDisposal()}}),r);try{E(t,n.pi,n.isCurrentInvocation),e.on(`session_shutdown`,i)}catch(e){throw await i(),e}}export{b as createDispatcherBridge,D as default,D as workflowExtension,E as installWorkflowRuntime,S as isWorkflowDispatcherProcess,x as resolveDispatcherParentSession};
1
+ import{registerLeaderContribution as e}from"./leader.mjs";import{installWorkflowPiRuntime as t}from"./workflow/piExtension.mjs";import{AsyncLocalStorage as n}from"node:async_hooks";import{existsSync as r}from"node:fs";import{dirname as i,resolve as a}from"node:path";import{fileURLToPath as o}from"node:url";import{SUBAGENT_PARENT_SESSION_ENV as s,readChildProcessContext as c,resolveRootSessionId as l}from"@agimon-ai/doompi-extension-contracts/child-process";import{connectDoomCordisHost as u}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{DOOM_HELP_SERVICE as d,requireDoomHelpService as f}from"@agimon-ai/doompi-extension-contracts/help";import{DOOM_SKILL_SOURCES_SERVICE as p,requireDoomSkillSourcesService as m}from"@agimon-ai/doompi-extension-contracts/skills";import{DOOM_UI_HUB_SERVICE as h,requireDoomUiHub as g}from"@agimon-ai/doompi-extension-contracts/ui-hub";const _=`@agimon-ai/doompi-workflow`,v=`agiflow-dispatcher`,y=`The workflow runtime is no longer active.`,b=Symbol(`doom-workflow-cleanup`),x=new Set([`list_workflows`,`launch_workflow`]),S=new Set([`launch_workflow`]);function C(e,t){let n=Reflect.get(e,t,e);return typeof n==`function`?n.bind(e):n}function w(e,t){let n=new Proxy(e.sessionManager,{get(e,n){return n===`getSessionId`?()=>t:C(e,n)}});return new Proxy(e,{get(e,t){return t===`sessionManager`?n:C(e,t)}})}function T(e,t,n=process.env){let r=t?l(t,n):void 0;return new Proxy(e,{get(e,t){return t===`setActiveTools`?t=>e.setActiveTools(t.filter(e=>e!==`workflow_run`)):t===`registerTool`?t=>{if(x.has(t.name)){if(!r||!S.has(t.name)){e.registerTool(t);return}e.registerTool({...t,execute:(e,n,i,a,o)=>t.execute(e,n,i,a,w(o,r))})}}:C(e,t)}})}function E(e){return c(e)?.parentSessionId??(e[s]?.trim()||void 0)}function D(e){return c(e)?.mode===v||e.PI_SUBAGENT_CHILD_AGENT===v&&!!e[s]?.trim()}function O(){return{content:[{type:`text`,text:y}],details:void 0}}function k(e){let t=new n,r=!0,i=!1,a=0,o,s,c=()=>{if(!r)return!1;let e=t.getStore();return e===void 0||e===b||e===a},l=e=>{if(!r)return!1;let n=t.getStore();return n===b||e===a&&(n===void 0||n===e)},u=(e,t)=>{let n=new Proxy(e.ui,{get(e,n){let r=Reflect.get(e,n,e);return typeof r==`function`?(...i)=>{if(l(t))return Reflect.apply(r,e,i);if(n===`confirm`)return Promise.resolve(!1);if(n===`custom`||n===`editor`||n===`input`||n===`select`)return Promise.resolve(void 0)}:r}});return new Proxy(e,{get(e,t){return t===`ui`?n:C(e,t)}})},d=n=>{c()&&e.registerTool({...n,execute:async(e,o,s,c,l)=>{let d=a;if(!r||i||s?.aborted)return O();let f=u(l,d),p=c?e=>{r&&d===a&&!s?.aborted&&c(e)}:void 0,m=await t.run(d,()=>n.execute(e,o,s,p,f));return r&&!i&&d===a?m:O()}})},f=(n,o)=>{c()&&e.registerCommand(n,{...o,handler:async(e,n)=>{let s=a;!r||i||await t.run(s,()=>o.handler(e,u(n,s)))}})},p=(n,o)=>{c()&&e.registerShortcut(n,{...o,handler:e=>{let n=a;if(!(!r||i))return t.run(n,()=>o.handler(u(e,n)))}})};return{pi:new Proxy(e,{get(e,n){return n===`on`?(n,c)=>{C(e,`on`)(n,(e,l)=>{if(!r||i)return;n===`session_start`&&(e!==o||l!==s)&&(a+=1,o=e,s=l);let d=a;return t.run(d,()=>c(e,u(l,d)))})}:n===`registerTool`?d:n===`registerCommand`?f:n===`registerShortcut`?p:n===`getActiveTools`?()=>c()?e.getActiveTools():[]:n===`setActiveTools`?t=>{c()&&e.setActiveTools(t)}:n===`sendMessage`?(...t)=>{c()&&e.sendMessage(...t)}:n===`sendUserMessage`?(...t)=>{c()&&e.sendUserMessage(...t)}:n===`exec`?(...t)=>c()?e.exec(...t):Promise.resolve({code:1,killed:!1,stderr:y,stdout:``}):C(e,n)}}),beginDisposal(){i||!r||(i=!0,a+=1)},finishDisposal(){r=!1,i=!1,a+=1},isCurrentInvocation:c,runCleanup:e=>t.run(b,e)}}function A(n,s,c,l=process.env){let u=D(l),v=u?E(l):void 0,y=u?T(s,v,l):s,b;if(n.effect(()=>()=>b?b.dispose():Promise.resolve(),`${_}/runtime`),n.inject([p],e=>{let t=a(i(o(import.meta.url)),`../../../skills`);if(!r(t))return;let n=m(e).register({source:_,directories:[t]});return()=>n.dispose()}),u){b=t({cordis:n,initialMode:!0,isActive:c})(y);return}let x=!1,S;n.inject([h],t=>{let n=e(g(t),x);return S=n,()=>{n.dispose(),S===n&&(S=void 0)}}),n.inject([d],e=>{let t=f(e).register({source:_,moduleUrl:import.meta.url,skills:[{name:`workflow-help`,description:`Use Doom Pi workflows, monitor long-running jobs, and recover failed runs safely.`}]});return()=>t.dispose()}),b=t({cordis:n,isActive:c,onModeChange:e=>{x=e,S?.setMode(e)}})(y)}function j(e,{fence:t,environment:n}){A(e,t.pi,t.isCurrentInvocation,n)}async function M(e){let t=await u(e,_),n=k(e),r=t.root.plugin(j,{fence:n,environment:process.env}),i,a=()=>i||(n.beginDisposal(),i=n.runCleanup(async()=>{try{await r.dispose()}finally{try{n.finishDisposal()}finally{await t.dispose()}}}),i);try{await r}catch(e){throw await a(),e}e.on(`session_shutdown`,a)}export{T as createDispatcherBridge,M as default,M as workflowExtension,A as installWorkflowRuntime,D as isWorkflowDispatcherProcess,E as resolveDispatcherParentSession};
2
2
  //# sourceMappingURL=extension.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport {\n readChildProcessContext,\n resolveRootSessionId,\n SUBAGENT_PARENT_SESSION_ENV,\n} from '@agimon-ai/doompi-extension-contracts/child-process';\nimport { registerDoomHelpContribution } from '@agimon-ai/doompi-extension-contracts/help';\nimport { createProtocolRuntime, type EventBusLike } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport { WorkflowModeChanged } from '@agimon-ai/doompi-extension-contracts/workflow';\nimport { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { registerLeaderContribution } from './leader.ts';\nimport { installWorkflowPiRuntime, type WorkflowPiRuntime } from './workflow/piExtension.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-workflow';\nconst DISPATCHER_SOURCE = `${PACKAGE_SOURCE}/dispatcher`;\nconst DISPATCHER_AGENT_NAME = 'agiflow-dispatcher';\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\nconst INACTIVE_RUNTIME_MESSAGE = 'The workflow runtime is no longer active.';\nconst CLEANUP_SCOPE = Symbol('doom-workflow-cleanup');\n\nconst DISPATCHER_TOOL_NAMES = new Set(['list_workflows', 'launch_workflow']);\nconst ROOT_SCOPED_TOOL_NAMES = new Set(['launch_workflow']);\n\ntype RegisteredTool = Parameters<ExtensionAPI['registerTool']>[0];\ntype CommandOptions = Parameters<ExtensionAPI['registerCommand']>[1];\ntype ShortcutOptions = Parameters<ExtensionAPI['registerShortcut']>[1];\ntype RuntimeScope = number | typeof CLEANUP_SCOPE;\ntype LifecycleHandler = (event: unknown, context: ExtensionContext) => unknown;\n\ninterface WorkflowFence {\n readonly pi: ExtensionAPI;\n readonly beginDisposal: () => void;\n readonly disposeExternalSubscriptions: () => void;\n readonly finishDisposal: () => void;\n readonly isCurrentInvocation: () => boolean;\n readonly runCleanup: <T>(operation: () => T) => T;\n}\n\nfunction boundValue(target: object, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\nfunction withParentSession(ctx: ExtensionContext, parentSessionId: string): ExtensionContext {\n const sessionManager = new Proxy(ctx.sessionManager, {\n get(target, property) {\n if (property === 'getSessionId') return () => parentSessionId;\n return boundValue(target, property);\n },\n });\n return new Proxy(ctx, {\n get(target, property) {\n if (property === 'sessionManager') return sessionManager;\n return boundValue(target, property);\n },\n });\n}\n\n/** Restrict a dispatcher child to discovery and root-owned launch. */\nexport function createDispatcherBridge(\n pi: ExtensionAPI,\n parentSessionId: string | undefined,\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): ExtensionAPI {\n const rootSessionId = parentSessionId ? resolveRootSessionId(parentSessionId, environment) : undefined;\n return new Proxy(pi, {\n get(target, property) {\n if (property === 'setActiveTools') {\n return (names: string[]): void => target.setActiveTools(names.filter((name) => name !== 'workflow_run'));\n }\n if (property !== 'registerTool') return boundValue(target, property);\n return (tool: RegisteredTool): void => {\n if (!DISPATCHER_TOOL_NAMES.has(tool.name)) return;\n if (!rootSessionId || !ROOT_SCOPED_TOOL_NAMES.has(tool.name)) {\n target.registerTool(tool);\n return;\n }\n target.registerTool({\n ...tool,\n execute: (toolCallId, params, signal, onUpdate, ctx) =>\n tool.execute(toolCallId, params, signal, onUpdate, withParentSession(ctx, rootSessionId)),\n });\n };\n },\n });\n}\n\nexport function resolveDispatcherParentSession(\n environment: Readonly<Record<string, string | undefined>>,\n): string | undefined {\n const childContext = readChildProcessContext(environment);\n return childContext?.parentSessionId ?? (environment[SUBAGENT_PARENT_SESSION_ENV]?.trim() || undefined);\n}\n\nexport function isWorkflowDispatcherProcess(environment: Readonly<Record<string, string | undefined>>): boolean {\n const childContext = readChildProcessContext(environment);\n if (childContext?.mode === DISPATCHER_AGENT_NAME) return true;\n return (\n environment.PI_SUBAGENT_CHILD_AGENT === DISPATCHER_AGENT_NAME &&\n Boolean(environment[SUBAGENT_PARENT_SESSION_ENV]?.trim())\n );\n}\n\nfunction inactiveToolResult(): Awaited<ReturnType<RegisteredTool['execute']>> {\n return {\n content: [{ type: 'text', text: INACTIVE_RUNTIME_MESSAGE }],\n details: undefined,\n };\n}\n\n/** Fence every callback retained by Pi after this package root is replaced. */\nfunction createWorkflowFence(host: ExtensionAPI): WorkflowFence {\n const scope = new AsyncLocalStorage<RuntimeScope>();\n let active = true;\n let disposing = false;\n let generation = 0;\n let lastSessionStartEvent: unknown;\n let lastSessionStartContext: ExtensionContext | undefined;\n const eventUnsubscribers = new Set<() => void>();\n\n const isCurrentInvocation = (): boolean => {\n if (!active) return false;\n const currentScope = scope.getStore();\n return currentScope === undefined || currentScope === CLEANUP_SCOPE || currentScope === generation;\n };\n const ownsContext = (contextGeneration: number): boolean => {\n if (!active) return false;\n const currentScope = scope.getStore();\n return (\n currentScope === CLEANUP_SCOPE ||\n (contextGeneration === generation && (currentScope === undefined || currentScope === contextGeneration))\n );\n };\n\n const guardContext = <TContext extends ExtensionContext>(context: TContext, contextGeneration: number): TContext => {\n const guardedUi = new Proxy(context.ui, {\n get(target, property) {\n const value = Reflect.get(target, property, target);\n if (typeof value !== 'function') return value;\n return (...args: unknown[]): unknown => {\n if (ownsContext(contextGeneration)) return Reflect.apply(value, target, args);\n if (property === 'confirm') return Promise.resolve(false);\n if (property === 'custom' || property === 'editor' || property === 'input' || property === 'select') {\n return Promise.resolve(undefined);\n }\n return undefined;\n };\n },\n });\n return new Proxy(context, {\n get(target, property) {\n if (property === 'ui') return guardedUi;\n return boundValue(target, property);\n },\n }) as TContext;\n };\n\n const events: EventBusLike = {\n emit(channel, data) {\n if (isCurrentInvocation()) host.events.emit(channel, data);\n },\n on(channel, handler) {\n if (!isCurrentInvocation()) return () => undefined;\n const ownerScope = scope.getStore();\n const unsubscribe = host.events.on(channel, (data) => {\n if (!active) return;\n const callbackGeneration = typeof ownerScope === 'number' ? ownerScope : generation;\n if (typeof ownerScope === 'number' && ownerScope !== generation) return;\n scope.run(callbackGeneration, () => handler(data));\n });\n let subscribed = true;\n const disposeSubscription = (): void => {\n if (!subscribed) return;\n subscribed = false;\n eventUnsubscribers.delete(disposeSubscription);\n unsubscribe();\n };\n eventUnsubscribers.add(disposeSubscription);\n return disposeSubscription;\n },\n };\n\n const registerTool = (tool: RegisteredTool): void => {\n if (!isCurrentInvocation()) return;\n host.registerTool({\n ...tool,\n execute: async (toolCallId, params, signal, onUpdate, context) => {\n const executionGeneration = generation;\n if (!active || disposing || signal?.aborted) return inactiveToolResult();\n const guardedContext = guardContext(context, executionGeneration);\n const guardedUpdate = onUpdate\n ? (update: Parameters<NonNullable<typeof onUpdate>>[0]): void => {\n if (active && executionGeneration === generation && !signal?.aborted) onUpdate(update);\n }\n : undefined;\n const result = await scope.run(executionGeneration, () =>\n tool.execute(toolCallId, params, signal, guardedUpdate, guardedContext),\n );\n return active && !disposing && executionGeneration === generation ? result : inactiveToolResult();\n },\n });\n };\n\n const registerCommand = (name: string, options: CommandOptions): void => {\n if (!isCurrentInvocation()) return;\n host.registerCommand(name, {\n ...options,\n handler: async (args, context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n await scope.run(executionGeneration, () => options.handler(args, guardContext(context, executionGeneration)));\n },\n });\n };\n\n const registerShortcut = (\n shortcut: Parameters<ExtensionAPI['registerShortcut']>[0],\n options: ShortcutOptions,\n ): void => {\n if (!isCurrentInvocation()) return;\n host.registerShortcut(shortcut, {\n ...options,\n handler: (context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n return scope.run(executionGeneration, () => options.handler(guardContext(context, executionGeneration)));\n },\n });\n };\n\n const guardedPi = new Proxy(host, {\n get(target, property) {\n if (property === 'events') return events;\n if (property === 'on') {\n return (eventName: string, handler: LifecycleHandler): void => {\n const registerLifecycleHandler = boundValue(target, 'on') as (\n name: string,\n callback: LifecycleHandler,\n ) => void;\n registerLifecycleHandler(eventName, (event: unknown, context: ExtensionContext) => {\n if (!active || disposing) return undefined;\n if (\n eventName === SESSION_START_EVENT &&\n (event !== lastSessionStartEvent || context !== lastSessionStartContext)\n ) {\n generation += 1;\n lastSessionStartEvent = event;\n lastSessionStartContext = context;\n }\n const eventGeneration = generation;\n return scope.run(eventGeneration, () => handler(event, guardContext(context, eventGeneration)));\n });\n };\n }\n if (property === 'registerTool') return registerTool;\n if (property === 'registerCommand') return registerCommand;\n if (property === 'registerShortcut') return registerShortcut;\n if (property === 'getActiveTools') {\n return (): string[] => (isCurrentInvocation() ? target.getActiveTools() : []);\n }\n if (property === 'setActiveTools') {\n return (names: string[]): void => {\n if (isCurrentInvocation()) target.setActiveTools(names);\n };\n }\n if (property === 'sendMessage') {\n return (...args: Parameters<ExtensionAPI['sendMessage']>): void => {\n if (isCurrentInvocation()) target.sendMessage(...args);\n };\n }\n if (property === 'sendUserMessage') {\n return (...args: Parameters<ExtensionAPI['sendUserMessage']>): void => {\n if (isCurrentInvocation()) target.sendUserMessage(...args);\n };\n }\n if (property === 'exec') {\n return (...args: Parameters<ExtensionAPI['exec']>): ReturnType<ExtensionAPI['exec']> =>\n isCurrentInvocation()\n ? target.exec(...args)\n : Promise.resolve({ code: 1, killed: false, stderr: INACTIVE_RUNTIME_MESSAGE, stdout: '' });\n }\n return boundValue(target, property);\n },\n });\n\n return {\n pi: guardedPi,\n beginDisposal() {\n if (disposing || !active) return;\n disposing = true;\n generation += 1;\n },\n disposeExternalSubscriptions() {\n const errors: unknown[] = [];\n for (const unsubscribe of eventUnsubscribers) {\n try {\n unsubscribe();\n } catch (error) {\n errors.push(error);\n }\n }\n if (errors.length > 0) throw new AggregateError(errors, 'Could not dispose workflow event subscriptions.');\n },\n finishDisposal() {\n active = false;\n disposing = false;\n generation += 1;\n },\n isCurrentInvocation,\n runCleanup: (operation) => scope.run(CLEANUP_SCOPE, operation),\n };\n}\n\nasync function disposeSafely(label: string, cleanup: () => void | Promise<void>): Promise<void> {\n try {\n await cleanup();\n } catch (error) {\n process.emitWarning(`Doom-workflow cleanup could not ${label}: ${String(error)}`);\n }\n}\n\n/** Install one normal or dispatcher runtime into a package-local Cordis root. */\nexport function installWorkflowRuntime(\n cordis: Context,\n pi: ExtensionAPI,\n isCurrentInvocation: () => boolean,\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): void {\n const dispatcher = isWorkflowDispatcherProcess(environment);\n const parentSessionId = dispatcher ? resolveDispatcherParentSession(environment) : undefined;\n const rootSessionId = parentSessionId ? resolveRootSessionId(parentSessionId, environment) : undefined;\n const runtimePi = dispatcher ? createDispatcherBridge(pi, parentSessionId, environment) : pi;\n\n let runtime: WorkflowPiRuntime | undefined;\n cordis.effect(() => () => (runtime ? runtime.dispose() : Promise.resolve()), `${PACKAGE_SOURCE}/runtime`);\n\n if (dispatcher) {\n runtime = installWorkflowPiRuntime({ isActive: isCurrentInvocation })(runtimePi);\n pi.on(SESSION_START_EVENT, (_event, context) => {\n const sessionId = resolveRootSessionId(context.sessionManager.getSessionId());\n createProtocolRuntime({ bus: pi.events, source: DISPATCHER_SOURCE, sessionId }).notify(WorkflowModeChanged, {\n mode: 'on',\n ...(rootSessionId ? { parentSessionId: rootSessionId } : {}),\n });\n });\n return;\n }\n\n const leader = registerLeaderContribution(pi);\n cordis.effect(\n () => () => disposeSafely('dispose the workflow leader contribution', () => leader.dispose()),\n `${PACKAGE_SOURCE}/leader`,\n );\n const help = registerDoomHelpContribution(pi, {\n source: PACKAGE_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'workflow-help',\n description: 'Use Doom Pi workflows, monitor long-running jobs, and recover failed runs safely.',\n },\n ],\n });\n cordis.effect(\n () => () => disposeSafely('dispose the workflow help contribution', () => help.dispose()),\n `${PACKAGE_SOURCE}/help`,\n );\n runtime = installWorkflowPiRuntime({\n isActive: isCurrentInvocation,\n onModeChange: (enabled) => leader.setMode(enabled),\n })(runtimePi);\n}\n\n/** The package's sole Pi factory; Pi reloads it and Cordis owns all package resources. */\nexport async function workflowExtension(pi: ExtensionAPI): Promise<void> {\n const cordis = new Context();\n const fence = createWorkflowFence(pi);\n cordis.effect(() => () => fence.disposeExternalSubscriptions(), `${PACKAGE_SOURCE}/event-subscriptions`);\n let disposal: Promise<void> | undefined;\n const dispose = (): Promise<void> => {\n if (disposal) return disposal;\n fence.beginDisposal();\n disposal = fence.runCleanup(async () => {\n try {\n await cordis.fiber.dispose();\n } finally {\n fence.finishDisposal();\n }\n });\n return disposal;\n };\n\n try {\n installWorkflowRuntime(cordis, fence.pi, fence.isCurrentInvocation);\n pi.on(SESSION_SHUTDOWN_EVENT, dispose);\n } catch (error) {\n await dispose();\n throw error;\n }\n}\n\nexport default workflowExtension;\n"],"mappings":"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"}
1
+ {"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'node:async_hooks';\nimport { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n readChildProcessContext,\n resolveRootSessionId,\n SUBAGENT_PARENT_SESSION_ENV,\n} from '@agimon-ai/doompi-extension-contracts/child-process';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_HELP_SERVICE, requireDoomHelpService } from '@agimon-ai/doompi-extension-contracts/help';\nimport {\n DOOM_SKILL_SOURCES_SERVICE,\n requireDoomSkillSourcesService,\n} from '@agimon-ai/doompi-extension-contracts/skills';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { registerLeaderContribution } from './leader.ts';\nimport { installWorkflowPiRuntime, type WorkflowPiRuntime } from './workflow/piExtension.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-workflow';\nconst SKILL_RELATIVE_PATH = '../../../skills';\nconst DISPATCHER_AGENT_NAME = 'agiflow-dispatcher';\nconst SESSION_START_EVENT = 'session_start';\nconst SESSION_SHUTDOWN_EVENT = 'session_shutdown';\nconst INACTIVE_RUNTIME_MESSAGE = 'The workflow runtime is no longer active.';\nconst CLEANUP_SCOPE = Symbol('doom-workflow-cleanup');\n\nconst DISPATCHER_TOOL_NAMES = new Set(['list_workflows', 'launch_workflow']);\nconst ROOT_SCOPED_TOOL_NAMES = new Set(['launch_workflow']);\n\ntype RegisteredTool = Parameters<ExtensionAPI['registerTool']>[0];\ntype CommandOptions = Parameters<ExtensionAPI['registerCommand']>[1];\ntype ShortcutOptions = Parameters<ExtensionAPI['registerShortcut']>[1];\ntype RuntimeScope = number | typeof CLEANUP_SCOPE;\ntype LifecycleHandler = (event: unknown, context: ExtensionContext) => unknown;\n\ninterface WorkflowFence {\n readonly pi: ExtensionAPI;\n readonly beginDisposal: () => void;\n readonly finishDisposal: () => void;\n readonly isCurrentInvocation: () => boolean;\n readonly runCleanup: <T>(operation: () => T) => T;\n}\n\nfunction boundValue(target: object, property: PropertyKey): unknown {\n const value = Reflect.get(target, property, target);\n return typeof value === 'function' ? value.bind(target) : value;\n}\n\nfunction withParentSession(ctx: ExtensionContext, parentSessionId: string): ExtensionContext {\n const sessionManager = new Proxy(ctx.sessionManager, {\n get(target, property) {\n if (property === 'getSessionId') return () => parentSessionId;\n return boundValue(target, property);\n },\n });\n return new Proxy(ctx, {\n get(target, property) {\n if (property === 'sessionManager') return sessionManager;\n return boundValue(target, property);\n },\n });\n}\n\n/** Restrict a dispatcher child to discovery and root-owned launch. */\nexport function createDispatcherBridge(\n pi: ExtensionAPI,\n parentSessionId: string | undefined,\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): ExtensionAPI {\n const rootSessionId = parentSessionId ? resolveRootSessionId(parentSessionId, environment) : undefined;\n return new Proxy(pi, {\n get(target, property) {\n if (property === 'setActiveTools') {\n return (names: string[]): void => target.setActiveTools(names.filter((name) => name !== 'workflow_run'));\n }\n if (property !== 'registerTool') return boundValue(target, property);\n return (tool: RegisteredTool): void => {\n if (!DISPATCHER_TOOL_NAMES.has(tool.name)) return;\n if (!rootSessionId || !ROOT_SCOPED_TOOL_NAMES.has(tool.name)) {\n target.registerTool(tool);\n return;\n }\n target.registerTool({\n ...tool,\n execute: (toolCallId, params, signal, onUpdate, ctx) =>\n tool.execute(toolCallId, params, signal, onUpdate, withParentSession(ctx, rootSessionId)),\n });\n };\n },\n });\n}\n\nexport function resolveDispatcherParentSession(\n environment: Readonly<Record<string, string | undefined>>,\n): string | undefined {\n const childContext = readChildProcessContext(environment);\n return childContext?.parentSessionId ?? (environment[SUBAGENT_PARENT_SESSION_ENV]?.trim() || undefined);\n}\n\nexport function isWorkflowDispatcherProcess(environment: Readonly<Record<string, string | undefined>>): boolean {\n const childContext = readChildProcessContext(environment);\n if (childContext?.mode === DISPATCHER_AGENT_NAME) return true;\n return (\n environment.PI_SUBAGENT_CHILD_AGENT === DISPATCHER_AGENT_NAME &&\n Boolean(environment[SUBAGENT_PARENT_SESSION_ENV]?.trim())\n );\n}\n\nfunction inactiveToolResult(): Awaited<ReturnType<RegisteredTool['execute']>> {\n return {\n content: [{ type: 'text', text: INACTIVE_RUNTIME_MESSAGE }],\n details: undefined,\n };\n}\n\n/** Fence every callback retained by Pi after this package root is replaced. */\nfunction createWorkflowFence(host: ExtensionAPI): WorkflowFence {\n const scope = new AsyncLocalStorage<RuntimeScope>();\n let active = true;\n let disposing = false;\n let generation = 0;\n let lastSessionStartEvent: unknown;\n let lastSessionStartContext: ExtensionContext | undefined;\n\n const isCurrentInvocation = (): boolean => {\n if (!active) return false;\n const currentScope = scope.getStore();\n return currentScope === undefined || currentScope === CLEANUP_SCOPE || currentScope === generation;\n };\n const ownsContext = (contextGeneration: number): boolean => {\n if (!active) return false;\n const currentScope = scope.getStore();\n return (\n currentScope === CLEANUP_SCOPE ||\n (contextGeneration === generation && (currentScope === undefined || currentScope === contextGeneration))\n );\n };\n\n const guardContext = <TContext extends ExtensionContext>(context: TContext, contextGeneration: number): TContext => {\n const guardedUi = new Proxy(context.ui, {\n get(target, property) {\n const value = Reflect.get(target, property, target);\n if (typeof value !== 'function') return value;\n return (...args: unknown[]): unknown => {\n if (ownsContext(contextGeneration)) return Reflect.apply(value, target, args);\n if (property === 'confirm') return Promise.resolve(false);\n if (property === 'custom' || property === 'editor' || property === 'input' || property === 'select') {\n return Promise.resolve(undefined);\n }\n return undefined;\n };\n },\n });\n return new Proxy(context, {\n get(target, property) {\n if (property === 'ui') return guardedUi;\n return boundValue(target, property);\n },\n }) as TContext;\n };\n\n const registerTool = (tool: RegisteredTool): void => {\n if (!isCurrentInvocation()) return;\n host.registerTool({\n ...tool,\n execute: async (toolCallId, params, signal, onUpdate, context) => {\n const executionGeneration = generation;\n if (!active || disposing || signal?.aborted) return inactiveToolResult();\n const guardedContext = guardContext(context, executionGeneration);\n const guardedUpdate = onUpdate\n ? (update: Parameters<NonNullable<typeof onUpdate>>[0]): void => {\n if (active && executionGeneration === generation && !signal?.aborted) onUpdate(update);\n }\n : undefined;\n const result = await scope.run(executionGeneration, () =>\n tool.execute(toolCallId, params, signal, guardedUpdate, guardedContext),\n );\n return active && !disposing && executionGeneration === generation ? result : inactiveToolResult();\n },\n });\n };\n\n const registerCommand = (name: string, options: CommandOptions): void => {\n if (!isCurrentInvocation()) return;\n host.registerCommand(name, {\n ...options,\n handler: async (args, context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n await scope.run(executionGeneration, () => options.handler(args, guardContext(context, executionGeneration)));\n },\n });\n };\n\n const registerShortcut = (\n shortcut: Parameters<ExtensionAPI['registerShortcut']>[0],\n options: ShortcutOptions,\n ): void => {\n if (!isCurrentInvocation()) return;\n host.registerShortcut(shortcut, {\n ...options,\n handler: (context) => {\n const executionGeneration = generation;\n if (!active || disposing) return;\n return scope.run(executionGeneration, () => options.handler(guardContext(context, executionGeneration)));\n },\n });\n };\n\n const guardedPi = new Proxy(host, {\n get(target, property) {\n if (property === 'on') {\n return (eventName: string, handler: LifecycleHandler): void => {\n const registerLifecycleHandler = boundValue(target, 'on') as (\n name: string,\n callback: LifecycleHandler,\n ) => void;\n registerLifecycleHandler(eventName, (event: unknown, context: ExtensionContext) => {\n if (!active || disposing) return undefined;\n if (\n eventName === SESSION_START_EVENT &&\n (event !== lastSessionStartEvent || context !== lastSessionStartContext)\n ) {\n generation += 1;\n lastSessionStartEvent = event;\n lastSessionStartContext = context;\n }\n const eventGeneration = generation;\n return scope.run(eventGeneration, () => handler(event, guardContext(context, eventGeneration)));\n });\n };\n }\n if (property === 'registerTool') return registerTool;\n if (property === 'registerCommand') return registerCommand;\n if (property === 'registerShortcut') return registerShortcut;\n if (property === 'getActiveTools') {\n return (): string[] => (isCurrentInvocation() ? target.getActiveTools() : []);\n }\n if (property === 'setActiveTools') {\n return (names: string[]): void => {\n if (isCurrentInvocation()) target.setActiveTools(names);\n };\n }\n if (property === 'sendMessage') {\n return (...args: Parameters<ExtensionAPI['sendMessage']>): void => {\n if (isCurrentInvocation()) target.sendMessage(...args);\n };\n }\n if (property === 'sendUserMessage') {\n return (...args: Parameters<ExtensionAPI['sendUserMessage']>): void => {\n if (isCurrentInvocation()) target.sendUserMessage(...args);\n };\n }\n if (property === 'exec') {\n return (...args: Parameters<ExtensionAPI['exec']>): ReturnType<ExtensionAPI['exec']> =>\n isCurrentInvocation()\n ? target.exec(...args)\n : Promise.resolve({ code: 1, killed: false, stderr: INACTIVE_RUNTIME_MESSAGE, stdout: '' });\n }\n return boundValue(target, property);\n },\n });\n\n return {\n pi: guardedPi,\n beginDisposal() {\n if (disposing || !active) return;\n disposing = true;\n generation += 1;\n },\n finishDisposal() {\n active = false;\n disposing = false;\n generation += 1;\n },\n isCurrentInvocation,\n runCleanup: (operation) => scope.run(CLEANUP_SCOPE, operation),\n };\n}\n\n/** Install one normal or dispatcher runtime into its host-owned Cordis plugin fiber. */\nexport function installWorkflowRuntime(\n cordis: Context,\n pi: ExtensionAPI,\n isCurrentInvocation: () => boolean,\n environment: Readonly<Record<string, string | undefined>> = process.env,\n): void {\n const dispatcher = isWorkflowDispatcherProcess(environment);\n const parentSessionId = dispatcher ? resolveDispatcherParentSession(environment) : undefined;\n const runtimePi = dispatcher ? createDispatcherBridge(pi, parentSessionId, environment) : pi;\n\n let runtime: WorkflowPiRuntime | undefined;\n cordis.effect(() => () => (runtime ? runtime.dispose() : Promise.resolve()), `${PACKAGE_SOURCE}/runtime`);\n\n cordis.inject([DOOM_SKILL_SOURCES_SERVICE], (skillContext) => {\n const directory = resolve(dirname(fileURLToPath(import.meta.url)), SKILL_RELATIVE_PATH);\n if (!existsSync(directory)) return undefined;\n const contribution = requireDoomSkillSourcesService(skillContext).register({\n source: PACKAGE_SOURCE,\n directories: [directory],\n });\n return () => contribution.dispose();\n });\n\n if (dispatcher) {\n runtime = installWorkflowPiRuntime({ cordis, initialMode: true, isActive: isCurrentInvocation })(runtimePi);\n return;\n }\n\n let workflowMode = false;\n let leader: ReturnType<typeof registerLeaderContribution> | undefined;\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n const contribution = registerLeaderContribution(requireDoomUiHub(uiContext), workflowMode);\n leader = contribution;\n return () => {\n contribution.dispose();\n if (leader === contribution) leader = undefined;\n };\n });\n cordis.inject([DOOM_HELP_SERVICE], (helpContext) => {\n const help = requireDoomHelpService(helpContext).register({\n source: PACKAGE_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'workflow-help',\n description: 'Use Doom Pi workflows, monitor long-running jobs, and recover failed runs safely.',\n },\n ],\n });\n return () => help.dispose();\n });\n runtime = installWorkflowPiRuntime({\n cordis,\n isActive: isCurrentInvocation,\n onModeChange: (enabled) => {\n workflowMode = enabled;\n leader?.setMode(enabled);\n },\n })(runtimePi);\n}\n\ninterface WorkflowPluginConfig {\n readonly fence: WorkflowFence;\n readonly environment: Readonly<Record<string, string | undefined>>;\n}\n\nfunction workflowPlugin(cordis: Context, { fence, environment }: WorkflowPluginConfig): void {\n installWorkflowRuntime(cordis, fence.pi, fence.isCurrentInvocation, environment);\n}\n\n/** The package's sole Pi factory; Pi reloads it and Cordis owns all package resources. */\nexport async function workflowExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fence = createWorkflowFence(pi);\n const fiber = connection.root.plugin(workflowPlugin, { fence, environment: process.env });\n let disposal: Promise<void> | undefined;\n const dispose = (): Promise<void> => {\n if (disposal) return disposal;\n fence.beginDisposal();\n disposal = fence.runCleanup(async () => {\n try {\n await fiber.dispose();\n } finally {\n try {\n fence.finishDisposal();\n } finally {\n await connection.dispose();\n }\n }\n });\n return disposal;\n };\n\n try {\n await fiber;\n } catch (error) {\n await dispose();\n throw error;\n }\n pi.on(SESSION_SHUTDOWN_EVENT, dispose);\n}\n\nexport default workflowExtension;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require("../../types/index.cjs");let t=require("@agimon-ai/doompi-extension-contracts/leader");const n=`doom-workflow`,r={key:`w`,label:e.LEADER_LABEL,order:50};function i(t){return[{id:`${n}.manage`,path:[r,{key:`l`,label:`manage`,detail:`running workflows`}],action:{name:e.LEADER_MANAGE_ACTION}},{id:`${n}.launch`,path:[r,{key:`w`,label:`launch`,detail:`start a workflow`}],action:{name:e.LEADER_LAUNCH_ACTION}},t?{id:`${n}.disable`,path:[r,{key:`e`,label:`exit`,detail:`take back workflow tools`}],action:{name:e.LEADER_DISABLE_ACTION}}:{id:`${n}.enable`,path:[r,{key:`e`,label:`enter`,detail:`give the agent workflow tools`}],action:{name:e.LEADER_ENABLE_ACTION}},{id:`${n}.recover`,path:[r,{key:`r`,label:`recover`,detail:`failed workflow`}],action:{name:e.LEADER_RECOVER_ACTION}}]}function a(n){let r=(0,t.createDoomLeaderContribution)(n,{source:e.PACKAGE_SOURCE,bindings:i(!1)});return{setMode(e){r.update(i(e))},dispose(){r.dispose()}}}exports.registerLeaderContribution=a,exports.workflowLeaderBindings=i;
1
+ const e=require("../../types/index.cjs"),t=`doom-workflow`,n={key:`w`,label:e.LEADER_LABEL,order:50};function r(r){return[{id:`${t}.manage`,path:[n,{key:`l`,label:`manage`,detail:`running workflows`}],action:{name:e.LEADER_MANAGE_ACTION}},{id:`${t}.launch`,path:[n,{key:`w`,label:`launch`,detail:`start a workflow`}],action:{name:e.LEADER_LAUNCH_ACTION}},r?{id:`${t}.disable`,path:[n,{key:`e`,label:`exit`,detail:`take back workflow tools`}],action:{name:e.LEADER_DISABLE_ACTION}}:{id:`${t}.enable`,path:[n,{key:`e`,label:`enter`,detail:`give the agent workflow tools`}],action:{name:e.LEADER_ENABLE_ACTION}},{id:`${t}.recover`,path:[n,{key:`r`,label:`recover`,detail:`failed workflow`}],action:{name:e.LEADER_RECOVER_ACTION}}]}function i(t,n=!1){let i=t.registerLeader({source:e.PACKAGE_SOURCE,bindings:r(n)});return{setMode(e){i.update(r(e))},dispose(){i.dispose()}}}exports.registerLeaderContribution=i,exports.workflowLeaderBindings=r;
2
2
  //# sourceMappingURL=leader.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"leader.cjs","names":["LEADER_LABEL","LEADER_MANAGE_ACTION","LEADER_LAUNCH_ACTION","LEADER_DISABLE_ACTION","LEADER_ENABLE_ACTION","LEADER_RECOVER_ACTION","createDoomLeaderContribution","PACKAGE_SOURCE"],"sources":["../../../src/adapters/pi/leader.ts"],"sourcesContent":["import { createDoomLeaderContribution, type LeaderBinding } from '@agimon-ai/doompi-extension-contracts/leader';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport {\n LEADER_DISABLE_ACTION,\n LEADER_ENABLE_ACTION,\n LEADER_KEY,\n LEADER_LABEL,\n LEADER_LAUNCH_ACTION,\n LEADER_MANAGE_ACTION,\n LEADER_ORDER,\n LEADER_RECOVER_ACTION,\n PACKAGE_SOURCE,\n} from '../../types/index.ts';\n\nconst LEADER_BINDING_PREFIX = 'doom-workflow';\nconst GROUP_SEGMENT = { key: LEADER_KEY, label: LEADER_LABEL, order: LEADER_ORDER } as const;\n\nexport interface WorkflowLeaderHandle {\n /** Republish the menu for the mode's current state. */\n setMode(enabled: boolean): void;\n dispose(): void;\n}\n\n/**\n * The menu as it stands with the mode on or off.\n *\n * One entry on `e` rather than an enable row beside a disable row: only one of\n * the two ever does anything, and a menu that prints both makes the reader\n * check the mode line to find out which. The label says which way it flips.\n */\nexport function workflowLeaderBindings(mode: boolean): LeaderBinding[] {\n return [\n {\n id: `${LEADER_BINDING_PREFIX}.manage`,\n path: [GROUP_SEGMENT, { key: 'l', label: 'manage', detail: 'running workflows' }],\n action: { name: LEADER_MANAGE_ACTION },\n },\n {\n id: `${LEADER_BINDING_PREFIX}.launch`,\n path: [GROUP_SEGMENT, { key: 'w', label: 'launch', detail: 'start a workflow' }],\n action: { name: LEADER_LAUNCH_ACTION },\n },\n mode\n ? {\n id: `${LEADER_BINDING_PREFIX}.disable`,\n path: [GROUP_SEGMENT, { key: 'e', label: 'exit', detail: 'take back workflow tools' }],\n action: { name: LEADER_DISABLE_ACTION },\n }\n : {\n id: `${LEADER_BINDING_PREFIX}.enable`,\n path: [GROUP_SEGMENT, { key: 'e', label: 'enter', detail: 'give the agent workflow tools' }],\n action: { name: LEADER_ENABLE_ACTION },\n },\n {\n id: `${LEADER_BINDING_PREFIX}.recover`,\n path: [GROUP_SEGMENT, { key: 'r', label: 'recover', detail: 'failed workflow' }],\n action: { name: LEADER_RECOVER_ACTION },\n },\n ];\n}\n\nexport function registerLeaderContribution(pi: Pick<ExtensionAPI, 'events' | 'on'>): WorkflowLeaderHandle {\n const contribution = createDoomLeaderContribution(pi, {\n source: PACKAGE_SOURCE,\n bindings: workflowLeaderBindings(false),\n });\n return {\n setMode(enabled) {\n contribution.update(workflowLeaderBindings(enabled));\n },\n dispose() {\n contribution.dispose();\n },\n };\n}\n"],"mappings":"uGAcA,MAAM,EAAwB,gBACxB,EAAgB,CAAE,IAAA,IAAiB,MAAOA,EAAAA,aAAc,MAAA,EAAoB,EAelF,SAAgB,EAAuB,EAAgC,CACrE,MAAO,CACL,CACE,GAAI,GAAG,EAAsB,SAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,SAAU,OAAQ,mBAAoB,CAAC,EAChF,OAAQ,CAAE,KAAMC,EAAAA,oBAAqB,CACvC,EACA,CACE,GAAI,GAAG,EAAsB,SAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,SAAU,OAAQ,kBAAmB,CAAC,EAC/E,OAAQ,CAAE,KAAMC,EAAAA,oBAAqB,CACvC,EACA,EACI,CACE,GAAI,GAAG,EAAsB,UAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,OAAQ,OAAQ,0BAA2B,CAAC,EACrF,OAAQ,CAAE,KAAMC,EAAAA,qBAAsB,CACxC,EACA,CACE,GAAI,GAAG,EAAsB,SAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,QAAS,OAAQ,+BAAgC,CAAC,EAC3F,OAAQ,CAAE,KAAMC,EAAAA,oBAAqB,CACvC,EACJ,CACE,GAAI,GAAG,EAAsB,UAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,UAAW,OAAQ,iBAAkB,CAAC,EAC/E,OAAQ,CAAE,KAAMC,EAAAA,qBAAsB,CACxC,CACF,CACF,CAEA,SAAgB,EAA2B,EAA+D,CACxG,IAAM,GAAA,EAAeC,EAAAA,6BAAAA,CAA6B,EAAI,CACpD,OAAQC,EAAAA,eACR,SAAU,EAAuB,EAAK,CACxC,CAAC,EACD,MAAO,CACL,QAAQ,EAAS,CACf,EAAa,OAAO,EAAuB,CAAO,CAAC,CACrD,EACA,SAAU,CACR,EAAa,QAAQ,CACvB,CACF,CACF"}
1
+ {"version":3,"file":"leader.cjs","names":["LEADER_LABEL","LEADER_MANAGE_ACTION","LEADER_LAUNCH_ACTION","LEADER_DISABLE_ACTION","LEADER_ENABLE_ACTION","LEADER_RECOVER_ACTION","PACKAGE_SOURCE"],"sources":["../../../src/adapters/pi/leader.ts"],"sourcesContent":["import type { LeaderBinding } from '@agimon-ai/doompi-extension-contracts/leader';\nimport type { DoomUiHubService } from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport {\n LEADER_DISABLE_ACTION,\n LEADER_ENABLE_ACTION,\n LEADER_KEY,\n LEADER_LABEL,\n LEADER_LAUNCH_ACTION,\n LEADER_MANAGE_ACTION,\n LEADER_ORDER,\n LEADER_RECOVER_ACTION,\n PACKAGE_SOURCE,\n} from '../../types/index.ts';\n\nconst LEADER_BINDING_PREFIX = 'doom-workflow';\nconst GROUP_SEGMENT = { key: LEADER_KEY, label: LEADER_LABEL, order: LEADER_ORDER } as const;\n\nexport interface WorkflowLeaderHandle {\n /** Republish the menu for the mode's current state. */\n setMode(enabled: boolean): void;\n dispose(): void;\n}\n\n/**\n * The menu as it stands with the mode on or off.\n *\n * One entry on `e` rather than an enable row beside a disable row: only one of\n * the two ever does anything, and a menu that prints both makes the reader\n * check the mode line to find out which. The label says which way it flips.\n */\nexport function workflowLeaderBindings(mode: boolean): LeaderBinding[] {\n return [\n {\n id: `${LEADER_BINDING_PREFIX}.manage`,\n path: [GROUP_SEGMENT, { key: 'l', label: 'manage', detail: 'running workflows' }],\n action: { name: LEADER_MANAGE_ACTION },\n },\n {\n id: `${LEADER_BINDING_PREFIX}.launch`,\n path: [GROUP_SEGMENT, { key: 'w', label: 'launch', detail: 'start a workflow' }],\n action: { name: LEADER_LAUNCH_ACTION },\n },\n mode\n ? {\n id: `${LEADER_BINDING_PREFIX}.disable`,\n path: [GROUP_SEGMENT, { key: 'e', label: 'exit', detail: 'take back workflow tools' }],\n action: { name: LEADER_DISABLE_ACTION },\n }\n : {\n id: `${LEADER_BINDING_PREFIX}.enable`,\n path: [GROUP_SEGMENT, { key: 'e', label: 'enter', detail: 'give the agent workflow tools' }],\n action: { name: LEADER_ENABLE_ACTION },\n },\n {\n id: `${LEADER_BINDING_PREFIX}.recover`,\n path: [GROUP_SEGMENT, { key: 'r', label: 'recover', detail: 'failed workflow' }],\n action: { name: LEADER_RECOVER_ACTION },\n },\n ];\n}\n\nexport function registerLeaderContribution(hub: DoomUiHubService, enabled = false): WorkflowLeaderHandle {\n const contribution = hub.registerLeader({\n source: PACKAGE_SOURCE,\n bindings: workflowLeaderBindings(enabled),\n });\n return {\n setMode(enabled) {\n contribution.update(workflowLeaderBindings(enabled));\n },\n dispose() {\n contribution.dispose();\n },\n };\n}\n"],"mappings":"yCAcM,EAAwB,gBACxB,EAAgB,CAAE,IAAA,IAAiB,MAAOA,EAAAA,aAAc,MAAA,EAAoB,EAelF,SAAgB,EAAuB,EAAgC,CACrE,MAAO,CACL,CACE,GAAI,GAAG,EAAsB,SAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,SAAU,OAAQ,mBAAoB,CAAC,EAChF,OAAQ,CAAE,KAAMC,EAAAA,oBAAqB,CACvC,EACA,CACE,GAAI,GAAG,EAAsB,SAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,SAAU,OAAQ,kBAAmB,CAAC,EAC/E,OAAQ,CAAE,KAAMC,EAAAA,oBAAqB,CACvC,EACA,EACI,CACE,GAAI,GAAG,EAAsB,UAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,OAAQ,OAAQ,0BAA2B,CAAC,EACrF,OAAQ,CAAE,KAAMC,EAAAA,qBAAsB,CACxC,EACA,CACE,GAAI,GAAG,EAAsB,SAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,QAAS,OAAQ,+BAAgC,CAAC,EAC3F,OAAQ,CAAE,KAAMC,EAAAA,oBAAqB,CACvC,EACJ,CACE,GAAI,GAAG,EAAsB,UAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,UAAW,OAAQ,iBAAkB,CAAC,EAC/E,OAAQ,CAAE,KAAMC,EAAAA,qBAAsB,CACxC,CACF,CACF,CAEA,SAAgB,EAA2B,EAAuB,EAAU,GAA6B,CACvG,IAAM,EAAe,EAAI,eAAe,CACtC,OAAQC,EAAAA,eACR,SAAU,EAAuB,CAAO,CAC1C,CAAC,EACD,MAAO,CACL,QAAQ,EAAS,CACf,EAAa,OAAO,EAAuB,CAAO,CAAC,CACrD,EACA,SAAU,CACR,EAAa,QAAQ,CACvB,CACF,CACF"}
@@ -1,2 +1,2 @@
1
- import{LEADER_DISABLE_ACTION as e,LEADER_ENABLE_ACTION as t,LEADER_LABEL as n,LEADER_LAUNCH_ACTION as r,LEADER_MANAGE_ACTION as i,LEADER_RECOVER_ACTION as a,PACKAGE_SOURCE as o}from"../../types/index.mjs";import{createDoomLeaderContribution as s}from"@agimon-ai/doompi-extension-contracts/leader";const c=`doom-workflow`,l={key:`w`,label:n,order:50};function u(n){return[{id:`${c}.manage`,path:[l,{key:`l`,label:`manage`,detail:`running workflows`}],action:{name:i}},{id:`${c}.launch`,path:[l,{key:`w`,label:`launch`,detail:`start a workflow`}],action:{name:r}},n?{id:`${c}.disable`,path:[l,{key:`e`,label:`exit`,detail:`take back workflow tools`}],action:{name:e}}:{id:`${c}.enable`,path:[l,{key:`e`,label:`enter`,detail:`give the agent workflow tools`}],action:{name:t}},{id:`${c}.recover`,path:[l,{key:`r`,label:`recover`,detail:`failed workflow`}],action:{name:a}}]}function d(e){let t=s(e,{source:o,bindings:u(!1)});return{setMode(e){t.update(u(e))},dispose(){t.dispose()}}}export{d as registerLeaderContribution,u as workflowLeaderBindings};
1
+ import{LEADER_DISABLE_ACTION as e,LEADER_ENABLE_ACTION as t,LEADER_LABEL as n,LEADER_LAUNCH_ACTION as r,LEADER_MANAGE_ACTION as i,LEADER_RECOVER_ACTION as a,PACKAGE_SOURCE as o}from"../../types/index.mjs";const s=`doom-workflow`,c={key:`w`,label:n,order:50};function l(n){return[{id:`${s}.manage`,path:[c,{key:`l`,label:`manage`,detail:`running workflows`}],action:{name:i}},{id:`${s}.launch`,path:[c,{key:`w`,label:`launch`,detail:`start a workflow`}],action:{name:r}},n?{id:`${s}.disable`,path:[c,{key:`e`,label:`exit`,detail:`take back workflow tools`}],action:{name:e}}:{id:`${s}.enable`,path:[c,{key:`e`,label:`enter`,detail:`give the agent workflow tools`}],action:{name:t}},{id:`${s}.recover`,path:[c,{key:`r`,label:`recover`,detail:`failed workflow`}],action:{name:a}}]}function u(e,t=!1){let n=e.registerLeader({source:o,bindings:l(t)});return{setMode(e){n.update(l(e))},dispose(){n.dispose()}}}export{u as registerLeaderContribution,l as workflowLeaderBindings};
2
2
  //# sourceMappingURL=leader.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"leader.mjs","names":[],"sources":["../../../src/adapters/pi/leader.ts"],"sourcesContent":["import { createDoomLeaderContribution, type LeaderBinding } from '@agimon-ai/doompi-extension-contracts/leader';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport {\n LEADER_DISABLE_ACTION,\n LEADER_ENABLE_ACTION,\n LEADER_KEY,\n LEADER_LABEL,\n LEADER_LAUNCH_ACTION,\n LEADER_MANAGE_ACTION,\n LEADER_ORDER,\n LEADER_RECOVER_ACTION,\n PACKAGE_SOURCE,\n} from '../../types/index.ts';\n\nconst LEADER_BINDING_PREFIX = 'doom-workflow';\nconst GROUP_SEGMENT = { key: LEADER_KEY, label: LEADER_LABEL, order: LEADER_ORDER } as const;\n\nexport interface WorkflowLeaderHandle {\n /** Republish the menu for the mode's current state. */\n setMode(enabled: boolean): void;\n dispose(): void;\n}\n\n/**\n * The menu as it stands with the mode on or off.\n *\n * One entry on `e` rather than an enable row beside a disable row: only one of\n * the two ever does anything, and a menu that prints both makes the reader\n * check the mode line to find out which. The label says which way it flips.\n */\nexport function workflowLeaderBindings(mode: boolean): LeaderBinding[] {\n return [\n {\n id: `${LEADER_BINDING_PREFIX}.manage`,\n path: [GROUP_SEGMENT, { key: 'l', label: 'manage', detail: 'running workflows' }],\n action: { name: LEADER_MANAGE_ACTION },\n },\n {\n id: `${LEADER_BINDING_PREFIX}.launch`,\n path: [GROUP_SEGMENT, { key: 'w', label: 'launch', detail: 'start a workflow' }],\n action: { name: LEADER_LAUNCH_ACTION },\n },\n mode\n ? {\n id: `${LEADER_BINDING_PREFIX}.disable`,\n path: [GROUP_SEGMENT, { key: 'e', label: 'exit', detail: 'take back workflow tools' }],\n action: { name: LEADER_DISABLE_ACTION },\n }\n : {\n id: `${LEADER_BINDING_PREFIX}.enable`,\n path: [GROUP_SEGMENT, { key: 'e', label: 'enter', detail: 'give the agent workflow tools' }],\n action: { name: LEADER_ENABLE_ACTION },\n },\n {\n id: `${LEADER_BINDING_PREFIX}.recover`,\n path: [GROUP_SEGMENT, { key: 'r', label: 'recover', detail: 'failed workflow' }],\n action: { name: LEADER_RECOVER_ACTION },\n },\n ];\n}\n\nexport function registerLeaderContribution(pi: Pick<ExtensionAPI, 'events' | 'on'>): WorkflowLeaderHandle {\n const contribution = createDoomLeaderContribution(pi, {\n source: PACKAGE_SOURCE,\n bindings: workflowLeaderBindings(false),\n });\n return {\n setMode(enabled) {\n contribution.update(workflowLeaderBindings(enabled));\n },\n dispose() {\n contribution.dispose();\n },\n };\n}\n"],"mappings":"ySAcA,MAAM,EAAwB,gBACxB,EAAgB,CAAE,IAAA,IAAiB,MAAO,EAAc,MAAA,EAAoB,EAelF,SAAgB,EAAuB,EAAgC,CACrE,MAAO,CACL,CACE,GAAI,GAAG,EAAsB,SAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,SAAU,OAAQ,mBAAoB,CAAC,EAChF,OAAQ,CAAE,KAAM,CAAqB,CACvC,EACA,CACE,GAAI,GAAG,EAAsB,SAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,SAAU,OAAQ,kBAAmB,CAAC,EAC/E,OAAQ,CAAE,KAAM,CAAqB,CACvC,EACA,EACI,CACE,GAAI,GAAG,EAAsB,UAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,OAAQ,OAAQ,0BAA2B,CAAC,EACrF,OAAQ,CAAE,KAAM,CAAsB,CACxC,EACA,CACE,GAAI,GAAG,EAAsB,SAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,QAAS,OAAQ,+BAAgC,CAAC,EAC3F,OAAQ,CAAE,KAAM,CAAqB,CACvC,EACJ,CACE,GAAI,GAAG,EAAsB,UAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,UAAW,OAAQ,iBAAkB,CAAC,EAC/E,OAAQ,CAAE,KAAM,CAAsB,CACxC,CACF,CACF,CAEA,SAAgB,EAA2B,EAA+D,CACxG,IAAM,EAAe,EAA6B,EAAI,CACpD,OAAQ,EACR,SAAU,EAAuB,EAAK,CACxC,CAAC,EACD,MAAO,CACL,QAAQ,EAAS,CACf,EAAa,OAAO,EAAuB,CAAO,CAAC,CACrD,EACA,SAAU,CACR,EAAa,QAAQ,CACvB,CACF,CACF"}
1
+ {"version":3,"file":"leader.mjs","names":[],"sources":["../../../src/adapters/pi/leader.ts"],"sourcesContent":["import type { LeaderBinding } from '@agimon-ai/doompi-extension-contracts/leader';\nimport type { DoomUiHubService } from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport {\n LEADER_DISABLE_ACTION,\n LEADER_ENABLE_ACTION,\n LEADER_KEY,\n LEADER_LABEL,\n LEADER_LAUNCH_ACTION,\n LEADER_MANAGE_ACTION,\n LEADER_ORDER,\n LEADER_RECOVER_ACTION,\n PACKAGE_SOURCE,\n} from '../../types/index.ts';\n\nconst LEADER_BINDING_PREFIX = 'doom-workflow';\nconst GROUP_SEGMENT = { key: LEADER_KEY, label: LEADER_LABEL, order: LEADER_ORDER } as const;\n\nexport interface WorkflowLeaderHandle {\n /** Republish the menu for the mode's current state. */\n setMode(enabled: boolean): void;\n dispose(): void;\n}\n\n/**\n * The menu as it stands with the mode on or off.\n *\n * One entry on `e` rather than an enable row beside a disable row: only one of\n * the two ever does anything, and a menu that prints both makes the reader\n * check the mode line to find out which. The label says which way it flips.\n */\nexport function workflowLeaderBindings(mode: boolean): LeaderBinding[] {\n return [\n {\n id: `${LEADER_BINDING_PREFIX}.manage`,\n path: [GROUP_SEGMENT, { key: 'l', label: 'manage', detail: 'running workflows' }],\n action: { name: LEADER_MANAGE_ACTION },\n },\n {\n id: `${LEADER_BINDING_PREFIX}.launch`,\n path: [GROUP_SEGMENT, { key: 'w', label: 'launch', detail: 'start a workflow' }],\n action: { name: LEADER_LAUNCH_ACTION },\n },\n mode\n ? {\n id: `${LEADER_BINDING_PREFIX}.disable`,\n path: [GROUP_SEGMENT, { key: 'e', label: 'exit', detail: 'take back workflow tools' }],\n action: { name: LEADER_DISABLE_ACTION },\n }\n : {\n id: `${LEADER_BINDING_PREFIX}.enable`,\n path: [GROUP_SEGMENT, { key: 'e', label: 'enter', detail: 'give the agent workflow tools' }],\n action: { name: LEADER_ENABLE_ACTION },\n },\n {\n id: `${LEADER_BINDING_PREFIX}.recover`,\n path: [GROUP_SEGMENT, { key: 'r', label: 'recover', detail: 'failed workflow' }],\n action: { name: LEADER_RECOVER_ACTION },\n },\n ];\n}\n\nexport function registerLeaderContribution(hub: DoomUiHubService, enabled = false): WorkflowLeaderHandle {\n const contribution = hub.registerLeader({\n source: PACKAGE_SOURCE,\n bindings: workflowLeaderBindings(enabled),\n });\n return {\n setMode(enabled) {\n contribution.update(workflowLeaderBindings(enabled));\n },\n dispose() {\n contribution.dispose();\n },\n };\n}\n"],"mappings":"6MAcA,MAAM,EAAwB,gBACxB,EAAgB,CAAE,IAAA,IAAiB,MAAO,EAAc,MAAA,EAAoB,EAelF,SAAgB,EAAuB,EAAgC,CACrE,MAAO,CACL,CACE,GAAI,GAAG,EAAsB,SAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,SAAU,OAAQ,mBAAoB,CAAC,EAChF,OAAQ,CAAE,KAAM,CAAqB,CACvC,EACA,CACE,GAAI,GAAG,EAAsB,SAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,SAAU,OAAQ,kBAAmB,CAAC,EAC/E,OAAQ,CAAE,KAAM,CAAqB,CACvC,EACA,EACI,CACE,GAAI,GAAG,EAAsB,UAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,OAAQ,OAAQ,0BAA2B,CAAC,EACrF,OAAQ,CAAE,KAAM,CAAsB,CACxC,EACA,CACE,GAAI,GAAG,EAAsB,SAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,QAAS,OAAQ,+BAAgC,CAAC,EAC3F,OAAQ,CAAE,KAAM,CAAqB,CACvC,EACJ,CACE,GAAI,GAAG,EAAsB,UAC7B,KAAM,CAAC,EAAe,CAAE,IAAK,IAAK,MAAO,UAAW,OAAQ,iBAAkB,CAAC,EAC/E,OAAQ,CAAE,KAAM,CAAsB,CACxC,CACF,CACF,CAEA,SAAgB,EAA2B,EAAuB,EAAU,GAA6B,CACvG,IAAM,EAAe,EAAI,eAAe,CACtC,OAAQ,EACR,SAAU,EAAuB,CAAO,CAC1C,CAAC,EACD,MAAO,CACL,QAAQ,EAAS,CACf,EAAa,OAAO,EAAuB,CAAO,CAAC,CACrD,EACA,SAAU,CACR,EAAa,QAAQ,CACvB,CACF,CACF"}