@agimon-ai/doompi-workflow 0.0.1-alpha.37 → 0.0.1-alpha.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/LICENSE +6 -0
  2. package/README.md +14 -8
  3. package/dist/_virtual/_rolldown/runtime.cjs +1 -0
  4. package/dist/adapters/pi/extension.cjs +1 -1
  5. package/dist/adapters/pi/extension.mjs +1 -1
  6. package/dist/adapters/pi/workflow/piExtension.cjs +6 -8
  7. package/dist/adapters/pi/workflow/piExtension.cjs.map +1 -1
  8. package/dist/adapters/pi/workflow/piExtension.mjs +6 -8
  9. package/dist/adapters/pi/workflow/piExtension.mjs.map +1 -1
  10. package/dist/adapters/pi/workflow/piTools.cjs +3 -3
  11. package/dist/adapters/pi/workflow/piTools.mjs +3 -3
  12. package/dist/adapters/pi/workflow/workflowLauncher.cjs +1 -1
  13. package/dist/adapters/pi/workflow/workflowLauncher.cjs.map +1 -1
  14. package/dist/adapters/pi/workflow/workflowLauncher.mjs +1 -1
  15. package/dist/adapters/pi/workflow/workflowLauncher.mjs.map +1 -1
  16. package/dist/adapters/workflowCatalogChannel.cjs +2 -0
  17. package/dist/adapters/workflowCatalogChannel.cjs.map +1 -0
  18. package/dist/adapters/workflowCatalogChannel.d.cts +23 -0
  19. package/dist/adapters/workflowCatalogChannel.d.cts.map +1 -0
  20. package/dist/adapters/workflowCatalogChannel.d.mts +23 -0
  21. package/dist/adapters/workflowCatalogChannel.d.mts.map +1 -0
  22. package/dist/adapters/workflowCatalogChannel.mjs +2 -0
  23. package/dist/adapters/workflowCatalogChannel.mjs.map +1 -0
  24. package/dist/adapters/workflowHubApi.cjs +2 -0
  25. package/dist/adapters/workflowHubApi.cjs.map +1 -0
  26. package/dist/adapters/workflowHubApi.d.cts +24 -0
  27. package/dist/adapters/workflowHubApi.d.cts.map +1 -0
  28. package/dist/adapters/workflowHubApi.d.mts +24 -0
  29. package/dist/adapters/workflowHubApi.d.mts.map +1 -0
  30. package/dist/adapters/workflowHubApi.mjs +2 -0
  31. package/dist/adapters/workflowHubApi.mjs.map +1 -0
  32. package/dist/adapters/workflowWatcher.cjs +2 -0
  33. package/dist/adapters/workflowWatcher.cjs.map +1 -0
  34. package/dist/adapters/workflowWatcher.d.cts +24 -0
  35. package/dist/adapters/workflowWatcher.d.cts.map +1 -0
  36. package/dist/adapters/workflowWatcher.d.mts +24 -0
  37. package/dist/adapters/workflowWatcher.d.mts.map +1 -0
  38. package/dist/adapters/workflowWatcher.mjs +2 -0
  39. package/dist/adapters/workflowWatcher.mjs.map +1 -0
  40. package/dist/adapters/workflowsHubChannel.cjs +2 -0
  41. package/dist/adapters/workflowsHubChannel.cjs.map +1 -0
  42. package/dist/adapters/workflowsHubChannel.d.cts +20 -0
  43. package/dist/adapters/workflowsHubChannel.d.cts.map +1 -0
  44. package/dist/adapters/workflowsHubChannel.d.mts +20 -0
  45. package/dist/adapters/workflowsHubChannel.d.mts.map +1 -0
  46. package/dist/adapters/workflowsHubChannel.mjs +2 -0
  47. package/dist/adapters/workflowsHubChannel.mjs.map +1 -0
  48. package/dist/hubApi.cjs +1 -0
  49. package/dist/hubApi.d.cts +2 -0
  50. package/dist/hubApi.d.mts +2 -0
  51. package/dist/hubApi.mjs +1 -0
  52. package/dist/schemas/workflowPi.cjs +1 -1
  53. package/dist/schemas/workflowPi.cjs.map +1 -1
  54. package/dist/schemas/workflowPi.mjs +1 -1
  55. package/dist/schemas/workflowPi.mjs.map +1 -1
  56. package/dist/services/webWorkflowCatalog.cjs +2 -0
  57. package/dist/services/webWorkflowCatalog.cjs.map +1 -0
  58. package/dist/services/webWorkflowCatalog.d.cts +49 -0
  59. package/dist/services/webWorkflowCatalog.d.cts.map +1 -0
  60. package/dist/services/webWorkflowCatalog.d.mts +49 -0
  61. package/dist/services/webWorkflowCatalog.d.mts.map +1 -0
  62. package/dist/services/webWorkflowCatalog.mjs +2 -0
  63. package/dist/services/webWorkflowCatalog.mjs.map +1 -0
  64. package/dist/services/workflowLaunchCommand.cjs +2 -0
  65. package/dist/services/workflowLaunchCommand.cjs.map +1 -0
  66. package/dist/services/workflowLaunchCommand.mjs +2 -0
  67. package/dist/services/workflowLaunchCommand.mjs.map +1 -0
  68. package/dist/services/workflowRuns.cjs +3 -0
  69. package/dist/services/workflowRuns.cjs.map +1 -0
  70. package/dist/services/workflowRuns.d.cts +17 -0
  71. package/dist/services/workflowRuns.d.cts.map +1 -0
  72. package/dist/services/workflowRuns.d.mts +17 -0
  73. package/dist/services/workflowRuns.d.mts.map +1 -0
  74. package/dist/services/workflowRuns.mjs +3 -0
  75. package/dist/services/workflowRuns.mjs.map +1 -0
  76. package/dist/services/workflowTerminal.cjs +2 -0
  77. package/dist/services/workflowTerminal.cjs.map +1 -0
  78. package/dist/services/workflowTerminal.mjs +2 -0
  79. package/dist/services/workflowTerminal.mjs.map +1 -0
  80. package/dist/tui/workflow/workflowCatalog.cjs +1 -1
  81. package/dist/tui/workflow/workflowCatalog.cjs.map +1 -1
  82. package/dist/tui/workflow/workflowCatalog.mjs +1 -1
  83. package/dist/tui/workflow/workflowCatalog.mjs.map +1 -1
  84. package/dist/types/webWorkflowTerminal.cjs +2 -0
  85. package/dist/types/webWorkflowTerminal.cjs.map +1 -0
  86. package/dist/types/webWorkflowTerminal.mjs +2 -0
  87. package/dist/types/webWorkflowTerminal.mjs.map +1 -0
  88. package/dist/types/webWorkflows.cjs +2 -0
  89. package/dist/types/webWorkflows.cjs.map +1 -0
  90. package/dist/types/webWorkflows.d.cts +95 -0
  91. package/dist/types/webWorkflows.d.cts.map +1 -0
  92. package/dist/types/webWorkflows.d.mts +95 -0
  93. package/dist/types/webWorkflows.d.mts.map +1 -0
  94. package/dist/types/webWorkflows.mjs +2 -0
  95. package/dist/types/webWorkflows.mjs.map +1 -0
  96. package/dist/webHub.cjs +1 -0
  97. package/dist/webHub.d.cts +3 -0
  98. package/dist/webHub.d.mts +3 -0
  99. package/dist/webHub.mjs +1 -0
  100. package/package.json +47 -11
  101. package/src/prompts/doompi-author-workflow/SKILL.md +1 -3
  102. package/src/types/webWorkflowTerminal.ts +92 -0
  103. package/src/types/webWorkflows.ts +145 -0
  104. package/web/ArtifactsPane.tsx +433 -0
  105. package/web/LICENSE +29 -0
  106. package/web/LaunchWorkflowDialog.tsx +249 -0
  107. package/web/StepTerminalPanel.tsx +251 -0
  108. package/web/WorkflowCatalogDrawer.tsx +228 -0
  109. package/web/WorkflowToolMessage.tsx +54 -0
  110. package/web/WorkflowsActivitySection.tsx +152 -0
  111. package/web/WorkflowsPanel.tsx +737 -0
  112. package/web/ansiSpans.ts +230 -0
  113. package/web/catalogStore.ts +112 -0
  114. package/web/index.ts +61 -0
  115. package/web/launchLine.ts +66 -0
  116. package/web/runDuration.ts +15 -0
  117. package/web/terminalApi.ts +151 -0
  118. package/web/tsconfig.json +22 -0
  119. package/web/workflowActivity.ts +102 -0
  120. package/web/workflowToolRender.ts +585 -0
  121. package/web/workflowsStore.ts +90 -0
  122. package/dist/tui/workflow/terminalGrid.cjs +0 -2
  123. package/dist/tui/workflow/terminalGrid.cjs.map +0 -1
  124. package/dist/tui/workflow/terminalGrid.mjs +0 -2
  125. package/dist/tui/workflow/terminalGrid.mjs.map +0 -1
package/LICENSE CHANGED
@@ -1,3 +1,9 @@
1
+ Portions of this software are licensed as follows:
2
+
3
+ * All content under the "web/" directory is licensed under the DoomPi Web
4
+ License defined in "web/LICENSE": free to use, not to redistribute.
5
+ * All other content is licensed under the MIT license below.
6
+
1
7
  MIT License
2
8
 
3
9
  Copyright (c) 2026 Vuong Ngo
package/README.md CHANGED
@@ -13,7 +13,7 @@ host-executed steps, while DoomPi provides session-scoped tools and TUI surfaces
13
13
  ## Requirements
14
14
 
15
15
  - Node.js 22.19.0 or newer
16
- - Pi 0.84.2 and Pi TUI 0.84.2
16
+ - Pi 0.84.3 and Pi TUI 0.84.3
17
17
 
18
18
  ## Install
19
19
 
@@ -36,23 +36,20 @@ name: verify
36
36
 
37
37
  jobs:
38
38
  test:
39
- runs-on: ubuntu-latest
40
39
  steps:
41
40
  - name: Run tests
42
41
  run: pnpm test
43
42
 
44
43
  summarize:
45
- runs-on: ubuntu-latest
46
44
  needs: test
47
45
  steps:
48
46
  - name: Record result
49
47
  run: node scripts/write-verification-summary.mjs
50
48
  ```
51
49
 
52
- The GitHub-style `runs-on` value does not create an Ubuntu VM or container. `run` commands execute
53
- on the host with the workflow process's environment and privileges. Review workflow files as
54
- executable code. Runner-specific `interactiveRun` mappings are available for commands that require
55
- a TTY.
50
+ `run` commands execute on the host with the workflow process's environment and privileges. There is
51
+ no VM, container, or sandbox. Review workflow files as executable code. Runner-specific
52
+ `interactiveRun` mappings are available for commands that require a TTY.
56
53
 
57
54
  ## Launch and monitor
58
55
 
@@ -119,6 +116,15 @@ pnpm lint
119
116
 
120
117
  Maintained by [Agimon](https://agimon.ai/about).
121
118
 
119
+ ## Web cockpit plugin
120
+
121
+ The `web/` directory is this package's DoomPi web cockpit plugin: the workflows tab, its store,
122
+ and its `workflow_runs` session channel, compiled into the cockpit bundle by `doompi-web`'s build.
123
+ The hub-side data source ships behind the `./web-hub` subpath and reads the workflow registry
124
+ (run.json plus progress.ndjson) exactly as the engine writes it. Both halves are declared by the
125
+ `doompiWeb` block in package.json.
126
+
122
127
  ## License
123
128
 
124
- MIT
129
+ MIT, except the `web/` directory, which is source available under the DoomPi Web License (see
130
+ `web/LICENSE`): free to use, including commercially, but not to redistribute.
@@ -0,0 +1 @@
1
+ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,s)=>(s=n==null?{}:e(i(n)),o(r||!n||!n.__esModule||!a.call(n,`default`)?t(s,`default`,{value:n,enumerable:!0}):s,n));exports.__toESM=s;
@@ -1,2 +1,2 @@
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:`doompi-author-workflow`,description:`Author DoomPi workflow definitions. Use when creating or changing a *.workflow.yml graph, arranging job dependencies and host-executed steps, or deciding how a command requiring a TTY should run.`},{name:`doompi-use-workflow`,description:`Use DoomPi workflows. Use when discovering or launching workflows, monitoring or controlling asynchronous runs, interpreting terminal notifications, or recovering a failed run 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;
1
+ const e=require("./leader.cjs"),t=require("./workflow/piExtension.cjs");let n=require("node:fs"),r=require("node:path"),i=require("node:async_hooks"),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 i.AsyncLocalStorage,n=!0,r=!1,a=0,o,s,c=()=>{if(!n)return!1;let e=t.getStore();return e===void 0||e===m||e===a},l=e=>{if(!n)return!1;let r=t.getStore();return r===m||e===a&&(r===void 0||r===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=i=>{c()&&e.registerTool({...i,execute:async(e,o,s,c,l)=>{let d=a;if(!n||r||s?.aborted)return S();let f=u(l,d),p=c?e=>{n&&d===a&&!s?.aborted&&c(e)}:void 0,m=await t.run(d,()=>i.execute(e,o,s,p,f));return n&&!r&&d===a?m:S()}})},f=(i,o)=>{c()&&e.registerCommand(i,{...o,handler:async(e,i)=>{let s=a;!n||r||await t.run(s,()=>o.handler(e,u(i,s)))}})},h=(i,o)=>{c()&&e.registerShortcut(i,{...o,handler:e=>{let i=a;if(!(!n||r))return t.run(i,()=>o.handler(u(e,i)))}})};return{pi:new Proxy(e,{get(e,i){return i===`on`?(i,c)=>{_(e,`on`)(i,(e,l)=>{if(!n||r)return;i===`session_start`&&(e!==o||l!==s)&&(a+=1,o=e,s=l);let d=a;return t.run(d,()=>c(e,u(l,d)))})}:i===`registerTool`?d:i===`registerCommand`?f:i===`registerShortcut`?h:i===`getActiveTools`?()=>c()?e.getActiveTools():[]:i===`setActiveTools`?t=>{c()&&e.setActiveTools(t)}:i===`sendMessage`?(...t)=>{c()&&e.sendMessage(...t)}:i===`sendUserMessage`?(...t)=>{c()&&e.sendUserMessage(...t)}:i===`exec`?(...t)=>c()?e.exec(...t):Promise.resolve({code:1,killed:!1,stderr:p,stdout:``}):_(e,i)}}),beginDisposal(){r||!n||(r=!0,a+=1)},finishDisposal(){n=!1,r=!1,a+=1},isCurrentInvocation:c,runCleanup:e=>t.run(m,e)}}function w(i,o,s,f=process.env){let p=x(f),m=p?b(f):void 0,h=p?y(o,m,f):o,g;if(i.effect(()=>()=>g?g.dispose():Promise.resolve(),`${d}/runtime`),i.inject([l.DOOM_SKILL_SOURCES_SERVICE],e=>{let t=(0,r.resolve)((0,r.dirname)((0,a.fileURLToPath)(require("url").pathToFileURL(__filename).href)),`../../../skills`);if(!(0,n.existsSync)(t))return;let i=(0,l.requireDoomSkillSourcesService)(e).register({source:d,directories:[t]});return()=>i.dispose()}),p){g=t.installWorkflowPiRuntime({cordis:i,initialMode:!0,isActive:s})(h);return}let _=!1,v;i.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)}}),i.inject([c.DOOM_HELP_SERVICE],e=>{let t=(0,c.requireDoomHelpService)(e).register({source:d,moduleUrl:require("url").pathToFileURL(__filename).href,skills:[{name:`doompi-author-workflow`,description:`Author DoomPi workflow definitions. Use when creating or changing a *.workflow.yml graph, arranging job dependencies and host-executed steps, or deciding how a command requiring a TTY should run.`},{name:`doompi-use-workflow`,description:`Use DoomPi workflows. Use when discovering or launching workflows, monitoring or controlling asynchronous runs, interpreting terminal notifications, or recovering a failed run safely.`}]});return()=>t.dispose()}),g=t.installWorkflowPiRuntime({cordis:i,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,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{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:`doompi-author-workflow`,description:`Author DoomPi workflow definitions. Use when creating or changing a *.workflow.yml graph, arranging job dependencies and host-executed steps, or deciding how a command requiring a TTY should run.`},{name:`doompi-use-workflow`,description:`Use DoomPi workflows. Use when discovering or launching workflows, monitoring or controlling asynchronous runs, interpreting terminal notifications, or recovering a failed run 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};
1
+ import{registerLeaderContribution as e}from"./leader.mjs";import{installWorkflowPiRuntime as t}from"./workflow/piExtension.mjs";import{existsSync as n}from"node:fs";import{dirname as r,resolve as i}from"node:path";import{AsyncLocalStorage as a}from"node:async_hooks";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 a,n=!0,r=!1,i=0,o,s,c=()=>{if(!n)return!1;let e=t.getStore();return e===void 0||e===b||e===i},l=e=>{if(!n)return!1;let r=t.getStore();return r===b||e===i&&(r===void 0||r===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=a=>{c()&&e.registerTool({...a,execute:async(e,o,s,c,l)=>{let d=i;if(!n||r||s?.aborted)return O();let f=u(l,d),p=c?e=>{n&&d===i&&!s?.aborted&&c(e)}:void 0,m=await t.run(d,()=>a.execute(e,o,s,p,f));return n&&!r&&d===i?m:O()}})},f=(a,o)=>{c()&&e.registerCommand(a,{...o,handler:async(e,a)=>{let s=i;!n||r||await t.run(s,()=>o.handler(e,u(a,s)))}})},p=(a,o)=>{c()&&e.registerShortcut(a,{...o,handler:e=>{let a=i;if(!(!n||r))return t.run(a,()=>o.handler(u(e,a)))}})};return{pi:new Proxy(e,{get(e,a){return a===`on`?(a,c)=>{C(e,`on`)(a,(e,l)=>{if(!n||r)return;a===`session_start`&&(e!==o||l!==s)&&(i+=1,o=e,s=l);let d=i;return t.run(d,()=>c(e,u(l,d)))})}:a===`registerTool`?d:a===`registerCommand`?f:a===`registerShortcut`?p:a===`getActiveTools`?()=>c()?e.getActiveTools():[]:a===`setActiveTools`?t=>{c()&&e.setActiveTools(t)}:a===`sendMessage`?(...t)=>{c()&&e.sendMessage(...t)}:a===`sendUserMessage`?(...t)=>{c()&&e.sendUserMessage(...t)}:a===`exec`?(...t)=>c()?e.exec(...t):Promise.resolve({code:1,killed:!1,stderr:y,stdout:``}):C(e,a)}}),beginDisposal(){r||!n||(r=!0,i+=1)},finishDisposal(){n=!1,r=!1,i+=1},isCurrentInvocation:c,runCleanup:e=>t.run(b,e)}}function A(a,s,c,l=process.env){let u=D(l),v=u?E(l):void 0,y=u?T(s,v,l):s,b;if(a.effect(()=>()=>b?b.dispose():Promise.resolve(),`${_}/runtime`),a.inject([p],e=>{let t=i(r(o(import.meta.url)),`../../../skills`);if(!n(t))return;let a=m(e).register({source:_,directories:[t]});return()=>a.dispose()}),u){b=t({cordis:a,initialMode:!0,isActive:c})(y);return}let x=!1,S;a.inject([h],t=>{let n=e(g(t),x);return S=n,()=>{n.dispose(),S===n&&(S=void 0)}}),a.inject([d],e=>{let t=f(e).register({source:_,moduleUrl:import.meta.url,skills:[{name:`doompi-author-workflow`,description:`Author DoomPi workflow definitions. Use when creating or changing a *.workflow.yml graph, arranging job dependencies and host-executed steps, or deciding how a command requiring a TTY should run.`},{name:`doompi-use-workflow`,description:`Use DoomPi workflows. Use when discovering or launching workflows, monitoring or controlling asynchronous runs, interpreting terminal notifications, or recovering a failed run safely.`}]});return()=>t.dispose()}),b=t({cordis:a,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,11 +1,9 @@
1
- const e=require("../../../types/index.cjs"),t=require("../../../services/backgroundWork.cjs"),n=require("../../../services/workflowNarration.cjs"),r=require("../../../tui/workflow/workflowInspector.cjs"),i=require("../../../tui/workflow/workflowOverlay.cjs"),a=require("../../../schemas/workflowPi.cjs"),o=require("../../../tui/workflow/terminalGrid.cjs"),s=require("../../../tui/workflow/workflowFinishedMessage.cjs"),c=require("../../../tui/workflow/workflowCatalog.cjs"),l=require("../../../tui/workflow/workflowPicker.cjs"),u=require("../../../tui/workflow/workflowProgressOverlay.cjs"),d=require("../../../tui/workflow/workflowPrompt.cjs"),ee=require("../../../tui/workflow/workflowRunPanel.cjs"),te=require("../../../tui/workflow/workflowStepMessage.cjs"),f=require("./piToolBridge.cjs"),ne=require("./piTools.cjs"),re=require("./workflowLauncher.cjs");let ie=require("node:fs"),p=require("node:path"),ae=require("node:url"),m=require("@agimon-ai/doompi-extension-contracts/child-process"),oe=require("@agimon-ai/doompi-extension-contracts/ui-hub"),h=require("node:child_process"),se=require("node:crypto"),ce=require("node:fs/promises"),g=require("node:module"),le=require("@agimon-ai/doompi-extension-contracts/mode"),ue=require("@agimon-ai/doompi-extension-contracts/narration"),de=require("@agimon-ai/doompi-extension-contracts/readiness"),fe=require("@agimon-ai/doompi-telemetry"),_=require("@agimon-ai/workflow-mcp"),v=require("@earendil-works/pi-tui");const pe={overlay:!0,overlayOptions:{anchor:`top-left`,width:`100%`,maxHeight:`100%`,margin:0}},me=`workflow-mcp-follow`,he=`activate`,ge=`deactivate`;function _e(e,t){return{activation:e?`active`:`inactive`,condition:`ready`,...e?{detail:t>0?`${t} active runs`:`tools enabled`,color:`accent`}:{},actions:[...e?[{id:he,enabled:!1,disabledReason:`Workflow mode is active.`}]:[{id:he,enabled:!0}],...e?[{id:ge,enabled:!0}]:[{id:ge,enabled:!1,disabledReason:`Workflow mode is inactive.`}]]}}const y=`ctrl+alt+w`,b=`ctrl+alt+q`,ve={alt:`⌥`,cmd:`⌘`,ctrl:`⌃`,meta:`⌘`,shift:`⇧`};function x(e,t=process.platform){let n=e.split(`+`);return t===`darwin`?n.map(e=>ve[e]??e.toUpperCase()).join(``):n.map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(`+`)}const S=1e4,C=`running`,ye=`completed`,w=`failed`,T=`error`,be=`error`,xe=`doom_workflow.launch_requested`,Se=`../../../../skills`,E={running:`▸`,repair:`⚠`,completed:`✔`,failed:`✖`,separator:`·`};function Ce(e,t=process.platform){let n=x(b,t);return e?[`Esc Esc closes this view`,`${x(y,t)} switches typing`,`${n} closes`].join(` ${E.separator} `):`view only ${E.separator} ${n} closes this view`}function we(e,t=process.platform){let n=[x(b,t),`close`];return e?[[`Esc Esc`,`close`],[x(y,t),`switch typing`],n]:[n]}function Te(e,t,n,r){let i=`${E.running} ${e.runKey}`,a=[e.workspace,Oe(e),e.runner].filter(Boolean).join(` ${E.separator} `),o=`${x(y)} to background`,s=n.fg(`accent`,(0,v.truncateToWidth)(i,r));return(0,v.visibleWidth)(i)+3+(0,v.visibleWidth)(a)<=r&&(s+=` `+n.fg(`muted`,a),(0,v.visibleWidth)(i)+3+(0,v.visibleWidth)(a)+3+(0,v.visibleWidth)(o)<=r&&(s+=` `+n.fg(`dim`,o))),[s,...t.map(e=>(0,v.truncateToWidth)(e,r))]}function Ee(e,t,n){let r=[];for(let i of e){let e=i.status===ye?E.completed:i.status===w?E.failed:E.running,a=i.status===ye?`success`:i.status===w?be:`accent`,o=i.total?` ${E.separator} ${(i.index??0)+1}/${i.total}`:``;if(r.push((0,v.truncateToWidth)(t.fg(a,`${e} ${i.name}`)+t.fg(`dim`,o),n)),i.status===C)for(let e of i.steps){let i=e.status===ye?E.completed:e.status===w?E.failed:E.running,a=e.status===C?`muted`:e.status===w?be:`dim`;r.push((0,v.truncateToWidth)(t.fg(a,` ${i} ${e.name}`),n))}}return r}function De(e,t){let n=Date.parse(e.startedAt);return Number.isFinite(n)?t.filter(e=>{let t=Date.parse(e.at);return!Number.isFinite(t)||t>=n}):t}function Oe(e){return e.stale?`stale`:e.stage===T?w:e.stage}const ke=`CMUX_WORKSPACE_ID`,D=`TMUX_PANE`,O=`WORKFLOW_TMUX_SESSION_NAME`,Ae=[`CMUX_SURFACE_ID`,m.SUBAGENT_ROOT_SESSION_ENV,ke,D,`WORKFLOW_LAUNCHER_TYPE`,O,`WORKFLOW_STATUS_FILE`],k=`tmux`,A=`cmux`,je=`native`,Me=`This run points at Pi's own terminal, so its launcher screen is hidden. Use workflow status instead.`;function Ne(e){let t=e.launcher;if(t?.type===A){let e=process.env[ke];return!!e&&t.workspaceId===e}if(t?.type!==k)return!1;let n=process.env[D],r=process.env[O];return!!n&&t.paneId===n||!!r&&t.sessionName===r}const Pe=`No durable launcher identity is recorded for this run.`;function Fe(e){return(0,p.basename)(e,(0,p.extname)(e))}function Ie(){let e={...process.env};for(let t of Ae)delete e[t];return e}function Le(){let e=process.env.WORKFLOW_LAUNCHER;return e===k||e===A?e:void 0}function Re(e){return e.map(e=>`'${e.replaceAll(`'`,`'\\''`)}'`).join(` `)}function ze(){try{return(0,g.createRequire)(require("url").pathToFileURL(__filename).href).resolve(`@agimon-ai/workflow-mcp/cli`)}catch{return}}const Be=async(e,t,n)=>{await new Promise((r,i)=>{let a=(0,h.spawn)(e,[...t],{...n,detached:!0,stdio:`ignore`});a.once(`error`,i),a.once(`spawn`,()=>{a.off(`error`,i),a.unref(),r()})})};function j(e,t){if(Array.isArray(e)){for(let n of e)j(n,t);return}if(!(!e||typeof e!=`object`))for(let[n,r]of Object.entries(e))(n===`interactiveRun`||n===`run`)&&r&&typeof r==`object`&&!Array.isArray(r)?t.push(Object.keys(r)):j(r,t)}function Ve(e){let t=[];if(j(e,t),t.length!==0)return t[0].filter(e=>t.every(t=>t.includes(e))).sort()}async function He(e,t){let n=[],r=1,i=!0;for(;i;){let a=await e.listRunsPage({page:r,pageSize:100,workspace:t});n.push(...a.items),i=a.hasNextPage,r+=1}return n}function Ue(e){return[e.runKey,e.workspace,Oe(e),e.runner].filter(Boolean).join(` ${E.separator} `)}function We(h={}){return g=>{let v=h.featureFactory?.()??(0,_.createEmbeddedWorkflowFeature)(),ve=(0,se.randomUUID)(),w=!0,be=0,ke,D,O,Ae=h.isActive??(()=>!0),j=()=>w&&Ae(),We=e=>{let t=e.diagnostics.join(`; `),n=(e.error?.message??t)||`Initialization did not complete.`,r=`${e.packageId} initialization ${e.state}: ${n}`;V?.hasUI?V.ui.notify(r,`warning`):process.emitWarning(r)},Ge=e=>(h.cordis?(0,de.readDoomReadinessCoordinator)(h.cordis):void 0)||(O??=(0,de.createDoomReadinessCoordinator)({notify:We}),O),M=async e=>{e?.throwIfAborted();let t=D;if(!t)throw Error(`Workflow session initialization has not started.`);let n=await t;if(e?.throwIfAborted(),await n.wait(e?{signal:e}:void 0),!j()||t!==D)throw Error(`Workflow readiness belongs to a stale extension generation.`)},Ke=(e,t)=>{let n=Reflect.get(e,t,e);return typeof n==`function`?n.bind(e):n},qe=new Proxy(g,{get(e,t){return t===`registerTool`?t=>{e.registerTool({...t,execute:async(e,n,r,i,a)=>(await M(r),t.execute(e,n,r,i,a))})}:Ke(e,t)}}),{parser:Je,recoverService:Ye,registry:N,runService:Xe,runTool:Ze}=v,Qe=h.spawnDetached??Be,$e=h.monitorIntervalMs??3e4,et=h.followIntervalMs??2e3,P,tt=!1,F,nt=!1,I,rt=new Map,L=new Map,it=new Set,at=0,ot=h.cordis?t.registerRunProvider(h.cordis):void 0,st=!1,R=0,z=!1,ct,B;h.cordis?.inject([le.DOOM_MINOR_MODE_CATALOG_SERVICE],t=>{let n=_e(z,R),r=(0,le.registerMinorModeOwner)((0,le.requireMinorModeCatalog)(t),{descriptor:{source:e.PACKAGE_SOURCE,id:`workflow`,label:`Workflow`,description:`Workflow discovery, launch, inspection, control, and recovery tools.`,order:20,actions:[{id:he,label:`Activate`,description:`Enable workflow tools for this session.`,contexts:[`tui`,`headless`],parameters:[]},{id:ge,label:`Deactivate`,description:`Disable workflow tools without stopping active runs.`,contexts:[`tui`,`headless`],parameters:[]}]},initialState:n,async handleAction(e,t,n){if(await M(),e===he)return await ln(!0,n.context),{message:`Workflow mode activated.`};if(e===ge)return await ln(!1,n.context),{message:`Workflow mode deactivated.`};throw Error(`Unknown workflow mode action: ${e}`)}});return B=r,ct=JSON.stringify(n),()=>{r.dispose(),B===r&&(B=void 0,ct=void 0)}});let V,H,U,lt=!1,ut=new Map,W,dt=new Set,G=new Map,ft=[],K=new Map,pt=0,mt=new u.WorkflowProgressOverlay,ht,gt,q=e=>(gt??=(0,fe.createDoomTelemetry)({serviceName:`doom-workflow`,packageName:`@agimon-ai/doompi-workflow`,cwd:e?.cwd,env:process.env,enableLogs:!0,enableTraces:!0}),gt),_t,vt=e=>{q(V).recordWarning(`doom_workflow.narration_failed`,e).catch(e=>{process.emitWarning(`Doom-workflow could not record a narration failure: ${String(e)}`)})},yt={narrate(e){let t=_t,n=(0,ue.createNarrationRequest)(e);if(!(!t||!n))try{Promise.resolve(t.request(n)).catch(vt)}catch(e){vt(e)}}};h.cordis?.inject([ue.DOOM_NARRATION_SERVICE],e=>{let t=(0,ue.requireDoomNarrationService)(e);return _t=t,()=>{_t===t&&(_t=void 0)}});let bt=e=>{e&&j()&&(ht=(0,m.resolveRootSessionId)(e))},xt=()=>{let e=ht??V?.sessionManager.getSessionId();return e?(0,m.resolveRootSessionId)(e):void 0},St=(e,t)=>e.sessionManager.getSessionId().trim()===t,Ct=v.createRecoverTool({ownerSessionId:xt}),wt=v.createControlTool(),J=new Set,Tt=e=>{let t=Date.now(),n=q();return J.add(e),n.recordEvent(`doom_workflow.run_started`,{outcome:`started`}),e.then(()=>(J.delete(e),n.recordEvent(`doom_workflow.run_finished`,{duration_ms:Date.now()-t,outcome:`completed`})),r=>(J.delete(e),n.recordError(`doom_workflow.run_failed`,r,{duration_ms:Date.now()-t}))),e},Et=(e,t)=>{let n=Ve(Je.parseWorkflowFile(e));if(!(!n||n.includes(t)))return`Runner ${JSON.stringify(t)} is not available across this workflow. Compatible runners: ${n.join(`, `)||`none`}.`},Dt=ne.createWorkflowLaunchExecutor({activeRunCount:async()=>R,observeSession:bt,rejectRunner:Et,runTool:Ze,trackPendingRun:Tt,...h.launchAckPollMs===void 0?{}:{launchAckPollMs:h.launchAckPollMs},...h.launchAckTimeoutMs===void 0?{}:{launchAckTimeoutMs:h.launchAckTimeoutMs},findLaunchedRun:async({sessionId:e,since:t,workflowPath:n})=>{let r=Fe(n),i=n=>{if(!f.isSessionRun(n,e)||n.stale||n.workflowId&&n.workflowId!==r)return!1;let i=Date.parse(n.startedAt);return Number.isFinite(i)&&i>=t-2e3};return W?(await W.refresh(),ft.find(i)):(await He(N)).find(i)},onLateFailure:(e,t)=>{let n=e instanceof Error?e.message:String(e);t.ui.notify(f.launchNotice(`Workflow launch failed after it was reported started.\n${n}`),`warning`)},onLaunch:async e=>(await q(e).recordEvent(xe,{outcome:`requested`}),Z(e,!1))}),Ot=()=>{let e=[...K.values()].sort((e,t)=>Date.parse(e.startedAt)-Date.parse(t.startedAt)||X(e).localeCompare(X(t)));mt.update(e.map(e=>u.workflowProgressRow(e,G.get(X(e))??[])))},kt=e=>{pt+=1;let t=X(e);e.stage===C&&!e.stale?K.set(t,e):K.delete(t),Ot()},At=e=>{K.clear();for(let t of e)K.set(X(t),t);Ot()},jt=(e,t)=>{let n=G.get(e)??[];n.push(t),G.set(e,n)},Y,Mt=e=>{!j()||e!==V||Y||(Y=setTimeout(()=>{Y=void 0,j()&&e===V&&Z(e,!0)},120),Y.unref?.())},Nt=e=>{G.delete(e)},Pt=async e=>{let t=(0,m.resolveRootSessionId)(e.sessionManager.getSessionId()),n=v.createRunControl({recordFilter:e=>f.isSessionRun(e,t)});W=n;let r=()=>j()&&e===V&&W===n,i=[n.on(`step`,t=>{if(!r())return;let n=X(t.record);jt(n,{at:t.at,job:t.job,status:t.status,step:t.step,type:`step`,...t.reason===void 0?{}:{reason:t.reason}}),kt(t.record),Mt(e)}),n.on(`job`,t=>{if(!r())return;let n=X(t.record);jt(n,{at:t.at,job:t.job,status:t.status,type:`job`,...t.index===void 0?{}:{index:t.index},...t.reason===void 0?{}:{reason:t.reason},...t.total===void 0?{}:{total:t.total}}),kt(t.record),Mt(e)}),n.on(`runStarted`,t=>{r()&&(ft.unshift(t.record),ft.length>32&&(ft.length=32),kt(t.record),Mt(e))}),n.on(`runUpdated`,t=>{r()&&(kt(t.record),Z(e,!0))}),n.on(`runFinished`,t=>{r()&&(kt(t.record),Z(e,!0))})];for(let e of i)dt.add(e);try{await n.start()}catch(e){for(let e of i)dt.delete(e),e();throw n.dispose(),W===n&&(W=void 0),e}if(!j()||e!==V||W!==n){for(let e of i)dt.delete(e),e();n.dispose(),W===n&&(W=void 0)}},Ft=()=>{Y&&clearTimeout(Y),Y=void 0;for(let e of dt)e();dt.clear(),W?.dispose(),W=void 0,G.clear(),pt+=1,K.clear(),Ot()},It=()=>{H?.teardown(),H?.handle?.hide(),H=void 0},X=e=>e.runId??`${e.workspace}/${e.runKey}`,Lt=()=>{let e=B;if(!e)return;let t=_e(z,R),n=JSON.stringify(t);n!==ct&&(ct=n,e.publish(t))},Z=async(e,t)=>{if(!j()||e!==V)return;let r=q(e);if(tt){r.recordEvent(`doom_workflow.monitor_skipped`,{outcome:`already_running`});return}let i=Date.now(),a=pt;tt=!0;try{let o=await He(N);if(!j()||e!==V)return;let c=(0,m.resolveRootSessionId)(e.sessionManager.getSessionId()),l=St(e,c),u=o.filter(e=>f.isSessionRun(e,c)),d=u.filter(e=>e.stage===C&&!e.stale),ee=u.filter(e=>e.stage===T);a===pt&&At(d),r.recordEvent(`doom_workflow.monitor_counts`,{"workflow.run_count":u.length,"workflow.running_count":d.length,"workflow.failed_count":ee.length,mode:z?`on`:`off`});let te=f.runsForSession(o,c).filter(e=>!e.stale);R=te.length,Lt(),ot?.update(te.map(e=>({id:e.runId??e.runKey,sessionId:c}))),Gt(new Set(u.map(e=>X(e))));let ne=new Map(u.map(e=>[X(e),e.stage]));for(let e of u){let r=X(e),i=rt.get(r),a=Date.parse(e.startedAt),o=i===void 0&&(at===0||!Number.isFinite(a)||a>=at);st&&n.narrateWorkflowTransition(yt,e,i===C||i===ye||i===T?i:void 0,o),!(!t||!l||e.stage===C)&&!it.has(r)&&(i===C||o)&&L.set(r,e)}let re=new Set([...u.filter(e=>e.stage===C&&!e.stale).map(e=>X(e)),...L.keys()]);for(let e of G.keys())re.has(e)||Nt(e);if(t)for(let t of u){if(rt.get(X(t))!==C||t.stage===C)continue;let n=t.stage===ye,i=t.failedJob?` at ${t.failedJob}`:``;e.ui.notify(n?`${E.completed} ${t.runKey} completed`:`${E.failed} ${t.runKey} ${Oe(t)}${i}`,n?`info`:`warning`),r.recordEvent(`doom_workflow.run_transition`,{outcome:n?`completed`:Oe(t)})}if(l&&L.size>0)try{let e=[...L.values()],t=await Promise.all(e.map(async e=>{if(e.stage===ye)return f.finishedRunSummary(e,[]);let t=X(e),n=G.get(t)??De(e,await(0,_.readWorkflowProgress)(N.runDirectoryFor(e)));return f.finishedRunSummary(e,(0,_.summarizeWorkflowProgress)(n))}));g.sendMessage({customType:s.WORKFLOW_FINISHED_MESSAGE,content:t.join(`
1
+ const e=require("../../../services/workflowTerminal.cjs"),t=require("../../../types/index.cjs"),n=require("../../../services/backgroundWork.cjs"),r=require("../../../services/workflowNarration.cjs"),i=require("../../../tui/workflow/workflowInspector.cjs"),a=require("../../../tui/workflow/workflowOverlay.cjs"),o=require("../../../tui/workflow/workflowFinishedMessage.cjs"),s=require("../../../tui/workflow/workflowCatalog.cjs"),c=require("../../../tui/workflow/workflowPicker.cjs"),l=require("../../../tui/workflow/workflowProgressOverlay.cjs"),u=require("../../../tui/workflow/workflowPrompt.cjs"),ee=require("../../../tui/workflow/workflowRunPanel.cjs"),d=require("../../../tui/workflow/workflowStepMessage.cjs"),f=require("./piToolBridge.cjs"),p=require("./piTools.cjs"),m=require("./workflowLauncher.cjs"),te=require("../../../services/workflowLaunchCommand.cjs");let ne=require("node:crypto"),re=require("node:fs"),h=require("node:path"),g=require("@agimon-ai/workflow-mcp"),ie=require("node:url"),_=require("@agimon-ai/doompi-extension-contracts/child-process"),ae=require("@agimon-ai/doompi-extension-contracts/ui-hub"),v=require("node:child_process"),oe=require("node:fs/promises"),y=require("node:module"),se=require("@agimon-ai/doompi-extension-contracts/mode"),ce=require("@agimon-ai/doompi-extension-contracts/narration"),le=require("@agimon-ai/doompi-extension-contracts/readiness"),ue=require("@agimon-ai/doompi-telemetry"),b=require("@earendil-works/pi-tui");const de={overlay:!0,overlayOptions:{anchor:`top-left`,width:`100%`,maxHeight:`100%`,margin:0}},fe=`workflow-mcp-follow`,pe=`activate`,me=`deactivate`;function he(e,t){return{activation:e?`active`:`inactive`,condition:`ready`,...e?{detail:t>0?`${t} active runs`:`tools enabled`,color:`accent`}:{},actions:[...e?[{id:pe,enabled:!1,disabledReason:`Workflow mode is active.`}]:[{id:pe,enabled:!0}],...e?[{id:me,enabled:!0}]:[{id:me,enabled:!1,disabledReason:`Workflow mode is inactive.`}]]}}const x=`ctrl+alt+w`,S=`ctrl+alt+q`,ge={alt:`⌥`,cmd:`⌘`,ctrl:`⌃`,meta:`⌘`,shift:`⇧`};function C(e,t=process.platform){let n=e.split(`+`);return t===`darwin`?n.map(e=>ge[e]??e.toUpperCase()).join(``):n.map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(`+`)}const _e=1e4,w=`running`,T=`completed`,E=`failed`,ve=`error`,ye=`error`,be=`doom_workflow.launch_requested`,xe=`../../../../skills`,D={running:`▸`,repair:`⚠`,completed:`✔`,failed:`✖`,separator:`·`};function Se(e,t=process.platform){let n=C(S,t);return e?[`Esc Esc closes this view`,`${C(x,t)} switches typing`,`${n} closes`].join(` ${D.separator} `):`view only ${D.separator} ${n} closes this view`}function Ce(e,t=process.platform){let n=[C(S,t),`close`];return e?[[`Esc Esc`,`close`],[C(x,t),`switch typing`],n]:[n]}function we(e,t,n,r){let i=`${D.running} ${e.runKey}`,a=[e.workspace,De(e),e.runner].filter(Boolean).join(` ${D.separator} `),o=`${C(x)} to background`,s=n.fg(`accent`,(0,b.truncateToWidth)(i,r));return(0,b.visibleWidth)(i)+3+(0,b.visibleWidth)(a)<=r&&(s+=` `+n.fg(`muted`,a),(0,b.visibleWidth)(i)+3+(0,b.visibleWidth)(a)+3+(0,b.visibleWidth)(o)<=r&&(s+=` `+n.fg(`dim`,o))),[s,...t.map(e=>(0,b.truncateToWidth)(e,r))]}function Te(e,t,n){let r=[];for(let i of e){let e=i.status===T?D.completed:i.status===E?D.failed:D.running,a=i.status===T?`success`:i.status===E?ye:`accent`,o=i.total?` ${D.separator} ${(i.index??0)+1}/${i.total}`:``;if(r.push((0,b.truncateToWidth)(t.fg(a,`${e} ${i.name}`)+t.fg(`dim`,o),n)),i.status===w)for(let e of i.steps){let i=e.status===T?D.completed:e.status===E?D.failed:D.running,a=e.status===w?`muted`:e.status===E?ye:`dim`;r.push((0,b.truncateToWidth)(t.fg(a,` ${i} ${e.name}`),n))}}return r}function Ee(e,t){let n=Date.parse(e.startedAt);return Number.isFinite(n)?t.filter(e=>{let t=Date.parse(e.at);return!Number.isFinite(t)||t>=n}):t}function De(e){return e.stale?`stale`:e.stage===ve?E:e.stage}const Oe=[`CMUX_SURFACE_ID`,_.SUBAGENT_ROOT_SESSION_ENV,`CMUX_WORKSPACE_ID`,`TMUX_PANE`,`WORKFLOW_LAUNCHER_TYPE`,`WORKFLOW_TMUX_SESSION_NAME`,`WORKFLOW_STATUS_FILE`],ke=`tmux`,Ae=`cmux`,je=`This run points at Pi's own terminal, so its launcher screen is hidden. Use workflow status instead.`;function Me(e){return(0,h.basename)(e,(0,h.extname)(e))}function Ne(){let e={...process.env};for(let t of Oe)delete e[t];return e}function Pe(){let e=process.env.WORKFLOW_LAUNCHER;return e===ke||e===Ae?e:void 0}function Fe(e){return e.map(e=>`'${e.replaceAll(`'`,`'\\''`)}'`).join(` `)}function Ie(){try{return(0,y.createRequire)(require("url").pathToFileURL(__filename).href).resolve(`@agimon-ai/workflow-mcp/cli`)}catch{return}}const Le=async(e,t,n)=>{await new Promise((r,i)=>{let a=(0,v.spawn)(e,[...t],{...n,detached:!0,stdio:`ignore`});a.once(`error`,i),a.once(`spawn`,()=>{a.off(`error`,i),a.unref(),r()})})};function O(e,t){if(Array.isArray(e)){for(let n of e)O(n,t);return}if(!(!e||typeof e!=`object`))for(let[n,r]of Object.entries(e))(n===`interactiveRun`||n===`run`)&&r&&typeof r==`object`&&!Array.isArray(r)?t.push(Object.keys(r)):O(r,t)}function Re(e){let t=[];if(O(e,t),t.length!==0)return t[0].filter(e=>t.every(t=>t.includes(e))).sort()}async function k(e,t){let n=[],r=1,i=!0;for(;i;){let a=await e.listRunsPage({page:r,pageSize:100,workspace:t});n.push(...a.items),i=a.hasNextPage,r+=1}return n}function ze(e){return[e.runKey,e.workspace,De(e),e.runner].filter(Boolean).join(` ${D.separator} `)}function Be(v={}){return y=>{let b=v.featureFactory?.()??(0,g.createEmbeddedWorkflowFeature)(),ge=(0,ne.randomUUID)(),E=!0,ye=0,Oe,O,Be,Ve=v.isActive??(()=>!0),A=()=>E&&Ve(),He=e=>{let t=e.diagnostics.join(`; `),n=(e.error?.message??t)||`Initialization did not complete.`,r=`${e.packageId} initialization ${e.state}: ${n}`;B?.hasUI?B.ui.notify(r,`warning`):process.emitWarning(r)},Ue=e=>(v.cordis?(0,le.readDoomReadinessCoordinator)(v.cordis):void 0)||(Be??=(0,le.createDoomReadinessCoordinator)({notify:He}),Be),j=async e=>{e?.throwIfAborted();let t=O;if(!t)throw Error(`Workflow session initialization has not started.`);let n=await t;if(e?.throwIfAborted(),await n.wait(e?{signal:e}:void 0),!A()||t!==O)throw Error(`Workflow readiness belongs to a stale extension generation.`)},We=(e,t)=>{let n=Reflect.get(e,t,e);return typeof n==`function`?n.bind(e):n},Ge=new Proxy(y,{get(e,t){return t===`registerTool`?t=>{e.registerTool({...t,execute:async(e,n,r,i,a)=>(await j(r),t.execute(e,n,r,i,a))})}:We(e,t)}}),{parser:Ke,recoverService:qe,registry:M,runService:Je,runTool:Ye}=b,Xe=v.spawnDetached??Le,Ze=v.monitorIntervalMs??3e4,Qe=v.followIntervalMs??2e3,N,$e=!1,P,et=!1,F,tt=new Map,I=new Map,nt=new Set,rt=0,it=v.cordis?n.registerRunProvider(v.cordis):void 0,at=!1,L=0,R=!1,ot,z;v.cordis?.inject([se.DOOM_MINOR_MODE_CATALOG_SERVICE],e=>{let n=he(R,L),r=(0,se.registerMinorModeOwner)((0,se.requireMinorModeCatalog)(e),{descriptor:{source:t.PACKAGE_SOURCE,id:`workflow`,label:`Workflow`,description:`Workflow discovery, launch, inspection, control, and recovery tools.`,order:20,actions:[{id:pe,label:`Activate`,description:`Enable workflow tools for this session.`,contexts:[`tui`,`headless`],parameters:[]},{id:me,label:`Deactivate`,description:`Disable workflow tools without stopping active runs.`,contexts:[`tui`,`headless`],parameters:[]}]},initialState:n,async handleAction(e,t,n){if(await j(),e===pe)return await on(!0,n.context),{message:`Workflow mode activated.`};if(e===me)return await on(!1,n.context),{message:`Workflow mode deactivated.`};throw Error(`Unknown workflow mode action: ${e}`)}});return z=r,ot=JSON.stringify(n),()=>{r.dispose(),z===r&&(z=void 0,ot=void 0)}});let B,V,H,st=!1,ct=new Map,U,lt=new Set,W=new Map,ut=[],G=new Map,dt=0,ft=new l.WorkflowProgressOverlay,pt,mt,K=e=>(mt??=(0,ue.createDoomTelemetry)({serviceName:`doom-workflow`,packageName:`@agimon-ai/doompi-workflow`,cwd:e?.cwd,env:process.env,enableLogs:!0,enableTraces:!0}),mt),ht,gt=e=>{K(B).recordWarning(`doom_workflow.narration_failed`,e).catch(e=>{process.emitWarning(`Doom-workflow could not record a narration failure: ${String(e)}`)})},_t={narrate(e){let t=ht,n=(0,ce.createNarrationRequest)(e);if(!(!t||!n))try{Promise.resolve(t.request(n)).catch(gt)}catch(e){gt(e)}}};v.cordis?.inject([ce.DOOM_NARRATION_SERVICE],e=>{let t=(0,ce.requireDoomNarrationService)(e);return ht=t,()=>{ht===t&&(ht=void 0)}});let vt=e=>{e&&A()&&(pt=(0,_.resolveRootSessionId)(e))},yt=()=>{let e=pt??B?.sessionManager.getSessionId();return e?(0,_.resolveRootSessionId)(e):void 0},bt=(e,t)=>e.sessionManager.getSessionId().trim()===t,xt=b.createRecoverTool({ownerSessionId:yt}),St=b.createControlTool(),q=new Set,Ct=e=>{let t=Date.now(),n=K();return q.add(e),n.recordEvent(`doom_workflow.run_started`,{outcome:`started`}),e.then(()=>(q.delete(e),n.recordEvent(`doom_workflow.run_finished`,{duration_ms:Date.now()-t,outcome:`completed`})),r=>(q.delete(e),n.recordError(`doom_workflow.run_failed`,r,{duration_ms:Date.now()-t}))),e},wt=(e,t)=>{let n=Re(Ke.parseWorkflowFile(e));if(!(!n||n.includes(t)))return`Runner ${JSON.stringify(t)} is not available across this workflow. Compatible runners: ${n.join(`, `)||`none`}.`},Tt=p.createWorkflowLaunchExecutor({activeRunCount:async()=>L,observeSession:vt,rejectRunner:wt,runTool:Ye,trackPendingRun:Ct,...v.launchAckPollMs===void 0?{}:{launchAckPollMs:v.launchAckPollMs},...v.launchAckTimeoutMs===void 0?{}:{launchAckTimeoutMs:v.launchAckTimeoutMs},findLaunchedRun:async({sessionId:e,since:t,workflowPath:n})=>{let r=Me(n),i=n=>{if(!f.isSessionRun(n,e)||n.stale||n.workflowId&&n.workflowId!==r)return!1;let i=Date.parse(n.startedAt);return Number.isFinite(i)&&i>=t-2e3};return U?(await U.refresh(),ut.find(i)):(await k(M)).find(i)},onLateFailure:(e,t)=>{let n=e instanceof Error?e.message:String(e);t.ui.notify(f.launchNotice(`Workflow launch failed after it was reported started.\n${n}`),`warning`)},onLaunch:async e=>(await K(e).recordEvent(be,{outcome:`requested`}),X(e,!1))}),Et=()=>{let e=[...G.values()].sort((e,t)=>Date.parse(e.startedAt)-Date.parse(t.startedAt)||Y(e).localeCompare(Y(t)));ft.update(e.map(e=>l.workflowProgressRow(e,W.get(Y(e))??[])))},Dt=e=>{dt+=1;let t=Y(e);e.stage===w&&!e.stale?G.set(t,e):G.delete(t),Et()},Ot=e=>{G.clear();for(let t of e)G.set(Y(t),t);Et()},kt=(e,t)=>{let n=W.get(e)??[];n.push(t),W.set(e,n)},J,At=e=>{!A()||e!==B||J||(J=setTimeout(()=>{J=void 0,A()&&e===B&&X(e,!0)},120),J.unref?.())},jt=e=>{W.delete(e)},Mt=async e=>{let t=(0,_.resolveRootSessionId)(e.sessionManager.getSessionId()),n=b.createRunControl({recordFilter:e=>f.isSessionRun(e,t)});U=n;let r=()=>A()&&e===B&&U===n,i=[n.on(`step`,t=>{if(!r())return;let n=Y(t.record);kt(n,{at:t.at,job:t.job,status:t.status,step:t.step,type:`step`,...t.reason===void 0?{}:{reason:t.reason}}),Dt(t.record),At(e)}),n.on(`job`,t=>{if(!r())return;let n=Y(t.record);kt(n,{at:t.at,job:t.job,status:t.status,type:`job`,...t.index===void 0?{}:{index:t.index},...t.reason===void 0?{}:{reason:t.reason},...t.total===void 0?{}:{total:t.total}}),Dt(t.record),At(e)}),n.on(`runStarted`,t=>{r()&&(ut.unshift(t.record),ut.length>32&&(ut.length=32),Dt(t.record),At(e))}),n.on(`runUpdated`,t=>{r()&&(Dt(t.record),X(e,!0))}),n.on(`runFinished`,t=>{r()&&(Dt(t.record),X(e,!0))})];for(let e of i)lt.add(e);try{await n.start()}catch(e){for(let e of i)lt.delete(e),e();throw n.dispose(),U===n&&(U=void 0),e}if(!A()||e!==B||U!==n){for(let e of i)lt.delete(e),e();n.dispose(),U===n&&(U=void 0)}},Nt=()=>{J&&clearTimeout(J),J=void 0;for(let e of lt)e();lt.clear(),U?.dispose(),U=void 0,W.clear(),dt+=1,G.clear(),Et()},Pt=()=>{V?.teardown(),V?.handle?.hide(),V=void 0},Y=e=>e.runId??`${e.workspace}/${e.runKey}`,Ft=()=>{let e=z;if(!e)return;let t=he(R,L),n=JSON.stringify(t);n!==ot&&(ot=n,e.publish(t))},X=async(e,t)=>{if(!A()||e!==B)return;let n=K(e);if($e){n.recordEvent(`doom_workflow.monitor_skipped`,{outcome:`already_running`});return}let i=Date.now(),a=dt;$e=!0;try{let s=await k(M);if(!A()||e!==B)return;let c=(0,_.resolveRootSessionId)(e.sessionManager.getSessionId()),l=bt(e,c),u=s.filter(e=>f.isSessionRun(e,c)),ee=u.filter(e=>e.stage===w&&!e.stale),d=u.filter(e=>e.stage===ve);a===dt&&Ot(ee),n.recordEvent(`doom_workflow.monitor_counts`,{"workflow.run_count":u.length,"workflow.running_count":ee.length,"workflow.failed_count":d.length,mode:R?`on`:`off`});let p=f.runsForSession(s,c).filter(e=>!e.stale);L=p.length,Ft(),it?.update(p.map(e=>({id:e.runId??e.runKey,sessionId:c}))),Vt(new Set(u.map(e=>Y(e))));let m=new Map(u.map(e=>[Y(e),e.stage]));for(let e of u){let n=Y(e),i=tt.get(n),a=Date.parse(e.startedAt),o=i===void 0&&(rt===0||!Number.isFinite(a)||a>=rt);at&&r.narrateWorkflowTransition(_t,e,i===w||i===T||i===ve?i:void 0,o),!(!t||!l||e.stage===w)&&!nt.has(n)&&(i===w||o)&&I.set(n,e)}let te=new Set([...u.filter(e=>e.stage===w&&!e.stale).map(e=>Y(e)),...I.keys()]);for(let e of W.keys())te.has(e)||jt(e);if(t)for(let t of u){if(tt.get(Y(t))!==w||t.stage===w)continue;let r=t.stage===T,i=t.failedJob?` at ${t.failedJob}`:``;e.ui.notify(r?`${D.completed} ${t.runKey} completed`:`${D.failed} ${t.runKey} ${De(t)}${i}`,r?`info`:`warning`),n.recordEvent(`doom_workflow.run_transition`,{outcome:r?`completed`:De(t)})}if(l&&I.size>0)try{let e=[...I.values()],t=await Promise.all(e.map(async e=>{if(e.stage===T)return f.finishedRunSummary(e,[]);let t=Y(e),n=W.get(t)??Ee(e,await(0,g.readWorkflowProgress)(M.runDirectoryFor(e)));return f.finishedRunSummary(e,(0,g.summarizeWorkflowProgress)(n))}));y.sendMessage({customType:o.WORKFLOW_FINISHED_MESSAGE,content:t.join(`
2
2
 
3
- `),display:!0,details:{runIds:e.map(e=>e.runId??X(e)),runs:e.map(e=>({runKey:e.runKey,workspace:e.workspace,stage:e.stage,...e.workflowId?{workflowId:e.workflowId}:{},...e.failedJob?{failedJob:e.failedJob}:{},...e.errorMessage?{error:e.errorMessage}:{}}))}},{triggerTurn:!0,deliverAs:`steer`});for(let t of e){let e=X(t);it.add(e),L.delete(e),Nt(e)}}catch(e){await r.recordError(`doom_workflow.terminal_delivery_failed`,e,{"workflow.pending_terminal_count":L.size})}rt=ne,r.recordEvent(`doom_workflow.monitor_finished`,{duration_ms:Date.now()-i,outcome:`completed`})}catch(t){await r.recordError(`doom_workflow.monitor_failed`,t,{duration_ms:Date.now()-i}),e.ui.notify(`Workflow status refresh failed: ${t instanceof Error?t.message:String(t)}`,`warning`)}finally{tt=!1}},Rt=e=>{F&&clearInterval(F),F=void 0,I=void 0,e.ui.setWidget(me,void 0)},zt=new Map,Bt=(e,t,n)=>{let r=e.launcher;if(!r||r.type!==k||Ne(e)||t<40||n<10)return;let i=X(e),a=`${t}x${n}`;if(zt.get(i)===a)return;zt.set(i,a);let o=r.windowId??r.paneId??r.sessionId??r.sessionName;g.exec(k,[`resize-window`,`-t`,o,`-x`,String(t),`-y`,String(n)],{timeout:S})},Vt=async e=>{let t=await g.exec(A,[`rpc`,`terminal.replay`,JSON.stringify({workspace_id:e})],{timeout:S});if(t.code!==0)return;let n;try{n=JSON.parse(t.stdout)}catch{return}let r=a.terminalReplaySchema.safeParse(n);if(!r.success)return;let i=o.renderGridLines(r.data.render_grid,24);return i.length>0?i:void 0},Ht=async e=>{let t=e.launcher;if(!t)return[Pe];if(Ne(e))return[Me];if(t.type===k){let n=t.paneId??t.sessionId??t.sessionName,r=await g.exec(k,[`capture-pane`,`-p`,`-e`,`-t`,n,`-S`,`-24`],{timeout:S});return r.code===0?r.stdout.trimEnd().split(`
4
- `).slice(-24):[`Unable to read ${e.runKey}: ${r.stderr.trim()||`tmux exited ${r.code}`}`]}if(t.type===je)return[`This run is hosted natively and has no launcher screen to read.`];let n=await Vt(t.workspaceId);if(n)return n;let r=await g.exec(A,[`read-screen`,`--workspace`,t.workspaceId,`--scrollback`,`--lines`,`24`],{timeout:S});return r.code===0?r.stdout.trimEnd().split(`
5
- `).slice(-24):[`Unable to read ${e.runKey}: ${r.stderr.trim()||`cmux exited ${r.code}`}`]},Ut=new Map,Wt=async e=>{let t=X(e),n=Ut.get(t)??{at:0,lines:[]};if(Ut.set(t,n),n.inFlight||Date.now()-n.at<750)return n.lines;n.inFlight=Ht(e);try{n.lines=await n.inFlight}finally{n.at=Date.now(),n.inFlight=void 0}return n.lines},Gt=e=>{for(let t of Ut.keys())e.has(t)||Ut.delete(t);for(let t of zt.keys())e.has(t)||zt.delete(t)},Kt=async e=>{let t=e.launcher;if(!t)return Pe;if(Ne(e))return Me;if(t.type===je)return`This run is hosted natively rather than in a multiplexer, so there is no separate window to bring forward.`;if(t.type===A)return await g.exec(A,[`select-workspace`,`--workspace`,t.workspaceId],{timeout:S}),`Opened ${e.runKey} in cmux.`;if(!process.env.TMUX)return`Pi is not attached to tmux. Follow the output instead, or attach to the recorded tmux session manually.`;let n=t.sessionId??t.sessionName,r=await g.exec(k,[`switch-client`,`-t`,n],{timeout:S});return r.code===0?(t.paneId&&await g.exec(k,[`select-pane`,`-t`,t.paneId],{timeout:S}),`Opened ${e.runKey} in tmux.`):r.stderr.trim()||`Unable to open tmux session ${n}.`},qt=async(e,t)=>{if(!nt){nt=!0;try{let n=(0,_.summarizeWorkflowProgress)(De(e,await(0,_.readWorkflowProgress)(N.runDirectoryFor(e)))),r=n.length>0?void 0:await Wt(e);t.ui.setWidget(me,(t,i)=>({render:t=>Te(e,r??Ee(n,i,t),i,t),invalidate:()=>{}}),{placement:`aboveEditor`})}finally{nt=!1}}},Jt=async(e,t)=>{Rt(t),I=e,await qt(e,t),F=setInterval(()=>{I&&qt(I,t)},et),F.unref?.()},Yt=async(e,t)=>{let n=e.launcher;if(!(!n||n.type===je||Ne(e))){if(n.type===k){let e=n.paneId??n.sessionId??n.sessionName;await g.exec(k,[`send-keys`,`-t`,e,`-l`,t],{timeout:S});return}await g.exec(A,[`send`,`--workspace`,n.workspaceId,t],{timeout:S})}},Xt=async(e,t)=>{It();let n=!Ne(e)&&(e.launcher?.type===k||e.launcher?.type===A),r=new i.TerminalInputBatcher(t=>Yt(e,t)),a=[],o=[],s,c=!1,l=async()=>{a=(0,_.summarizeWorkflowProgress)(De(e,await(0,_.readWorkflowProgress)(N.runDirectoryFor(e)))),o=await Wt(e)};await l();let u=()=>{s&&clearInterval(s),s=void 0,r.dispose()},d={interactive:n,runKey:e.runKey,teardown:u};H=d;let te=()=>{It(),t.ui.notify(`Closed the ${e.runKey} view. The run keeps going.`,`info`)};return t.ui.custom((i,f,ne,re)=>(s=setInterval(()=>{c||(c=!0,l().finally(()=>{c=!1,i.requestRender()}))},200),s.unref?.(),new ee.WorkflowRunPanelComponent(i,f,{runKey:e.runKey,label:`${E.running} ${Ue(e)}`,breadcrumb:`SPC › w / workflows › run`,interactive:n,footer:Ce(n),hints:we(n),snapshot:e=>({progress:Ee(a,f,e),output:o}),onViewport:(t,n)=>Bt(e,t,n),onUnfollow:()=>{d.handle?.unfocus(),t.ui.notify(`Typing goes to this session. The run keeps going.`,`info`)},onClose:te,sendInput:e=>r.write(e),flushInput:()=>void r.flush(),unfollowShortcut:y,closeShortcut:b,onDispose:()=>{u(),H===d&&(H=void 0),re()}})),{...ee.runPanelUiOptions(n),onHandle:e=>{d.handle=e}}),t.ui.notify(n?`${e.runKey}: typing goes to the run. Press Esc twice to close, ${x(y)} to type here instead.`:`${e.runKey}: view only, because this run is hosted natively. ${x(b)} closes it.`,`info`),n?[`Showing ${e.runKey} over Pi. Typing goes to the run.`,`Pressing Escape twice quickly closes the view, and a single Escape still reaches the run.`,`${x(y)} moves typing between the run and this session,`,`and ${x(b)} closes the view. The run keeps going either way.`].join(` `):[`Showing ${e.runKey} over Pi, as a view only:`,`the run is hosted natively rather than in a multiplexer, so there is no terminal to type into.`,`Typing stays with this session, and ${x(b)} closes the view.`].join(` `)},Zt=async(e,t=!1)=>{if(!(lt||H||I)){lt=!0;try{let n=await e.ui.custom((e,t,n,i)=>new r.WorkflowInspectorComponent(e,t,{list:async()=>{let e=xt(),t=(await He(N)).filter(t=>t.stage===C&&!t.stale&&f.isSessionRun(t,e));return ut=new Map(t.map(e=>[X(e),e])),Promise.all(t.map(async e=>({displayName:e.displayName,executionState:e.executionState,jobs:(0,_.summarizeWorkflowProgress)(De(e,await(0,_.readWorkflowProgress)(N.runDirectoryFor(e)))),key:X(e),output:[],runKey:e.runKey,startedAt:e.startedAt,workspace:e.workspace})))},output:async e=>{let t=ut.get(e.key);return t?Wt(t):[`Workflow is no longer active.`]}},i),{...pe,onHandle:e=>{U=e}});if(n){let r=await Q(n);t?await nn(r,e):await Xt(r,e)}}finally{U=void 0,lt=!1,ut.clear()}}},Q=async(e,t=xt())=>{bt(t);let n=(await He(N,e.workspace)).filter(n=>n.runKey===e.runKey&&f.isSessionRun(n,t));if(n.length>1)throw Error(f.withOptions(`Workflow run key ${JSON.stringify(e.runKey)} exists in more than one workspace in this session.`,[`Retry with the workspace from the run identity.`]));let r=n[0];if(!r)throw Error(f.withOptions(`No workflow run matches ${JSON.stringify(e.runKey)} in this session.`,[`workflow_run with action status: use a run key from this session before retrying.`,`Tell the user this session did not launch that run rather than guessing a similar key. A run launched by another Pi session, or from the command line, is managed there or with the workflow-mcp CLI.`]));return r},Qt=async e=>{let t=(await He(N,e.workspace)).filter(t=>t.runKey===e.runKey&&t.stage===T);if(t.length>1)throw Error(f.withOptions(`Failed workflow run key ${JSON.stringify(e.runKey)} exists in more than one workspace.`,[`Retry with the workspace from the recovery picker or run identity.`]));let n=t[0];if(!n)throw Error(f.withOptions(`No failed workflow run matches ${JSON.stringify(e.runKey)}.`,[`Use the recovery picker to select an interrupted or failed run, or retry with its workspace.`,`Do not recover a running or completed workflow.`]));return n},$t=async e=>{let t=N.runDirectoryFor(e),n=[(0,p.resolve)(t,`changelog.md`),(0,p.resolve)(t,`context.md`),(0,p.resolve)(t,`progress.ndjson`)],r=[];for(let e of n)try{let t=await(0,ce.readFile)(e,`utf-8`);r.push(`--- ${(0,p.basename)(e)} ---`,t.slice(-65536).trimEnd())}catch(e){if(e.code!==`ENOENT`)throw e}return r.length>0?r:[`No durable recovery evidence files are recorded for this run.`]},en=async(e,t)=>{let n=await Qt(e);return await q(t).recordEvent(`doom_workflow.recovery_evidence_requested`,{outcome:`requested`}),[`Workflow: ${Ue(n)}`,`--- run.json ---`,JSON.stringify(n,null,2),...await $t(n)].join(`
6
- `)},tn=async(e,t)=>{let n=ze();if(!n)return;let r=await Qt(e),i;try{i=Je.parseWorkflowFile(r.workflowPath)}catch{return}if(!i[`launch-command`])return;let a=(0,m.resolveRootSessionId)(t.sessionManager.getSessionId()),o=await N.claimRunRecovery(r.workspace,r.runKey,a),s=r.originalRepoPath??t.cwd,c=Re([process.execPath,n,`recover-workflow`,r.runKey,`--workspace`,r.workspace,`--recovery-claim`,o.claimId,...e.runner?[`--runner`,e.runner]:[]]),l=Le();try{await Qe(process.execPath,[n,`launch-process`,...l?[`--launcher`,l]:[],`--name`,`${r.displayName} recover`,`--cwd`,s,`--command`,c],{cwd:s,env:Ie()})}catch(e){throw await N.releaseRunRecoveryClaim(r.workspace,r.runKey,o.claimId),e}return await q(t).recordEvent(`doom_workflow.recover_delegated`,{launcher:l??`auto`,outcome:`delegated`}),`Recovering ${r.runKey} in a launcher of its own, so this session keeps its terminal. It reports back here when it ends.`},nn=async(e,t)=>{let n=e;for(;;){let e=[`Open output`],r=n.executionState??C;r===C&&e.push(`Pause`),r===`paused`&&e.push(`Resume`),n.stage===C&&e.push(`Stop`),e.push(`Back`);let i=await d.openWorkflowChoice(t,{title:`Manage ${n.runKey}`,breadcrumb:`SPC › w / workflows › r / runs`,choices:e});if(!i||i===`Back`)return;if(n=await Q(n),n.stage!==C){t.ui.notify(`${n.runKey} is no longer running.`,`warning`);return}if(i===`Open output`){await Xt(n,t);return}if(i===`Stop`){if(!await t.ui.confirm(`Stop ${n.runKey}?`,`The workflow will be interrupted and will not be restarted automatically.`))continue;if(n=await Q(n),n.stage!==C){t.ui.notify(`${n.runKey} is no longer running.`,`warning`);return}}if(i!==`Pause`&&i!==`Resume`&&i!==`Stop`)continue;if(!n.runId)throw Error(`${n.runKey} has no controllable run generation.`);let a=await wt.execute({action:i.toLowerCase(),expectedRunId:n.runId,...i===`Stop`?{reason:`Stopped from the workflow manager.`}:{},runKey:n.runKey,workspace:n.workspace});if(a.isError)throw Error(f.toolResultText(a)||`Unable to ${i.toLowerCase()} workflow.`);t.ui.notify(f.toolResultText(a)||`${i} requested for ${n.runKey}.`,`info`),await Z(t,!1),n=await Q(n)}},rn=(e,t)=>({editor:(t,n)=>e.ui.editor(t,n),input:(n,r)=>d.openWorkflowInput(e,{title:n,breadcrumb:t,...r?{fallback:r}:{}}),notify:(t,n)=>e.ui.notify(t,n),select:(n,r)=>d.openWorkflowChoice(e,{title:n,breadcrumb:t,choices:r})}),an=async e=>{if(!e.hasUI){e.ui.notify(`The workflow list needs an interactive Pi session.`,`warning`);return}let t=await re.loadWorkflowCatalog(v.listWorkflowsTool,e.cwd),n=new Map(t.map(e=>[e.path,e])),r={compatibleRunners:Ve,launch:(e,t)=>Dt.execute(e,t),parseWorkflow:e=>Je.parseWorkflowFile(e),ui:rn(e,`SPC › w / workflows › l / list`)};await c.openWorkflowCatalogOverlay(e,t.map(e=>({key:e.path,name:e.name,relativePath:e.relativePath,description:e.description,tags:e.tags})),{loadDetail:e=>re.summarizeWorkflowFile(e.key,r),launchWorkflow:t=>{let i=n.get(t.key);i&&re.launchWorkflowEntry(r,i,e).then(t=>{t&&e.ui.notify(f.launchNotice(f.toolResultText(t)),`info`)},t=>{e.ui.notify(t instanceof Error?t.message:String(t),`error`)})}})},on=async e=>{let t=(await He(N)).filter(e=>e.stage===T);if(t.length===0){e.ui.notify(`No failed workflows are available to recover.`,`info`);return}let n=await l.openWorkflowPickerOverlay(e,{title:`WORKFLOW RECOVERY`,breadcrumb:`SPC › w / workflows › c / recover`,unit:`failed runs`,action:`recover`,filterPlaceholder:`type to filter by name, run key or failed job`,emptyMessage:`No failed workflows are available to recover.`},t.map(e=>({key:`${e.workspace}/${e.runKey}`,name:e.displayName,detail:`${e.workspace}/${e.runKey}${e.failedJob?` · ${e.failedJob}`:``}`,...e.failedJob?{search:e.failedJob}:{},value:e})));if(!n)return;let r=await Qt(n);if(r.stage!==T)throw Error(`${r.runKey} is no longer failed.`);let i=(0,p.resolve)((0,p.dirname)((0,ae.fileURLToPath)(require("url").pathToFileURL(__filename).href)),Se,`workflow-recovery`,`SKILL.md`);if(!(0,ie.existsSync)(i))throw Error(`Workflow recovery skill is unavailable at ${i}.`);sn(!0),e.ui.notify(`Workflow tools enabled. The agent will investigate this failure and choose the safe next step.`,`info`),g.sendUserMessage([`Investigate recovery for this failed workflow run. This selection is permission to investigate, not permission to recover blindly.`,`Run identity: ${JSON.stringify({runKey:r.runKey,workspace:r.workspace})}`,`Read the package-owned recovery skill with the read tool at ${JSON.stringify(i)} before acting.`,`Inspect status, every relevant log source, process state, the staged run.json, and only the repair referenced by activeRepairId.`,`Choose exactly one outcome: recover, launch fresh, or defer. Never edit issue.md or repair.json, never scan historical repairs, and never pass recovery dryRun or a job override.`,`Do not recover terminal, approval-pending, blocked, or otherwise unsafe work. If evidence is incomplete, defer and explain what is missing.`,`If recovery is justified, preserve the recorded worktree and repair metadata, then verify real process and registry progress before reporting success.`].join(`
7
- `),{deliverAs:`followUp`})},sn=e=>{if(!j())return;let t=new Set(g.getActiveTools());for(let n of ne.WORKFLOW_PI_TOOL_NAMES)e?t.add(n):t.delete(n);g.setActiveTools([...t]),z=e,Lt(),h.onModeChange?.(e)},cn=()=>z?[`${E.completed} Workflow mode on`,`Ask for workflows in plain language: the agent can list, launch, inspect, pause, resume, stop, and recover runs.`,`${x(y)} stops following a run without stopping it.`].join(`
3
+ `),display:!0,details:{runIds:e.map(e=>e.runId??Y(e)),runs:e.map(e=>({runKey:e.runKey,workspace:e.workspace,stage:e.stage,...e.workflowId?{workflowId:e.workflowId}:{},...e.failedJob?{failedJob:e.failedJob}:{},...e.errorMessage?{error:e.errorMessage}:{}}))}},{triggerTurn:!0,deliverAs:`steer`});for(let t of e){let e=Y(t);nt.add(e),I.delete(e),jt(e)}}catch(e){await n.recordError(`doom_workflow.terminal_delivery_failed`,e,{"workflow.pending_terminal_count":I.size})}tt=m,n.recordEvent(`doom_workflow.monitor_finished`,{duration_ms:Date.now()-i,outcome:`completed`})}catch(t){await n.recordError(`doom_workflow.monitor_failed`,t,{duration_ms:Date.now()-i}),e.ui.notify(`Workflow status refresh failed: ${t instanceof Error?t.message:String(t)}`,`warning`)}finally{$e=!1}},It=e=>{P&&clearInterval(P),P=void 0,F=void 0,e.ui.setWidget(fe,void 0)},Z=new g.WorkflowTerminalService({run:async(e,t,n)=>{let r=await y.exec(e,[...t],{timeout:n.timeoutMs});return{code:r.code,stdout:r.stdout,stderr:r.stderr}},lines:24,timeoutMs:_e}),Lt=e.createWorkflowTerminalService({terminal:Z,now:()=>Date.now(),refreshMs:750}),Rt=new Map,zt=(e,t,n)=>{let r=Y(e),i=`${t}x${n}`;Rt.get(r)!==i&&(Rt.set(r,i),Z.resize(e,t,n))},Bt=e=>Z.targetsCurrentTerminal(e)?Promise.resolve([je]):Lt.screen(Y(e),e,24),Vt=e=>{Lt.forget(e);for(let t of Rt.keys())e.has(t)||Rt.delete(t)},Ht=async e=>{let t=e.launcher;if(!t)return`No durable launcher identity is recorded for this run.`;if(Z.targetsCurrentTerminal(e))return je;if(t.type===`native`)return`This run is hosted natively rather than in a multiplexer, so there is no separate window to bring forward.`;if(t.type===Ae)return await y.exec(Ae,[`select-workspace`,`--workspace`,t.workspaceId],{timeout:_e}),`Opened ${e.runKey} in cmux.`;if(!process.env.TMUX)return`Pi is not attached to tmux. Follow the output instead, or attach to the recorded tmux session manually.`;let n=t.sessionId??t.sessionName,r=await y.exec(ke,[`switch-client`,`-t`,n],{timeout:_e});return r.code===0?(t.paneId&&await y.exec(ke,[`select-pane`,`-t`,t.paneId],{timeout:_e}),`Opened ${e.runKey} in tmux.`):r.stderr.trim()||`Unable to open tmux session ${n}.`},Ut=async(e,t)=>{if(!et){et=!0;try{let n=(0,g.summarizeWorkflowProgress)(Ee(e,await(0,g.readWorkflowProgress)(M.runDirectoryFor(e)))),r=n.length>0?void 0:await Bt(e);t.ui.setWidget(fe,(t,i)=>({render:t=>we(e,r??Te(n,i,t),i,t),invalidate:()=>{}}),{placement:`aboveEditor`})}finally{et=!1}}},Wt=async(e,t)=>{It(t),F=e,await Ut(e,t),P=setInterval(()=>{F&&Ut(F,t)},Qe),P.unref?.()},Gt=async(e,t)=>{Z.capabilities(e).writable&&await Z.write(e,t)},Kt=async(e,t)=>{Pt();let n=Z.capabilities(e).writable,r=new a.TerminalInputBatcher(t=>Gt(e,t)),i=[],o=[],s,c=!1,l=async()=>{i=(0,g.summarizeWorkflowProgress)(Ee(e,await(0,g.readWorkflowProgress)(M.runDirectoryFor(e)))),o=await Bt(e)};await l();let u=()=>{s&&clearInterval(s),s=void 0,r.dispose()},d={interactive:n,runKey:e.runKey,teardown:u};V=d;let f=()=>{Pt(),t.ui.notify(`Closed the ${e.runKey} view. The run keeps going.`,`info`)};return t.ui.custom((a,p,m,te)=>(s=setInterval(()=>{c||(c=!0,l().finally(()=>{c=!1,a.requestRender()}))},200),s.unref?.(),new ee.WorkflowRunPanelComponent(a,p,{runKey:e.runKey,label:`${D.running} ${ze(e)}`,breadcrumb:`SPC › w / workflows › run`,interactive:n,footer:Se(n),hints:Ce(n),snapshot:e=>({progress:Te(i,p,e),output:o}),onViewport:(t,n)=>zt(e,t,n),onUnfollow:()=>{d.handle?.unfocus(),t.ui.notify(`Typing goes to this session. The run keeps going.`,`info`)},onClose:f,sendInput:e=>r.write(e),flushInput:()=>void r.flush(),unfollowShortcut:x,closeShortcut:S,onDispose:()=>{u(),V===d&&(V=void 0),te()}})),{...ee.runPanelUiOptions(n),onHandle:e=>{d.handle=e}}),t.ui.notify(n?`${e.runKey}: typing goes to the run. Press Esc twice to close, ${C(x)} to type here instead.`:`${e.runKey}: view only, because this run is hosted natively. ${C(S)} closes it.`,`info`),n?[`Showing ${e.runKey} over Pi. Typing goes to the run.`,`Pressing Escape twice quickly closes the view, and a single Escape still reaches the run.`,`${C(x)} moves typing between the run and this session,`,`and ${C(S)} closes the view. The run keeps going either way.`].join(` `):[`Showing ${e.runKey} over Pi, as a view only:`,`the run is hosted natively rather than in a multiplexer, so there is no terminal to type into.`,`Typing stays with this session, and ${C(S)} closes the view.`].join(` `)},qt=async(e,t=!1)=>{if(!(st||V||F)){st=!0;try{let n=await e.ui.custom((e,t,n,r)=>new i.WorkflowInspectorComponent(e,t,{list:async()=>{let e=yt(),t=(await k(M)).filter(t=>t.stage===w&&!t.stale&&f.isSessionRun(t,e));return ct=new Map(t.map(e=>[Y(e),e])),Promise.all(t.map(async e=>({displayName:e.displayName,executionState:e.executionState,jobs:(0,g.summarizeWorkflowProgress)(Ee(e,await(0,g.readWorkflowProgress)(M.runDirectoryFor(e)))),key:Y(e),output:[],runKey:e.runKey,startedAt:e.startedAt,workspace:e.workspace})))},output:async e=>{let t=ct.get(e.key);return t?Bt(t):[`Workflow is no longer active.`]}},r),{...de,onHandle:e=>{H=e}});if(n){let r=await Q(n);t?await Qt(r,e):await Kt(r,e)}}finally{H=void 0,st=!1,ct.clear()}}},Q=async(e,t=yt())=>{vt(t);let n=(await k(M,e.workspace)).filter(n=>n.runKey===e.runKey&&f.isSessionRun(n,t));if(n.length>1)throw Error(f.withOptions(`Workflow run key ${JSON.stringify(e.runKey)} exists in more than one workspace in this session.`,[`Retry with the workspace from the run identity.`]));let r=n[0];if(!r)throw Error(f.withOptions(`No workflow run matches ${JSON.stringify(e.runKey)} in this session.`,[`workflow_run with action status: use a run key from this session before retrying.`,`Tell the user this session did not launch that run rather than guessing a similar key. A run launched by another Pi session, or from the command line, is managed there or with the workflow-mcp CLI.`]));return r},Jt=async e=>{let t=(await k(M,e.workspace)).filter(t=>t.runKey===e.runKey&&t.stage===ve);if(t.length>1)throw Error(f.withOptions(`Failed workflow run key ${JSON.stringify(e.runKey)} exists in more than one workspace.`,[`Retry with the workspace from the recovery picker or run identity.`]));let n=t[0];if(!n)throw Error(f.withOptions(`No failed workflow run matches ${JSON.stringify(e.runKey)}.`,[`Use the recovery picker to select an interrupted or failed run, or retry with its workspace.`,`Do not recover a running or completed workflow.`]));return n},Yt=async e=>{let t=M.runDirectoryFor(e),n=[(0,h.resolve)(t,`changelog.md`),(0,h.resolve)(t,`context.md`),(0,h.resolve)(t,`progress.ndjson`)],r=[];for(let e of n)try{let t=await(0,oe.readFile)(e,`utf-8`);r.push(`--- ${(0,h.basename)(e)} ---`,t.slice(-65536).trimEnd())}catch(e){if(e.code!==`ENOENT`)throw e}return r.length>0?r:[`No durable recovery evidence files are recorded for this run.`]},Xt=async(e,t)=>{let n=await Jt(e);return await K(t).recordEvent(`doom_workflow.recovery_evidence_requested`,{outcome:`requested`}),[`Workflow: ${ze(n)}`,`--- run.json ---`,JSON.stringify(n,null,2),...await Yt(n)].join(`
4
+ `)},Zt=async(e,t)=>{let n=Ie();if(!n)return;let r=await Jt(e),i;try{i=Ke.parseWorkflowFile(r.workflowPath)}catch{return}if(!i[`launch-command`])return;let a=(0,_.resolveRootSessionId)(t.sessionManager.getSessionId()),o=await M.claimRunRecovery(r.workspace,r.runKey,a),s=r.originalRepoPath??t.cwd,c=Fe([process.execPath,n,`recover-workflow`,r.runKey,`--workspace`,r.workspace,`--recovery-claim`,o.claimId,...e.runner?[`--runner`,e.runner]:[]]),l=Pe();try{await Xe(process.execPath,[n,`launch-process`,...l?[`--launcher`,l]:[],`--name`,`${r.displayName} recover`,`--cwd`,s,`--command`,c],{cwd:s,env:Ne()})}catch(e){throw await M.releaseRunRecoveryClaim(r.workspace,r.runKey,o.claimId),e}return await K(t).recordEvent(`doom_workflow.recover_delegated`,{launcher:l??`auto`,outcome:`delegated`}),`Recovering ${r.runKey} in a launcher of its own, so this session keeps its terminal. It reports back here when it ends.`},Qt=async(e,t)=>{let n=e;for(;;){let e=[`Open output`],r=n.executionState??w;r===w&&e.push(`Pause`),r===`paused`&&e.push(`Resume`),n.stage===w&&e.push(`Stop`),e.push(`Back`);let i=await u.openWorkflowChoice(t,{title:`Manage ${n.runKey}`,breadcrumb:`SPC › w / workflows › r / runs`,choices:e});if(!i||i===`Back`)return;if(n=await Q(n),n.stage!==w){t.ui.notify(`${n.runKey} is no longer running.`,`warning`);return}if(i===`Open output`){await Kt(n,t);return}if(i===`Stop`){if(!await t.ui.confirm(`Stop ${n.runKey}?`,`The workflow will be interrupted and will not be restarted automatically.`))continue;if(n=await Q(n),n.stage!==w){t.ui.notify(`${n.runKey} is no longer running.`,`warning`);return}}if(i!==`Pause`&&i!==`Resume`&&i!==`Stop`)continue;if(!n.runId)throw Error(`${n.runKey} has no controllable run generation.`);let a=await St.execute({action:i.toLowerCase(),expectedRunId:n.runId,...i===`Stop`?{reason:`Stopped from the workflow manager.`}:{},runKey:n.runKey,workspace:n.workspace});if(a.isError)throw Error(f.toolResultText(a)||`Unable to ${i.toLowerCase()} workflow.`);t.ui.notify(f.toolResultText(a)||`${i} requested for ${n.runKey}.`,`info`),await X(t,!1),n=await Q(n)}},$t=(e,t)=>({editor:(t,n)=>e.ui.editor(t,n),input:(n,r)=>u.openWorkflowInput(e,{title:n,breadcrumb:t,...r?{fallback:r}:{}}),notify:(t,n)=>e.ui.notify(t,n),select:(n,r)=>u.openWorkflowChoice(e,{title:n,breadcrumb:t,choices:r})}),en=async e=>{if(!e.hasUI){e.ui.notify(`The workflow list needs an interactive Pi session.`,`warning`);return}let t=await m.loadWorkflowCatalog(b.listWorkflowsTool,e.cwd),n=new Map(t.map(e=>[e.path,e])),r={compatibleRunners:Re,launch:(e,t)=>Tt.execute(e,t),parseWorkflow:e=>Ke.parseWorkflowFile(e),ui:$t(e,`SPC › w / workflows › l / list`)};await s.openWorkflowCatalogOverlay(e,t.map(e=>({key:e.path,name:e.name,relativePath:e.relativePath,description:e.description,tags:e.tags})),{loadDetail:e=>m.summarizeWorkflowFile(e.key,r),launchWorkflow:t=>{let i=n.get(t.key);i&&m.launchWorkflowEntry(r,i,e).then(t=>{t&&e.ui.notify(f.launchNotice(f.toolResultText(t)),`info`)},t=>{e.ui.notify(t instanceof Error?t.message:String(t),`error`)})}})},tn=async(e,t)=>{let n=te.parseWorkflowLaunchCommand(e);if(te.isLaunchParseFailure(n)){t.ui.notify(n.error,`error`);return}let r=await m.loadWorkflowCatalog(b.listWorkflowsTool,t.cwd),i=te.resolveWorkflowEntry(r,n.workflow);if(!i){t.ui.notify(`No workflow matches '${n.workflow}' under ${t.cwd}.`,`error`);return}let a=m.summarizeWorkflowFile(i.path,{compatibleRunners:Re,parseWorkflow:e=>Ke.parseWorkflowFile(e)});if(a.error!==void 0){t.ui.notify(`${i.name} could not be read: ${a.error}`,`error`);return}let o=te.validateWorkflowLaunch(a,n);if(o.length>0){t.ui.notify(o.join(` `),`error`);return}let s=Ke.parseWorkflowFile(i.path),c={workflowPath:i.path,...n.runner===void 0?{}:{runner:n.runner},...typeof s.workspace==`string`?{workspace:s.workspace}:{},...n.prompt===void 0?{}:{prompt:n.prompt},...Object.keys(n.inputs).length===0?{}:{inputs:n.inputs}},l=await Tt.execute(c,t);t.ui.notify(f.launchNotice(f.toolResultText(l)),`info`)};y.registerCommand(`workflow-launch`,{description:`Launch a workflow: /workflow-launch <workflow> [runner=x] [key=value …] [prompt]`,handler:async(e,t)=>{await j();try{await tn(e,t)}catch(e){t.ui.notify(e instanceof Error?e.message:String(e),`error`)}}});let nn=async e=>{let t=(await k(M)).filter(e=>e.stage===ve);if(t.length===0){e.ui.notify(`No failed workflows are available to recover.`,`info`);return}let n=await c.openWorkflowPickerOverlay(e,{title:`WORKFLOW RECOVERY`,breadcrumb:`SPC › w / workflows › c / recover`,unit:`failed runs`,action:`recover`,filterPlaceholder:`type to filter by name, run key or failed job`,emptyMessage:`No failed workflows are available to recover.`},t.map(e=>({key:`${e.workspace}/${e.runKey}`,name:e.displayName,detail:`${e.workspace}/${e.runKey}${e.failedJob?` · ${e.failedJob}`:``}`,...e.failedJob?{search:e.failedJob}:{},value:e})));if(!n)return;let r=await Jt(n);if(r.stage!==ve)throw Error(`${r.runKey} is no longer failed.`);let i=(0,h.resolve)((0,h.dirname)((0,ie.fileURLToPath)(require("url").pathToFileURL(__filename).href)),xe,`workflow-recovery`,`SKILL.md`);if(!(0,re.existsSync)(i))throw Error(`Workflow recovery skill is unavailable at ${i}.`);rn(!0),e.ui.notify(`Workflow tools enabled. The agent will investigate this failure and choose the safe next step.`,`info`),y.sendUserMessage([`Investigate recovery for this failed workflow run. This selection is permission to investigate, not permission to recover blindly.`,`Run identity: ${JSON.stringify({runKey:r.runKey,workspace:r.workspace})}`,`Read the package-owned recovery skill with the read tool at ${JSON.stringify(i)} before acting.`,`Inspect status, every relevant log source, process state, the staged run.json, and only the repair referenced by activeRepairId.`,`Choose exactly one outcome: recover, launch fresh, or defer. Never edit issue.md or repair.json, never scan historical repairs, and never pass recovery dryRun or a job override.`,`Do not recover terminal, approval-pending, blocked, or otherwise unsafe work. If evidence is incomplete, defer and explain what is missing.`,`If recovery is justified, preserve the recorded worktree and repair metadata, then verify real process and registry progress before reporting success.`].join(`
5
+ `),{deliverAs:`followUp`})},rn=e=>{if(!A())return;let t=new Set(y.getActiveTools());for(let n of p.WORKFLOW_PI_TOOL_NAMES)e?t.add(n):t.delete(n);y.setActiveTools([...t]),R=e,Ft(),v.onModeChange?.(e)},an=()=>R?[`${D.completed} Workflow mode on`,`Ask for workflows in plain language: the agent can list, launch, inspect, pause, resume, stop, and recover runs.`,`${C(x)} stops following a run without stopping it.`].join(`
8
6
  `):[`Workflow mode off`,`Press SPC w e to give the agent its workflow tools. Runs already going are unaffected.`].join(`
9
- `),ln=async(e,t)=>{sn(e),z||Rt(t),t.ui.notify(cn(),`info`),await Z(t,!1)};g.registerShortcut(y,{description:`Open workflows or move typing between a workflow run and this session`,handler:async e=>{await M();let t=H?.handle;if(t){if(!H?.interactive){e.ui.notify(`This run is hosted natively, so the view takes no typing. Your keys stay here.`,`info`);return}t.isFocused()?(t.unfocus(),e.ui.notify(`Typing goes to this session. The run keeps going.`,`info`)):(t.focus(),e.ui.notify(`Typing goes to ${H?.runKey}.`,`info`));return}if(I){Rt(e),e.ui.notify(`Workflow continues in the background.`,`info`);return}await Zt(e)}}),g.registerShortcut(b,{description:`Close the workflow run view`,handler:async e=>{if(await M(),!H)return;let t=H.runKey;It(),e.ui.notify(`Closed the ${t} view. The run keeps going.`,`info`)}}),g.on(`resources_discover`,()=>{if(!z)return{skillPaths:[]};let e=(0,p.resolve)((0,p.dirname)((0,ae.fileURLToPath)(require("url").pathToFileURL(__filename).href)),Se);return{skillPaths:(0,ie.existsSync)(e)?[e]:[]}}),s.registerWorkflowFinishedRenderer(g),g.registerMessageRenderer(`workflow-step`,(e,{outputPad:t},n)=>{let r=te.isWorkflowStepMessageDetails(e.details)?e.details:void 0,i=typeof e.content==`string`?e.content:JSON.stringify(e.content);return te.renderWorkflowStepMessage(r,i,t,n)}),ne.registerWorkflowPiTools(qe,{runTool:Ze,recoverTool:Ct,launchExecutor:Dt,controlTool:wt,requireSessionRun:Q,requireRecoverableRun:Qt,readRecoveryEvidence:en,delegateRecovery:tn,trackPendingRun:Tt,observeSession:bt,activeRunCount:async()=>R,onLaunch:async e=>(await q(e).recordEvent(xe,{outcome:`requested`}),Z(e,!1)),followRun:async(e,t)=>{let n=await Q(e,t.sessionManager.getSessionId());return await q(t).recordEvent(`doom_workflow.follow_started`,{outcome:`started`}),await Jt(n,t),`Following ${Ue(n)}. Press ${x(y)} to stop following; the run keeps going.`},tailRun:async(e,t)=>{let n=await Q(e,t.sessionManager.getSessionId());return await q(t).recordEvent(`doom_workflow.tail_requested`,{outcome:`requested`}),[`Workflow: ${Ue(n)}`,`Stage: ${Oe(n)}`,`Raw launcher output is hidden from chat. Use action follow or open to view it.`].join(`
10
- `)},openRun:async(e,t)=>{let n=await Q(e,t.sessionManager.getSessionId());return await q(t).recordEvent(`doom_workflow.open_requested`,{outcome:`requested`}),t.hasUI?Xt(n,t):Kt(n)},rejectRunner:Et});let un;h.cordis?.inject([oe.DOOM_UI_HUB_SERVICE],t=>{let n=(0,oe.requireDoomUiHub)(t).registerLeaderActions({source:e.PACKAGE_SOURCE,handlers:{[e.LEADER_ENABLE_ACTION]:async e=>(await M(),ln(!0,e)),[e.LEADER_DISABLE_ACTION]:async e=>(await M(),ln(!1,e)),[e.LEADER_MANAGE_ACTION]:async e=>(await M(),Zt(e,!0)),[e.LEADER_CATALOG_ACTION]:async e=>(await M(),an(e)),[e.LEADER_RECOVER_ACTION]:async e=>(await M(),on(e))},onError:(e,t,n)=>{n.ui.notify(e instanceof Error?e.message:String(e),`error`)}});return un=n,()=>{n(),un===n&&(un=void 0)}}),g.on(`session_start`,(t,n)=>{if(!w||!Ae())return;let r=++be,i=D;ke?.abort();let a=new AbortController;ke=a,V=n;let o=()=>w&&r===be&&V===n&&Ae();Ft(),P&&clearInterval(P),P=void 0,ot?.update([]),Rt(n),U?.hide(),U=void 0,lt=!1,ut.clear(),It(),Ut.clear(),mt.setUICtx(n.ui),q(n).recordEvent(`doom_workflow.session_started`,{mode:process.env.WORKFLOW_MCP_MODE===`on`?`on`:`off`,outcome:`started`});let s=n.sessionManager.getSessionId(),c=(0,m.resolveRootSessionId)(s);bt(c),at=Date.now(),st=!1,rt=new Map,L.clear(),it.clear(),sn(h.initialMode??process.env.WORKFLOW_MCP_MODE===`on`);let l=Ge(n);D=(async()=>{if(i&&await Promise.allSettled([i.then(e=>e.wait())]),!o())throw Error(`Workflow session initialization was superseded.`);return l.start(e.PACKAGE_SOURCE,`${ve}:${r}`,async e=>{let t=()=>a.signal.aborted||!o();return e.throwIfAborted(),t()||(await Pt(n),e.throwIfAborted(),t())||(await Z(n,!1),e.throwIfAborted(),t())?{value:void 0}:(st=!0,P=setInterval(()=>{o()&&Z(n,!0)},$e),P.unref?.(),{value:void 0})})})(),Promise.allSettled([D.then(e=>e.wait())])});let $=async(e,t)=>{try{await t()}catch(t){process.emitWarning(`Doom-workflow cleanup could not ${e}: ${String(t)}`)}},dn;return{dispose:(e=V)=>(dn??=(async()=>{if(!w)return;w=!1,be+=1;let t=D;D=void 0,ke?.abort(),ke=void 0,await $(`stop the workflow observer`,Ft);let n=O;if(O=void 0,n?await $(`dispose standalone workflow readiness`,()=>n.dispose()):t&&await Promise.allSettled([t.then(e=>e.wait())]),J.size>0){for(let e of[Xe,Ye])await $(`interrupt an inline workflow`,()=>e.interrupt(`SIGTERM`,{phase:`workflow`,source:`pi-session-shutdown`}));await Promise.race([Promise.allSettled(J),new Promise(e=>setTimeout(e,1e4).unref?.())])}P&&clearInterval(P),P=void 0,Y&&clearTimeout(Y),Y=void 0;let r=ot;ot=void 0,r&&await $(`unregister the background-work provider`,()=>r.dispose()),st=!1,U?.hide(),U=void 0,lt=!1,ut.clear(),Ut.clear(),It(),R=0,e?Rt(e):F&&clearInterval(F),F=void 0,I=void 0,mt.dispose(),z=!1,ct=void 0;let i=B;B=void 0,i&&(await $(`publish the inactive workflow mode`,()=>i.publish(_e(!1,0))),await $(`dispose the workflow mode owner`,()=>i.dispose()));let a=un;un=void 0,a&&await $(`dispose workflow leader actions`,a);let o=J.size,s=gt;gt=void 0,s&&(await $(`record the workflow session finish`,()=>s.recordEvent(`doom_workflow.session_finished`,{"workflow.pending_count":o,outcome:o===0?`completed`:`interrupted`})),await $(`stop workflow telemetry`,()=>s.shutdown())),J.clear(),L.clear(),it.clear(),ft.length=0,ht=void 0,V=void 0})(),dn)}}}exports.compatibleRunners=Ve,exports.installWorkflowPiRuntime=We,exports.panelHint=Ce,exports.panelHints=we,exports.shortcutLabel=x;
7
+ `),on=async(e,t)=>{rn(e),R||It(t),t.ui.notify(an(),`info`),await X(t,!1)};y.registerShortcut(x,{description:`Open workflows or move typing between a workflow run and this session`,handler:async e=>{await j();let t=V?.handle;if(t){if(!V?.interactive){e.ui.notify(`This run is hosted natively, so the view takes no typing. Your keys stay here.`,`info`);return}t.isFocused()?(t.unfocus(),e.ui.notify(`Typing goes to this session. The run keeps going.`,`info`)):(t.focus(),e.ui.notify(`Typing goes to ${V?.runKey}.`,`info`));return}if(F){It(e),e.ui.notify(`Workflow continues in the background.`,`info`);return}await qt(e)}}),y.registerShortcut(S,{description:`Close the workflow run view`,handler:async e=>{if(await j(),!V)return;let t=V.runKey;Pt(),e.ui.notify(`Closed the ${t} view. The run keeps going.`,`info`)}}),y.on(`resources_discover`,()=>{if(!R)return{skillPaths:[]};let e=(0,h.resolve)((0,h.dirname)((0,ie.fileURLToPath)(require("url").pathToFileURL(__filename).href)),xe);return{skillPaths:(0,re.existsSync)(e)?[e]:[]}}),o.registerWorkflowFinishedRenderer(y),y.registerMessageRenderer(`workflow-step`,(e,{outputPad:t},n)=>{let r=d.isWorkflowStepMessageDetails(e.details)?e.details:void 0,i=typeof e.content==`string`?e.content:JSON.stringify(e.content);return d.renderWorkflowStepMessage(r,i,t,n)}),p.registerWorkflowPiTools(Ge,{runTool:Ye,recoverTool:xt,launchExecutor:Tt,controlTool:St,requireSessionRun:Q,requireRecoverableRun:Jt,readRecoveryEvidence:Xt,delegateRecovery:Zt,trackPendingRun:Ct,observeSession:vt,activeRunCount:async()=>L,onLaunch:async e=>(await K(e).recordEvent(be,{outcome:`requested`}),X(e,!1)),followRun:async(e,t)=>{let n=await Q(e,t.sessionManager.getSessionId());return await K(t).recordEvent(`doom_workflow.follow_started`,{outcome:`started`}),await Wt(n,t),`Following ${ze(n)}. Press ${C(x)} to stop following; the run keeps going.`},tailRun:async(e,t)=>{let n=await Q(e,t.sessionManager.getSessionId());return await K(t).recordEvent(`doom_workflow.tail_requested`,{outcome:`requested`}),[`Workflow: ${ze(n)}`,`Stage: ${De(n)}`,`Raw launcher output is hidden from chat. Use action follow or open to view it.`].join(`
8
+ `)},openRun:async(e,t)=>{let n=await Q(e,t.sessionManager.getSessionId());return await K(t).recordEvent(`doom_workflow.open_requested`,{outcome:`requested`}),t.hasUI?Kt(n,t):Ht(n)},rejectRunner:wt});let sn;v.cordis?.inject([ae.DOOM_UI_HUB_SERVICE],e=>{let n=(0,ae.requireDoomUiHub)(e).registerLeaderActions({source:t.PACKAGE_SOURCE,handlers:{[t.LEADER_ENABLE_ACTION]:async e=>(await j(),on(!0,e)),[t.LEADER_DISABLE_ACTION]:async e=>(await j(),on(!1,e)),[t.LEADER_MANAGE_ACTION]:async e=>(await j(),qt(e,!0)),[t.LEADER_CATALOG_ACTION]:async e=>(await j(),en(e)),[t.LEADER_RECOVER_ACTION]:async e=>(await j(),nn(e))},onError:(e,t,n)=>{n.ui.notify(e instanceof Error?e.message:String(e),`error`)}});return sn=n,()=>{n(),sn===n&&(sn=void 0)}}),y.on(`session_start`,(e,n)=>{if(!E||!Ve())return;let r=++ye,i=O;Oe?.abort();let a=new AbortController;Oe=a,B=n;let o=()=>E&&r===ye&&B===n&&Ve();Nt(),N&&clearInterval(N),N=void 0,it?.update([]),It(n),H?.hide(),H=void 0,st=!1,ct.clear(),Pt(),Lt.forget(new Set),ft.setUICtx(n.ui),K(n).recordEvent(`doom_workflow.session_started`,{mode:process.env.WORKFLOW_MCP_MODE===`on`?`on`:`off`,outcome:`started`});let s=n.sessionManager.getSessionId(),c=(0,_.resolveRootSessionId)(s);vt(c),rt=Date.now(),at=!1,tt=new Map,I.clear(),nt.clear(),rn(v.initialMode??process.env.WORKFLOW_MCP_MODE===`on`);let l=Ue(n);O=(async()=>{if(i&&await Promise.allSettled([i.then(e=>e.wait())]),!o())throw Error(`Workflow session initialization was superseded.`);return l.start(t.PACKAGE_SOURCE,`${ge}:${r}`,async e=>{let t=()=>a.signal.aborted||!o();return e.throwIfAborted(),t()||(await Mt(n),e.throwIfAborted(),t())||(await X(n,!1),e.throwIfAborted(),t())?{value:void 0}:(at=!0,N=setInterval(()=>{o()&&X(n,!0)},Ze),N.unref?.(),{value:void 0})})})(),Promise.allSettled([O.then(e=>e.wait())])});let $=async(e,t)=>{try{await t()}catch(t){process.emitWarning(`Doom-workflow cleanup could not ${e}: ${String(t)}`)}},cn;return{dispose:(e=B)=>(cn??=(async()=>{if(!E)return;E=!1,ye+=1;let t=O;O=void 0,Oe?.abort(),Oe=void 0,await $(`stop the workflow observer`,Nt);let n=Be;if(Be=void 0,n?await $(`dispose standalone workflow readiness`,()=>n.dispose()):t&&await Promise.allSettled([t.then(e=>e.wait())]),q.size>0){for(let e of[Je,qe])await $(`interrupt an inline workflow`,()=>e.interrupt(`SIGTERM`,{phase:`workflow`,source:`pi-session-shutdown`}));await Promise.race([Promise.allSettled(q),new Promise(e=>setTimeout(e,1e4).unref?.())])}N&&clearInterval(N),N=void 0,J&&clearTimeout(J),J=void 0;let r=it;it=void 0,r&&await $(`unregister the background-work provider`,()=>r.dispose()),at=!1,H?.hide(),H=void 0,st=!1,ct.clear(),Lt.forget(new Set),Pt(),L=0,e?It(e):P&&clearInterval(P),P=void 0,F=void 0,ft.dispose(),R=!1,ot=void 0;let i=z;z=void 0,i&&(await $(`publish the inactive workflow mode`,()=>i.publish(he(!1,0))),await $(`dispose the workflow mode owner`,()=>i.dispose()));let a=sn;sn=void 0,a&&await $(`dispose workflow leader actions`,a);let o=q.size,s=mt;mt=void 0,s&&(await $(`record the workflow session finish`,()=>s.recordEvent(`doom_workflow.session_finished`,{"workflow.pending_count":o,outcome:o===0?`completed`:`interrupted`})),await $(`stop workflow telemetry`,()=>s.shutdown())),q.clear(),I.clear(),nt.clear(),ut.length=0,pt=void 0,B=void 0})(),cn)}}}exports.compatibleRunners=Re,exports.installWorkflowPiRuntime=Be,exports.panelHint=Se,exports.panelHints=Ce,exports.shortcutLabel=C;
11
9
  //# sourceMappingURL=piExtension.cjs.map