@bastani/atomic 0.8.31-alpha.5 → 0.9.0-alpha.2

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 (1401) hide show
  1. package/CHANGELOG.md +28 -1
  2. package/dist/builtin/cursor/CHANGELOG.md +10 -1
  3. package/dist/builtin/cursor/package.json +2 -2
  4. package/dist/builtin/cursor/src/proto/protobuf-codec-json.ts +44 -0
  5. package/dist/builtin/cursor/src/proto/protobuf-codec-request.ts +271 -0
  6. package/dist/builtin/cursor/src/proto/protobuf-codec-wire.ts +231 -0
  7. package/dist/builtin/cursor/src/proto/protobuf-codec.ts +5 -523
  8. package/dist/builtin/cursor/src/stream.ts +6 -70
  9. package/dist/builtin/cursor/src/transport-errors.ts +74 -0
  10. package/dist/builtin/cursor/src/transport-frame.ts +56 -0
  11. package/dist/builtin/cursor/src/transport-http2.ts +122 -0
  12. package/dist/builtin/cursor/src/transport-native-client.ts +161 -0
  13. package/dist/builtin/cursor/src/transport-run-stream.ts +188 -0
  14. package/dist/builtin/cursor/src/transport-timeouts.ts +87 -0
  15. package/dist/builtin/cursor/src/transport-types.ts +140 -0
  16. package/dist/builtin/cursor/src/transport.ts +24 -790
  17. package/dist/builtin/intercom/CHANGELOG.md +9 -0
  18. package/dist/builtin/intercom/broker/client.ts +0 -35
  19. package/dist/builtin/intercom/contact-supervisor-tool.ts +289 -0
  20. package/dist/builtin/intercom/index-heavy.ts +77 -1336
  21. package/dist/builtin/intercom/intercom-tool.ts +409 -0
  22. package/dist/builtin/intercom/intercom-utils.ts +401 -0
  23. package/dist/builtin/intercom/lifecycle.ts +133 -0
  24. package/dist/builtin/intercom/overlay.ts +96 -0
  25. package/dist/builtin/intercom/package.json +2 -2
  26. package/dist/builtin/intercom/subagent-relay.ts +137 -0
  27. package/dist/builtin/mcp/CHANGELOG.md +9 -0
  28. package/dist/builtin/mcp/config-write-utils.ts +104 -0
  29. package/dist/builtin/mcp/config.ts +4 -180
  30. package/dist/builtin/mcp/mcp-panel-renderer.ts +243 -0
  31. package/dist/builtin/mcp/mcp-panel-state.ts +227 -0
  32. package/dist/builtin/mcp/mcp-panel-types.ts +86 -0
  33. package/dist/builtin/mcp/mcp-panel.ts +145 -579
  34. package/dist/builtin/mcp/mcp-setup-panel.ts +4 -81
  35. package/dist/builtin/mcp/package.json +3 -3
  36. package/dist/builtin/mcp/proxy-auth.ts +61 -0
  37. package/dist/builtin/mcp/proxy-call.ts +373 -0
  38. package/dist/builtin/mcp/proxy-connect.ts +58 -0
  39. package/dist/builtin/mcp/proxy-info-modes.ts +326 -0
  40. package/dist/builtin/mcp/proxy-modes.ts +3 -805
  41. package/dist/builtin/mcp/proxy-types.ts +3 -0
  42. package/dist/builtin/mcp/ui-server-http.ts +81 -0
  43. package/dist/builtin/mcp/ui-server.ts +2 -127
  44. package/dist/builtin/subagents/CHANGELOG.md +9 -0
  45. package/dist/builtin/subagents/package.json +4 -4
  46. package/dist/builtin/subagents/src/agents/agent-discovery.ts +127 -0
  47. package/dist/builtin/subagents/src/agents/agent-loaders.ts +175 -0
  48. package/dist/builtin/subagents/src/agents/agent-management-helpers.ts +310 -0
  49. package/dist/builtin/subagents/src/agents/agent-management.ts +3 -309
  50. package/dist/builtin/subagents/src/agents/agent-overrides.ts +397 -0
  51. package/dist/builtin/subagents/src/agents/agent-paths.ts +88 -0
  52. package/dist/builtin/subagents/src/agents/agent-types.ts +136 -0
  53. package/dist/builtin/subagents/src/agents/agents.ts +22 -895
  54. package/dist/builtin/subagents/src/agents/skills-paths.ts +333 -0
  55. package/dist/builtin/subagents/src/agents/skills.ts +3 -326
  56. package/dist/builtin/subagents/src/extension/index.ts +4 -118
  57. package/dist/builtin/subagents/src/extension/prompt-guidance.ts +13 -0
  58. package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +401 -0
  59. package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +131 -0
  60. package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +213 -0
  61. package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +84 -0
  62. package/dist/builtin/subagents/src/runs/background/async-execution.ts +13 -795
  63. package/dist/builtin/subagents/src/runs/background/subagent-runner-dynamic.ts +215 -0
  64. package/dist/builtin/subagents/src/runs/background/subagent-runner-finalize.ts +136 -0
  65. package/dist/builtin/subagents/src/runs/background/subagent-runner-output.ts +105 -0
  66. package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel-helpers.ts +112 -0
  67. package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel.ts +159 -0
  68. package/dist/builtin/subagents/src/runs/background/subagent-runner-sequential.ts +127 -0
  69. package/dist/builtin/subagents/src/runs/background/subagent-runner-state.ts +427 -0
  70. package/dist/builtin/subagents/src/runs/background/subagent-runner-step.ts +273 -0
  71. package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +269 -0
  72. package/dist/builtin/subagents/src/runs/background/subagent-runner-types.ts +196 -0
  73. package/dist/builtin/subagents/src/runs/background/subagent-runner-utils.ts +70 -0
  74. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +44 -2233
  75. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-behavior.ts +75 -0
  76. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-component.ts +202 -0
  77. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-edit.ts +97 -0
  78. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-editor.ts +160 -0
  79. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-frame.ts +72 -0
  80. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-render-modes.ts +161 -0
  81. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-render-selectors.ts +203 -0
  82. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-selectors.ts +234 -0
  83. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-state.ts +103 -0
  84. package/dist/builtin/subagents/src/runs/foreground/chain-clarify-types.ts +29 -0
  85. package/dist/builtin/subagents/src/runs/foreground/chain-clarify.ts +4 -1328
  86. package/dist/builtin/subagents/src/runs/foreground/chain-execution-clarify.ts +117 -0
  87. package/dist/builtin/subagents/src/runs/foreground/chain-execution-details.ts +35 -0
  88. package/dist/builtin/subagents/src/runs/foreground/chain-execution-dynamic-step.ts +194 -0
  89. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +183 -0
  90. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-step.ts +185 -0
  91. package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +229 -0
  92. package/dist/builtin/subagents/src/runs/foreground/chain-execution-types.ts +194 -0
  93. package/dist/builtin/subagents/src/runs/foreground/chain-execution.ts +94 -1043
  94. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-control.ts +135 -0
  95. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-finalize.ts +107 -0
  96. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-types.ts +17 -0
  97. package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +454 -0
  98. package/dist/builtin/subagents/src/runs/foreground/execution-run-sync.ts +219 -0
  99. package/dist/builtin/subagents/src/runs/foreground/execution-structured-retries.ts +77 -0
  100. package/dist/builtin/subagents/src/runs/foreground/execution-updates.ts +34 -0
  101. package/dist/builtin/subagents/src/runs/foreground/execution-utils.ts +56 -0
  102. package/dist/builtin/subagents/src/runs/foreground/execution.ts +6 -1082
  103. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +207 -0
  104. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-chain.ts +140 -0
  105. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +266 -0
  106. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-input.ts +270 -0
  107. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +157 -0
  108. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +375 -0
  109. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +463 -0
  110. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-runtime.ts +17 -0
  111. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +320 -0
  112. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +207 -0
  113. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +121 -0
  114. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-worktree.ts +113 -0
  115. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +150 -2522
  116. package/dist/builtin/subagents/src/runs/shared/model-fallback.ts +0 -16
  117. package/dist/builtin/subagents/src/runs/shared/nested-events-control.ts +167 -0
  118. package/dist/builtin/subagents/src/runs/shared/nested-events-core.ts +219 -0
  119. package/dist/builtin/subagents/src/runs/shared/nested-events-projection.ts +121 -0
  120. package/dist/builtin/subagents/src/runs/shared/nested-events-registry.ts +289 -0
  121. package/dist/builtin/subagents/src/runs/shared/nested-events-sanitize.ts +201 -0
  122. package/dist/builtin/subagents/src/runs/shared/nested-events.ts +50 -935
  123. package/dist/builtin/subagents/src/runs/shared/worktree.ts +0 -78
  124. package/dist/builtin/subagents/src/shared/types-async.ts +265 -0
  125. package/dist/builtin/subagents/src/shared/types-config.ts +125 -0
  126. package/dist/builtin/subagents/src/shared/types-depth.ts +121 -0
  127. package/dist/builtin/subagents/src/shared/types-output.ts +63 -0
  128. package/dist/builtin/subagents/src/shared/types-results.ts +318 -0
  129. package/dist/builtin/subagents/src/shared/types-runtime.ts +136 -0
  130. package/dist/builtin/subagents/src/shared/types.ts +10 -975
  131. package/dist/builtin/subagents/src/slash/slash-commands.ts +0 -12
  132. package/dist/builtin/subagents/src/tui/render-chain-graph.ts +247 -0
  133. package/dist/builtin/subagents/src/tui/render-event-formatting.ts +259 -0
  134. package/dist/builtin/subagents/src/tui/render-layout.ts +120 -0
  135. package/dist/builtin/subagents/src/tui/render-result-animation.ts +56 -0
  136. package/dist/builtin/subagents/src/tui/render-result-compact.ts +154 -0
  137. package/dist/builtin/subagents/src/tui/render-result.ts +390 -0
  138. package/dist/builtin/subagents/src/tui/render-stable-output.ts +83 -0
  139. package/dist/builtin/subagents/src/tui/render-status-progress.ts +133 -0
  140. package/dist/builtin/subagents/src/tui/render-widget-graph.ts +166 -0
  141. package/dist/builtin/subagents/src/tui/render-widget.ts +273 -0
  142. package/dist/builtin/subagents/src/tui/render.ts +14 -1801
  143. package/dist/builtin/web-access/CHANGELOG.md +9 -0
  144. package/dist/builtin/web-access/content-tools.ts +348 -0
  145. package/dist/builtin/web-access/curator-page-assets/script-1.ts +400 -0
  146. package/dist/builtin/web-access/curator-page-assets/script-2.ts +400 -0
  147. package/dist/builtin/web-access/curator-page-assets/script-3.ts +400 -0
  148. package/dist/builtin/web-access/curator-page-assets/script-4.ts +400 -0
  149. package/dist/builtin/web-access/curator-page-assets/script-5.ts +398 -0
  150. package/dist/builtin/web-access/curator-page-assets/styles-1.ts +394 -0
  151. package/dist/builtin/web-access/curator-page-assets/styles-2.ts +394 -0
  152. package/dist/builtin/web-access/curator-page-assets/styles-3.ts +393 -0
  153. package/dist/builtin/web-access/curator-page.ts +17 -3180
  154. package/dist/builtin/web-access/curator-server-helpers.ts +115 -0
  155. package/dist/builtin/web-access/curator-server.ts +2 -113
  156. package/dist/builtin/web-access/exa-mcp.ts +218 -0
  157. package/dist/builtin/web-access/exa.ts +2 -207
  158. package/dist/builtin/web-access/extract-frames.ts +228 -0
  159. package/dist/builtin/web-access/extract.ts +13 -214
  160. package/dist/builtin/web-access/github-config.ts +156 -0
  161. package/dist/builtin/web-access/github-extract.ts +3 -154
  162. package/dist/builtin/web-access/index-heavy.ts +8 -1904
  163. package/dist/builtin/web-access/package.json +3 -2
  164. package/dist/builtin/web-access/web-search-activity.ts +102 -0
  165. package/dist/builtin/web-access/web-search-browser.ts +116 -0
  166. package/dist/builtin/web-access/web-search-command.ts +242 -0
  167. package/dist/builtin/web-access/web-search-config.ts +163 -0
  168. package/dist/builtin/web-access/web-search-curator.ts +214 -0
  169. package/dist/builtin/web-access/web-search-features.ts +165 -0
  170. package/dist/builtin/web-access/web-search-formatting.ts +117 -0
  171. package/dist/builtin/web-access/web-search-return.ts +136 -0
  172. package/dist/builtin/web-access/web-search-summary.ts +170 -0
  173. package/dist/builtin/web-access/web-search-tool.ts +290 -0
  174. package/dist/builtin/web-access/web-search-types.ts +50 -0
  175. package/dist/builtin/workflows/CHANGELOG.md +16 -1
  176. package/dist/builtin/workflows/README.md +189 -122
  177. package/dist/builtin/workflows/builtin/deep-research-codebase-runner.ts +492 -0
  178. package/dist/builtin/workflows/builtin/deep-research-codebase-utils.ts +346 -0
  179. package/dist/builtin/workflows/builtin/deep-research-codebase.ts +36 -849
  180. package/dist/builtin/workflows/builtin/goal-artifacts.ts +43 -0
  181. package/dist/builtin/workflows/builtin/goal-ledger.ts +54 -0
  182. package/dist/builtin/workflows/builtin/goal-prompts.ts +360 -0
  183. package/dist/builtin/workflows/builtin/goal-reducer.ts +141 -0
  184. package/dist/builtin/workflows/builtin/goal-reports.ts +56 -0
  185. package/dist/builtin/workflows/builtin/goal-review.ts +84 -0
  186. package/dist/builtin/workflows/builtin/goal-runner.ts +336 -0
  187. package/dist/builtin/workflows/builtin/goal-schemas.ts +60 -0
  188. package/dist/builtin/workflows/builtin/goal-types.ts +132 -0
  189. package/dist/builtin/workflows/builtin/goal.ts +40 -1201
  190. package/dist/builtin/workflows/builtin/index.d.ts +1 -0
  191. package/dist/builtin/workflows/builtin/open-claude-design-phases.ts +432 -0
  192. package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +476 -0
  193. package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +312 -0
  194. package/dist/builtin/workflows/builtin/open-claude-design.d.ts +1 -0
  195. package/dist/builtin/workflows/builtin/open-claude-design.ts +47 -1131
  196. package/dist/builtin/workflows/builtin/ralph-core.ts +408 -0
  197. package/dist/builtin/workflows/builtin/ralph-models.ts +123 -0
  198. package/dist/builtin/workflows/builtin/ralph-runner.ts +499 -0
  199. package/dist/builtin/workflows/builtin/ralph.ts +50 -1019
  200. package/dist/builtin/workflows/package.json +2 -2
  201. package/dist/builtin/workflows/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +2 -2
  202. package/dist/builtin/workflows/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs +2 -2
  203. package/dist/builtin/workflows/skills/impeccable/scripts/detector/rules/checks.mjs +2 -2
  204. package/dist/builtin/workflows/skills/impeccable/scripts/detector/shared/page.mjs +8 -1
  205. package/dist/builtin/workflows/skills/impeccable/scripts/live-accept.mjs +13 -15
  206. package/dist/builtin/workflows/skills/impeccable/scripts/live-manual-edit-evidence.mjs +2 -2
  207. package/dist/builtin/workflows/skills/impeccable/scripts/live-server.mjs +9 -0
  208. package/dist/builtin/workflows/src/authoring/typebox-defaults.d.ts +41 -0
  209. package/dist/builtin/workflows/src/authoring/typebox-defaults.ts +217 -0
  210. package/dist/builtin/workflows/src/authoring/workflow.ts +184 -0
  211. package/dist/builtin/workflows/src/authoring.d.ts +14 -66
  212. package/dist/builtin/workflows/src/engine/graph-inference.ts +100 -0
  213. package/dist/builtin/workflows/src/engine/options.ts +40 -0
  214. package/dist/builtin/workflows/src/engine/primitives/chain.ts +29 -0
  215. package/dist/builtin/workflows/src/engine/primitives/exit.ts +2 -0
  216. package/dist/builtin/workflows/src/engine/primitives/parallel.ts +47 -0
  217. package/dist/builtin/workflows/src/engine/primitives/task.ts +108 -0
  218. package/dist/builtin/workflows/src/engine/primitives/ui.ts +41 -0
  219. package/dist/builtin/workflows/src/engine/primitives/workflow.ts +159 -0
  220. package/dist/builtin/workflows/src/engine/replay.ts +8 -0
  221. package/dist/builtin/workflows/src/engine/run.ts +356 -0
  222. package/dist/builtin/workflows/src/engine/runtime.ts +160 -0
  223. package/dist/builtin/workflows/src/extension/atomic-stage-session.ts +186 -0
  224. package/dist/builtin/workflows/src/extension/config-file-loader.ts +152 -0
  225. package/dist/builtin/workflows/src/extension/config-loader.ts +2 -167
  226. package/dist/builtin/workflows/src/extension/discovery-loaders.ts +115 -0
  227. package/dist/builtin/workflows/src/extension/discovery.ts +3 -117
  228. package/dist/builtin/workflows/src/extension/extension-factory.ts +120 -0
  229. package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +109 -0
  230. package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +270 -0
  231. package/dist/builtin/workflows/src/extension/index.ts +42 -4166
  232. package/dist/builtin/workflows/src/extension/public-types.ts +295 -0
  233. package/dist/builtin/workflows/src/extension/render-component.ts +14 -0
  234. package/dist/builtin/workflows/src/extension/runtime-direct.ts +96 -0
  235. package/dist/builtin/workflows/src/extension/runtime.ts +1 -92
  236. package/dist/builtin/workflows/src/extension/ui-surface.ts +286 -0
  237. package/dist/builtin/workflows/src/extension/wiring.ts +6 -475
  238. package/dist/builtin/workflows/src/extension/workflow-command-completions.ts +111 -0
  239. package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +213 -0
  240. package/dist/builtin/workflows/src/extension/workflow-command-surfaces.ts +81 -0
  241. package/dist/builtin/workflows/src/extension/workflow-command-utils.ts +181 -0
  242. package/dist/builtin/workflows/src/extension/workflow-module-loader.ts +9 -3
  243. package/dist/builtin/workflows/src/extension/workflow-policy.ts +15 -0
  244. package/dist/builtin/workflows/src/extension/workflow-ports.ts +41 -0
  245. package/dist/builtin/workflows/src/extension/workflow-prompts.ts +23 -0
  246. package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +286 -0
  247. package/dist/builtin/workflows/src/extension/workflow-schema.ts +1 -19
  248. package/dist/builtin/workflows/src/extension/workflow-stage-results.ts +264 -0
  249. package/dist/builtin/workflows/src/extension/workflow-targets.ts +181 -0
  250. package/dist/builtin/workflows/src/extension/workflow-tool-content.ts +175 -0
  251. package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +205 -0
  252. package/dist/builtin/workflows/src/extension/workflow-tool-helpers.ts +66 -0
  253. package/dist/builtin/workflows/src/extension/workflow-tool-inspection.ts +164 -0
  254. package/dist/builtin/workflows/src/extension/workflow-tool-registration.ts +54 -0
  255. package/dist/builtin/workflows/src/extension/workflow-tool-send.ts +164 -0
  256. package/dist/builtin/workflows/src/extension/workflow-tool.ts +102 -0
  257. package/dist/builtin/workflows/src/index.ts +0 -2
  258. package/dist/builtin/workflows/src/runs/background/runner.ts +6 -3
  259. package/dist/builtin/workflows/src/runs/foreground/executor-abort.ts +431 -0
  260. package/dist/builtin/workflows/src/runs/foreground/executor-child-boundary.ts +232 -0
  261. package/dist/builtin/workflows/src/runs/foreground/executor-child-helpers.ts +74 -0
  262. package/dist/builtin/workflows/src/runs/foreground/executor-child-workflow.ts +1 -0
  263. package/dist/builtin/workflows/src/runs/foreground/executor-continuation.ts +167 -0
  264. package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +450 -0
  265. package/dist/builtin/workflows/src/runs/foreground/executor-direct.ts +233 -0
  266. package/dist/builtin/workflows/src/runs/foreground/executor-exit-manager.ts +195 -0
  267. package/dist/builtin/workflows/src/runs/foreground/executor-hil.ts +368 -0
  268. package/dist/builtin/workflows/src/runs/foreground/executor-inputs.ts +83 -0
  269. package/dist/builtin/workflows/src/runs/foreground/executor-lifecycle.ts +441 -0
  270. package/dist/builtin/workflows/src/runs/foreground/executor-outputs.ts +160 -0
  271. package/dist/builtin/workflows/src/runs/foreground/executor-prompt-nodes.ts +274 -0
  272. package/dist/builtin/workflows/src/runs/foreground/executor-run-finalizers.ts +122 -0
  273. package/dist/builtin/workflows/src/runs/foreground/executor-run.ts +1 -0
  274. package/dist/builtin/workflows/src/runs/foreground/executor-scheduler.ts +204 -0
  275. package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +194 -0
  276. package/dist/builtin/workflows/src/runs/foreground/executor-stage-context.ts +120 -0
  277. package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +126 -0
  278. package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +359 -0
  279. package/dist/builtin/workflows/src/runs/foreground/executor-stage-replay.ts +135 -0
  280. package/dist/builtin/workflows/src/runs/foreground/executor-stage-types.ts +61 -0
  281. package/dist/builtin/workflows/src/runs/foreground/executor-task-context.ts +2 -0
  282. package/dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts +293 -0
  283. package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +109 -0
  284. package/dist/builtin/workflows/src/runs/foreground/executor.ts +19 -5354
  285. package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +219 -0
  286. package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +500 -0
  287. package/dist/builtin/workflows/src/runs/foreground/stage-runner-messages.ts +129 -0
  288. package/dist/builtin/workflows/src/runs/foreground/stage-runner-options.ts +53 -0
  289. package/dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts +146 -0
  290. package/dist/builtin/workflows/src/runs/foreground/stage-runner-session.ts +55 -0
  291. package/dist/builtin/workflows/src/runs/foreground/stage-runner-structured-output.ts +82 -0
  292. package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +141 -0
  293. package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +13 -1355
  294. package/dist/builtin/workflows/src/runs/shared/graph-inference.ts +2 -100
  295. package/dist/builtin/workflows/src/runs/shared/model-fallback-candidates.ts +453 -0
  296. package/dist/builtin/workflows/src/runs/shared/model-fallback-failures.ts +442 -0
  297. package/dist/builtin/workflows/src/runs/shared/model-fallback.ts +2 -836
  298. package/dist/builtin/workflows/src/runs/shared/worktree-diff.ts +165 -0
  299. package/dist/builtin/workflows/src/runs/shared/worktree-git.ts +220 -0
  300. package/dist/builtin/workflows/src/runs/shared/worktree-setup.ts +335 -0
  301. package/dist/builtin/workflows/src/runs/shared/worktree-types.ts +92 -0
  302. package/dist/builtin/workflows/src/runs/shared/worktree.ts +18 -791
  303. package/dist/builtin/workflows/src/sdk-surface.ts +6 -9
  304. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +371 -0
  305. package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +439 -0
  306. package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +206 -0
  307. package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +282 -0
  308. package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +5 -598
  309. package/dist/builtin/workflows/src/shared/persistence-restore-helpers.ts +428 -0
  310. package/dist/builtin/workflows/src/shared/persistence-restore.ts +9 -431
  311. package/dist/builtin/workflows/src/shared/store-factory.ts +16 -0
  312. package/dist/builtin/workflows/src/shared/store-internal.ts +219 -0
  313. package/dist/builtin/workflows/src/shared/store-prompt-methods.ts +219 -0
  314. package/dist/builtin/workflows/src/shared/store-public-types.ts +215 -0
  315. package/dist/builtin/workflows/src/shared/store-run-methods.ts +223 -0
  316. package/dist/builtin/workflows/src/shared/store-stage-methods.ts +305 -0
  317. package/dist/builtin/workflows/src/shared/store.ts +11 -1138
  318. package/dist/builtin/workflows/src/shared/types.ts +25 -8
  319. package/dist/builtin/workflows/src/shared/workflow-authoring-types.d.ts +49 -0
  320. package/dist/builtin/workflows/src/shared/workflow-authoring-types.ts +84 -0
  321. package/dist/builtin/workflows/src/shared/workflow-failures-classifier.ts +266 -0
  322. package/dist/builtin/workflows/src/shared/workflow-failures-contract.ts +75 -0
  323. package/dist/builtin/workflows/src/shared/workflow-failures-decisions.ts +477 -0
  324. package/dist/builtin/workflows/src/shared/workflow-failures-signals.ts +248 -0
  325. package/dist/builtin/workflows/src/shared/workflow-failures.ts +13 -1001
  326. package/dist/builtin/workflows/src/tui/chat-surface.ts +0 -66
  327. package/dist/builtin/workflows/src/tui/graph-view-constants.ts +45 -0
  328. package/dist/builtin/workflows/src/tui/graph-view-graph-render.ts +161 -0
  329. package/dist/builtin/workflows/src/tui/graph-view-input.ts +333 -0
  330. package/dist/builtin/workflows/src/tui/graph-view-render-helpers.ts +336 -0
  331. package/dist/builtin/workflows/src/tui/graph-view-render.ts +194 -0
  332. package/dist/builtin/workflows/src/tui/graph-view-state.ts +306 -0
  333. package/dist/builtin/workflows/src/tui/graph-view-types.ts +70 -0
  334. package/dist/builtin/workflows/src/tui/graph-view.ts +4 -1386
  335. package/dist/builtin/workflows/src/tui/inline-form-editor-text.ts +121 -0
  336. package/dist/builtin/workflows/src/tui/inline-form-editor.ts +11 -223
  337. package/dist/builtin/workflows/src/tui/inputs-picker-editing.ts +151 -0
  338. package/dist/builtin/workflows/src/tui/inputs-picker-input.ts +305 -0
  339. package/dist/builtin/workflows/src/tui/inputs-picker-render.ts +300 -0
  340. package/dist/builtin/workflows/src/tui/inputs-picker-types.ts +190 -0
  341. package/dist/builtin/workflows/src/tui/inputs-picker.ts +19 -997
  342. package/dist/builtin/workflows/src/tui/prompt-card-input.ts +226 -0
  343. package/dist/builtin/workflows/src/tui/prompt-card-render.ts +373 -0
  344. package/dist/builtin/workflows/src/tui/prompt-card-select.ts +116 -0
  345. package/dist/builtin/workflows/src/tui/prompt-card-state.ts +61 -0
  346. package/dist/builtin/workflows/src/tui/prompt-card-text.ts +129 -0
  347. package/dist/builtin/workflows/src/tui/prompt-card.ts +8 -910
  348. package/dist/builtin/workflows/src/tui/stage-chat-view-archive-history.ts +315 -0
  349. package/dist/builtin/workflows/src/tui/stage-chat-view-custom-ui.ts +127 -0
  350. package/dist/builtin/workflows/src/tui/stage-chat-view-footer-status.ts +187 -0
  351. package/dist/builtin/workflows/src/tui/stage-chat-view-input.ts +222 -0
  352. package/dist/builtin/workflows/src/tui/stage-chat-view-render-helpers.ts +152 -0
  353. package/dist/builtin/workflows/src/tui/stage-chat-view-state.ts +464 -0
  354. package/dist/builtin/workflows/src/tui/stage-chat-view-transcript.ts +242 -0
  355. package/dist/builtin/workflows/src/tui/stage-chat-view-types.ts +151 -0
  356. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +141 -1777
  357. package/dist/builtin/workflows/src/tui/workflow-attach-pane-types.ts +85 -0
  358. package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +1 -129
  359. package/dist/builtin/workflows/src/workflows/registry.ts +7 -3
  360. package/dist/config-self-update.d.ts +21 -0
  361. package/dist/config-self-update.d.ts.map +1 -0
  362. package/dist/config-self-update.js +265 -0
  363. package/dist/config-self-update.js.map +1 -0
  364. package/dist/config.d.ts +3 -12
  365. package/dist/config.d.ts.map +1 -1
  366. package/dist/config.js +15 -252
  367. package/dist/config.js.map +1 -1
  368. package/dist/core/agent-session-accessors.d.ts +3 -0
  369. package/dist/core/agent-session-accessors.d.ts.map +1 -0
  370. package/dist/core/agent-session-accessors.js +36 -0
  371. package/dist/core/agent-session-accessors.js.map +1 -0
  372. package/dist/core/agent-session-auto-compaction.d.ts +32 -0
  373. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -0
  374. package/dist/core/agent-session-auto-compaction.js +219 -0
  375. package/dist/core/agent-session-auto-compaction.js.map +1 -0
  376. package/dist/core/agent-session-bash.d.ts +30 -0
  377. package/dist/core/agent-session-bash.d.ts.map +1 -0
  378. package/dist/core/agent-session-bash.js +79 -0
  379. package/dist/core/agent-session-bash.js.map +1 -0
  380. package/dist/core/agent-session-compaction.d.ts +44 -0
  381. package/dist/core/agent-session-compaction.d.ts.map +1 -0
  382. package/dist/core/agent-session-compaction.js +282 -0
  383. package/dist/core/agent-session-compaction.js.map +1 -0
  384. package/dist/core/agent-session-events.d.ts +65 -0
  385. package/dist/core/agent-session-events.d.ts.map +1 -0
  386. package/dist/core/agent-session-events.js +373 -0
  387. package/dist/core/agent-session-events.js.map +1 -0
  388. package/dist/core/agent-session-export.d.ts +42 -0
  389. package/dist/core/agent-session-export.d.ts.map +1 -0
  390. package/dist/core/agent-session-export.js +199 -0
  391. package/dist/core/agent-session-export.js.map +1 -0
  392. package/dist/core/agent-session-extension-bindings.d.ts +37 -0
  393. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -0
  394. package/dist/core/agent-session-extension-bindings.js +231 -0
  395. package/dist/core/agent-session-extension-bindings.js.map +1 -0
  396. package/dist/core/agent-session-message-queue.d.ts +85 -0
  397. package/dist/core/agent-session-message-queue.d.ts.map +1 -0
  398. package/dist/core/agent-session-message-queue.js +264 -0
  399. package/dist/core/agent-session-message-queue.js.map +1 -0
  400. package/dist/core/agent-session-methods.d.ts +300 -0
  401. package/dist/core/agent-session-methods.d.ts.map +1 -0
  402. package/dist/core/agent-session-methods.js +2 -0
  403. package/dist/core/agent-session-methods.js.map +1 -0
  404. package/dist/core/agent-session-models.d.ts +111 -0
  405. package/dist/core/agent-session-models.d.ts.map +1 -0
  406. package/dist/core/agent-session-models.js +368 -0
  407. package/dist/core/agent-session-models.js.map +1 -0
  408. package/dist/core/agent-session-prompt.d.ts +61 -0
  409. package/dist/core/agent-session-prompt.d.ts.map +1 -0
  410. package/dist/core/agent-session-prompt.js +330 -0
  411. package/dist/core/agent-session-prompt.js.map +1 -0
  412. package/dist/core/agent-session-retry.d.ts +62 -0
  413. package/dist/core/agent-session-retry.d.ts.map +1 -0
  414. package/dist/core/agent-session-retry.js +202 -0
  415. package/dist/core/agent-session-retry.js.map +1 -0
  416. package/dist/core/agent-session-services.d.ts +0 -1
  417. package/dist/core/agent-session-services.d.ts.map +1 -1
  418. package/dist/core/agent-session-services.js +0 -1
  419. package/dist/core/agent-session-services.js.map +1 -1
  420. package/dist/core/agent-session-skill-block.d.ts +13 -0
  421. package/dist/core/agent-session-skill-block.d.ts.map +1 -0
  422. package/dist/core/agent-session-skill-block.js +37 -0
  423. package/dist/core/agent-session-skill-block.js.map +1 -0
  424. package/dist/core/agent-session-state.d.ts +48 -0
  425. package/dist/core/agent-session-state.d.ts.map +1 -0
  426. package/dist/core/agent-session-state.js +129 -0
  427. package/dist/core/agent-session-state.js.map +1 -0
  428. package/dist/core/agent-session-tool-hooks.d.ts +7 -0
  429. package/dist/core/agent-session-tool-hooks.d.ts.map +1 -0
  430. package/dist/core/agent-session-tool-hooks.js +72 -0
  431. package/dist/core/agent-session-tool-hooks.js.map +1 -0
  432. package/dist/core/agent-session-tool-registry.d.ts +15 -0
  433. package/dist/core/agent-session-tool-registry.d.ts.map +1 -0
  434. package/dist/core/agent-session-tool-registry.js +149 -0
  435. package/dist/core/agent-session-tool-registry.js.map +1 -0
  436. package/dist/core/agent-session-tree.d.ts +46 -0
  437. package/dist/core/agent-session-tree.d.ts.map +1 -0
  438. package/dist/core/agent-session-tree.js +217 -0
  439. package/dist/core/agent-session-tree.js.map +1 -0
  440. package/dist/core/agent-session-types.d.ts +157 -0
  441. package/dist/core/agent-session-types.d.ts.map +1 -0
  442. package/dist/core/agent-session-types.js +41 -0
  443. package/dist/core/agent-session-types.js.map +1 -0
  444. package/dist/core/agent-session.d.ts +66 -688
  445. package/dist/core/agent-session.d.ts.map +1 -1
  446. package/dist/core/agent-session.js +26 -3153
  447. package/dist/core/agent-session.js.map +1 -1
  448. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  449. package/dist/core/atomic-guide-command.js +1 -1
  450. package/dist/core/atomic-guide-command.js.map +1 -1
  451. package/dist/core/auth-storage-backends.d.ts +49 -0
  452. package/dist/core/auth-storage-backends.d.ts.map +1 -0
  453. package/dist/core/auth-storage-backends.js +185 -0
  454. package/dist/core/auth-storage-backends.js.map +1 -0
  455. package/dist/core/auth-storage.d.ts +2 -49
  456. package/dist/core/auth-storage.d.ts.map +1 -1
  457. package/dist/core/auth-storage.js +3 -183
  458. package/dist/core/auth-storage.js.map +1 -1
  459. package/dist/core/compaction/context-compaction-metrics.d.ts +16 -0
  460. package/dist/core/compaction/context-compaction-metrics.d.ts.map +1 -0
  461. package/dist/core/compaction/context-compaction-metrics.js +58 -0
  462. package/dist/core/compaction/context-compaction-metrics.js.map +1 -0
  463. package/dist/core/compaction/context-compaction-prompt.d.ts +9 -0
  464. package/dist/core/compaction/context-compaction-prompt.d.ts.map +1 -0
  465. package/dist/core/compaction/context-compaction-prompt.js +161 -0
  466. package/dist/core/compaction/context-compaction-prompt.js.map +1 -0
  467. package/dist/core/compaction/context-compaction-runner.d.ts +5 -0
  468. package/dist/core/compaction/context-compaction-runner.d.ts.map +1 -0
  469. package/dist/core/compaction/context-compaction-runner.js +181 -0
  470. package/dist/core/compaction/context-compaction-runner.js.map +1 -0
  471. package/dist/core/compaction/context-compaction-strategy.d.ts +5 -0
  472. package/dist/core/compaction/context-compaction-strategy.d.ts.map +1 -0
  473. package/dist/core/compaction/context-compaction-strategy.js +27 -0
  474. package/dist/core/compaction/context-compaction-strategy.js.map +1 -0
  475. package/dist/core/compaction/context-compaction-types.d.ts +73 -0
  476. package/dist/core/compaction/context-compaction-types.d.ts.map +1 -0
  477. package/dist/core/compaction/context-compaction-types.js +6 -0
  478. package/dist/core/compaction/context-compaction-types.js.map +1 -0
  479. package/dist/core/compaction/context-compaction.d.ts +9 -200
  480. package/dist/core/compaction/context-compaction.d.ts.map +1 -1
  481. package/dist/core/compaction/context-compaction.js +7 -1943
  482. package/dist/core/compaction/context-compaction.js.map +1 -1
  483. package/dist/core/compaction/context-deletion-application.d.ts +13 -0
  484. package/dist/core/compaction/context-deletion-application.d.ts.map +1 -0
  485. package/dist/core/compaction/context-deletion-application.js +259 -0
  486. package/dist/core/compaction/context-deletion-application.js.map +1 -0
  487. package/dist/core/compaction/context-deletion-store.d.ts +78 -0
  488. package/dist/core/compaction/context-deletion-store.d.ts.map +1 -0
  489. package/dist/core/compaction/context-deletion-store.js +162 -0
  490. package/dist/core/compaction/context-deletion-store.js.map +1 -0
  491. package/dist/core/compaction/context-deletion-targets.d.ts +40 -0
  492. package/dist/core/compaction/context-deletion-targets.d.ts.map +1 -0
  493. package/dist/core/compaction/context-deletion-targets.js +267 -0
  494. package/dist/core/compaction/context-deletion-targets.js.map +1 -0
  495. package/dist/core/compaction/context-deletion-tool-definitions.d.ts +187 -0
  496. package/dist/core/compaction/context-deletion-tool-definitions.d.ts.map +1 -0
  497. package/dist/core/compaction/context-deletion-tool-definitions.js +98 -0
  498. package/dist/core/compaction/context-deletion-tool-definitions.js.map +1 -0
  499. package/dist/core/compaction/context-deletion-tool-helpers.d.ts +19 -0
  500. package/dist/core/compaction/context-deletion-tool-helpers.d.ts.map +1 -0
  501. package/dist/core/compaction/context-deletion-tool-helpers.js +137 -0
  502. package/dist/core/compaction/context-deletion-tool-helpers.js.map +1 -0
  503. package/dist/core/compaction/context-deletion-tools.d.ts +4 -0
  504. package/dist/core/compaction/context-deletion-tools.d.ts.map +1 -0
  505. package/dist/core/compaction/context-deletion-tools.js +395 -0
  506. package/dist/core/compaction/context-deletion-tools.js.map +1 -0
  507. package/dist/core/compaction/context-transcript-analysis.d.ts +9 -0
  508. package/dist/core/compaction/context-transcript-analysis.d.ts.map +1 -0
  509. package/dist/core/compaction/context-transcript-analysis.js +234 -0
  510. package/dist/core/compaction/context-transcript-analysis.js.map +1 -0
  511. package/dist/core/export-html/index.d.ts.map +1 -1
  512. package/dist/core/export-html/index.js +2 -1
  513. package/dist/core/export-html/index.js.map +1 -1
  514. package/dist/core/export-html/template-js/data-tree.js +287 -0
  515. package/dist/core/export-html/template-js/entries-navigation.js +424 -0
  516. package/dist/core/export-html/template-js/initialization.js +312 -0
  517. package/dist/core/export-html/template-js/message-tools.js +415 -0
  518. package/dist/core/export-html/template-js/tree-filter-render.js +421 -0
  519. package/dist/core/export-html/template-script.d.ts +3 -0
  520. package/dist/core/export-html/template-script.d.ts.map +1 -0
  521. package/dist/core/export-html/template-script.js +13 -0
  522. package/dist/core/export-html/template-script.js.map +1 -0
  523. package/dist/core/export-html/template.js +3 -1
  524. package/dist/core/extensions/agent-events.d.ts +159 -0
  525. package/dist/core/extensions/agent-events.d.ts.map +1 -0
  526. package/dist/core/extensions/agent-events.js +2 -0
  527. package/dist/core/extensions/agent-events.js.map +1 -0
  528. package/dist/core/extensions/api-types.d.ts +189 -0
  529. package/dist/core/extensions/api-types.d.ts.map +1 -0
  530. package/dist/core/extensions/api-types.js +2 -0
  531. package/dist/core/extensions/api-types.js.map +1 -0
  532. package/dist/core/extensions/command-types.d.ts +14 -0
  533. package/dist/core/extensions/command-types.d.ts.map +1 -0
  534. package/dist/core/extensions/command-types.js +2 -0
  535. package/dist/core/extensions/command-types.js.map +1 -0
  536. package/dist/core/extensions/context-types.d.ts +130 -0
  537. package/dist/core/extensions/context-types.d.ts.map +1 -0
  538. package/dist/core/extensions/context-types.js +2 -0
  539. package/dist/core/extensions/context-types.js.map +1 -0
  540. package/dist/core/extensions/event-results.d.ts +61 -0
  541. package/dist/core/extensions/event-results.d.ts.map +1 -0
  542. package/dist/core/extensions/event-results.js +2 -0
  543. package/dist/core/extensions/event-results.js.map +1 -0
  544. package/dist/core/extensions/event-types.d.ts +6 -0
  545. package/dist/core/extensions/event-types.d.ts.map +1 -0
  546. package/dist/core/extensions/event-types.js +2 -0
  547. package/dist/core/extensions/event-types.js.map +1 -0
  548. package/dist/core/extensions/loader-api.d.ts +10 -0
  549. package/dist/core/extensions/loader-api.d.ts.map +1 -0
  550. package/dist/core/extensions/loader-api.js +143 -0
  551. package/dist/core/extensions/loader-api.js.map +1 -0
  552. package/dist/core/extensions/loader-core.d.ts +10 -0
  553. package/dist/core/extensions/loader-core.d.ts.map +1 -0
  554. package/dist/core/extensions/loader-core.js +98 -0
  555. package/dist/core/extensions/loader-core.js.map +1 -0
  556. package/dist/core/extensions/loader-discovery.d.ts +7 -0
  557. package/dist/core/extensions/loader-discovery.d.ts.map +1 -0
  558. package/dist/core/extensions/loader-discovery.js +139 -0
  559. package/dist/core/extensions/loader-discovery.js.map +1 -0
  560. package/dist/core/extensions/loader-resources.d.ts +11 -0
  561. package/dist/core/extensions/loader-resources.d.ts.map +1 -0
  562. package/dist/core/extensions/loader-resources.js +10 -0
  563. package/dist/core/extensions/loader-resources.js.map +1 -0
  564. package/dist/core/extensions/loader-runtime.d.ts +7 -0
  565. package/dist/core/extensions/loader-runtime.d.ts.map +1 -0
  566. package/dist/core/extensions/loader-runtime.js +51 -0
  567. package/dist/core/extensions/loader-runtime.js.map +1 -0
  568. package/dist/core/extensions/loader-virtual-modules.d.ts +9 -0
  569. package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -0
  570. package/dist/core/extensions/loader-virtual-modules.js +124 -0
  571. package/dist/core/extensions/loader-virtual-modules.js.map +1 -0
  572. package/dist/core/extensions/loader.d.ts +5 -28
  573. package/dist/core/extensions/loader.d.ts.map +1 -1
  574. package/dist/core/extensions/loader.js +4 -542
  575. package/dist/core/extensions/loader.js.map +1 -1
  576. package/dist/core/extensions/message-types.d.ts +34 -0
  577. package/dist/core/extensions/message-types.d.ts.map +1 -0
  578. package/dist/core/extensions/message-types.js +2 -0
  579. package/dist/core/extensions/message-types.js.map +1 -0
  580. package/dist/core/extensions/provider-types.d.ts +71 -0
  581. package/dist/core/extensions/provider-types.d.ts.map +1 -0
  582. package/dist/core/extensions/provider-types.js +2 -0
  583. package/dist/core/extensions/provider-types.js.map +1 -0
  584. package/dist/core/extensions/runner-context.d.ts +42 -0
  585. package/dist/core/extensions/runner-context.d.ts.map +1 -0
  586. package/dist/core/extensions/runner-context.js +112 -0
  587. package/dist/core/extensions/runner-context.js.map +1 -0
  588. package/dist/core/extensions/runner-events.d.ts +47 -0
  589. package/dist/core/extensions/runner-events.d.ts.map +1 -0
  590. package/dist/core/extensions/runner-events.js +280 -0
  591. package/dist/core/extensions/runner-events.js.map +1 -0
  592. package/dist/core/extensions/runner-handlers.d.ts +32 -0
  593. package/dist/core/extensions/runner-handlers.d.ts.map +1 -0
  594. package/dist/core/extensions/runner-handlers.js +2 -0
  595. package/dist/core/extensions/runner-handlers.js.map +1 -0
  596. package/dist/core/extensions/runner-project-trust.d.ts +6 -0
  597. package/dist/core/extensions/runner-project-trust.d.ts.map +1 -0
  598. package/dist/core/extensions/runner-project-trust.js +27 -0
  599. package/dist/core/extensions/runner-project-trust.js.map +1 -0
  600. package/dist/core/extensions/runner-registries.d.ts +8 -0
  601. package/dist/core/extensions/runner-registries.d.ts.map +1 -0
  602. package/dist/core/extensions/runner-registries.js +76 -0
  603. package/dist/core/extensions/runner-registries.js.map +1 -0
  604. package/dist/core/extensions/runner-shortcuts.d.ts +10 -0
  605. package/dist/core/extensions/runner-shortcuts.d.ts.map +1 -0
  606. package/dist/core/extensions/runner-shortcuts.js +71 -0
  607. package/dist/core/extensions/runner-shortcuts.js.map +1 -0
  608. package/dist/core/extensions/runner-ui.d.ts +3 -0
  609. package/dist/core/extensions/runner-ui.d.ts.map +1 -0
  610. package/dist/core/extensions/runner-ui.js +50 -0
  611. package/dist/core/extensions/runner-ui.js.map +1 -0
  612. package/dist/core/extensions/runner.d.ts +7 -74
  613. package/dist/core/extensions/runner.d.ts.map +1 -1
  614. package/dist/core/extensions/runner.js +67 -673
  615. package/dist/core/extensions/runner.js.map +1 -1
  616. package/dist/core/extensions/runtime-types.d.ts +179 -0
  617. package/dist/core/extensions/runtime-types.d.ts.map +1 -0
  618. package/dist/core/extensions/runtime-types.js +2 -0
  619. package/dist/core/extensions/runtime-types.js.map +1 -0
  620. package/dist/core/extensions/session-events.d.ts +89 -0
  621. package/dist/core/extensions/session-events.d.ts.map +1 -0
  622. package/dist/core/extensions/session-events.js +2 -0
  623. package/dist/core/extensions/session-events.js.map +1 -0
  624. package/dist/core/extensions/tool-events.d.ts +127 -0
  625. package/dist/core/extensions/tool-events.d.ts.map +1 -0
  626. package/dist/core/extensions/tool-events.js +26 -0
  627. package/dist/core/extensions/tool-events.js.map +1 -0
  628. package/dist/core/extensions/tool-types.d.ts +100 -0
  629. package/dist/core/extensions/tool-types.d.ts.map +1 -0
  630. package/dist/core/extensions/tool-types.js +11 -0
  631. package/dist/core/extensions/tool-types.js.map +1 -0
  632. package/dist/core/extensions/types.d.ts +20 -1288
  633. package/dist/core/extensions/types.d.ts.map +1 -1
  634. package/dist/core/extensions/types.js +4 -34
  635. package/dist/core/extensions/types.js.map +1 -1
  636. package/dist/core/extensions/ui-types.d.ts +200 -0
  637. package/dist/core/extensions/ui-types.d.ts.map +1 -0
  638. package/dist/core/extensions/ui-types.js +2 -0
  639. package/dist/core/extensions/ui-types.js.map +1 -0
  640. package/dist/core/index.d.ts +0 -1
  641. package/dist/core/index.d.ts.map +1 -1
  642. package/dist/core/index.js +0 -1
  643. package/dist/core/index.js.map +1 -1
  644. package/dist/core/model-registry-auth.d.ts +7 -0
  645. package/dist/core/model-registry-auth.d.ts.map +1 -0
  646. package/dist/core/model-registry-auth.js +64 -0
  647. package/dist/core/model-registry-auth.js.map +1 -0
  648. package/dist/core/model-registry-builtins.d.ts +9 -0
  649. package/dist/core/model-registry-builtins.d.ts.map +1 -0
  650. package/dist/core/model-registry-builtins.js +126 -0
  651. package/dist/core/model-registry-builtins.js.map +1 -0
  652. package/dist/core/model-registry-custom-loader.d.ts +3 -0
  653. package/dist/core/model-registry-custom-loader.d.ts.map +1 -0
  654. package/dist/core/model-registry-custom-loader.js +213 -0
  655. package/dist/core/model-registry-custom-loader.js.map +1 -0
  656. package/dist/core/model-registry-dynamic.d.ts +6 -0
  657. package/dist/core/model-registry-dynamic.d.ts.map +1 -0
  658. package/dist/core/model-registry-dynamic.js +155 -0
  659. package/dist/core/model-registry-dynamic.js.map +1 -0
  660. package/dist/core/model-registry-loader.d.ts +4 -0
  661. package/dist/core/model-registry-loader.d.ts.map +1 -0
  662. package/dist/core/model-registry-loader.js +20 -0
  663. package/dist/core/model-registry-loader.js.map +1 -0
  664. package/dist/core/model-registry-schemas.d.ts +1136 -0
  665. package/dist/core/model-registry-schemas.d.ts.map +1 -0
  666. package/dist/core/model-registry-schemas.js +171 -0
  667. package/dist/core/model-registry-schemas.js.map +1 -0
  668. package/dist/core/model-registry-types.d.ts +74 -0
  669. package/dist/core/model-registry-types.d.ts.map +1 -0
  670. package/dist/core/model-registry-types.js +2 -0
  671. package/dist/core/model-registry-types.js.map +1 -0
  672. package/dist/core/model-registry.d.ts +3 -76
  673. package/dist/core/model-registry.d.ts.map +1 -1
  674. package/dist/core/model-registry.js +24 -733
  675. package/dist/core/model-registry.js.map +1 -1
  676. package/dist/core/model-resolver-cli.d.ts +19 -0
  677. package/dist/core/model-resolver-cli.d.ts.map +1 -0
  678. package/dist/core/model-resolver-cli.js +118 -0
  679. package/dist/core/model-resolver-cli.js.map +1 -0
  680. package/dist/core/model-resolver-defaults.d.ts +5 -0
  681. package/dist/core/model-resolver-defaults.d.ts.map +1 -0
  682. package/dist/core/model-resolver-defaults.js +47 -0
  683. package/dist/core/model-resolver-defaults.js.map +1 -0
  684. package/dist/core/model-resolver-initial.d.ts +31 -0
  685. package/dist/core/model-resolver-initial.d.ts.map +1 -0
  686. package/dist/core/model-resolver-initial.js +116 -0
  687. package/dist/core/model-resolver-initial.js.map +1 -0
  688. package/dist/core/model-resolver-patterns.d.ts +26 -0
  689. package/dist/core/model-resolver-patterns.d.ts.map +1 -0
  690. package/dist/core/model-resolver-patterns.js +139 -0
  691. package/dist/core/model-resolver-patterns.js.map +1 -0
  692. package/dist/core/model-resolver-scope.d.ts +15 -0
  693. package/dist/core/model-resolver-scope.d.ts.map +1 -0
  694. package/dist/core/model-resolver-scope.js +66 -0
  695. package/dist/core/model-resolver-scope.js.map +1 -0
  696. package/dist/core/model-resolver-types.d.ts +29 -0
  697. package/dist/core/model-resolver-types.d.ts.map +1 -0
  698. package/dist/core/model-resolver-types.js +2 -0
  699. package/dist/core/model-resolver-types.js.map +1 -0
  700. package/dist/core/model-resolver.d.ts +6 -107
  701. package/dist/core/model-resolver.d.ts.map +1 -1
  702. package/dist/core/model-resolver.js +5 -549
  703. package/dist/core/model-resolver.js.map +1 -1
  704. package/dist/core/package-manager-auto-resources.d.ts +5 -0
  705. package/dist/core/package-manager-auto-resources.d.ts.map +1 -0
  706. package/dist/core/package-manager-auto-resources.js +109 -0
  707. package/dist/core/package-manager-auto-resources.js.map +1 -0
  708. package/dist/core/package-manager-command.d.ts +11 -0
  709. package/dist/core/package-manager-command.d.ts.map +1 -0
  710. package/dist/core/package-manager-command.js +102 -0
  711. package/dist/core/package-manager-command.js.map +1 -0
  712. package/dist/core/package-manager-constants.d.ts +4 -0
  713. package/dist/core/package-manager-constants.d.ts.map +1 -0
  714. package/dist/core/package-manager-constants.js +4 -0
  715. package/dist/core/package-manager-constants.js.map +1 -0
  716. package/dist/core/package-manager-env.d.ts +4 -0
  717. package/dist/core/package-manager-env.d.ts.map +1 -0
  718. package/dist/core/package-manager-env.js +40 -0
  719. package/dist/core/package-manager-env.js.map +1 -0
  720. package/dist/core/package-manager-git.d.ts +10 -0
  721. package/dist/core/package-manager-git.d.ts.map +1 -0
  722. package/dist/core/package-manager-git.js +271 -0
  723. package/dist/core/package-manager-git.js.map +1 -0
  724. package/dist/core/package-manager-manifest.d.ts +7 -0
  725. package/dist/core/package-manager-manifest.d.ts.map +1 -0
  726. package/dist/core/package-manager-manifest.js +45 -0
  727. package/dist/core/package-manager-manifest.js.map +1 -0
  728. package/dist/core/package-manager-npm.d.ts +25 -0
  729. package/dist/core/package-manager-npm.d.ts.map +1 -0
  730. package/dist/core/package-manager-npm.js +252 -0
  731. package/dist/core/package-manager-npm.js.map +1 -0
  732. package/dist/core/package-manager-operations.d.ts +11 -0
  733. package/dist/core/package-manager-operations.d.ts.map +1 -0
  734. package/dist/core/package-manager-operations.js +196 -0
  735. package/dist/core/package-manager-operations.js.map +1 -0
  736. package/dist/core/package-manager-paths.d.ts +14 -0
  737. package/dist/core/package-manager-paths.d.ts.map +1 -0
  738. package/dist/core/package-manager-paths.js +61 -0
  739. package/dist/core/package-manager-paths.js.map +1 -0
  740. package/dist/core/package-manager-progress.d.ts +4 -0
  741. package/dist/core/package-manager-progress.d.ts.map +1 -0
  742. package/dist/core/package-manager-progress.js +16 -0
  743. package/dist/core/package-manager-progress.js.map +1 -0
  744. package/dist/core/package-manager-resolver.d.ts +5 -0
  745. package/dist/core/package-manager-resolver.d.ts.map +1 -0
  746. package/dist/core/package-manager-resolver.js +149 -0
  747. package/dist/core/package-manager-resolver.js.map +1 -0
  748. package/dist/core/package-manager-resource-accumulator.d.ts +6 -0
  749. package/dist/core/package-manager-resource-accumulator.d.ts.map +1 -0
  750. package/dist/core/package-manager-resource-accumulator.js +67 -0
  751. package/dist/core/package-manager-resource-accumulator.js.map +1 -0
  752. package/dist/core/package-manager-resource-collector.d.ts +5 -0
  753. package/dist/core/package-manager-resource-collector.d.ts.map +1 -0
  754. package/dist/core/package-manager-resource-collector.js +148 -0
  755. package/dist/core/package-manager-resource-collector.js.map +1 -0
  756. package/dist/core/package-manager-resource-files.d.ts +14 -0
  757. package/dist/core/package-manager-resource-files.d.ts.map +1 -0
  758. package/dist/core/package-manager-resource-files.js +265 -0
  759. package/dist/core/package-manager-resource-files.js.map +1 -0
  760. package/dist/core/package-manager-resource-patterns.d.ts +12 -0
  761. package/dist/core/package-manager-resource-patterns.d.ts.map +1 -0
  762. package/dist/core/package-manager-resource-patterns.js +136 -0
  763. package/dist/core/package-manager-resource-patterns.js.map +1 -0
  764. package/dist/core/package-manager-settings.d.ts +10 -0
  765. package/dist/core/package-manager-settings.d.ts.map +1 -0
  766. package/dist/core/package-manager-settings.js +91 -0
  767. package/dist/core/package-manager-settings.js.map +1 -0
  768. package/dist/core/package-manager-source.d.ts +21 -0
  769. package/dist/core/package-manager-source.d.ts.map +1 -0
  770. package/dist/core/package-manager-source.js +146 -0
  771. package/dist/core/package-manager-source.js.map +1 -0
  772. package/dist/core/package-manager-types.d.ts +169 -0
  773. package/dist/core/package-manager-types.d.ts.map +1 -0
  774. package/dist/core/package-manager-types.js +9 -0
  775. package/dist/core/package-manager-types.js.map +1 -0
  776. package/dist/core/package-manager.d.ts +9 -174
  777. package/dist/core/package-manager.d.ts.map +1 -1
  778. package/dist/core/package-manager.js +56 -2100
  779. package/dist/core/package-manager.js.map +1 -1
  780. package/dist/core/resource-loader-assets.d.ts +6 -0
  781. package/dist/core/resource-loader-assets.d.ts.map +1 -0
  782. package/dist/core/resource-loader-assets.js +209 -0
  783. package/dist/core/resource-loader-assets.js.map +1 -0
  784. package/dist/core/resource-loader-context-files.d.ts +10 -0
  785. package/dist/core/resource-loader-context-files.d.ts.map +1 -0
  786. package/dist/core/resource-loader-context-files.js +74 -0
  787. package/dist/core/resource-loader-context-files.js.map +1 -0
  788. package/dist/core/resource-loader-core.d.ts +83 -0
  789. package/dist/core/resource-loader-core.d.ts.map +1 -0
  790. package/dist/core/resource-loader-core.js +170 -0
  791. package/dist/core/resource-loader-core.js.map +1 -0
  792. package/dist/core/resource-loader-discovery.d.ts +4 -0
  793. package/dist/core/resource-loader-discovery.d.ts.map +1 -0
  794. package/dist/core/resource-loader-discovery.js +28 -0
  795. package/dist/core/resource-loader-discovery.js.map +1 -0
  796. package/dist/core/resource-loader-extensions.d.ts +13 -0
  797. package/dist/core/resource-loader-extensions.d.ts.map +1 -0
  798. package/dist/core/resource-loader-extensions.js +110 -0
  799. package/dist/core/resource-loader-extensions.js.map +1 -0
  800. package/dist/core/resource-loader-helpers.d.ts +4 -0
  801. package/dist/core/resource-loader-helpers.d.ts.map +1 -0
  802. package/dist/core/resource-loader-helpers.js +23 -0
  803. package/dist/core/resource-loader-helpers.js.map +1 -0
  804. package/dist/core/resource-loader-internals.d.ts +97 -0
  805. package/dist/core/resource-loader-internals.d.ts.map +1 -0
  806. package/dist/core/resource-loader-internals.js +4 -0
  807. package/dist/core/resource-loader-internals.js.map +1 -0
  808. package/dist/core/resource-loader-package-resources.d.ts +31 -0
  809. package/dist/core/resource-loader-package-resources.d.ts.map +1 -0
  810. package/dist/core/resource-loader-package-resources.js +112 -0
  811. package/dist/core/resource-loader-package-resources.js.map +1 -0
  812. package/dist/core/resource-loader-paths.d.ts +4 -0
  813. package/dist/core/resource-loader-paths.d.ts.map +1 -0
  814. package/dist/core/resource-loader-paths.js +22 -0
  815. package/dist/core/resource-loader-paths.js.map +1 -0
  816. package/dist/core/resource-loader-reload.d.ts +6 -0
  817. package/dist/core/resource-loader-reload.d.ts.map +1 -0
  818. package/dist/core/resource-loader-reload.js +230 -0
  819. package/dist/core/resource-loader-reload.js.map +1 -0
  820. package/dist/core/resource-loader-source-info.d.ts +9 -0
  821. package/dist/core/resource-loader-source-info.d.ts.map +1 -0
  822. package/dist/core/resource-loader-source-info.js +101 -0
  823. package/dist/core/resource-loader-source-info.js.map +1 -0
  824. package/dist/core/resource-loader-types.d.ts +130 -0
  825. package/dist/core/resource-loader-types.d.ts.map +1 -0
  826. package/dist/core/resource-loader-types.js +2 -0
  827. package/dist/core/resource-loader-types.js.map +1 -0
  828. package/dist/core/resource-loader.d.ts +3 -242
  829. package/dist/core/resource-loader.d.ts.map +1 -1
  830. package/dist/core/resource-loader.js +2 -976
  831. package/dist/core/resource-loader.js.map +1 -1
  832. package/dist/core/sdk-exports.d.ts +7 -0
  833. package/dist/core/sdk-exports.d.ts.map +1 -0
  834. package/dist/core/sdk-exports.js +5 -0
  835. package/dist/core/sdk-exports.js.map +1 -0
  836. package/dist/core/sdk-types.d.ts +83 -0
  837. package/dist/core/sdk-types.d.ts.map +1 -0
  838. package/dist/core/sdk-types.js +2 -0
  839. package/dist/core/sdk-types.js.map +1 -0
  840. package/dist/core/sdk.d.ts +3 -91
  841. package/dist/core/sdk.d.ts.map +1 -1
  842. package/dist/core/sdk.js +2 -7
  843. package/dist/core/sdk.js.map +1 -1
  844. package/dist/core/session-manager-archive.d.ts +27 -0
  845. package/dist/core/session-manager-archive.d.ts.map +1 -0
  846. package/dist/core/session-manager-archive.js +114 -0
  847. package/dist/core/session-manager-archive.js.map +1 -0
  848. package/dist/core/session-manager-core.d.ts +104 -0
  849. package/dist/core/session-manager-core.d.ts.map +1 -0
  850. package/dist/core/session-manager-core.js +346 -0
  851. package/dist/core/session-manager-core.js.map +1 -0
  852. package/dist/core/session-manager-entries.d.ts +38 -0
  853. package/dist/core/session-manager-entries.d.ts.map +1 -0
  854. package/dist/core/session-manager-entries.js +124 -0
  855. package/dist/core/session-manager-entries.js.map +1 -0
  856. package/dist/core/session-manager-history.d.ts +38 -0
  857. package/dist/core/session-manager-history.d.ts.map +1 -0
  858. package/dist/core/session-manager-history.js +379 -0
  859. package/dist/core/session-manager-history.js.map +1 -0
  860. package/dist/core/session-manager-list.d.ts +5 -0
  861. package/dist/core/session-manager-list.d.ts.map +1 -0
  862. package/dist/core/session-manager-list.js +196 -0
  863. package/dist/core/session-manager-list.js.map +1 -0
  864. package/dist/core/session-manager-migrations.d.ts +11 -0
  865. package/dist/core/session-manager-migrations.d.ts.map +1 -0
  866. package/dist/core/session-manager-migrations.js +80 -0
  867. package/dist/core/session-manager-migrations.js.map +1 -0
  868. package/dist/core/session-manager-paths.d.ts +7 -0
  869. package/dist/core/session-manager-paths.d.ts.map +1 -0
  870. package/dist/core/session-manager-paths.js +22 -0
  871. package/dist/core/session-manager-paths.js.map +1 -0
  872. package/dist/core/session-manager-storage.d.ts +15 -0
  873. package/dist/core/session-manager-storage.d.ts.map +1 -0
  874. package/dist/core/session-manager-storage.js +127 -0
  875. package/dist/core/session-manager-storage.js.map +1 -0
  876. package/dist/core/session-manager-types.d.ts +172 -0
  877. package/dist/core/session-manager-types.d.ts.map +1 -0
  878. package/dist/core/session-manager-types.js +2 -0
  879. package/dist/core/session-manager-types.js.map +1 -0
  880. package/dist/core/session-manager-validation.d.ts +7 -0
  881. package/dist/core/session-manager-validation.d.ts.map +1 -0
  882. package/dist/core/session-manager-validation.js +34 -0
  883. package/dist/core/session-manager-validation.js.map +1 -0
  884. package/dist/core/session-manager.d.ts +8 -390
  885. package/dist/core/session-manager.d.ts.map +1 -1
  886. package/dist/core/session-manager.js +7 -1418
  887. package/dist/core/session-manager.js.map +1 -1
  888. package/dist/core/settings-manager-basic-accessors.d.ts +65 -0
  889. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -0
  890. package/dist/core/settings-manager-basic-accessors.js +253 -0
  891. package/dist/core/settings-manager-basic-accessors.js.map +1 -0
  892. package/dist/core/settings-manager-core.d.ts +57 -0
  893. package/dist/core/settings-manager-core.d.ts.map +1 -0
  894. package/dist/core/settings-manager-core.js +387 -0
  895. package/dist/core/settings-manager-core.js.map +1 -0
  896. package/dist/core/settings-manager-internals.d.ts +13 -0
  897. package/dist/core/settings-manager-internals.d.ts.map +1 -0
  898. package/dist/core/settings-manager-internals.js +4 -0
  899. package/dist/core/settings-manager-internals.js.map +1 -0
  900. package/dist/core/settings-manager-resource-accessors.d.ts +43 -0
  901. package/dist/core/settings-manager-resource-accessors.d.ts.map +1 -0
  902. package/dist/core/settings-manager-resource-accessors.js +172 -0
  903. package/dist/core/settings-manager-resource-accessors.js.map +1 -0
  904. package/dist/core/settings-manager-ui-accessors.d.ts +44 -0
  905. package/dist/core/settings-manager-ui-accessors.d.ts.map +1 -0
  906. package/dist/core/settings-manager-ui-accessors.js +208 -0
  907. package/dist/core/settings-manager-ui-accessors.js.map +1 -0
  908. package/dist/core/settings-manager.d.ts +6 -321
  909. package/dist/core/settings-manager.d.ts.map +1 -1
  910. package/dist/core/settings-manager.js +5 -1060
  911. package/dist/core/settings-manager.js.map +1 -1
  912. package/dist/core/settings-merge.d.ts +4 -0
  913. package/dist/core/settings-merge.d.ts.map +1 -0
  914. package/dist/core/settings-merge.js +26 -0
  915. package/dist/core/settings-merge.js.map +1 -0
  916. package/dist/core/settings-storage.d.ts +20 -0
  917. package/dist/core/settings-storage.d.ts.map +1 -0
  918. package/dist/core/settings-storage.js +100 -0
  919. package/dist/core/settings-storage.js.map +1 -0
  920. package/dist/core/settings-types.d.ts +123 -0
  921. package/dist/core/settings-types.d.ts.map +1 -0
  922. package/dist/core/settings-types.js +2 -0
  923. package/dist/core/settings-types.js.map +1 -0
  924. package/dist/core/system-prompt.d.ts.map +1 -1
  925. package/dist/core/system-prompt.js +7 -0
  926. package/dist/core/system-prompt.js.map +1 -1
  927. package/dist/core/tools/bash.d.ts +0 -5
  928. package/dist/core/tools/bash.d.ts.map +1 -1
  929. package/dist/core/tools/bash.js +10 -11
  930. package/dist/core/tools/bash.js.map +1 -1
  931. package/dist/core/tools/edit-diff-preserve.d.ts +18 -0
  932. package/dist/core/tools/edit-diff-preserve.d.ts.map +1 -0
  933. package/dist/core/tools/edit-diff-preserve.js +85 -0
  934. package/dist/core/tools/edit-diff-preserve.js.map +1 -0
  935. package/dist/core/tools/edit-diff.d.ts +3 -2
  936. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  937. package/dist/core/tools/edit-diff.js +15 -18
  938. package/dist/core/tools/edit-diff.js.map +1 -1
  939. package/dist/core/tools/index.d.ts +0 -1
  940. package/dist/core/tools/index.d.ts.map +1 -1
  941. package/dist/core/tools/index.js +0 -1
  942. package/dist/core/tools/index.js.map +1 -1
  943. package/dist/core/tools/todos-execute.d.ts +5 -0
  944. package/dist/core/tools/todos-execute.d.ts.map +1 -0
  945. package/dist/core/tools/todos-execute.js +200 -0
  946. package/dist/core/tools/todos-execute.js.map +1 -0
  947. package/dist/core/tools/todos-locks.d.ts +4 -0
  948. package/dist/core/tools/todos-locks.d.ts.map +1 -0
  949. package/dist/core/tools/todos-locks.js +80 -0
  950. package/dist/core/tools/todos-locks.js.map +1 -0
  951. package/dist/core/tools/todos-model.d.ts +21 -0
  952. package/dist/core/tools/todos-model.d.ts.map +1 -0
  953. package/dist/core/tools/todos-model.js +71 -0
  954. package/dist/core/tools/todos-model.js.map +1 -0
  955. package/dist/core/tools/todos-mutations.d.ts +6 -0
  956. package/dist/core/tools/todos-mutations.d.ts.map +1 -0
  957. package/dist/core/tools/todos-mutations.js +85 -0
  958. package/dist/core/tools/todos-mutations.js.map +1 -0
  959. package/dist/core/tools/todos-paths.d.ts +5 -0
  960. package/dist/core/tools/todos-paths.d.ts.map +1 -0
  961. package/dist/core/tools/todos-paths.js +25 -0
  962. package/dist/core/tools/todos-paths.js.map +1 -0
  963. package/dist/core/tools/todos-render.d.ts +10 -0
  964. package/dist/core/tools/todos-render.d.ts.map +1 -0
  965. package/dist/core/tools/todos-render.js +159 -0
  966. package/dist/core/tools/todos-render.js.map +1 -0
  967. package/dist/core/tools/todos-storage.d.ts +9 -0
  968. package/dist/core/tools/todos-storage.d.ts.map +1 -0
  969. package/dist/core/tools/todos-storage.js +183 -0
  970. package/dist/core/tools/todos-storage.js.map +1 -0
  971. package/dist/core/tools/todos-types.d.ts +46 -0
  972. package/dist/core/tools/todos-types.d.ts.map +1 -0
  973. package/dist/core/tools/todos-types.js +27 -0
  974. package/dist/core/tools/todos-types.js.map +1 -0
  975. package/dist/core/tools/todos.d.ts +12 -32
  976. package/dist/core/tools/todos.d.ts.map +1 -1
  977. package/dist/core/tools/todos.js +7 -893
  978. package/dist/core/tools/todos.js.map +1 -1
  979. package/dist/index-extensions.d.ts +3 -0
  980. package/dist/index-extensions.d.ts.map +1 -0
  981. package/dist/index-extensions.js +2 -0
  982. package/dist/index-extensions.js.map +1 -0
  983. package/dist/index.d.ts +3 -4
  984. package/dist/index.d.ts.map +1 -1
  985. package/dist/index.js +2 -2
  986. package/dist/index.js.map +1 -1
  987. package/dist/main-app-mode.d.ts +15 -0
  988. package/dist/main-app-mode.d.ts.map +1 -0
  989. package/dist/main-app-mode.js +51 -0
  990. package/dist/main-app-mode.js.map +1 -0
  991. package/dist/main-session-options.d.ts +12 -0
  992. package/dist/main-session-options.d.ts.map +1 -0
  993. package/dist/main-session-options.js +87 -0
  994. package/dist/main-session-options.js.map +1 -0
  995. package/dist/main-session.d.ts +9 -0
  996. package/dist/main-session.d.ts.map +1 -0
  997. package/dist/main-session.js +188 -0
  998. package/dist/main-session.js.map +1 -0
  999. package/dist/main-stdio.d.ts +12 -0
  1000. package/dist/main-stdio.d.ts.map +1 -0
  1001. package/dist/main-stdio.js +68 -0
  1002. package/dist/main-stdio.js.map +1 -0
  1003. package/dist/main.d.ts +2 -3
  1004. package/dist/main.d.ts.map +1 -1
  1005. package/dist/main.js +11 -388
  1006. package/dist/main.js.map +1 -1
  1007. package/dist/migrations-config-values.d.ts +9 -0
  1008. package/dist/migrations-config-values.d.ts.map +1 -0
  1009. package/dist/migrations-config-values.js +298 -0
  1010. package/dist/migrations-config-values.js.map +1 -0
  1011. package/dist/migrations.d.ts.map +1 -1
  1012. package/dist/migrations.js +2 -296
  1013. package/dist/migrations.js.map +1 -1
  1014. package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
  1015. package/dist/modes/interactive/components/chat-message-renderer.js +0 -7
  1016. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  1017. package/dist/modes/interactive/components/chat-session-host-actions.d.ts +9 -0
  1018. package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -0
  1019. package/dist/modes/interactive/components/chat-session-host-actions.js +244 -0
  1020. package/dist/modes/interactive/components/chat-session-host-actions.js.map +1 -0
  1021. package/dist/modes/interactive/components/chat-session-host-editor.d.ts +18 -0
  1022. package/dist/modes/interactive/components/chat-session-host-editor.d.ts.map +1 -0
  1023. package/dist/modes/interactive/components/chat-session-host-editor.js +165 -0
  1024. package/dist/modes/interactive/components/chat-session-host-editor.js.map +1 -0
  1025. package/dist/modes/interactive/components/chat-session-host-events.d.ts +5 -0
  1026. package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -0
  1027. package/dist/modes/interactive/components/chat-session-host-events.js +200 -0
  1028. package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -0
  1029. package/dist/modes/interactive/components/chat-session-host-rendering.d.ts +13 -0
  1030. package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -0
  1031. package/dist/modes/interactive/components/chat-session-host-rendering.js +185 -0
  1032. package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -0
  1033. package/dist/modes/interactive/components/chat-session-host-runtime.d.ts +13 -0
  1034. package/dist/modes/interactive/components/chat-session-host-runtime.d.ts.map +1 -0
  1035. package/dist/modes/interactive/components/chat-session-host-runtime.js +101 -0
  1036. package/dist/modes/interactive/components/chat-session-host-runtime.js.map +1 -0
  1037. package/dist/modes/interactive/components/chat-session-host-state.d.ts +53 -0
  1038. package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -0
  1039. package/dist/modes/interactive/components/chat-session-host-state.js +42 -0
  1040. package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -0
  1041. package/dist/modes/interactive/components/chat-session-host-types.d.ts +63 -0
  1042. package/dist/modes/interactive/components/chat-session-host-types.d.ts.map +1 -0
  1043. package/dist/modes/interactive/components/chat-session-host-types.js +2 -0
  1044. package/dist/modes/interactive/components/chat-session-host-types.js.map +1 -0
  1045. package/dist/modes/interactive/components/chat-session-host-utils.d.ts +28 -0
  1046. package/dist/modes/interactive/components/chat-session-host-utils.d.ts.map +1 -0
  1047. package/dist/modes/interactive/components/chat-session-host-utils.js +103 -0
  1048. package/dist/modes/interactive/components/chat-session-host-utils.js.map +1 -0
  1049. package/dist/modes/interactive/components/chat-session-host.d.ts +6 -129
  1050. package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
  1051. package/dist/modes/interactive/components/chat-session-host.js +50 -1022
  1052. package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
  1053. package/dist/modes/interactive/components/config-selector-list.d.ts +65 -0
  1054. package/dist/modes/interactive/components/config-selector-list.d.ts.map +1 -0
  1055. package/dist/modes/interactive/components/config-selector-list.js +458 -0
  1056. package/dist/modes/interactive/components/config-selector-list.js.map +1 -0
  1057. package/dist/modes/interactive/components/config-selector.d.ts +3 -58
  1058. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  1059. package/dist/modes/interactive/components/config-selector.js +2 -457
  1060. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  1061. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  1062. package/dist/modes/interactive/components/model-selector.js +2 -2
  1063. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  1064. package/dist/modes/interactive/components/session-selector-delete.d.ts +10 -0
  1065. package/dist/modes/interactive/components/session-selector-delete.d.ts.map +1 -0
  1066. package/dist/modes/interactive/components/session-selector-delete.js +40 -0
  1067. package/dist/modes/interactive/components/session-selector-delete.js.map +1 -0
  1068. package/dist/modes/interactive/components/session-selector-header.d.ts +33 -0
  1069. package/dist/modes/interactive/components/session-selector-header.d.ts.map +1 -0
  1070. package/dist/modes/interactive/components/session-selector-header.js +117 -0
  1071. package/dist/modes/interactive/components/session-selector-header.js.map +1 -0
  1072. package/dist/modes/interactive/components/session-selector-list.d.ts +49 -0
  1073. package/dist/modes/interactive/components/session-selector-list.d.ts.map +1 -0
  1074. package/dist/modes/interactive/components/session-selector-list.js +307 -0
  1075. package/dist/modes/interactive/components/session-selector-list.js.map +1 -0
  1076. package/dist/modes/interactive/components/session-selector-tree.d.ts +25 -0
  1077. package/dist/modes/interactive/components/session-selector-tree.d.ts.map +1 -0
  1078. package/dist/modes/interactive/components/session-selector-tree.js +53 -0
  1079. package/dist/modes/interactive/components/session-selector-tree.js.map +1 -0
  1080. package/dist/modes/interactive/components/session-selector-types.d.ts +4 -0
  1081. package/dist/modes/interactive/components/session-selector-types.d.ts.map +1 -0
  1082. package/dist/modes/interactive/components/session-selector-types.js +2 -0
  1083. package/dist/modes/interactive/components/session-selector-types.js.map +1 -0
  1084. package/dist/modes/interactive/components/session-selector-utils.d.ts +4 -0
  1085. package/dist/modes/interactive/components/session-selector-utils.d.ts.map +1 -0
  1086. package/dist/modes/interactive/components/session-selector-utils.js +37 -0
  1087. package/dist/modes/interactive/components/session-selector-utils.js.map +1 -0
  1088. package/dist/modes/interactive/components/session-selector.d.ts +3 -49
  1089. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  1090. package/dist/modes/interactive/components/session-selector.js +5 -542
  1091. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  1092. package/dist/modes/interactive/components/settings-selector-handlers.d.ts +3 -0
  1093. package/dist/modes/interactive/components/settings-selector-handlers.d.ts.map +1 -0
  1094. package/dist/modes/interactive/components/settings-selector-handlers.js +84 -0
  1095. package/dist/modes/interactive/components/settings-selector-handlers.js.map +1 -0
  1096. package/dist/modes/interactive/components/settings-selector-items.d.ts +4 -0
  1097. package/dist/modes/interactive/components/settings-selector-items.d.ts.map +1 -0
  1098. package/dist/modes/interactive/components/settings-selector-items.js +211 -0
  1099. package/dist/modes/interactive/components/settings-selector-items.js.map +1 -0
  1100. package/dist/modes/interactive/components/settings-selector-options.d.ts +6 -0
  1101. package/dist/modes/interactive/components/settings-selector-options.d.ts.map +1 -0
  1102. package/dist/modes/interactive/components/settings-selector-options.js +14 -0
  1103. package/dist/modes/interactive/components/settings-selector-options.js.map +1 -0
  1104. package/dist/modes/interactive/components/settings-selector-submenus.d.ts +44 -0
  1105. package/dist/modes/interactive/components/settings-selector-submenus.d.ts.map +1 -0
  1106. package/dist/modes/interactive/components/settings-selector-submenus.js +228 -0
  1107. package/dist/modes/interactive/components/settings-selector-submenus.js.map +1 -0
  1108. package/dist/modes/interactive/components/settings-selector-types.d.ts +67 -0
  1109. package/dist/modes/interactive/components/settings-selector-types.d.ts.map +1 -0
  1110. package/dist/modes/interactive/components/settings-selector-types.js +2 -0
  1111. package/dist/modes/interactive/components/settings-selector-types.js.map +1 -0
  1112. package/dist/modes/interactive/components/settings-selector.d.ts +2 -63
  1113. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  1114. package/dist/modes/interactive/components/settings-selector.js +5 -538
  1115. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  1116. package/dist/modes/interactive/components/tree-selector-component.d.ts +21 -0
  1117. package/dist/modes/interactive/components/tree-selector-component.d.ts.map +1 -0
  1118. package/dist/modes/interactive/components/tree-selector-component.js +80 -0
  1119. package/dist/modes/interactive/components/tree-selector-component.js.map +1 -0
  1120. package/dist/modes/interactive/components/tree-selector-content.d.ts +8 -0
  1121. package/dist/modes/interactive/components/tree-selector-content.d.ts.map +1 -0
  1122. package/dist/modes/interactive/components/tree-selector-content.js +263 -0
  1123. package/dist/modes/interactive/components/tree-selector-content.js.map +1 -0
  1124. package/dist/modes/interactive/components/tree-selector-help.d.ts +16 -0
  1125. package/dist/modes/interactive/components/tree-selector-help.d.ts.map +1 -0
  1126. package/dist/modes/interactive/components/tree-selector-help.js +103 -0
  1127. package/dist/modes/interactive/components/tree-selector-help.js.map +1 -0
  1128. package/dist/modes/interactive/components/tree-selector-label-input.d.ts +16 -0
  1129. package/dist/modes/interactive/components/tree-selector-label-input.d.ts.map +1 -0
  1130. package/dist/modes/interactive/components/tree-selector-label-input.js +46 -0
  1131. package/dist/modes/interactive/components/tree-selector-label-input.js.map +1 -0
  1132. package/dist/modes/interactive/components/tree-selector-list.d.ts +33 -0
  1133. package/dist/modes/interactive/components/tree-selector-list.d.ts.map +1 -0
  1134. package/dist/modes/interactive/components/tree-selector-list.js +336 -0
  1135. package/dist/modes/interactive/components/tree-selector-list.js.map +1 -0
  1136. package/dist/modes/interactive/components/tree-selector-model.d.ts +7 -0
  1137. package/dist/modes/interactive/components/tree-selector-model.d.ts.map +1 -0
  1138. package/dist/modes/interactive/components/tree-selector-model.js +358 -0
  1139. package/dist/modes/interactive/components/tree-selector-model.js.map +1 -0
  1140. package/dist/modes/interactive/components/tree-selector-types.d.ts +57 -0
  1141. package/dist/modes/interactive/components/tree-selector-types.d.ts.map +1 -0
  1142. package/dist/modes/interactive/components/tree-selector-types.js +6 -0
  1143. package/dist/modes/interactive/components/tree-selector-types.js.map +1 -0
  1144. package/dist/modes/interactive/components/tree-selector-viewport.d.ts +10 -0
  1145. package/dist/modes/interactive/components/tree-selector-viewport.d.ts.map +1 -0
  1146. package/dist/modes/interactive/components/tree-selector-viewport.js +32 -0
  1147. package/dist/modes/interactive/components/tree-selector-viewport.js.map +1 -0
  1148. package/dist/modes/interactive/components/tree-selector.d.ts +2 -88
  1149. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  1150. package/dist/modes/interactive/components/tree-selector.js +1 -1200
  1151. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  1152. package/dist/modes/interactive/interactive-agent-events.d.ts +2 -0
  1153. package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -0
  1154. package/dist/modes/interactive/interactive-agent-events.js +370 -0
  1155. package/dist/modes/interactive/interactive-agent-events.js.map +1 -0
  1156. package/dist/modes/interactive/interactive-auth-login.d.ts +2 -0
  1157. package/dist/modes/interactive/interactive-auth-login.d.ts.map +1 -0
  1158. package/dist/modes/interactive/interactive-auth-login.js +214 -0
  1159. package/dist/modes/interactive/interactive-auth-login.js.map +1 -0
  1160. package/dist/modes/interactive/interactive-auth-routing.d.ts +2 -0
  1161. package/dist/modes/interactive/interactive-auth-routing.d.ts.map +1 -0
  1162. package/dist/modes/interactive/interactive-auth-routing.js +128 -0
  1163. package/dist/modes/interactive/interactive-auth-routing.js.map +1 -0
  1164. package/dist/modes/interactive/interactive-autocomplete.d.ts +2 -0
  1165. package/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -0
  1166. package/dist/modes/interactive/interactive-autocomplete.js +140 -0
  1167. package/dist/modes/interactive/interactive-autocomplete.js.map +1 -0
  1168. package/dist/modes/interactive/interactive-bash-compact.d.ts +2 -0
  1169. package/dist/modes/interactive/interactive-bash-compact.d.ts.map +1 -0
  1170. package/dist/modes/interactive/interactive-bash-compact.js +112 -0
  1171. package/dist/modes/interactive/interactive-bash-compact.js.map +1 -0
  1172. package/dist/modes/interactive/interactive-editor-actions.d.ts +2 -0
  1173. package/dist/modes/interactive/interactive-editor-actions.d.ts.map +1 -0
  1174. package/dist/modes/interactive/interactive-editor-actions.js +131 -0
  1175. package/dist/modes/interactive/interactive-editor-actions.js.map +1 -0
  1176. package/dist/modes/interactive/interactive-extension-context.d.ts +2 -0
  1177. package/dist/modes/interactive/interactive-extension-context.d.ts.map +1 -0
  1178. package/dist/modes/interactive/interactive-extension-context.js +159 -0
  1179. package/dist/modes/interactive/interactive-extension-context.js.map +1 -0
  1180. package/dist/modes/interactive/interactive-extension-custom-ui.d.ts +2 -0
  1181. package/dist/modes/interactive/interactive-extension-custom-ui.d.ts.map +1 -0
  1182. package/dist/modes/interactive/interactive-extension-custom-ui.js +208 -0
  1183. package/dist/modes/interactive/interactive-extension-custom-ui.js.map +1 -0
  1184. package/dist/modes/interactive/interactive-extension-dialogs.d.ts +2 -0
  1185. package/dist/modes/interactive/interactive-extension-dialogs.d.ts.map +1 -0
  1186. package/dist/modes/interactive/interactive-extension-dialogs.js +162 -0
  1187. package/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -0
  1188. package/dist/modes/interactive/interactive-extension-runtime.d.ts +2 -0
  1189. package/dist/modes/interactive/interactive-extension-runtime.d.ts.map +1 -0
  1190. package/dist/modes/interactive/interactive-extension-runtime.js +179 -0
  1191. package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -0
  1192. package/dist/modes/interactive/interactive-extension-widgets.d.ts +2 -0
  1193. package/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -0
  1194. package/dist/modes/interactive/interactive-extension-widgets.js +113 -0
  1195. package/dist/modes/interactive/interactive-extension-widgets.js.map +1 -0
  1196. package/dist/modes/interactive/interactive-hotkeys-debug.d.ts +2 -0
  1197. package/dist/modes/interactive/interactive-hotkeys-debug.d.ts.map +1 -0
  1198. package/dist/modes/interactive/interactive-hotkeys-debug.js +186 -0
  1199. package/dist/modes/interactive/interactive-hotkeys-debug.js.map +1 -0
  1200. package/dist/modes/interactive/interactive-input-handling.d.ts +2 -0
  1201. package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -0
  1202. package/dist/modes/interactive/interactive-input-handling.js +275 -0
  1203. package/dist/modes/interactive/interactive-input-handling.js.map +1 -0
  1204. package/dist/modes/interactive/interactive-mode-base.d.ts +103 -0
  1205. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -0
  1206. package/dist/modes/interactive/interactive-mode-base.js +130 -0
  1207. package/dist/modes/interactive/interactive-mode-base.js.map +1 -0
  1208. package/dist/modes/interactive/interactive-mode-deps.d.ts +81 -0
  1209. package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -0
  1210. package/dist/modes/interactive/interactive-mode-deps.js +74 -0
  1211. package/dist/modes/interactive/interactive-mode-deps.js.map +1 -0
  1212. package/dist/modes/interactive/interactive-mode-helpers.d.ts +21 -0
  1213. package/dist/modes/interactive/interactive-mode-helpers.d.ts.map +1 -0
  1214. package/dist/modes/interactive/interactive-mode-helpers.js +77 -0
  1215. package/dist/modes/interactive/interactive-mode-helpers.js.map +1 -0
  1216. package/dist/modes/interactive/interactive-mode-surface.d.ts +313 -0
  1217. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -0
  1218. package/dist/modes/interactive/interactive-mode-surface.js +2 -0
  1219. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -0
  1220. package/dist/modes/interactive/interactive-mode-types.d.ts +29 -0
  1221. package/dist/modes/interactive/interactive-mode-types.d.ts.map +1 -0
  1222. package/dist/modes/interactive/interactive-mode-types.js +2 -0
  1223. package/dist/modes/interactive/interactive-mode-types.js.map +1 -0
  1224. package/dist/modes/interactive/interactive-mode.d.ts +30 -404
  1225. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  1226. package/dist/modes/interactive/interactive-mode.js +29 -5260
  1227. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  1228. package/dist/modes/interactive/interactive-model-routing.d.ts +2 -0
  1229. package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -0
  1230. package/dist/modes/interactive/interactive-model-routing.js +269 -0
  1231. package/dist/modes/interactive/interactive-model-routing.js.map +1 -0
  1232. package/dist/modes/interactive/interactive-process-lifecycle.d.ts +2 -0
  1233. package/dist/modes/interactive/interactive-process-lifecycle.d.ts.map +1 -0
  1234. package/dist/modes/interactive/interactive-process-lifecycle.js +189 -0
  1235. package/dist/modes/interactive/interactive-process-lifecycle.js.map +1 -0
  1236. package/dist/modes/interactive/interactive-queueing.d.ts +2 -0
  1237. package/dist/modes/interactive/interactive-queueing.d.ts.map +1 -0
  1238. package/dist/modes/interactive/interactive-queueing.js +163 -0
  1239. package/dist/modes/interactive/interactive-queueing.js.map +1 -0
  1240. package/dist/modes/interactive/interactive-render-chat.d.ts +2 -0
  1241. package/dist/modes/interactive/interactive-render-chat.d.ts.map +1 -0
  1242. package/dist/modes/interactive/interactive-render-chat.js +170 -0
  1243. package/dist/modes/interactive/interactive-render-chat.js.map +1 -0
  1244. package/dist/modes/interactive/interactive-resource-disclosure.d.ts +2 -0
  1245. package/dist/modes/interactive/interactive-resource-disclosure.d.ts.map +1 -0
  1246. package/dist/modes/interactive/interactive-resource-disclosure.js +101 -0
  1247. package/dist/modes/interactive/interactive-resource-disclosure.js.map +1 -0
  1248. package/dist/modes/interactive/interactive-resource-paths.d.ts +2 -0
  1249. package/dist/modes/interactive/interactive-resource-paths.d.ts.map +1 -0
  1250. package/dist/modes/interactive/interactive-resource-paths.js +228 -0
  1251. package/dist/modes/interactive/interactive-resource-paths.js.map +1 -0
  1252. package/dist/modes/interactive/interactive-resource-rendering.d.ts +2 -0
  1253. package/dist/modes/interactive/interactive-resource-rendering.d.ts.map +1 -0
  1254. package/dist/modes/interactive/interactive-resource-rendering.js +181 -0
  1255. package/dist/modes/interactive/interactive-resource-rendering.js.map +1 -0
  1256. package/dist/modes/interactive/interactive-selectors.d.ts +2 -0
  1257. package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -0
  1258. package/dist/modes/interactive/interactive-selectors.js +198 -0
  1259. package/dist/modes/interactive/interactive-selectors.js.map +1 -0
  1260. package/dist/modes/interactive/interactive-session-routing.d.ts +2 -0
  1261. package/dist/modes/interactive/interactive-session-routing.d.ts.map +1 -0
  1262. package/dist/modes/interactive/interactive-session-routing.js +232 -0
  1263. package/dist/modes/interactive/interactive-session-routing.js.map +1 -0
  1264. package/dist/modes/interactive/interactive-session-runtime.d.ts +2 -0
  1265. package/dist/modes/interactive/interactive-session-runtime.d.ts.map +1 -0
  1266. package/dist/modes/interactive/interactive-session-runtime.js +131 -0
  1267. package/dist/modes/interactive/interactive-session-runtime.js.map +1 -0
  1268. package/dist/modes/interactive/interactive-slash-commands.d.ts +2 -0
  1269. package/dist/modes/interactive/interactive-slash-commands.d.ts.map +1 -0
  1270. package/dist/modes/interactive/interactive-slash-commands.js +338 -0
  1271. package/dist/modes/interactive/interactive-slash-commands.js.map +1 -0
  1272. package/dist/modes/interactive/interactive-startup.d.ts +2 -0
  1273. package/dist/modes/interactive/interactive-startup.d.ts.map +1 -0
  1274. package/dist/modes/interactive/interactive-startup.js +348 -0
  1275. package/dist/modes/interactive/interactive-startup.js.map +1 -0
  1276. package/dist/modes/interactive/model-search.d.ts +5 -0
  1277. package/dist/modes/interactive/model-search.d.ts.map +1 -1
  1278. package/dist/modes/interactive/model-search.js +9 -0
  1279. package/dist/modes/interactive/model-search.js.map +1 -1
  1280. package/dist/modes/interactive/theme/color-utils.d.ts +20 -0
  1281. package/dist/modes/interactive/theme/color-utils.d.ts.map +1 -0
  1282. package/dist/modes/interactive/theme/color-utils.js +204 -0
  1283. package/dist/modes/interactive/theme/color-utils.js.map +1 -0
  1284. package/dist/modes/interactive/theme/export-colors.d.ts +19 -0
  1285. package/dist/modes/interactive/theme/export-colors.d.ts.map +1 -0
  1286. package/dist/modes/interactive/theme/export-colors.js +69 -0
  1287. package/dist/modes/interactive/theme/export-colors.js.map +1 -0
  1288. package/dist/modes/interactive/theme/global-theme.d.ts +12 -0
  1289. package/dist/modes/interactive/theme/global-theme.d.ts.map +1 -0
  1290. package/dist/modes/interactive/theme/global-theme.js +150 -0
  1291. package/dist/modes/interactive/theme/global-theme.js.map +1 -0
  1292. package/dist/modes/interactive/theme/terminal-detection.d.ts +30 -0
  1293. package/dist/modes/interactive/theme/terminal-detection.d.ts.map +1 -0
  1294. package/dist/modes/interactive/theme/terminal-detection.js +89 -0
  1295. package/dist/modes/interactive/theme/terminal-detection.js.map +1 -0
  1296. package/dist/modes/interactive/theme/theme-class.d.ts +30 -0
  1297. package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -0
  1298. package/dist/modes/interactive/theme/theme-class.js +83 -0
  1299. package/dist/modes/interactive/theme/theme-class.js.map +1 -0
  1300. package/dist/modes/interactive/theme/theme-loading.d.ts +17 -0
  1301. package/dist/modes/interactive/theme/theme-loading.d.ts.map +1 -0
  1302. package/dist/modes/interactive/theme/theme-loading.js +155 -0
  1303. package/dist/modes/interactive/theme/theme-loading.js.map +1 -0
  1304. package/dist/modes/interactive/theme/theme-parse.d.ts +5 -0
  1305. package/dist/modes/interactive/theme/theme-parse.d.ts.map +1 -0
  1306. package/dist/modes/interactive/theme/theme-parse.js +52 -0
  1307. package/dist/modes/interactive/theme/theme-parse.js.map +1 -0
  1308. package/dist/modes/interactive/theme/theme-schema.d.ts +255 -0
  1309. package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -0
  1310. package/dist/modes/interactive/theme/theme-schema.js +78 -0
  1311. package/dist/modes/interactive/theme/theme-schema.js.map +1 -0
  1312. package/dist/modes/interactive/theme/theme.d.ts +6 -108
  1313. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  1314. package/dist/modes/interactive/theme/theme.js +6 -1065
  1315. package/dist/modes/interactive/theme/theme.js.map +1 -1
  1316. package/dist/modes/interactive/theme/tui-theme.d.ts +15 -0
  1317. package/dist/modes/interactive/theme/tui-theme.d.ts.map +1 -0
  1318. package/dist/modes/interactive/theme/tui-theme.js +199 -0
  1319. package/dist/modes/interactive/theme/tui-theme.js.map +1 -0
  1320. package/dist/modes/rpc/rpc-client.d.ts +1 -61
  1321. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  1322. package/dist/modes/rpc/rpc-client.js +1 -72
  1323. package/dist/modes/rpc/rpc-client.js.map +1 -1
  1324. package/dist/modes/rpc/rpc-command-handler.d.ts +14 -0
  1325. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -0
  1326. package/dist/modes/rpc/rpc-command-handler.js +226 -0
  1327. package/dist/modes/rpc/rpc-command-handler.js.map +1 -0
  1328. package/dist/modes/rpc/rpc-extension-ui.d.ts +15 -0
  1329. package/dist/modes/rpc/rpc-extension-ui.d.ts.map +1 -0
  1330. package/dist/modes/rpc/rpc-extension-ui.js +196 -0
  1331. package/dist/modes/rpc/rpc-extension-ui.js.map +1 -0
  1332. package/dist/modes/rpc/rpc-input.d.ts +12 -0
  1333. package/dist/modes/rpc/rpc-input.d.ts.map +1 -0
  1334. package/dist/modes/rpc/rpc-input.js +54 -0
  1335. package/dist/modes/rpc/rpc-input.js.map +1 -0
  1336. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  1337. package/dist/modes/rpc/rpc-mode.js +43 -607
  1338. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  1339. package/dist/modes/rpc/rpc-responses.d.ts +8 -0
  1340. package/dist/modes/rpc/rpc-responses.d.ts.map +1 -0
  1341. package/dist/modes/rpc/rpc-responses.js +27 -0
  1342. package/dist/modes/rpc/rpc-responses.js.map +1 -0
  1343. package/dist/modes/rpc/rpc-session-binding.d.ts +25 -0
  1344. package/dist/modes/rpc/rpc-session-binding.d.ts.map +1 -0
  1345. package/dist/modes/rpc/rpc-session-binding.js +70 -0
  1346. package/dist/modes/rpc/rpc-session-binding.js.map +1 -0
  1347. package/dist/package-manager-cli-parser.d.ts +28 -0
  1348. package/dist/package-manager-cli-parser.d.ts.map +1 -0
  1349. package/dist/package-manager-cli-parser.js +269 -0
  1350. package/dist/package-manager-cli-parser.js.map +1 -0
  1351. package/dist/package-manager-cli.d.ts +0 -1
  1352. package/dist/package-manager-cli.d.ts.map +1 -1
  1353. package/dist/package-manager-cli.js +2 -267
  1354. package/dist/package-manager-cli.js.map +1 -1
  1355. package/dist/utils/git.d.ts.map +1 -1
  1356. package/dist/utils/git.js +10 -0
  1357. package/dist/utils/git.js.map +1 -1
  1358. package/dist/utils/shell.d.ts +1 -0
  1359. package/dist/utils/shell.d.ts.map +1 -1
  1360. package/dist/utils/shell.js +12 -5
  1361. package/dist/utils/shell.js.map +1 -1
  1362. package/dist/utils/version-check.d.ts +1 -0
  1363. package/dist/utils/version-check.d.ts.map +1 -1
  1364. package/dist/utils/version-check.js +17 -0
  1365. package/dist/utils/version-check.js.map +1 -1
  1366. package/docs/custom-provider.md +4 -3
  1367. package/docs/development.md +4 -0
  1368. package/docs/models.md +3 -2
  1369. package/docs/packages.md +2 -2
  1370. package/docs/quickstart.md +1 -1
  1371. package/docs/sdk.md +2 -40
  1372. package/docs/security.md +1 -1
  1373. package/docs/workflows.md +246 -179
  1374. package/examples/extensions/custom-provider-anthropic/index.ts +1 -106
  1375. package/examples/extensions/gondolin/index.ts +0 -23
  1376. package/examples/extensions/overlay-qa-animation-components.ts +255 -0
  1377. package/examples/extensions/overlay-qa-focus-components.ts +222 -0
  1378. package/examples/extensions/overlay-qa-position-components.ts +433 -0
  1379. package/examples/extensions/overlay-qa-shared.ts +37 -0
  1380. package/examples/extensions/overlay-qa-streaming-input-components.ts +205 -0
  1381. package/examples/extensions/overlay-qa-tests.ts +17 -1156
  1382. package/examples/extensions/overlay-qa-toggle-passive-components.ts +169 -0
  1383. package/examples/extensions/space-invaders.ts +0 -60
  1384. package/examples/extensions/subagent/display.ts +148 -0
  1385. package/examples/extensions/subagent/index.ts +11 -858
  1386. package/examples/extensions/subagent/render.ts +383 -0
  1387. package/examples/extensions/subagent/runner.ts +252 -0
  1388. package/examples/extensions/subagent/schemas.ts +59 -0
  1389. package/examples/extensions/subagent/types.ts +36 -0
  1390. package/examples/extensions/tic-tac-toe-instructions.ts +65 -0
  1391. package/examples/extensions/tic-tac-toe-rendering.ts +414 -0
  1392. package/examples/extensions/tic-tac-toe-state.ts +158 -0
  1393. package/examples/extensions/tic-tac-toe.ts +92 -754
  1394. package/examples/rpc-extension-ui-components.ts +189 -0
  1395. package/examples/rpc-extension-ui.ts +2 -179
  1396. package/package.json +7 -7
  1397. package/dist/builtin/workflows/src/workflows/define-workflow.ts +0 -277
  1398. package/dist/core/tools/bash-policy.d.ts +0 -62
  1399. package/dist/core/tools/bash-policy.d.ts.map +0 -1
  1400. package/dist/core/tools/bash-policy.js +0 -1069
  1401. package/dist/core/tools/bash-policy.js.map +0 -1
@@ -1,4166 +1,42 @@
1
- import { renderCall } from "./render-call.js";
2
- import { renderResult } from "./render-result.js";
3
- import type {
4
- RenderResultOpts,
5
- WorkflowInputEntry,
6
- WorkflowToolResult,
7
- } from "./render-result.js";
8
- import { renderInputsSchema } from "../shared/render-inputs-schema.js";
9
- import { deriveInputFields, schemaIsRequired, schemaChoices, schemaFieldKind, schemaDescription } from "../shared/schema-introspection.js";
10
- import { WorkflowParametersSchema } from "./workflow-schema.js";
11
- import { renderRunBanner, renderRunSummary } from "./renderers.js";
12
- import type { RunEndPayload, RunStartPayload } from "./renderers.js";
13
- import type { RunStatus, StageSnapshot, StageStatus, ToolEvent } from "../shared/store-types.js";
14
- import { store } from "../shared/store.js";
15
- import { stageUiBroker } from "../shared/stage-ui-broker.js";
16
- import {
17
- coerceStageInputAnswer,
18
- hasStageInputAnswerContent,
19
- type StageInputAnswer,
20
- } from "../shared/stage-prompt.js";
21
- import { restoreOnSessionStart } from "../shared/persistence-restore.js";
22
- import type { SessionManager } from "../shared/persistence-restore.js";
23
- import { installCompactionHook } from "../shared/persistence-compaction-policy.js";
24
- import {
25
- killRun,
26
- killAllRuns,
27
- resumeRun,
28
- pauseRun,
29
- pauseAllRuns,
30
- interruptRun,
31
- interruptAllRuns,
32
- inspectRun,
33
- type RunDetail,
34
- } from "../runs/background/status.js";
35
- import { cancellationRegistry } from "../runs/background/cancellation-registry.js";
36
- import { stageControlRegistry } from "../runs/foreground/stage-control-registry.js";
37
- import { registerIntercomParentSession } from "../intercom/intercom-bridge.js";
38
- import { subscribeIntercomControl } from "../intercom/result-intercom.js";
39
- import { buildIntercomCallbacks } from "../intercom/intercom-routing.js";
40
- import {
41
- installStoreWidget,
42
- installToolExecutionHooks,
43
- } from "../tui/store-widget-installer.js";
44
- import type { WidgetFactory } from "../tui/store-widget-installer.js";
45
- import { buildGraphOverlayAdapter } from "../tui/overlay-adapter.js";
46
- import type { OverlayPiSurface } from "../tui/overlay-adapter.js";
47
- import type { GraphOverlayPort } from "../tui/overlay-adapter.js";
48
- import { renderSessionList } from "../tui/session-list.js";
49
- import { selectRunsForPicker } from "../tui/session-picker.js";
50
- import { renderRunDetail } from "../tui/run-detail.js";
51
-
52
- import { openSessionPicker, openKillConfirm } from "../tui/session-overlays.js";
53
- import {
54
- openInlineInputsForm,
55
- registerInlineFormRenderer,
56
- } from "../tui/inline-form-overlay.js";
57
- import { clearForms } from "../tui/inline-form-store.js";
58
- import {
59
- registerChatSurfaceRenderer,
60
- emitChatSurface,
61
- } from "../tui/chat-surface-message.js";
62
- import { openInputsPicker } from "../tui/inputs-overlay.js";
63
- import { deriveGraphTheme } from "../tui/graph-theme.js";
64
- import { createExtensionRuntime } from "./runtime.js";
65
- import type { ExtensionRuntime } from "./runtime.js";
66
- import {
67
- discoverWorkflows,
68
- discoverStartupWorkflowsSync,
69
- } from "./discovery.js";
70
- import type { DiscoveryResult } from "./discovery.js";
71
- import {
72
- loadWorkflowConfig,
73
- toScopedDiscoveryConfig,
74
- WORKFLOW_CONFIG_DEFAULTS,
75
- withWorkflowDefaults,
76
- } from "./config-loader.js";
77
- import {
78
- createWorkflowLifecycleNotificationState,
79
- installWorkflowLifecycleNotifications,
80
- registerLifecycleNoticeRenderer,
81
- resetWorkflowLifecycleNotificationState,
82
- seedWorkflowLifecycleNotificationState,
83
- withWorkflowLifecycleNotificationsSuppressed,
84
- withWorkflowLifecycleNotificationsSuppressedAsync,
85
- } from "./lifecycle-notifications.js";
86
- import type { WorkflowLifecycleNotificationConfig } from "./lifecycle-notifications.js";
87
- import {
88
- createWorkflowHilAnswerNotificationState,
89
- installWorkflowHilAnswerNotifications,
90
- registerHilAnswerNoticeRenderer,
91
- resetWorkflowHilAnswerNotificationState,
92
- } from "./hil-answer-notifications.js";
93
- import type { ConfigLoadResult } from "./config-loader.js";
94
- import type {
95
- WorkflowPersistencePort,
96
- WorkflowMcpPort,
97
- WorkflowRuntimeConfig,
98
- WorkflowChainStep,
99
- WorkflowDirectTaskItem,
100
- WorkflowDetails,
101
- WorkflowMaxOutput,
102
- WorkflowModelCatalogPort,
103
- WorkflowModelInfo,
104
- StageOptions,
105
- WorkflowExecutionPolicy,
106
- WorkflowInputValues,
107
- WorkflowSerializableValue,
108
- } from "../shared/types.js";
109
- import { INTERACTIVE_WORKFLOW_POLICY, NON_INTERACTIVE_WORKFLOW_POLICY } from "../shared/types.js";
110
- import { buildRuntimeAdapters } from "./wiring.js";
111
- import type { PiUISurface } from "./wiring.js";
112
- import { createStatusWriter } from "./status-writer.js";
113
- import type { StatusWriter } from "./status-writer.js";
114
- import { setMcpScope, clearMcpScope } from "./mcp.js";
115
- import type { PiMcpExtensionAPI, PiEventBus } from "./mcp.js";
116
- import type { StageSessionRuntime } from "../runs/foreground/stage-runner.js";
117
- import {
118
- expandWorkflowGraph,
119
- expandedStageLabel,
120
- stageMatchesExpandedIdentifier,
121
- } from "../shared/expanded-workflow-graph.js";
122
- import { topLevelWorkflowRuns } from "../shared/run-visibility.js";
123
- import {
124
- WORKFLOW_STAGE_SUBAGENT_GUARD_ENV,
125
- getEnvValue,
126
- type CreateAgentSessionOptions,
127
- type DefaultResourceLoaderInheritanceSnapshot,
128
- } from "@bastani/atomic";
129
-
130
- export const WORKFLOW_TOOL_DESCRIPTION =
131
- "Run named workflows or direct one-off task/tasks/chain workflows; " +
132
- "discover with list/get/inputs, inspect status/stages/stage details, " +
133
- "send prompt answers or steering, pause/resume/interrupt/kill runs, and reload workflow resources. " +
134
- "For large stage handoffs, write context to files/artifacts, pass paths via reads, and prompt downstream agents to 'Read the file at <path>...' instead of injecting large previous text. " +
135
- "For transcripts, prefer status/stages/stage to get sessionFile/transcriptPath, " +
136
- "quote the exact path without rewriting separators (Windows backslashes are valid), " +
137
- "then search it with rg/grep and read small ranges; transcript is path-only by default when sessionFile/transcriptPath exists, explicit tail/limit returns bounded previews, and missing transcript paths fall back to a small preview.";
138
-
139
- export const DEFAULT_PROMPT_GUIDANCE: string[] = [
140
- `**Workflows**: Use the \`workflow\` tool for existing named workflows and for repeatable, inspectable, resumable, or multi-stage processes; use direct \`task\`, \`tasks\`, or \`chain\` workflow calls for one-off tracked work when that is useful.
141
- - For unfamiliar named workflows, discover with \`action: "list"\`, inspect with \`action: "get"\` or \`action: "inputs"\`, and run with \`action: "run"\`, \`workflow\`, and validated \`inputs\`; do not invent workflow names or input keys.
142
- - When designing or editing workflows, read docs/workflows.md and reference its Workflow Starter Patterns: Classify-and-act, Fan-out-and-synthesize, Adversarial verification, Generate-and-filter, Tournament, and Loop until done. Choose or combine these patterns before inventing a custom stage graph, and reflect the selected pattern in the spec and Mermaid diagram when using the create-spec skill.
143
- - Once you run a workflow with the workflow tool, end your current turn and wait for the next user input or lifecycle notice.
144
- - You will automatically be alerted of key lifecycle events like start, finish, failure; do not micro-manage the run with sleep/status polling loops or read its logs/stages unless the user asks you to or you need information for the next step.
145
- - If the user needs information from the workflow run, use targeted \`status\`/\`stages\`/\`stage\` checks instead of trying to read everything.
146
- - Offer to help the user on another task instead of anxiously polling or help the user run another workflow if they need.
147
- - Use run-control and messaging actions (\`send\`, \`pause\`, \`resume\`, \`interrupt\`, \`kill\`) only when needed to answer prompts, steer a stage, resume or interrupt paused work, or respond to user requests/control signals.
148
- - For transcripts, avoid reading whole session transcripts at once. Use \`stages\` or \`stage\` to get \`sessionFile\`/\`transcriptPath\`, quote the exact path without rewriting separators (preserve Windows backslashes), search it with \`rg\`/\`grep\`, and read small relevant ranges; use \`transcript\` with explicit \`tail\` or \`limit\` only for quick recent-context checks.
149
- - If a user asks to create or edit a workflow, use the create-spec skill when available and ask detailed clarifying questions until you understand its purpose, inputs, stages, handoffs, validation, success criteria, and selected starter pattern. Then read the workflow docs/examples and implement the workflow from the created spec directly as a TypeScript definition. After you implement the workflow, reload it to access it and run it with test inputs to validate it works as intended before presenting it to the user.
150
- - Tip: when designing workflows, implement it in a way that you pass information from stage to stage by writing it to a file or artifact (either deterministic or model-driven), pass the path with \`reads\`, and explicitly prompt the downstream agent with wording like \`Read the file at <path>...\`; do not inject large \`previous\` payloads or session history into the next prompt unless explicitly requested to.
151
- - If you run \`ralph\` or \`goal\` workflow, define an objective that includes tight scope, concrete and verifiable done criteria, and validation steps; then monitor progress as above instead of doing parallel implementation yourself.`,
152
- ];
153
-
154
- // ---------------------------------------------------------------------------
155
- // Minimal ExtensionAPI structural types
156
- // No `any`; all optional fields use explicit union with undefined.
157
- // cross-ref: pi docs/skills/authoring-extensions.md (ExtensionAPI shape)
158
- // ---------------------------------------------------------------------------
159
-
160
- /** Theme object passed to renderCall/renderResult slots (opaque — not consumed in stubs). */
161
- export type PiTheme = Record<string, string>;
162
-
163
- /** Context object passed to renderCall/renderResult slots. */
164
- export interface PiRenderContext {
165
- state?: {
166
- runId?: string;
167
- stages?: unknown[];
168
- };
169
- invalidate?: () => void;
170
- }
171
-
172
- /** Options bag passed to renderResult. */
173
- export interface PiRenderResultOpts extends RenderResultOpts {}
174
-
175
- export interface PiRenderComponent {
176
- render(width: number): string[];
177
- invalidate?: () => void;
178
- includes(searchString: string): boolean;
179
- }
180
-
181
- export interface PiMessageRenderComponent {
182
- render(width: number): string[];
183
- invalidate?: () => void;
184
- }
185
-
186
- export interface PiMessageRenderOptions {
187
- expanded: boolean;
188
- }
189
-
190
- export type PiMessageRendererResult = string | PiMessageRenderComponent | null | undefined;
191
- export type PiMessageRenderer = (
192
- payload: unknown,
193
- options?: PiMessageRenderOptions,
194
- theme?: unknown,
195
- ) => PiMessageRendererResult;
196
-
197
- function dynamicTextRenderComponent(renderText: (width: number) => string): PiRenderComponent {
198
- return {
199
- render(width: number): string[] {
200
- return renderText(width).split("\n");
201
- },
202
- includes(searchString: string): boolean {
203
- return renderText(120).includes(searchString);
204
- },
205
- };
206
- }
207
-
208
- /**
209
- * Completion for a slash-command argument. Matches pi-tui's `AutocompleteItem`.
210
- * `value` is the text inserted on selection; `label` is the menu display; the
211
- * optional `description` is the secondary line. Without `value`, pi-tui crashes
212
- * in `getBestAutocompleteMatchIndex` (`value.startsWith(prefix)`).
213
- * cross-ref: @earendil-works/pi-tui autocomplete AutocompleteItem
214
- */
215
- export interface PiArgumentCompletion {
216
- value: string;
217
- label: string;
218
- description?: string;
219
- }
220
-
221
- /**
222
- * Canonical slash command options for pi.registerCommand(name, options).
223
- * Mirrors `RegisteredCommand` from pi's `extensibility/extensions/types.ts`
224
- * minus the `name` field (which is the first arg to registerCommand).
225
- * cross-ref: research/docs/2026-05-11-pi-coding-agent-reference.md §4.2
226
- */
227
- export type PiArgumentCompletionResult = PiArgumentCompletion[] | null;
228
-
229
- export interface PiCommandOptions {
230
- description: string;
231
- handler: (args: string, ctx: PiCommandContext) => Promise<void> | void;
232
- getArgumentCompletions?: (partial: string) => PiArgumentCompletionResult;
233
- }
234
-
235
- /**
236
- * Context provided to slash command handlers. Aligns with pi's
237
- * `ExtensionCommandContext` (subset of what we actually consume): the
238
- * host always supplies `ui` and `ui.notify`, so callers print via
239
- * `ctx.ui.notify("…", "info")` directly — no wrapper indirection.
240
- */
241
- interface PiRuntimeModel {
242
- readonly provider: string;
243
- readonly id: string;
244
- }
245
-
246
- interface PiRuntimeModelRegistry {
247
- getAvailable(): PiRuntimeModel[];
248
- }
249
-
250
- interface PiModelContext {
251
- readonly model?: PiRuntimeModel;
252
- readonly modelRegistry?: PiRuntimeModelRegistry;
253
- }
254
-
255
- export interface PiCommandContext extends PiModelContext {
256
- ui: {
257
- notify: (message: string, type?: "info" | "warning" | "error") => void;
258
- } & PiUISurface;
259
- /**
260
- * False when the host bound a no-op UI surface (print/JSON `-p` modes).
261
- * Absent on older hosts and unit-test stubs; treat absence as interactive.
262
- */
263
- hasUI?: boolean;
264
- }
265
-
266
- /** CLI flag registration options. Mirrors the inline options on `ExtensionAPI.registerFlag`. */
267
- export interface PiFlagNamedOpts {
268
- description: string;
269
- type?: "string" | "boolean";
270
- default?: unknown;
271
- }
272
-
273
- /**
274
- * Pi's AgentToolResult shape — returned by `execute` and consumed by
275
- * `renderResult`. `details` carries the original workflow result for the
276
- * renderer; `content` is what the model sees on tool completion.
277
- */
278
- export interface PiAgentToolResult<TDetails> {
279
- content: Array<
280
- { type: "text"; text: string } | { type: "image"; [key: string]: unknown }
281
- >;
282
- details: TDetails;
283
- terminate?: boolean;
284
- }
285
-
286
- /** Tool registration options aligned with pi's `ToolDefinition`. */
287
- export interface PiToolOpts<TArgs, TDetails> {
288
- name: string;
289
- label: string;
290
- description: string;
291
- parameters: unknown; // TypeBox TSchema — pi consumes it opaquely
292
- promptGuidelines?: string[];
293
- renderShell?: "default" | "self";
294
- /**
295
- * Pi calls execute positionally: `(toolCallId, params, signal, onUpdate, ctx)`.
296
- * cross-ref: pi-coding-agent dist/core/extensions/types.d.ts ToolDefinition.execute
297
- */
298
- execute: (
299
- toolCallId: string,
300
- params: TArgs,
301
- signal: AbortSignal | undefined,
302
- onUpdate: ((partial: PiAgentToolResult<TDetails>) => void) | undefined,
303
- ctx: PiExecuteContext,
304
- ) => Promise<PiAgentToolResult<TDetails>>;
305
- /** Pi passes args directly as the first positional arg (not wrapped). */
306
- renderCall?: (
307
- args: TArgs,
308
- theme: PiTheme,
309
- context: PiRenderContext,
310
- ) => PiRenderComponent | string;
311
- /** Pi passes the full AgentToolResult as the first positional arg. */
312
- renderResult?: (
313
- result: PiAgentToolResult<TDetails>,
314
- opts: PiRenderResultOpts,
315
- theme: PiTheme,
316
- context: PiRenderContext,
317
- ) => PiRenderComponent | string;
318
- }
319
-
320
- /** Execution context provided to tool execute handlers. */
321
- export interface PiExecuteContext extends PiModelContext {
322
- sessionId?: string;
323
- ui?: PiUISurface;
324
- hasUI?: boolean;
325
- orchestrationContext?: CreateAgentSessionOptions["orchestrationContext"];
326
- sessionManager?: SessionManager & {
327
- getSessionFile?: () => string | undefined;
328
- };
329
- [key: string]: unknown;
330
- }
331
-
332
- /**
333
- * Structural subset of pi's `ExtensionAPI` (see
334
- * `packages/coding-agent/src/extensibility/extensions/types.ts`) covering
335
- * the methods this extension consumes. Fields are optional so test
336
- * mocks can stub a minimal surface; production runtime supplies all of
337
- * them.
338
- */
339
- export interface WorkflowResourceInfo {
340
- readonly path: string;
341
- readonly enabled: boolean;
342
- readonly metadata?: {
343
- readonly source?: string;
344
- readonly scope?: string;
345
- readonly origin?: string;
346
- readonly baseDir?: string;
347
- };
348
- }
349
-
350
- export interface ExtensionAPI {
351
- registerTool?: <TArgs, TResult>(opts: PiToolOpts<TArgs, TResult>) => void;
352
- /**
353
- * `pi.registerCommand(name, options)` — sole slash-command registration
354
- * surface. Mirrors pi's `ExtensionAPI.registerCommand`.
355
- */
356
- registerCommand?: (name: string, options: PiCommandOptions) => void;
357
- registerMessageRenderer?: (
358
- event: string,
359
- renderer: PiMessageRenderer,
360
- ) => void;
361
- /**
362
- * Inject a custom message into chat history. Used by inline workflow surfaces
363
- * such as `workflows:input-form`; cards stay in scrollback and are
364
- * re-rendered by the registered renderer on every `tui.requestRender()`.
365
- */
366
- sendMessage?: <T = unknown>(
367
- message: {
368
- customType: string;
369
- content?: string;
370
- display?: boolean;
371
- details?: T;
372
- },
373
- options?: {
374
- triggerTurn?: boolean;
375
- deliverAs?: "steer" | "followUp" | "nextTurn" | "interrupt";
376
- excludeFromContext?: boolean;
377
- interruptAbortMessage?: string;
378
- },
379
- ) => void | Promise<void>;
380
- registerFlag?: (name: string, opts: PiFlagNamedOpts) => void;
381
- /** Return package-provided workflow files discovered by Atomic's package loader. */
382
- getWorkflowResources?: () => readonly WorkflowResourceInfo[];
383
- /** Refresh package-provided workflow files before rediscovery, when supported by host. */
384
- refreshWorkflowResources?: () => Promise<readonly WorkflowResourceInfo[]>;
385
- /** Return resource-loader options child Atomic workflow stages should inherit. */
386
- getResourceLoaderInheritanceSnapshot?: () => DefaultResourceLoaderInheritanceSnapshot | undefined;
387
- /**
388
- * Register a keyboard shortcut.
389
- * Present on pi >= 1.x; absent on older runtimes.
390
- */
391
- registerShortcut?: (
392
- key: string,
393
- opts: {
394
- description: string;
395
- handler: (ctx?: PiCommandContext) => void | Promise<void>;
396
- },
397
- ) => void;
398
- /**
399
- * Read the model's currently-active tool names. Present on pi's ExtensionAPI;
400
- * absent on older runtimes.
401
- */
402
- getActiveTools?: () => string[];
403
- /**
404
- * Replace the model's active tool set by name. Present on pi's ExtensionAPI;
405
- * absent on older runtimes.
406
- */
407
- setActiveTools?: (toolNames: string[]) => void;
408
- /**
409
- * Sets the current session name. Present on pi's ExtensionAPI.
410
- */
411
- setSessionName?: (name: string) => void | Promise<void>;
412
- /**
413
- * pi events bus — used for workflow-scoped MCP events and subagent
414
- * lifecycle/result routing.
415
- */
416
- events?: {
417
- emit?: (event: string, payload: Record<string, unknown>) => void;
418
- on?: (event: string, handler: (payload: unknown) => void) => void;
419
- };
420
- /**
421
- * Execute a shell command and return stdout/stderr/exit code.
422
- * Present on the pi ExtensionAPI.
423
- */
424
- exec?: (
425
- command: string,
426
- args: string[],
427
- opts?: { signal?: AbortSignal; timeout?: number },
428
- ) => Promise<{
429
- stdout: string;
430
- stderr: string;
431
- code: number;
432
- killed: boolean;
433
- }>;
434
- /** Test seam: inject a stub session factory instead of importing the pi SDK at runtime. */
435
- createAgentSession?: (
436
- options?: CreateAgentSessionOptions,
437
- ) => Promise<{ session: StageSessionRuntime }>;
438
- /** Test/degraded-runtime seam: skip project/global discovery work at startup. */
439
- disableAsyncDiscovery?: boolean;
440
- // -------------------------------------------------------------------------
441
- // Persistence API (§5.6)
442
- // -------------------------------------------------------------------------
443
- /** Appends a typed entry to the session transcript. Returns the entry ID. */
444
- appendEntry?: (
445
- type: string,
446
- payload: Record<string, unknown>,
447
- ) => string | undefined;
448
- /** Labels an entry for /tree bookmark filtering. */
449
- setLabel?: (entryId: string, label: string) => void;
450
- /** Appends a synthetic system/assistant message entry. */
451
- appendCustomMessageEntry?: (
452
- content: string,
453
- meta?: Record<string, unknown>,
454
- ) => string | undefined;
455
- // -------------------------------------------------------------------------
456
- // Lifecycle events (§5.6, §8.1 Phase D)
457
- // -------------------------------------------------------------------------
458
- /** Register a listener for a pi lifecycle event (e.g. session_start, session_before_compact). */
459
- on?: (
460
- event: string,
461
- handler: (
462
- event?: unknown,
463
- ctx?: PiCommandContext & {
464
- sessionManager?: SessionManager;
465
- hasUI?: boolean;
466
- },
467
- ) => void | object | Promise<void | object>,
468
- ) => void;
469
- // -------------------------------------------------------------------------
470
- // Session manager (§5.6 restore)
471
- // -------------------------------------------------------------------------
472
- sessionManager?: SessionManager;
473
- ui?: {
474
- setWidget?: (
475
- key: string,
476
- factory: WidgetFactory | undefined,
477
- opts?: { placement?: string },
478
- ) => void;
479
- /**
480
- * Spawn a custom TUI component (overlay or inline).
481
- * When overlay: true, the panel floats over existing content.
482
- * Returns a handle with close() to dismiss, or undefined when unsupported.
483
- */
484
- custom?: PiUISurface["custom"];
485
- } & PiUISurface;
486
- [key: string]: unknown;
487
- }
488
-
489
- // ---------------------------------------------------------------------------
490
- // Workflow tool argument shape
491
- // ---------------------------------------------------------------------------
492
-
493
- export interface WorkflowToolArgs extends StageOptions {
494
- /** Canonical named workflow identifier. */
495
- workflow?: string;
496
- inputs?: WorkflowInputValues;
497
- action?:
498
- | "run"
499
- | "list"
500
- | "get"
501
- | "status"
502
- | "stages"
503
- | "stage"
504
- | "transcript"
505
- | "send"
506
- | "pause"
507
- | "interrupt"
508
- | "kill"
509
- | "resume"
510
- | "reload"
511
- | "inputs";
512
- /** Canonical run identifier or unique prefix for status/interrupt/kill/resume. */
513
- runId?: string;
514
- /** Apply supported run-control actions to all in-flight runs. */
515
- all?: boolean;
516
- /** Stage id, unique prefix, or name for stage-scoped resume. */
517
- stageId?: string;
518
- /** Optional message forwarded when resuming paused work. */
519
- message?: string;
520
- statusFilter?: StageStatus | "all";
521
- format?: "text" | "json";
522
- limit?: number;
523
- tail?: number;
524
- includeToolOutput?: boolean;
525
- text?: string;
526
- response?: unknown;
527
- delivery?: "auto" | "answer" | "prompt" | "steer" | "followUp" | "resume";
528
- promptId?: string;
529
- reason?: string;
530
- /** Direct single-task mode, or root task string when chain is present. */
531
- task?: WorkflowDirectTaskItem | string;
532
- /** Direct top-level parallel mode. */
533
- tasks?: WorkflowDirectTaskItem[];
534
- /** Direct sequential/parallel chain mode. */
535
- chain?: WorkflowChainStep[];
536
- chainName?: string;
537
- context?: "fresh" | "fork";
538
- /** Internal host-derived parent session file for context:"fork". */
539
- forkFromSessionFile?: string;
540
- concurrency?: number;
541
- failFast?: boolean;
542
- async?: boolean;
543
- intercom?: {
544
- enabled?: boolean;
545
- delivery?: "off" | "notify" | "result" | "control-and-result";
546
- parentSession?: string;
547
- notifyOn?: Array<
548
- "active_long_running" | "needs_attention" | "completed" | "failed"
549
- >;
550
- };
551
- output?: string | false;
552
- outputMode?: "inline" | "file-only";
553
- reads?: readonly string[] | false;
554
- chainDir?: string;
555
- maxOutput?: WorkflowMaxOutput;
556
- artifacts?: boolean;
557
- worktree?: boolean;
558
- gitWorktreeDir?: string;
559
- baseBranch?: string;
560
- }
561
-
562
- // ---------------------------------------------------------------------------
563
- // Tool parameter schema
564
- // ---------------------------------------------------------------------------
565
-
566
- const workflowParameters = WorkflowParametersSchema;
567
-
568
- function hasDirectExecutionMode(args: WorkflowToolArgs): boolean {
569
- return (
570
- (args.task !== undefined && typeof args.task === "object") ||
571
- Array.isArray(args.tasks) ||
572
- Array.isArray(args.chain)
573
- );
574
- }
575
-
576
- function directModeCount(args: WorkflowToolArgs): number {
577
- return [
578
- args.task !== undefined && typeof args.task === "object",
579
- Array.isArray(args.tasks),
580
- Array.isArray(args.chain),
581
- ].filter(Boolean).length;
582
- }
583
-
584
- function hasNamedExecutionMode(args: WorkflowToolArgs): boolean {
585
- return typeof args.workflow === "string" && args.workflow.trim().length > 0;
586
- }
587
-
588
- function directRequestsFork(args: WorkflowToolArgs): boolean {
589
- if (args.context === "fork") return true;
590
- if (
591
- args.task !== undefined &&
592
- typeof args.task === "object" &&
593
- args.task.context === "fork"
594
- )
595
- return true;
596
- if (args.tasks?.some((task) => task.context === "fork")) return true;
597
- return (
598
- args.chain?.some((step) =>
599
- "parallel" in step
600
- ? step.parallel.some((task) => task.context === "fork")
601
- : step.context === "fork",
602
- ) ?? false
603
- );
604
- }
605
-
606
- function withForkParentSession(
607
- args: WorkflowToolArgs,
608
- ctx: PiExecuteContext,
609
- ): WorkflowToolArgs {
610
- if (!directRequestsFork(args) || args.forkFromSessionFile !== undefined)
611
- return args;
612
- const sessionFile = ctx.sessionManager?.getSessionFile?.();
613
- return typeof sessionFile === "string" && sessionFile.length > 0
614
- ? { ...args, forkFromSessionFile: sessionFile }
615
- : args;
616
- }
617
-
618
- function workflowRunResultFromDetails(
619
- details: WorkflowDetails,
620
- ): WorkflowToolResult {
621
- return {
622
- action: "run",
623
- name: `direct-${details.mode}`,
624
- runId: details.runId ?? "",
625
- status: details.status,
626
- result: details.output,
627
- details,
628
- error: details.error,
629
- stages: [],
630
- };
631
- }
632
-
633
- function stringifyWorkflowToolResult(result: WorkflowToolResult): string {
634
- return JSON.stringify(result, null, 2);
635
- }
636
-
637
- function compactWorkflowToolMessage(
638
- result: Extract<WorkflowToolResult, {
639
- action: "send" | "pause" | "reload" | "interrupt" | "kill" | "resume";
640
- }>,
641
- ): string {
642
- if (result.action === "reload") {
643
- return `${result.action}: ${result.status} — ${result.message}`;
644
- }
645
- const target = [
646
- result.runId,
647
- result.action === "send" ? result.stageId : undefined,
648
- ].filter((part): part is string => part !== undefined && part.length > 0)
649
- .join("/");
650
- return `${result.action}:${target ? ` ${target}` : ""} ${result.status} — ${result.message}`;
651
- }
652
-
653
- function renderTranscriptToolContent(
654
- result: Extract<WorkflowToolResult, { action: "transcript" }>,
655
- ): string {
656
- const lines = [
657
- `action: transcript`,
658
- `runId: ${result.runId}`,
659
- `stageId: ${result.stageId}`,
660
- `source: ${result.source}`,
661
- `truncated: ${result.truncated}`,
662
- ];
663
- if (result.sessionId) lines.push(`sessionId: ${result.sessionId}`);
664
- if (result.sessionFile) lines.push(`sessionFile: ${result.sessionFile}`);
665
- if (result.sessionFile) lines.push(`sessionFileJson: ${JSON.stringify(result.sessionFile)}`);
666
- if (result.transcriptPath) lines.push(`transcriptPath: ${result.transcriptPath}`);
667
- if (result.transcriptPath) lines.push(`transcriptPathJson: ${JSON.stringify(result.transcriptPath)}`);
668
- if (result.entryCount !== undefined) lines.push(`availableEntries: ${result.entryCount}`);
669
- if (result.entryLimit !== undefined) lines.push(`entryLimit: ${result.entryLimit}`);
670
- if (result.lazyReadPrompt) lines.push(`lazyReadPrompt: ${result.lazyReadPrompt}`);
671
- if (result.fallbackNote) lines.push(`fallbackNote: ${result.fallbackNote}`);
672
- if (result.entries.length === 0) {
673
- lines.push(result.inlineMode === "path_only" || result.lazyReadPrompt ? "entries: not inlined" : "entries: none");
674
- return lines.join("\n");
675
- }
676
- lines.push("entries:");
677
- result.entries.forEach((entry, index) => {
678
- const metadata = [
679
- `[${index + 1}]`,
680
- `role=${entry.role}`,
681
- entry.toolName ? `tool=${entry.toolName}` : undefined,
682
- entry.timestamp !== undefined ? `timestamp=${entry.timestamp}` : undefined,
683
- ].filter((part): part is string => part !== undefined);
684
- lines.push(metadata.join(" "));
685
- if (entry.text !== undefined) lines.push(entry.text);
686
- if (entry.output !== undefined) {
687
- lines.push("tool output:");
688
- lines.push(entry.output);
689
- }
690
- if (entry.text === undefined && entry.output === undefined) {
691
- lines.push("(no body)");
692
- }
693
- });
694
- return lines.join("\n");
695
- }
696
-
697
- function renderStagesToolContent(
698
- result: Extract<WorkflowToolResult, { action: "stages" }>,
699
- ): string {
700
- const lines = [
701
- "action: stages",
702
- `runId: ${result.runId}`,
703
- `filter: ${result.filter}`,
704
- ];
705
- if (result.error) lines.push(`error: ${result.error}`);
706
- if (result.stages.length === 0) {
707
- lines.push("stages: none");
708
- return lines.join("\n");
709
- }
710
- lines.push("stages:");
711
- result.stages.forEach((stage, index) => {
712
- lines.push(`[${index + 1}] ${stage.name} (${stage.id}) ${stage.status}`);
713
- if (stage.sessionId) lines.push(`sessionId: ${stage.sessionId}`);
714
- if (stage.sessionFile) lines.push(`sessionFile: ${stage.sessionFile}`);
715
- if (stage.sessionFile) lines.push(`sessionFileJson: ${JSON.stringify(stage.sessionFile)}`);
716
- if (stage.transcriptPath) lines.push(`transcriptPath: ${stage.transcriptPath}`);
717
- if (stage.transcriptPath) lines.push(`transcriptPathJson: ${JSON.stringify(stage.transcriptPath)}`);
718
- if (stage.error) lines.push(`error: ${stage.error}`);
719
- if (stage.skippedReason) lines.push(`skippedReason: ${stage.skippedReason}`);
720
- if (stage.awaitingInputSince !== undefined) {
721
- lines.push(`awaitingInputSince: ${stage.awaitingInputSince}`);
722
- }
723
- if (stage.pendingPrompt !== undefined) {
724
- lines.push("pendingPrompt:");
725
- lines.push(JSON.stringify(stage.pendingPrompt, null, 2));
726
- }
727
- if (stage.inputRequest !== undefined) {
728
- lines.push("inputRequest:");
729
- lines.push(JSON.stringify(stage.inputRequest, null, 2));
730
- }
731
- if (stage.promptFootprint !== undefined) {
732
- lines.push("promptFootprint:");
733
- lines.push(JSON.stringify(stage.promptFootprint, null, 2));
734
- }
735
- });
736
- return lines.join("\n");
737
- }
738
-
739
- function renderStageToolContent(
740
- result: Extract<WorkflowToolResult, { action: "stage" }>,
741
- ): string {
742
- const lines = ["action: stage", `runId: ${result.runId}`];
743
- if (result.error || result.stage === undefined) {
744
- lines.push(`error: ${result.error ?? "stage not found"}`);
745
- return lines.join("\n");
746
- }
747
- lines.push("stage:");
748
- lines.push(JSON.stringify(result.stage, null, 2));
749
- if (result.stage.sessionFile) {
750
- lines.push(`transcriptPath: ${result.stage.sessionFile}`);
751
- lines.push(`transcriptPathJson: ${JSON.stringify(result.stage.sessionFile)}`);
752
- }
753
- return lines.join("\n");
754
- }
755
-
756
- function renderWorkflowToolContent(
757
- result: WorkflowToolResult,
758
- args: WorkflowToolArgs,
759
- ): string {
760
- if (args.format === "json") return stringifyWorkflowToolResult(result);
761
-
762
- switch (result.action) {
763
- case "transcript":
764
- return renderTranscriptToolContent(result);
765
- case "stages":
766
- return renderStagesToolContent(result);
767
- case "stage":
768
- return renderStageToolContent(result);
769
- case "send":
770
- case "pause":
771
- case "reload":
772
- case "interrupt":
773
- case "kill":
774
- case "resume":
775
- return compactWorkflowToolMessage(result);
776
- case "list":
777
- case "status":
778
- case "statusDetail":
779
- case "inputs":
780
- case "get":
781
- case "run":
782
- return stringifyWorkflowToolResult(result);
783
- }
784
- }
785
-
786
- function workflowGetResult(
787
- runtime: ExtensionRuntime,
788
- args: WorkflowToolArgs,
789
- ): WorkflowToolResult {
790
- const workflow = args.workflow ?? "";
791
- const def = runtime.registry.get(workflow);
792
- if (!def) {
793
- return {
794
- action: "get",
795
- workflow,
796
- error: `Workflow not found: "${workflow}"`,
797
- };
798
- }
799
- const inputs = deriveInputFields(def.inputs);
800
- return {
801
- action: "get",
802
- workflow: def.normalizedName,
803
- details: {
804
- mode: "inspection",
805
- action: "get",
806
- status: "completed",
807
- output: {
808
- workflow: def.normalizedName,
809
- name: def.name,
810
- description: def.description,
811
- inputs: inputs as unknown as WorkflowSerializableValue[],
812
- },
813
- progress: { completed: 0, total: 0 },
814
- },
815
- };
816
- }
817
-
818
- // ---------------------------------------------------------------------------
819
- // Stage tool helpers
820
- // ---------------------------------------------------------------------------
821
-
822
- type WorkflowStageSummary = {
823
- id: string;
824
- name: string;
825
- status: StageStatus;
826
- sessionId?: string;
827
- sessionFile?: string;
828
- transcriptPath?: string;
829
- error?: string;
830
- skippedReason?: string;
831
- awaitingInputSince?: number;
832
- pendingPrompt?: StageSnapshot["pendingPrompt"];
833
- inputRequest?: StageSnapshot["inputRequest"];
834
- promptFootprint?: StageSnapshot["promptFootprint"];
835
- };
836
-
837
- type WorkflowTranscriptEntry = {
838
- role: string;
839
- text?: string;
840
- toolName?: string;
841
- output?: string;
842
- timestamp?: number;
843
- };
844
-
845
- type MessageContentBlock = { readonly type?: string; readonly text?: string };
846
- type MessageLike = {
847
- readonly role?: string;
848
- readonly content?: string | readonly MessageContentBlock[];
849
- readonly name?: string;
850
- readonly toolName?: string;
851
- readonly timestamp?: number;
852
- readonly createdAt?: number;
853
- };
854
-
855
- function cloneStage(stage: StageSnapshot): StageSnapshot & { transcriptPath?: string } {
856
- const cloned = structuredClone(stage) as StageSnapshot & { transcriptPath?: string };
857
- if (cloned.sessionFile !== undefined) cloned.transcriptPath = cloned.sessionFile;
858
- return cloned;
859
- }
860
-
861
- function summarizeStage(stage: StageSnapshot): WorkflowStageSummary {
862
- return {
863
- id: stage.id,
864
- name: stage.name,
865
- status: stage.status,
866
- sessionId: stage.sessionId,
867
- sessionFile: stage.sessionFile,
868
- transcriptPath: stage.sessionFile,
869
- error: stage.error,
870
- skippedReason: stage.skippedReason,
871
- awaitingInputSince: stage.awaitingInputSince,
872
- pendingPrompt: stage.pendingPrompt === undefined
873
- ? undefined
874
- : structuredClone(stage.pendingPrompt),
875
- inputRequest: stage.inputRequest === undefined
876
- ? undefined
877
- : structuredClone(stage.inputRequest),
878
- promptFootprint: stage.promptFootprint === undefined
879
- ? undefined
880
- : structuredClone(stage.promptFootprint),
881
- };
882
- }
883
-
884
- const DEFAULT_TRANSCRIPT_LIMIT = 5;
885
-
886
- type TranscriptEntrySelection = {
887
- entries: WorkflowTranscriptEntry[];
888
- truncated: boolean;
889
- entryCount: number;
890
- entryLimit?: number;
891
- };
892
-
893
- type WorkflowTranscriptResult = Extract<WorkflowToolResult, { action: "transcript" }>;
894
-
895
- function isTranscriptPreviewExplicit(args: WorkflowToolArgs): boolean {
896
- return args.tail !== undefined || args.limit !== undefined;
897
- }
898
-
899
- function requestedTranscriptEntryLimit(args: WorkflowToolArgs): number {
900
- const raw = args.tail ?? args.limit;
901
- if (raw === undefined) return DEFAULT_TRANSCRIPT_LIMIT;
902
- if (!Number.isFinite(raw) || raw <= 0) return 0;
903
- return Math.floor(raw);
904
- }
905
-
906
- function selectTranscriptEntries(
907
- entries: readonly WorkflowTranscriptEntry[],
908
- args: WorkflowToolArgs,
909
- ): TranscriptEntrySelection {
910
- const count = requestedTranscriptEntryLimit(args);
911
- const entryCount = entries.length;
912
- if (count === 0) {
913
- return {
914
- entries: [],
915
- truncated: false,
916
- entryCount,
917
- entryLimit: count,
918
- };
919
- }
920
- if (entries.length <= count) {
921
- return {
922
- entries: [...entries],
923
- truncated: false,
924
- entryCount,
925
- entryLimit: count,
926
- };
927
- }
928
- return {
929
- entries: entries.slice(entries.length - count),
930
- truncated: true,
931
- entryCount,
932
- entryLimit: count,
933
- };
934
- }
935
-
936
- function transcriptLazyReadPrompt(path: string): string {
937
- return `Transcript not inlined to protect context. Read it lazily from ${path} with your file read tools (read small ranges; rg/grep for targeted lookups).`;
938
- }
939
-
940
- function transcriptFallbackNote(limit: number): string {
941
- return `No transcript file path is available for this stage; falling back to a bounded inline preview of up to ${limit} recent ${limit === 1 ? "entry" : "entries"}.`;
942
- }
943
-
944
- /**
945
- * Shape a transcript tool result, keeping the context-safe path-only default
946
- * the cheap hot path for the large runs #1314 protects against.
947
- *
948
- * `buildEntries` is a thunk so the default case (a transcript file path exists
949
- * and no explicit `tail`/`limit` was requested) never materializes entry bodies
950
- * just to discard them. Only the caller-provided `entryCount` is needed for the
951
- * advisory count, which matches what `buildEntries()` would yield. The thunk is
952
- * invoked solely for the explicit-preview and no-path fallback branches.
953
- */
954
- function shapeTranscriptResult(input: {
955
- runId: string;
956
- stageId: string;
957
- source: "live" | "snapshot";
958
- entryCount: number;
959
- buildEntries: () => readonly WorkflowTranscriptEntry[];
960
- args: WorkflowToolArgs;
961
- sessionId?: string | undefined;
962
- sessionFile?: string | undefined;
963
- transcriptPath?: string | undefined;
964
- }): WorkflowTranscriptResult {
965
- // `transcriptPath` already falls back to `sessionFile`, so it is the single
966
- // resolved path the agent should lazily read.
967
- const transcriptPath = input.transcriptPath ?? input.sessionFile;
968
- if (transcriptPath !== undefined && !isTranscriptPreviewExplicit(input.args)) {
969
- const result: WorkflowTranscriptResult = {
970
- action: "transcript",
971
- runId: input.runId,
972
- stageId: input.stageId,
973
- source: input.source,
974
- entries: [],
975
- // `truncated` here means "more transcript exists on disk than was inlined"
976
- // (everything, since the default inlines nothing), not "an explicit limit
977
- // clipped results". It only drives the cosmetic "(truncated)" notice
978
- // suffix; no consumer re-fetches on it.
979
- truncated: input.entryCount > 0,
980
- entryCount: input.entryCount,
981
- entryLimit: 0,
982
- lazyReadPrompt: transcriptLazyReadPrompt(transcriptPath),
983
- inlineMode: "path_only",
984
- };
985
- if (input.sessionId !== undefined) result.sessionId = input.sessionId;
986
- if (input.sessionFile !== undefined) result.sessionFile = input.sessionFile;
987
- result.transcriptPath = transcriptPath;
988
- return result;
989
- }
990
-
991
- const limited = selectTranscriptEntries(input.buildEntries(), input.args);
992
- const result: WorkflowTranscriptResult = {
993
- action: "transcript",
994
- runId: input.runId,
995
- stageId: input.stageId,
996
- source: input.source,
997
- entries: limited.entries,
998
- truncated: limited.truncated,
999
- entryCount: limited.entryCount,
1000
- entryLimit: limited.entryLimit,
1001
- inlineMode: transcriptPath === undefined ? "fallback_preview" : "preview",
1002
- };
1003
- if (input.sessionId !== undefined) result.sessionId = input.sessionId;
1004
- if (input.sessionFile !== undefined) result.sessionFile = input.sessionFile;
1005
- if (transcriptPath !== undefined) result.transcriptPath = transcriptPath;
1006
- if (transcriptPath === undefined) result.fallbackNote = transcriptFallbackNote(limited.entryLimit ?? DEFAULT_TRANSCRIPT_LIMIT);
1007
- return result;
1008
- }
1009
-
1010
- function messageText(content: MessageLike["content"]): string | undefined {
1011
- if (typeof content === "string") return content;
1012
- if (!Array.isArray(content)) return undefined;
1013
- let sawTextBlock = false;
1014
- const text = content
1015
- .map((block) => {
1016
- if (block.type === "text" && typeof block.text === "string") {
1017
- sawTextBlock = true;
1018
- return block.text;
1019
- }
1020
- return "";
1021
- })
1022
- .join("");
1023
- return sawTextBlock ? text : undefined;
1024
- }
1025
-
1026
- function transcriptEntryFromMessage(message: MessageLike): WorkflowTranscriptEntry {
1027
- const entry: WorkflowTranscriptEntry = { role: message.role ?? "unknown" };
1028
- const text = messageText(message.content);
1029
- if (text !== undefined) entry.text = text;
1030
- const toolName = message.toolName ?? message.name;
1031
- if (toolName !== undefined) entry.toolName = toolName;
1032
- const timestamp = message.timestamp ?? message.createdAt;
1033
- if (timestamp !== undefined) entry.timestamp = timestamp;
1034
- return entry;
1035
- }
1036
-
1037
- function transcriptEntriesFromToolEvents(
1038
- events: readonly ToolEvent[],
1039
- includeOutput: boolean,
1040
- ): WorkflowTranscriptEntry[] {
1041
- return events.map((event) => ({
1042
- role: "tool",
1043
- toolName: event.name,
1044
- output: includeOutput ? event.output : undefined,
1045
- timestamp: event.endedAt ?? event.startedAt,
1046
- }));
1047
- }
1048
-
1049
- function hasPayloadProperty(args: WorkflowToolArgs): boolean {
1050
- return (
1051
- args.text !== undefined ||
1052
- args.response !== undefined ||
1053
- args.message !== undefined
1054
- );
1055
- }
1056
-
1057
- function promptPayloadFromArgs(args: WorkflowToolArgs): unknown {
1058
- if (args.response !== undefined) return args.response;
1059
- if (args.text !== undefined) return args.text;
1060
- return args.message;
1061
- }
1062
-
1063
- /**
1064
- * Shape a `send` payload into a headless answer for a brokered stage prompt
1065
- * (ask_user_question / readiness gate). A structured `response` (object or
1066
- * JSON string) is normalized so it matches the question's options instead of
1067
- * being forwarded verbatim as a result that violates the QuestionnaireResult
1068
- * contract; otherwise the plain text / message payload is matched against
1069
- * option labels / indices by the stage prompt adapter.
1070
- */
1071
- function brokerAnswerFromArgs(args: WorkflowToolArgs): StageInputAnswer {
1072
- if (args.response !== undefined) {
1073
- const coerced = coerceStageInputAnswer(args.response);
1074
- if (hasStageInputAnswerContent(coerced)) return coerced;
1075
- }
1076
- const text = textPayloadFromArgs(args);
1077
- return text !== undefined ? { text } : {};
1078
- }
1079
-
1080
- function textPayloadFromArgs(args: WorkflowToolArgs): string | undefined {
1081
- if (args.text !== undefined) return args.text;
1082
- if (typeof args.response === "string") {
1083
- return args.response;
1084
- }
1085
- if (args.message !== undefined) return args.message;
1086
- return undefined;
1087
- }
1088
-
1089
- type WorkflowSendToolResult = Extract<WorkflowToolResult, { action: "send" }>;
1090
-
1091
- function workflowSendResult(
1092
- runId: string,
1093
- stageId: string,
1094
- delivery: WorkflowSendToolResult["delivery"],
1095
- status: WorkflowSendToolResult["status"],
1096
- message: string,
1097
- ): WorkflowSendToolResult {
1098
- return { action: "send", runId, stageId, delivery, status, message };
1099
- }
1100
-
1101
- function sortTranscriptEntriesChronologically(
1102
- entries: readonly WorkflowTranscriptEntry[],
1103
- ): WorkflowTranscriptEntry[] {
1104
- return entries
1105
- .map((entry, index) => ({ entry, index }))
1106
- .sort((a, b) => {
1107
- const aTimestamp = a.entry.timestamp;
1108
- const bTimestamp = b.entry.timestamp;
1109
- if (
1110
- typeof aTimestamp === "number" &&
1111
- typeof bTimestamp === "number" &&
1112
- aTimestamp !== bTimestamp
1113
- ) {
1114
- return aTimestamp - bTimestamp;
1115
- }
1116
- return a.index - b.index;
1117
- })
1118
- .map(({ entry }) => entry);
1119
- }
1120
-
1121
- function terminalTranscriptEntry(
1122
- role: "assistant" | "notice",
1123
- text: string,
1124
- endedAt: number | undefined,
1125
- ): WorkflowTranscriptEntry {
1126
- const entry: WorkflowTranscriptEntry = { role, text };
1127
- if (endedAt !== undefined) entry.timestamp = endedAt;
1128
- return entry;
1129
- }
1130
-
1131
- function snapshotTranscriptEntries(
1132
- snapshot: StageSnapshot | undefined,
1133
- includeOutput: boolean,
1134
- ): WorkflowTranscriptEntry[] {
1135
- if (snapshot === undefined) return [];
1136
- const entries: WorkflowTranscriptEntry[] = [
1137
- ...transcriptEntriesFromToolEvents(snapshot.toolEvents ?? [], includeOutput),
1138
- ];
1139
- if (snapshot.result !== undefined) {
1140
- entries.push(terminalTranscriptEntry("assistant", snapshot.result, snapshot.endedAt));
1141
- }
1142
- if (snapshot.error !== undefined) {
1143
- entries.push(terminalTranscriptEntry("notice", snapshot.error, snapshot.endedAt));
1144
- }
1145
- return sortTranscriptEntriesChronologically(entries);
1146
- }
1147
-
1148
- function formatAlreadyEndedRetainedMessage(runId: string): string {
1149
- return `Run ${runId.slice(0, 8)} already ended; retained for inspection.`;
1150
- }
1151
-
1152
- function stageFailureMessage(
1153
- runId: string,
1154
- resultReason: string,
1155
- action: "pause" | "interrupt",
1156
- ): string {
1157
- switch (resultReason) {
1158
- case "not_found":
1159
- return `Run not found: ${runId}`;
1160
- case "already_ended":
1161
- return `Run already ended: ${runId}`;
1162
- case "stage_not_found":
1163
- return `Stage not found for run: ${runId}`;
1164
- default:
1165
- return `No active stages to ${action} for run: ${runId}`;
1166
- }
1167
- }
1168
-
1169
- function inFlightRunCount(): number {
1170
- return topLevelWorkflowRuns(store.runs()).filter((run) => run.endedAt === undefined).length;
1171
- }
1172
-
1173
- function topLevelExpandedSnapshots() {
1174
- const snapshot = store.snapshot();
1175
- return topLevelWorkflowRuns(snapshot.runs).map((run) => ({
1176
- ...structuredClone(run),
1177
- stages: expandWorkflowGraph(snapshot, run.id).stages.map((stage) => structuredClone(stage)),
1178
- }));
1179
- }
1180
-
1181
- function reloadBlockedMessage(count = inFlightRunCount()): string {
1182
- return `Reload skipped: ${count} workflow run(s) still in flight. Wait for them to finish, or pause/kill them before reloading workflow resources.`;
1183
- }
1184
-
1185
- function allStageConflictMessage(action: "pause" | "interrupt" | "kill"): string {
1186
- return `Cannot ${action} --all with a stageId; omit stageId or target a single run.`;
1187
- }
1188
-
1189
- class WorkflowReloadBlockedError extends Error {
1190
- constructor(message: string) {
1191
- super(message);
1192
- this.name = "WorkflowReloadBlockedError";
1193
- }
1194
- }
1195
-
1196
- function reloadFailureMessage(error: unknown): string {
1197
- if (error instanceof WorkflowReloadBlockedError) return error.message;
1198
- return `Reload failed: ${error instanceof Error ? error.message : String(error)}`;
1199
- }
1200
-
1201
- function hasWorkflowStageSubagentGuardEnv(): boolean {
1202
- return getEnvValue(WORKFLOW_STAGE_SUBAGENT_GUARD_ENV) === "1";
1203
- }
1204
-
1205
- function isWorkflowStageToolContext(ctx: PiExecuteContext): boolean {
1206
- return hasWorkflowStageSubagentGuardEnv() || ctx.orchestrationContext?.kind === "workflow-stage";
1207
- }
1208
-
1209
- /**
1210
- * Legacy message retained for consumers that imported the old refusal string.
1211
- * Non-interactive sessions now keep the workflow tool and `/workflow` command
1212
- * available; policy gates interactive pickers and runtime human-input APIs.
1213
- */
1214
- export const WORKFLOW_NON_INTERACTIVE_MESSAGE =
1215
- "Workflows are policy-gated in non-interactive (-p) mode; deterministic workflows can run headlessly while runtime human input remains unavailable.";
1216
-
1217
- export function workflowPolicyFromContext(ctx?: { readonly hasUI?: boolean }): WorkflowExecutionPolicy {
1218
- if (ctx?.hasUI === false) {
1219
- return NON_INTERACTIVE_WORKFLOW_POLICY;
1220
- }
1221
- return INTERACTIVE_WORKFLOW_POLICY;
1222
- }
1223
-
1224
- function isRunStatus(value: string): value is RunStatus {
1225
- switch (value) {
1226
- case "pending":
1227
- case "running":
1228
- case "paused":
1229
- case "completed":
1230
- case "skipped":
1231
- case "cancelled":
1232
- case "blocked":
1233
- case "failed":
1234
- case "killed":
1235
- return true;
1236
- default:
1237
- return false;
1238
- }
1239
- }
1240
-
1241
- function fallbackRunDetailFromResult(
1242
- workflowName: string,
1243
- inputs: Readonly<WorkflowInputValues>,
1244
- result: Extract<WorkflowToolResult, { action: "run"; runId: string }>,
1245
- ): RunDetail {
1246
- const now = Date.now();
1247
- const stages = result.stages?.map((stage) => structuredClone(stage)) ?? [];
1248
- // This path is a degraded last-resort view used only when the retained run
1249
- // snapshot has disappeared before output rendering. Timestamps are synthetic,
1250
- // so prefer a conservative failed status over fabricating success if the tool
1251
- // result status is not one of the known run states.
1252
- return {
1253
- runId: result.runId,
1254
- name: result.name ?? workflowName,
1255
- status: isRunStatus(result.status) ? result.status : "failed",
1256
- mode: stages.length > 1 ? "chain" : "single",
1257
- startedAt: now,
1258
- endedAt: now,
1259
- durationMs: 0,
1260
- inputs,
1261
- stages,
1262
- result: result.result,
1263
- error: result.error,
1264
- exited: result.exited,
1265
- exitReason: result.exitReason,
1266
- };
1267
- }
1268
-
1269
- function emitTerminalRunDetailSurface(
1270
- pi: ExtensionAPI,
1271
- workflowName: string,
1272
- inputs: Readonly<WorkflowInputValues>,
1273
- result: Extract<WorkflowToolResult, { action: "run"; runId: string }>,
1274
- ): void {
1275
- const inspected = inspectRun(result.runId);
1276
- const detail = inspected.ok
1277
- ? inspected.detail
1278
- : fallbackRunDetailFromResult(workflowName, inputs, result);
1279
- emitChatSurface(
1280
- pi,
1281
- { kind: "detail", detail },
1282
- { content: renderRunDetail(detail, { width: 100 }) },
1283
- );
1284
- }
1285
-
1286
- export const WORKFLOW_COMMAND_OUTPUT_CUSTOM_TYPE = "workflows:command-output";
1287
-
1288
- interface WorkflowCommandOutputDetails {
1289
- readonly command: string;
1290
- readonly workflowName?: string;
1291
- }
1292
-
1293
- function emitWorkflowCommandOutput(
1294
- pi: ExtensionAPI,
1295
- content: string,
1296
- details: WorkflowCommandOutputDetails,
1297
- ): void {
1298
- if (typeof pi.sendMessage !== "function") return;
1299
- void pi.sendMessage<WorkflowCommandOutputDetails>({
1300
- customType: WORKFLOW_COMMAND_OUTPUT_CUSTOM_TYPE,
1301
- content,
1302
- display: true,
1303
- details,
1304
- });
1305
- }
1306
-
1307
- interface WorkflowCommandReporter {
1308
- info(message: string): void;
1309
- error(message: string): void;
1310
- }
1311
-
1312
- function formatAvailableWorkflowNames(names: readonly string[]): string {
1313
- return names.length > 0 ? names.join(", ") : "(none)";
1314
- }
1315
-
1316
- const ASK_USER_QUESTION_TOOL_NAME = "ask_user_question";
1317
-
1318
- function deAdvertiseAskUserQuestionWhenHeadless(
1319
- pi: ExtensionAPI,
1320
- hasUI: boolean | undefined,
1321
- ): void {
1322
- if (hasUI !== false) return;
1323
- if (typeof pi.getActiveTools !== "function" || typeof pi.setActiveTools !== "function") return;
1324
-
1325
- const activeTools = pi.getActiveTools();
1326
- if (!activeTools.includes(ASK_USER_QUESTION_TOOL_NAME)) return;
1327
-
1328
- pi.setActiveTools(activeTools.filter((toolName) => toolName !== ASK_USER_QUESTION_TOOL_NAME));
1329
- }
1330
-
1331
- class WorkflowHeadlessCommandError extends Error {
1332
- constructor(message: string) {
1333
- super(message);
1334
- this.name = "WorkflowHeadlessCommandError";
1335
- }
1336
- }
1337
-
1338
- function createWorkflowCommandReporter(
1339
- ctx: PiCommandContext,
1340
- policy: WorkflowExecutionPolicy = workflowPolicyFromContext(ctx),
1341
- pi?: ExtensionAPI,
1342
- ): WorkflowCommandReporter {
1343
- return {
1344
- info(message: string): void {
1345
- if (policy.mode === "non_interactive") {
1346
- if (pi) {
1347
- emitWorkflowCommandOutput(pi, message, { command: "message" });
1348
- }
1349
- return;
1350
- }
1351
- ctx.ui.notify(message, "info");
1352
- },
1353
- error(message: string): void {
1354
- if (policy.mode === "non_interactive") {
1355
- throw new WorkflowHeadlessCommandError(message);
1356
- }
1357
- ctx.ui.notify(message, "error");
1358
- },
1359
- };
1360
- }
1361
-
1362
- // ---------------------------------------------------------------------------
1363
- // Tool execute — dispatch with real registry for list/inputs/run (Phase E)
1364
- // + real status/interrupt/resume (Phase D)
1365
- // ---------------------------------------------------------------------------
1366
-
1367
- export function makeExecuteWorkflowTool(
1368
- runtime: ExtensionRuntime | ((ctx: PiExecuteContext) => ExtensionRuntime),
1369
- getPersistence: () => WorkflowPersistencePort | undefined,
1370
- reloadWorkflowResources: () => Promise<void> | void,
1371
- ) {
1372
- return async function executeWorkflowTool(
1373
- args: WorkflowToolArgs,
1374
- ctx: PiExecuteContext,
1375
- ): Promise<WorkflowToolResult> {
1376
- const action = args.action ?? "run";
1377
- const runId = args.runId ?? "";
1378
- if (isWorkflowStageToolContext(ctx)) {
1379
- // Workflow stages must not invoke the workflow tool at all, including
1380
- // read-only inspection actions. The tool is normally excluded from stage
1381
- // sessions; this guard is a defense-in-depth fallback for stale or
1382
- // hand-crafted registrations.
1383
- return {
1384
- action: "run",
1385
- runId,
1386
- status: "failed",
1387
- error: "workflows cannot invoke workflows from workflow stages",
1388
- stages: [],
1389
- };
1390
- }
1391
- const activeRuntime =
1392
- typeof runtime === "function" ? runtime(ctx) : runtime;
1393
- const policy = workflowPolicyFromContext(ctx);
1394
-
1395
- switch (action) {
1396
- case "get":
1397
- return workflowGetResult(activeRuntime, args);
1398
-
1399
- case "list":
1400
- case "inputs":
1401
- case "run":
1402
- if (action === "run" && hasDirectExecutionMode(args)) {
1403
- const normalModeCount =
1404
- directModeCount(args) + (hasNamedExecutionMode(args) ? 1 : 0);
1405
- if (normalModeCount !== 1) {
1406
- throw new Error(
1407
- "Workflow extension: specify exactly one normal execution mode: workflow, task, tasks, or chain",
1408
- );
1409
- }
1410
- const details = await activeRuntime.runDirect(
1411
- withForkParentSession(args, ctx),
1412
- { policy },
1413
- );
1414
- return workflowRunResultFromDetails(details);
1415
- }
1416
- // Delegate to registry-backed dispatcher.
1417
- // Real errors propagate — no broad catch.
1418
- return activeRuntime.dispatch(args, { policy });
1419
-
1420
- case "status": {
1421
- // Detail mode — single-run lookup via id.
1422
- const target = args.runId;
1423
- if (target !== undefined) {
1424
- const result = inspectRun(target);
1425
- if (result.ok) {
1426
- return {
1427
- action: "statusDetail",
1428
- runId: result.runId,
1429
- detail: result.detail,
1430
- };
1431
- }
1432
- return {
1433
- action: "statusDetail",
1434
- runId: target,
1435
- error: `run not found: ${target}`,
1436
- };
1437
- }
1438
- // List mode — emit all retained snapshots; the renderer produces the
1439
- // canonical band + card surface.
1440
- return {
1441
- action: "status",
1442
- snapshots: topLevelExpandedSnapshots(),
1443
- };
1444
- }
1445
-
1446
- case "stages": {
1447
- const target = resolveToolRunTarget(args, "No active run to inspect.");
1448
- const filter = args.statusFilter ?? "all";
1449
- if (target.kind === "all") {
1450
- return {
1451
- action: "stages",
1452
- runId: "--all",
1453
- filter,
1454
- stages: [],
1455
- error: "Stage listing requires a single run.",
1456
- };
1457
- }
1458
- if (target.kind === "ambiguous") {
1459
- return {
1460
- action: "stages",
1461
- runId: target.target,
1462
- filter,
1463
- stages: [],
1464
- error: ambiguousRunMessage(target.target, target.matches),
1465
- };
1466
- }
1467
- if (target.kind === "not_found") {
1468
- return {
1469
- action: "stages",
1470
- runId: target.target,
1471
- filter,
1472
- stages: [],
1473
- error: target.message,
1474
- };
1475
- }
1476
- const run = store.runs().find((r) => r.id === target.runId);
1477
- const stages = (run?.stages ?? [])
1478
- .filter((stage) => filter === "all" || stage.status === filter)
1479
- .map(summarizeStage);
1480
- return { action: "stages", runId: target.runId, filter, stages };
1481
- }
1482
-
1483
- case "stage": {
1484
- const target = resolveToolRunTarget(args, "No active run to inspect.");
1485
- if (target.kind === "all") {
1486
- return {
1487
- action: "stage",
1488
- runId: "--all",
1489
- error: "Stage inspection requires a single run.",
1490
- };
1491
- }
1492
- if (target.kind === "ambiguous") {
1493
- return {
1494
- action: "stage",
1495
- runId: target.target,
1496
- error: ambiguousRunMessage(target.target, target.matches),
1497
- };
1498
- }
1499
- if (target.kind === "not_found") {
1500
- return {
1501
- action: "stage",
1502
- runId: target.target,
1503
- error: target.message,
1504
- };
1505
- }
1506
- const stage = resolveToolStageTarget(target.runId, args.stageId);
1507
- if (!stage.ok || stage.stageId === undefined) {
1508
- return {
1509
- action: "stage",
1510
- runId: target.runId,
1511
- error: stage.ok
1512
- ? "Stage id, prefix, or name is required."
1513
- : stage.message,
1514
- };
1515
- }
1516
- const stageRunId = stage.runId ?? target.runId;
1517
- const run = store.runs().find((r) => r.id === stageRunId);
1518
- const snapshot = run?.stages.find((s) => s.id === stage.stageId);
1519
- return snapshot
1520
- ? { action: "stage", runId: stageRunId, stage: cloneStage(snapshot) }
1521
- : {
1522
- action: "stage",
1523
- runId: stageRunId,
1524
- error: `Stage not found in run ${stageRunId.slice(0, 8)}: ${stage.stageId}`,
1525
- };
1526
- }
1527
-
1528
- case "transcript": {
1529
- const target = resolveToolRunTarget(args, "No active run to inspect.");
1530
- if (target.kind === "all") {
1531
- return {
1532
- action: "transcript",
1533
- runId: "--all",
1534
- stageId: "",
1535
- source: "error",
1536
- entries: [],
1537
- truncated: false,
1538
- };
1539
- }
1540
- if (target.kind === "ambiguous") {
1541
- return {
1542
- action: "transcript",
1543
- runId: target.target,
1544
- stageId: "",
1545
- source: "error",
1546
- entries: [
1547
- { role: "notice", text: ambiguousRunMessage(target.target, target.matches) },
1548
- ],
1549
- truncated: false,
1550
- };
1551
- }
1552
- if (target.kind === "not_found") {
1553
- return {
1554
- action: "transcript",
1555
- runId: target.target,
1556
- stageId: "",
1557
- source: "error",
1558
- entries: [{ role: "notice", text: target.message }],
1559
- truncated: false,
1560
- };
1561
- }
1562
- const stage = resolveToolStageTarget(target.runId, args.stageId);
1563
- if (!stage.ok || stage.stageId === undefined) {
1564
- return {
1565
- action: "transcript",
1566
- runId: target.runId,
1567
- stageId: "",
1568
- source: "error",
1569
- entries: [
1570
- {
1571
- role: "notice",
1572
- text: stage.ok
1573
- ? "Stage id, prefix, or name is required."
1574
- : stage.message,
1575
- },
1576
- ],
1577
- truncated: false,
1578
- };
1579
- }
1580
- const stageRunId = stage.runId ?? target.runId;
1581
- const run = store.runs().find((r) => r.id === stageRunId);
1582
- const snapshot = run?.stages.find((s) => s.id === stage.stageId);
1583
- const liveHandle = stageControlRegistry.get(stageRunId, stage.stageId);
1584
- if (liveHandle !== undefined) {
1585
- const sessionFile = liveHandle.sessionFile ?? snapshot?.sessionFile;
1586
- const sessionId = liveHandle.sessionId ?? snapshot?.sessionId;
1587
- return shapeTranscriptResult({
1588
- runId: stageRunId,
1589
- stageId: stage.stageId,
1590
- source: "live",
1591
- entryCount: liveHandle.messages.length,
1592
- buildEntries: () =>
1593
- liveHandle.messages.map((m) => transcriptEntryFromMessage(m as MessageLike)),
1594
- args,
1595
- sessionId,
1596
- sessionFile,
1597
- transcriptPath: sessionFile,
1598
- });
1599
- }
1600
- const snapshotSessionFile = snapshot?.sessionFile;
1601
- const includeSnapshotOutput = args.includeToolOutput === true && (
1602
- isTranscriptPreviewExplicit(args) || snapshotSessionFile === undefined
1603
- );
1604
- // Cheap count matches `snapshotTranscriptEntries(...).length` (one entry
1605
- // per tool event plus the optional terminal result/error entries)
1606
- // without building bodies for the path-only default.
1607
- const snapshotEntryCount = (snapshot?.toolEvents?.length ?? 0)
1608
- + (snapshot?.result !== undefined ? 1 : 0)
1609
- + (snapshot?.error !== undefined ? 1 : 0);
1610
- return shapeTranscriptResult({
1611
- runId: stageRunId,
1612
- stageId: stage.stageId,
1613
- source: "snapshot",
1614
- entryCount: snapshotEntryCount,
1615
- buildEntries: () => snapshotTranscriptEntries(snapshot, includeSnapshotOutput),
1616
- args,
1617
- sessionId: snapshot?.sessionId,
1618
- sessionFile: snapshotSessionFile,
1619
- transcriptPath: snapshotSessionFile,
1620
- });
1621
- }
1622
-
1623
- case "send": {
1624
- const target = resolveToolRunTarget(args, "No active run to message.");
1625
- const requestedDelivery = args.delivery ?? "auto";
1626
- if (target.kind === "all") {
1627
- return workflowSendResult("--all", "", requestedDelivery, "noop", "Send requires a single run.");
1628
- }
1629
- if (target.kind === "ambiguous") {
1630
- return workflowSendResult(target.target, "", requestedDelivery, "noop", ambiguousRunMessage(target.target, target.matches));
1631
- }
1632
- if (target.kind === "not_found") {
1633
- return workflowSendResult(target.target, "", requestedDelivery, "noop", target.message);
1634
- }
1635
- const stage = resolveToolStageTarget(target.runId, args.stageId);
1636
- if (!stage.ok || stage.stageId === undefined) {
1637
- return workflowSendResult(
1638
- target.runId,
1639
- "",
1640
- requestedDelivery,
1641
- "noop",
1642
- stage.ok ? "Stage id, prefix, or name is required." : stage.message,
1643
- );
1644
- }
1645
- const stageRunId = stage.runId ?? target.runId;
1646
- const run = store.runs().find((r) => r.id === stageRunId);
1647
- const snapshot = run?.stages.find((s) => s.id === stage.stageId);
1648
- // Brokered structured prompts (in-stage ask_user_question / readiness
1649
- // gate) resolve through StageUiBroker rather than store.pendingPrompt.
1650
- // Answer those first when one is pending and the promptId (if any) lines
1651
- // up — otherwise fall through to the store-prompt / live-handle paths.
1652
- const brokerPrompt = stageUiBroker.peekStagePrompt(stageRunId, stage.stageId);
1653
- const targetsBrokerPrompt =
1654
- brokerPrompt !== undefined &&
1655
- (args.promptId === undefined || args.promptId === brokerPrompt.id) &&
1656
- (requestedDelivery === "answer" ||
1657
- args.promptId !== undefined ||
1658
- requestedDelivery === "auto");
1659
- if (targetsBrokerPrompt && brokerPrompt !== undefined) {
1660
- if (!hasPayloadProperty(args)) {
1661
- return workflowSendResult(stageRunId, stage.stageId, "answer", "noop", "Send requires text, response, or message.");
1662
- }
1663
- const ok = stageUiBroker.answerStagePrompt(stageRunId, stage.stageId, brokerAnswerFromArgs(args), {
1664
- answerSource: "workflow_tool",
1665
- });
1666
- return workflowSendResult(
1667
- stageRunId,
1668
- stage.stageId,
1669
- "answer",
1670
- ok ? "ok" : "noop",
1671
- ok ? `Answered input request ${brokerPrompt.id}.` : `No matching pending input request ${brokerPrompt.id}.`,
1672
- );
1673
- }
1674
- const customPrompt = snapshot?.status === "awaiting_input" && snapshot.promptFootprint?.kind === "custom"
1675
- ? snapshot.promptFootprint
1676
- : undefined;
1677
- const targetsCustomPrompt =
1678
- customPrompt !== undefined &&
1679
- (args.promptId === undefined || args.promptId === customPrompt.id) &&
1680
- (requestedDelivery === "answer" ||
1681
- args.promptId !== undefined ||
1682
- requestedDelivery === "auto");
1683
- if (targetsCustomPrompt && customPrompt !== undefined) {
1684
- return workflowSendResult(
1685
- stageRunId,
1686
- stage.stageId,
1687
- "answer",
1688
- "noop",
1689
- `Custom UI prompt ${customPrompt.id} requires the interactive workflow graph; arbitrary ctx.ui.custom<T> results cannot be answered through workflow send.`,
1690
- );
1691
- }
1692
- const targetsPrompt =
1693
- requestedDelivery === "answer" ||
1694
- args.promptId !== undefined ||
1695
- (requestedDelivery === "auto" && snapshot?.pendingPrompt !== undefined);
1696
- if (targetsPrompt) {
1697
- const promptId = args.promptId ?? snapshot?.pendingPrompt?.id;
1698
- if (promptId === undefined) {
1699
- return workflowSendResult(stageRunId, stage.stageId, "answer", "noop", "No pending prompt to answer.");
1700
- }
1701
- if (!hasPayloadProperty(args)) {
1702
- return workflowSendResult(stageRunId, stage.stageId, "answer", "noop", "Send requires text, response, or message.");
1703
- }
1704
- if (stageUiBroker.wasStagePromptResolved(stageRunId, stage.stageId, promptId)) {
1705
- return workflowSendResult(
1706
- stageRunId,
1707
- stage.stageId,
1708
- "answer",
1709
- "ok",
1710
- `Input request ${promptId} was already answered.`,
1711
- );
1712
- }
1713
- const ok = store.resolveStagePendingPrompt(stageRunId, stage.stageId, promptId, promptPayloadFromArgs(args), {
1714
- answerSource: "workflow_tool",
1715
- });
1716
- return workflowSendResult(
1717
- stageRunId,
1718
- stage.stageId,
1719
- "answer",
1720
- ok ? "ok" : "noop",
1721
- ok ? `Answered prompt ${promptId}.` : `No matching pending prompt ${promptId}.`,
1722
- );
1723
- }
1724
- const text = textPayloadFromArgs(args);
1725
- if (text === undefined) {
1726
- return workflowSendResult(stageRunId, stage.stageId, requestedDelivery, "noop", "Send requires text, response, or message.");
1727
- }
1728
- const handle = stageControlRegistry.get(stageRunId, stage.stageId);
1729
- if (handle === undefined) {
1730
- return workflowSendResult(stageRunId, stage.stageId, requestedDelivery, "noop", "No live handle for stage.");
1731
- }
1732
- if (requestedDelivery === "resume" || (requestedDelivery === "auto" && handle.status === "paused")) {
1733
- await handle.resume(text);
1734
- return workflowSendResult(stageRunId, stage.stageId, "resume", "ok", "Resumed stage with message.");
1735
- }
1736
- if (requestedDelivery === "steer" || (requestedDelivery === "auto" && handle.isStreaming)) {
1737
- await handle.steer(text);
1738
- return workflowSendResult(stageRunId, stage.stageId, "steer", "ok", "Steered live stage.");
1739
- }
1740
- if (requestedDelivery === "prompt") {
1741
- await handle.prompt(text);
1742
- return workflowSendResult(stageRunId, stage.stageId, "prompt", "ok", "Prompt sent to stage.");
1743
- }
1744
- await handle.followUp(text);
1745
- return workflowSendResult(stageRunId, stage.stageId, "followUp", "ok", "Follow-up queued for stage.");
1746
- }
1747
-
1748
- case "pause": {
1749
- const target = resolveToolRunTarget(args, "No in-flight runs to pause.");
1750
- if (target.kind === "all") {
1751
- if (args.stageId !== undefined && args.stageId.length > 0) {
1752
- return {
1753
- action,
1754
- runId: "--all",
1755
- status: "noop",
1756
- message: allStageConflictMessage("pause"),
1757
- };
1758
- }
1759
- const results = pauseAllRuns();
1760
- const paused = results.filter((r) => r.ok).length;
1761
- return {
1762
- action,
1763
- runId: "--all",
1764
- status: paused > 0 ? "paused" : "noop",
1765
- message: paused > 0
1766
- ? `Paused ${paused} run(s).`
1767
- : "No in-flight runs to pause.",
1768
- };
1769
- }
1770
- if (target.kind === "ambiguous") return { action, runId: target.target, status: "noop", message: ambiguousRunMessage(target.target, target.matches) };
1771
- if (target.kind === "not_found") return { action, runId: target.target, status: "noop", message: target.message };
1772
- const stage = resolveToolStageTarget(target.runId, args.stageId);
1773
- if (!stage.ok) return { action, runId: target.runId, status: "noop", message: stage.message };
1774
- const stageRunId = stage.runId ?? target.runId;
1775
- const result = pauseRun(stageRunId, { stageId: stage.stageId });
1776
- return result.ok
1777
- ? { action, runId: result.runId, status: "paused", message: `Paused ${result.paused.length} stage(s) on run ${result.runId.slice(0, 8)}.` }
1778
- : {
1779
- action,
1780
- runId: stageRunId,
1781
- status: "noop",
1782
- message: stageFailureMessage(stageRunId, result.reason, "pause"),
1783
- };
1784
- }
1785
-
1786
- case "reload": {
1787
- // Fast UX check; reloadWorkflowResourcesNow re-checks inside the
1788
- // serialized reload queue and remains the authoritative TOCTOU guard.
1789
- const activeRuns = inFlightRunCount();
1790
- if (activeRuns > 0) {
1791
- return {
1792
- action: "reload",
1793
- status: "noop",
1794
- message: reloadBlockedMessage(activeRuns),
1795
- };
1796
- }
1797
- try {
1798
- await reloadWorkflowResources();
1799
- } catch (error) {
1800
- return {
1801
- action: "reload",
1802
- status: "noop",
1803
- message: reloadFailureMessage(error),
1804
- };
1805
- }
1806
- return {
1807
- action: "reload",
1808
- status: "ok",
1809
- message: args.reason?.trim()
1810
- ? `Reloaded workflow resources (${args.reason.trim()}).`
1811
- : "Reloaded workflow resources.",
1812
- };
1813
- }
1814
-
1815
- case "kill": {
1816
- const target = resolveToolRunTarget(args, "No in-flight runs to kill.");
1817
- if (target.kind === "all") {
1818
- if (args.stageId !== undefined && args.stageId.length > 0) {
1819
- return {
1820
- action,
1821
- runId: "--all",
1822
- status: "noop",
1823
- message: allStageConflictMessage("kill"),
1824
- };
1825
- }
1826
- const results = killAllRuns({
1827
- cancellation: cancellationRegistry,
1828
- persistence: getPersistence(),
1829
- });
1830
- const killed = results.filter((r) => r.ok).length;
1831
- return {
1832
- action,
1833
- runId: "--all",
1834
- status: killed > 0 ? "killed" : "noop",
1835
- message:
1836
- killed > 0
1837
- ? `Killed and retained ${killed} run(s) for inspection.`
1838
- : "No in-flight runs to kill.",
1839
- };
1840
- }
1841
- if (target.kind === "ambiguous") {
1842
- return { action, runId: target.target, status: "noop", message: ambiguousRunMessage(target.target, target.matches) };
1843
- }
1844
- if (target.kind === "not_found") {
1845
- return { action, runId: target.target, status: "noop", message: target.message };
1846
- }
1847
- const result = killRun(target.runId, {
1848
- cancellation: cancellationRegistry,
1849
- persistence: getPersistence(),
1850
- });
1851
- if (result.ok) {
1852
- return {
1853
- action,
1854
- runId: result.runId,
1855
- status: "killed",
1856
- message: `Run ${result.runId} killed and retained for inspection (was ${result.previousStatus}).`,
1857
- };
1858
- }
1859
- return {
1860
- action,
1861
- runId: target.runId,
1862
- status: "noop",
1863
- message: result.reason === "already_ended"
1864
- ? formatAlreadyEndedRetainedMessage(target.runId)
1865
- // Defensive fallback: resolveRunTarget already found this run, and killRun no longer removes runs.
1866
- : `Run not found: ${target.runId}`,
1867
- };
1868
- }
1869
-
1870
- case "interrupt": {
1871
- // Interrupt is resumable: it pauses live work and keeps runs in history/status.
1872
- const target = resolveToolRunTarget(args, "No in-flight runs to interrupt.");
1873
- if (target.kind === "all") {
1874
- if (args.stageId !== undefined && args.stageId.length > 0) {
1875
- return {
1876
- action,
1877
- runId: "--all",
1878
- status: "noop",
1879
- message: allStageConflictMessage("interrupt"),
1880
- };
1881
- }
1882
- const results = interruptAllRuns();
1883
- const interrupted = results.filter((r) => r.ok).length;
1884
- return {
1885
- action,
1886
- runId: "--all",
1887
- status: interrupted > 0 ? "paused" : "noop",
1888
- message:
1889
- interrupted > 0
1890
- ? `Interrupted ${interrupted} run(s).`
1891
- : "No in-flight runs to interrupt.",
1892
- };
1893
- }
1894
- if (target.kind === "ambiguous") {
1895
- return { action, runId: target.target, status: "noop", message: ambiguousRunMessage(target.target, target.matches) };
1896
- }
1897
- if (target.kind === "not_found") {
1898
- return { action, runId: target.target, status: "noop", message: target.message };
1899
- }
1900
- const stage = resolveToolStageTarget(target.runId, args.stageId);
1901
- if (!stage.ok) {
1902
- return { action, runId: target.runId, status: "noop", message: stage.message };
1903
- }
1904
- const stageRunId = stage.runId ?? target.runId;
1905
- const result = interruptRun(stageRunId, { stageId: stage.stageId });
1906
- if (result.ok) {
1907
- return {
1908
- action,
1909
- runId: result.runId,
1910
- status: "paused",
1911
- message: stage.stageId
1912
- ? `Stage ${stage.stageId} interrupted on run ${result.runId} and can be resumed.`
1913
- : `Run ${result.runId} interrupted and can be resumed.`,
1914
- };
1915
- }
1916
- return {
1917
- action,
1918
- runId: stageRunId,
1919
- status: "noop",
1920
- message: stageFailureMessage(stageRunId, result.reason, "interrupt"),
1921
- };
1922
- }
1923
-
1924
- case "resume": {
1925
- const target = resolveToolRunTarget(args, "No active run to resume.");
1926
- if (target.kind === "all") {
1927
- return { action: "resume", runId: "--all", status: "noop", message: "Resume does not support --all." };
1928
- }
1929
- if (target.kind === "ambiguous") {
1930
- return { action: "resume", runId: target.target, status: "noop", message: ambiguousRunMessage(target.target, target.matches) };
1931
- }
1932
- if (target.kind === "not_found") {
1933
- return { action: "resume", runId: target.target, status: "noop", message: target.message };
1934
- }
1935
- const stage = resolveToolStageTarget(target.runId, args.stageId);
1936
- if (!stage.ok) {
1937
- return { action: "resume", runId: target.runId, status: "noop", message: stage.message };
1938
- }
1939
- const stageRunId = stage.runId ?? target.runId;
1940
- const run = store.runs().find((r) => r.id === stageRunId);
1941
- const isPaused =
1942
- run?.status === "paused" ||
1943
- (run?.stages.some((s) => s.status === "paused") ?? false);
1944
- const isResumableContinuation = run !== undefined && !isPaused && (
1945
- (run.status === "failed" && run.endedAt !== undefined && run.resumable !== false) ||
1946
- (run.endedAt === undefined && run.resumable === true && run.failureRecoverability === "recoverable")
1947
- );
1948
- if (isResumableContinuation) {
1949
- const continuation = activeRuntime.resumeFailedRun(stageRunId, stage.stageId, { policy });
1950
- return {
1951
- action: "resume",
1952
- runId: continuation.ok ? continuation.runId : stageRunId,
1953
- status: continuation.ok ? "running" : "noop",
1954
- message: continuation.message,
1955
- };
1956
- }
1957
- const result = resumeRun(stageRunId, { stageId: stage.stageId, message: args.message });
1958
- if (result.ok) {
1959
- const message = result.message ?? (isPaused
1960
- ? result.resumed.length === 0
1961
- ? `No paused stages on run ${result.runId.slice(0, 8)}.`
1962
- : `Resumed ${result.resumed.length} stage(s) on run ${result.runId.slice(0, 8)}${args.message ? ` with message: "${args.message}"` : ""}.`
1963
- : `Snapshot available: run ${result.runId} (${result.snapshot.name}) — status: ${result.snapshot.status}, stages: ${result.snapshot.stages.length}`);
1964
- return {
1965
- action: "resume",
1966
- runId: result.runId,
1967
- status: "ok",
1968
- message,
1969
- };
1970
- }
1971
- return {
1972
- action: "resume",
1973
- runId: stageRunId,
1974
- status: "noop",
1975
- message: `Run not found: ${stageRunId}`,
1976
- };
1977
- }
1978
-
1979
- default: {
1980
- // Exhaustive — all action variants handled above.
1981
- const _exhaustive: never = action;
1982
- throw new Error(`Workflow extension: unknown action "${_exhaustive}"`);
1983
- }
1984
- }
1985
- };
1986
- }
1987
-
1988
- // ---------------------------------------------------------------------------
1989
- // Slash command helpers
1990
- // ---------------------------------------------------------------------------
1991
-
1992
- /**
1993
- * Local registry of workflow command (name → handler). Populated by
1994
- * `registerWorkflowCommand` alongside the host registration so the
1995
- * `on("input", …)` interceptor below can dispatch our commands directly
1996
- * — bypassing pi's optimistic `startPendingSubmission` flow which
1997
- * fires the `Working… (esc to interrupt)` loader before the host knows
1998
- * the input is a synchronous picker/connect UI, not a streaming turn.
1999
- *
2000
- * See `installInputInterceptor()` for the dispatch path and rationale.
2001
- */
2002
- type WorkflowCommandHandler = PiCommandOptions["handler"];
2003
-
2004
- interface ParsedWorkflowSlashCommand {
2005
- name: string;
2006
- args: string;
2007
- }
2008
-
2009
- function parseWorkflowSlashCommand(text: string): ParsedWorkflowSlashCommand | undefined {
2010
- const trimmed = text.trim();
2011
- if (!trimmed.startsWith("/")) return undefined;
2012
-
2013
- // First token (after `/`) is the command name. Whitespace splits
2014
- // command from args; quote handling lives inside the command
2015
- // handler itself (`tokenizeWorkflowArgs`).
2016
- const firstSpace = trimmed.indexOf(" ");
2017
- const name =
2018
- firstSpace === -1 ? trimmed.slice(1) : trimmed.slice(1, firstSpace);
2019
- const args = firstSpace === -1 ? "" : trimmed.slice(firstSpace + 1);
2020
-
2021
- return { name, args };
2022
- }
2023
-
2024
- /**
2025
- * Register a slash command with the host AND remember the handler so
2026
- * the input interceptor can dispatch directly.
2027
- *
2028
- * `pi.registerCommand` is the sole supported registration surface
2029
- * (mirrors pi's `ExtensionAPI.registerCommand`). When the host
2030
- * lacks `registerCommand` (degraded runtime — RPC mode, headless, or a
2031
- * mock that didn't stub it) we still populate the registry so the
2032
- * input interceptor can intercept the command text the user typed.
2033
- *
2034
- * We forward to `pi.registerCommand` first so any host-side wrapping
2035
- * (telemetry, logging, sandboxing) of `options.handler` lands in the
2036
- * registry; the input interceptor then dispatches the same callable
2037
- * the host would dispatch from `session.prompt`.
2038
- */
2039
- function registerWorkflowCommand(
2040
- pi: ExtensionAPI,
2041
- name: string,
2042
- options: PiCommandOptions,
2043
- registry: Map<string, WorkflowCommandHandler>,
2044
- ): void {
2045
- pi.registerCommand?.(name, options);
2046
- registry.set(name, options.handler);
2047
- }
2048
-
2049
- /**
2050
- * Install an `on("input", …)` interceptor that short-circuits the host
2051
- * submission pipeline for our registered workflow commands.
2052
- *
2053
- * Why this exists
2054
- * ---------------
2055
- * pi's editor `onSubmit` handler unconditionally calls
2056
- * `startPendingSubmission` for any text that isn't a built-in slash /
2057
- * skill / bash / python command — this echoes the message into chat
2058
- * scrollback AND starts the `Working… (esc to interrupt)` loader in
2059
- * `statusContainer` before `session.prompt` even runs. The loader is
2060
- * an optimistic affordance for the agent-streaming case; for our
2061
- * synchronous picker/connect UIs (`/workflow connect`, `/workflow run`,
2062
- * `/workflow pause`, …) it's noise — the
2063
- * spinner sits above the picker until the handler returns.
2064
- *
2065
- * `runner.emitInput` runs BEFORE `startPendingSubmission` (see
2066
- * `packages/coding-agent/src/modes/controllers/input-controller.ts`
2067
- * `setupEditorSubmitHandler`). Returning `{ action: "handled" }` from an
2068
- * `on("input", …)` handler short-circuits the function: the host
2069
- * clears the editor and returns without echoing or starting the
2070
- * loader. We dispatch the command handler ourselves with the same
2071
- * context the host would have passed.
2072
- *
2073
- * Shape note: pi's `InputEventResult` is `{ action: "continue" } |
2074
- * { action: "transform"; text; images? } | { action: "handled" }`. The
2075
- * older `{ handled: true }` shape is silently ignored by the runner
2076
- * (`result?.action === "handled"` check), which lets the loader fire.
2077
- *
2078
- * cross-ref:
2079
- * - pi docs/extensions.md (input event)
2080
- * - pi docs/slash-command-internals.md (#tryExecuteExtensionCommand)
2081
- * - pi packages/coding-agent/src/modes/interactive-mode.ts
2082
- * `startPendingSubmission` / `ensureLoadingAnimation`
2083
- */
2084
- function installInputInterceptor(
2085
- pi: ExtensionAPI,
2086
- commands: Map<string, WorkflowCommandHandler>,
2087
- ): void {
2088
- if (typeof pi.on !== "function") return;
2089
-
2090
- pi.on("input", async (event, ctx) => {
2091
- const text = (event as { text?: unknown } | undefined)?.text;
2092
- if (typeof text !== "string") return undefined;
2093
- const parsedCommand = parseWorkflowSlashCommand(text);
2094
- if (!parsedCommand) return undefined;
2095
-
2096
- const { name, args } = parsedCommand;
2097
- const handler = commands.get(name);
2098
- if (!handler) return undefined; // not ours — let host run its normal flow.
2099
- const commandCtx = ctx as PiCommandContext;
2100
- try {
2101
- await handler(args, commandCtx);
2102
- } catch (err) {
2103
- if (commandCtx.hasUI === false) {
2104
- throw err;
2105
- }
2106
- // Match the host command runner for interactive contexts: swallow
2107
- // handler exceptions so a throw never bubbles out and crashes the
2108
- // editor submit pipeline. Surface the failure via `ctx.ui.notify` so
2109
- // the user sees it. Headless contexts rethrow above because notify is
2110
- // a no-op in print mode and would otherwise hide command failures.
2111
- const message = err instanceof Error ? err.message : String(err);
2112
- commandCtx.ui.notify(`/${name} failed: ${message}`, "error");
2113
- }
2114
- return { action: "handled" };
2115
- });
2116
- }
2117
-
2118
- function formatStartupDiagnostics(
2119
- configResult: ConfigLoadResult | null,
2120
- discoveryResult: DiscoveryResult | null,
2121
- ): string | null {
2122
- const lines: string[] = [];
2123
- for (const diagnostic of configResult?.diagnostics ?? []) {
2124
- lines.push(`- [${diagnostic.level} ${diagnostic.code}] ${diagnostic.source ?? "workflow config"}: ${diagnostic.message}`);
2125
- }
2126
- for (const diagnostic of discoveryResult?.errors ?? []) {
2127
- lines.push(`- [${diagnostic.level} ${diagnostic.code}] ${diagnostic.source ?? "workflow discovery"}: ${diagnostic.message}`);
2128
- }
2129
-
2130
- if (lines.length === 0) return null;
2131
-
2132
- const maxVisible = 8;
2133
- const visible = lines.slice(0, maxVisible);
2134
- const remaining = lines.length - visible.length;
2135
- return [
2136
- `Workflow discovery diagnostics (${lines.length}): some workflow resources were skipped or need attention.`,
2137
- ...visible,
2138
- ...(remaining > 0 ? [`- … ${remaining} more`] : []),
2139
- ].join("\n");
2140
- }
2141
-
2142
- /**
2143
- * Resolve a user-supplied run identifier (full UUID or unique prefix) to
2144
- * a concrete runId. The widget surfaces an 8-char prefix to keep the
2145
- * status line scannable; users copy that prefix straight into the interrupt
2146
- * slash command, so prefix matching is the expected affordance.
2147
- */
2148
- type RunIdResolution =
2149
- | { kind: "exact"; runId: string }
2150
- | { kind: "ambiguous"; matches: string[] }
2151
- | { kind: "not_found" };
2152
-
2153
- function resolveRunIdPrefix(target: string): RunIdResolution {
2154
- const runs = store.runs();
2155
- const exact = runs.find((r) => r.id === target);
2156
- if (exact) return { kind: "exact", runId: exact.id };
2157
-
2158
- const prefixed = runs.filter((r) => r.id.startsWith(target));
2159
- if (prefixed.length === 0) return { kind: "not_found" };
2160
- if (prefixed.length === 1) return { kind: "exact", runId: prefixed[0]!.id };
2161
- return { kind: "ambiguous", matches: prefixed.map((r) => r.id) };
2162
- }
2163
-
2164
- type ToolRunTarget =
2165
- | { kind: "all" }
2166
- | { kind: "run"; runId: string }
2167
- | { kind: "ambiguous"; target: string; matches: string[] }
2168
- | { kind: "not_found"; target: string; message: string };
2169
-
2170
- function resolveToolRunTarget(
2171
- args: WorkflowToolArgs,
2172
- emptyMessage: string,
2173
- ): ToolRunTarget {
2174
- const rawTarget = args.runId?.trim() ?? "";
2175
- if (args.all === true || rawTarget === "--all") return { kind: "all" };
2176
-
2177
- const target = rawTarget || store.activeRunId() || "";
2178
- if (!target) return { kind: "not_found", target: rawTarget, message: emptyMessage };
2179
-
2180
- const resolved = resolveRunIdPrefix(target);
2181
- if (resolved.kind === "exact") return { kind: "run", runId: resolved.runId };
2182
- if (resolved.kind === "ambiguous") {
2183
- return { kind: "ambiguous", target, matches: resolved.matches };
2184
- }
2185
- return { kind: "not_found", target, message: `Run not found: ${target}` };
2186
- }
2187
-
2188
- type ToolStageTarget =
2189
- | { ok: true; runId?: string; stageId?: string }
2190
- | { ok: false; message: string };
2191
-
2192
- function resolveStageTarget(runId: string, stageTarget?: string): ToolStageTarget {
2193
- const target = stageTarget?.trim();
2194
- if (!target) return { ok: true, runId };
2195
-
2196
- const graph = expandWorkflowGraph(store.snapshot(), runId);
2197
- const exactId = graph.stages.find(
2198
- (stage) => stage.id === target || stage.workflowGraphTarget.stageId === target,
2199
- );
2200
- if (exactId !== undefined) {
2201
- return {
2202
- ok: true,
2203
- runId: exactId.workflowGraphTarget.runId,
2204
- stageId: exactId.workflowGraphTarget.stageId,
2205
- };
2206
- }
2207
-
2208
- const exactNames = graph.stages.filter((stage) => stage.name === target);
2209
- if (exactNames.length === 1) {
2210
- const stage = exactNames[0]!;
2211
- return {
2212
- ok: true,
2213
- runId: stage.workflowGraphTarget.runId,
2214
- stageId: stage.workflowGraphTarget.stageId,
2215
- };
2216
- }
2217
- if (exactNames.length > 1) return { ok: false, message: `Ambiguous stage identifier "${target}" matches: ${exactNames.map(expandedStageLabel).join(", ")}` };
2218
-
2219
- const matches = graph.stages.filter((stage) => stageMatchesExpandedIdentifier(stage, target));
2220
- if (matches.length === 0) return { ok: false, message: `Stage not found in run ${runId.slice(0, 8)}: ${target}` };
2221
- if (matches.length > 1) return { ok: false, message: `Ambiguous stage identifier "${target}" matches: ${matches.map(expandedStageLabel).join(", ")}` };
2222
- const stage = matches[0]!;
2223
- return {
2224
- ok: true,
2225
- runId: stage.workflowGraphTarget.runId,
2226
- stageId: stage.workflowGraphTarget.stageId,
2227
- };
2228
- }
2229
-
2230
- function resolveToolStageTarget(runId: string, stageTarget?: string): ToolStageTarget {
2231
- return resolveStageTarget(runId, stageTarget);
2232
- }
2233
-
2234
- function ambiguousRunMessage(target: string, matches: readonly string[]): string {
2235
- return `Ambiguous run prefix "${target}" matches: ${matches
2236
- .map((id) => id.slice(0, 12))
2237
- .join(", ")}`;
2238
- }
2239
-
2240
- function overlaySurfaceFromContext(ctx?: {
2241
- ui?: PiUISurface;
2242
- }): OverlayPiSurface | undefined {
2243
- // Only forward `ctx.ui` to the overlay adapter when it actually
2244
- // carries the `custom` mount surface. Inline pickers (replace-editor)
2245
- // hand us a print-only `ui.notify` which would otherwise shadow
2246
- // `pi.ui` inside the adapter and short-circuit the open.
2247
- return typeof ctx?.ui?.custom === "function" ? { ui: ctx.ui } : undefined;
2248
- }
2249
-
2250
- /**
2251
- * Strip the clack-style `--yes` / `-y` confirmation skip flag from a token
2252
- * list. Used by `/workflow interrupt` and `/workflow kill` to skip the confirmation overlay.
2253
- */
2254
- export function stripYesFlag(tokens: string[]): {
2255
- tokens: string[];
2256
- yes: boolean;
2257
- } {
2258
- const yes = tokens.some((t) => t === "--yes" || t === "-y");
2259
- return { tokens: tokens.filter((t) => t !== "--yes" && t !== "-y"), yes };
2260
- }
2261
-
2262
- /**
2263
- * Shell-aware split for `/workflow <name> [args…]` chat tokens.
2264
- *
2265
- * `prompt="map the codebase"` is one token, not three. Both single and
2266
- * double quotes are honoured; the quote characters themselves are kept
2267
- * inside the token so {@link parseWorkflowArgs} can `JSON.parse` the
2268
- * value and the wrapping quotes coerce it back to a plain string.
2269
- * Backslash-escaping is **not** supported — workflow inputs are short,
2270
- * the picker overlay is always available as a fallback for anything
2271
- * exotic, and the simpler grammar matches what users type in shells.
2272
- *
2273
- * An unterminated quote is treated as if a closing quote sat at EOL —
2274
- * we never throw on user input mid-stream; the parser downstream sees
2275
- * a partial JSON literal and falls back to keeping it as a string.
2276
- */
2277
- export function tokenizeWorkflowArgs(args: string): string[] {
2278
- const tokens: string[] = [];
2279
- let buf = "";
2280
- let quote: '"' | "'" | undefined;
2281
- let hasBuf = false;
2282
- for (let i = 0; i < args.length; i++) {
2283
- const ch = args[i]!;
2284
- if (quote !== undefined) {
2285
- buf += ch;
2286
- if (ch === quote) quote = undefined;
2287
- continue;
2288
- }
2289
- if (ch === '"' || ch === "'") {
2290
- buf += ch;
2291
- hasBuf = true;
2292
- quote = ch;
2293
- continue;
2294
- }
2295
- if (ch === " " || ch === "\t" || ch === "\n" || ch === "\r") {
2296
- if (hasBuf) {
2297
- tokens.push(buf);
2298
- buf = "";
2299
- hasBuf = false;
2300
- }
2301
- continue;
2302
- }
2303
- buf += ch;
2304
- hasBuf = true;
2305
- }
2306
- if (hasBuf) tokens.push(buf);
2307
- return tokens;
2308
- }
2309
-
2310
- /**
2311
- * Parse remaining args tokens as key=value pairs.
2312
- * Tokens matching `key=value` are split on the first `=`.
2313
- * Tokens that are standalone valid JSON objects/arrays are merged in.
2314
- * All other tokens are ignored (non-kv positional args not supported).
2315
- */
2316
- export function parseWorkflowArgs(tokens: string[]): WorkflowInputValues {
2317
- const result: Record<string, WorkflowSerializableValue> = {};
2318
- for (const token of tokens) {
2319
- // Try JSON object/array merge
2320
- if (
2321
- (token.startsWith("{") && token.endsWith("}")) ||
2322
- (token.startsWith("[") && token.endsWith("]"))
2323
- ) {
2324
- try {
2325
- const parsed = JSON.parse(token) as unknown;
2326
- if (
2327
- parsed !== null &&
2328
- typeof parsed === "object" &&
2329
- !Array.isArray(parsed)
2330
- ) {
2331
- Object.assign(result, parsed as WorkflowInputValues);
2332
- }
2333
- continue;
2334
- } catch {
2335
- // not valid JSON — fall through to kv parse
2336
- }
2337
- }
2338
- // key=value
2339
- const eqIdx = token.indexOf("=");
2340
- if (eqIdx > 0) {
2341
- const key = token.slice(0, eqIdx);
2342
- const raw = token.slice(eqIdx + 1);
2343
- // Try to parse value as JSON for typed values (numbers, booleans, objects)
2344
- let value: WorkflowSerializableValue = raw;
2345
- try {
2346
- value = JSON.parse(raw) as WorkflowSerializableValue;
2347
- } catch {
2348
- // keep as string
2349
- }
2350
- result[key] = value;
2351
- }
2352
- }
2353
- return result;
2354
- }
2355
-
2356
- // ---------------------------------------------------------------------------
2357
- // Persistence port builder
2358
- // ---------------------------------------------------------------------------
2359
-
2360
- /**
2361
- * Build a WorkflowPersistencePort from the pi ExtensionAPI when persistence
2362
- * is enabled. Returns undefined when:
2363
- * - persistRuns is false, OR
2364
- * - pi.appendEntry is absent (older pi runtime without persistence API).
2365
- */
2366
- export function makePersistencePort(
2367
- pi: ExtensionAPI,
2368
- persistRuns: boolean,
2369
- ): WorkflowPersistencePort | undefined {
2370
- if (!persistRuns) return undefined;
2371
- if (typeof pi.appendEntry !== "function") return undefined;
2372
-
2373
- const port: WorkflowPersistencePort = {
2374
- appendEntry: (type, payload) => pi.appendEntry!(type, payload),
2375
- };
2376
- if (typeof pi.setLabel === "function") {
2377
- port.setLabel = (entryId, label) => pi.setLabel!(entryId, label);
2378
- }
2379
- if (typeof pi.appendCustomMessageEntry === "function") {
2380
- port.appendCustomMessageEntry = (content, meta) =>
2381
- pi.appendCustomMessageEntry!(content, meta);
2382
- }
2383
- return port;
2384
- }
2385
-
2386
- // ---------------------------------------------------------------------------
2387
- // MCP port builder
2388
- // ---------------------------------------------------------------------------
2389
-
2390
- /**
2391
- * Build a WorkflowMcpPort from the pi ExtensionAPI when MCP scope gating is
2392
- * supported. Returns undefined when pi.events?.emit is absent (adapter not
2393
- * installed or older runtime without events bus) — scoping becomes a no-op.
2394
- */
2395
- export function makeMcpPort(pi: ExtensionAPI): WorkflowMcpPort | undefined {
2396
- if (typeof pi.events?.emit !== "function") return undefined;
2397
-
2398
- // Adapt ExtensionAPI to the minimal PiMcpExtensionAPI shape expected by
2399
- // setMcpScope / clearMcpScope. We only forward events.emit (confirmed above).
2400
- const piForMcp: PiMcpExtensionAPI = {
2401
- events: { emit: pi.events.emit as PiEventBus["emit"] },
2402
- };
2403
-
2404
- return {
2405
- setScope(stageId: string, allow: string[] | null, deny: string[] | null) {
2406
- setMcpScope(piForMcp, {
2407
- stageId,
2408
- allow: allow ?? undefined,
2409
- deny: deny ?? undefined,
2410
- });
2411
- },
2412
- clearScope(stageId: string) {
2413
- clearMcpScope(piForMcp, stageId);
2414
- },
2415
- };
2416
- }
2417
-
2418
- // ---------------------------------------------------------------------------
2419
- // Factory — the default export consumed by the pi runtime
2420
- // ---------------------------------------------------------------------------
2421
-
2422
- function factory(pi: ExtensionAPI): void {
2423
- // -------------------------------------------------------------------------
2424
- // 0. Build StageAdapters from pi runtime surfaces. Stage prompting uses
2425
- // pi's in-process SDK `createAgentSession()` surface; HIL prompts
2426
- // flow through the store-backed background adapter built inside
2427
- // `runDetached()` — they never touch pi.ui.
2428
- // -------------------------------------------------------------------------
2429
- const adapters = buildRuntimeAdapters(pi);
2430
-
2431
- // Local registry of workflow command (name → handler). Populated by
2432
- // `registerWorkflowCommand` calls below and consumed by the
2433
- // `pi.on("input", …)` interceptor at the end of the factory — see
2434
- // `installInputInterceptor` for the rationale.
2435
- const workflowCommands = new Map<string, WorkflowCommandHandler>();
2436
-
2437
- // -------------------------------------------------------------------------
2438
- // 1. Create ExtensionRuntime — mutable ref seeded from startup discovery,
2439
- // upgraded to unified async discovery once discoverWorkflows() resolves.
2440
- //
2441
- // runtimeProxy delegates all calls to runtimeRef.current so every
2442
- // registration closure automatically uses the most-current registry without
2443
- // needing to be re-registered.
2444
- // -------------------------------------------------------------------------
2445
- const persistenceRef: { current: WorkflowPersistencePort | undefined } = {
2446
- current: makePersistencePort(pi, WORKFLOW_CONFIG_DEFAULTS.persistRuns),
2447
- };
2448
-
2449
- // Build graph overlay adapter — wraps GraphView + pi.ui.custom.
2450
- // noopOverlay returned when pi.ui?.custom is absent (degraded runtime).
2451
- const overlay: GraphOverlayPort = buildGraphOverlayAdapter(pi, store, {
2452
- onKillRun: (runId) => {
2453
- const run = store.runs().find((r) => r.id === runId);
2454
- const result = killRun(runId, {
2455
- cancellation: cancellationRegistry,
2456
- persistence: persistenceRef.current,
2457
- });
2458
- if (run && result.ok) {
2459
- emitChatSurface(pi, {
2460
- kind: "killed",
2461
- run,
2462
- previousStatus: result.previousStatus,
2463
- });
2464
- }
2465
- },
2466
- });
2467
-
2468
- const mcpPort: WorkflowMcpPort | undefined = makeMcpPort(pi);
2469
-
2470
- /**
2471
- * Mutable ref for the resolved runtime config.
2472
- * Seeded with WORKFLOW_CONFIG_DEFAULTS at startup; replaced after async config load.
2473
- * Injected into every createExtensionRuntime() call so the dispatcher, executor,
2474
- * and detached runner all receive the same resolved tunables.
2475
- */
2476
- const runtimeConfigRef: { current: WorkflowRuntimeConfig } = {
2477
- current: {
2478
- maxDepth: WORKFLOW_CONFIG_DEFAULTS.maxDepth,
2479
- defaultConcurrency: WORKFLOW_CONFIG_DEFAULTS.defaultConcurrency,
2480
- persistRuns: WORKFLOW_CONFIG_DEFAULTS.persistRuns,
2481
- statusFile: WORKFLOW_CONFIG_DEFAULTS.statusFile,
2482
- resumeInFlight: WORKFLOW_CONFIG_DEFAULTS.resumeInFlight,
2483
- },
2484
- };
2485
-
2486
- /**
2487
- * Mutable ref for the status writer instance.
2488
- * Replaced (old unsubscribed) each time runtimeConfigRef is updated after
2489
- * async config resolution. Starts as a no-op (statusFile defaults to false).
2490
- */
2491
- let statusWriterRef: StatusWriter = createStatusWriter(
2492
- store,
2493
- runtimeConfigRef.current,
2494
- );
2495
- let lifecycleNotificationsUnsubscribe: (() => void) | null = null;
2496
- let lifecycleNotificationsActive = false;
2497
- let hilAnswerNotificationsUnsubscribe: (() => void) | null = null;
2498
- let hilAnswerNotificationsActive = false;
2499
- const lifecycleNotificationState = createWorkflowLifecycleNotificationState();
2500
- const hilAnswerNotificationState = createWorkflowHilAnswerNotificationState();
2501
- const lifecycleNotificationConfigRef: { current: WorkflowLifecycleNotificationConfig } = {
2502
- current: WORKFLOW_CONFIG_DEFAULTS.workflowNotifications,
2503
- };
2504
- const registerMessageRenderer: ExtensionAPI["registerMessageRenderer"] | undefined =
2505
- typeof pi.registerMessageRenderer === "function"
2506
- ? (event, renderer) => pi.registerMessageRenderer!(event, renderer)
2507
- : undefined;
2508
- registerLifecycleNoticeRenderer({
2509
- rendererHost: pi,
2510
- registerMessageRenderer,
2511
- });
2512
- registerHilAnswerNoticeRenderer({
2513
- rendererHost: pi,
2514
- registerMessageRenderer,
2515
- });
2516
- const sendWorkflowNotificationMessage: ExtensionAPI["sendMessage"] | undefined =
2517
- typeof pi.sendMessage === "function"
2518
- ? (message, options) => pi.sendMessage!(message, options)
2519
- : undefined;
2520
- const reinstallLifecycleNotifications = (): void => {
2521
- lifecycleNotificationsUnsubscribe?.();
2522
- lifecycleNotificationsUnsubscribe = null;
2523
- if (!lifecycleNotificationsActive) return;
2524
- lifecycleNotificationsUnsubscribe = installWorkflowLifecycleNotifications({
2525
- store,
2526
- config: lifecycleNotificationConfigRef.current,
2527
- state: lifecycleNotificationState,
2528
- seedExisting: true,
2529
- sendMessage: sendWorkflowNotificationMessage,
2530
- });
2531
- };
2532
- const reinstallHilAnswerNotifications = (): void => {
2533
- hilAnswerNotificationsUnsubscribe?.();
2534
- hilAnswerNotificationsUnsubscribe = null;
2535
- if (!hilAnswerNotificationsActive) return;
2536
- hilAnswerNotificationsUnsubscribe = installWorkflowHilAnswerNotifications({
2537
- store,
2538
- stageUiBroker,
2539
- state: hilAnswerNotificationState,
2540
- sendMessage: sendWorkflowNotificationMessage,
2541
- });
2542
- };
2543
-
2544
- async function runWithLifecycleSuppressedForPolicy<T>(
2545
- policy: WorkflowExecutionPolicy,
2546
- fn: () => Promise<T>,
2547
- ): Promise<T> {
2548
- if (policy.mode !== "non_interactive" || policy.awaitTerminalRun !== true) {
2549
- return fn();
2550
- }
2551
- return withWorkflowLifecycleNotificationsSuppressedAsync(
2552
- lifecycleNotificationState,
2553
- fn,
2554
- );
2555
- }
2556
- let intercomParentSession: string | null = null;
2557
- const intercomPort = {
2558
- emit:
2559
- typeof pi.events?.emit === "function"
2560
- ? (event: string, payload: Record<string, unknown>) =>
2561
- pi.events!.emit!(event, payload)
2562
- : undefined,
2563
- parentSession: () => intercomParentSession ?? undefined,
2564
- };
2565
- const hostStageSessionDir: { current: string | undefined } = { current: undefined };
2566
- const resolveDefaultStageSessionDir = (): string | undefined => hostStageSessionDir.current;
2567
- const updateHostStageSessionDir = (sessionManager: SessionManager | undefined): void => {
2568
- try {
2569
- hostStageSessionDir.current = sessionManager?.usesDefaultSessionDir?.() === false
2570
- ? sessionManager.getSessionDir?.()
2571
- : undefined;
2572
- } catch {
2573
- hostStageSessionDir.current = undefined;
2574
- }
2575
- };
2576
-
2577
- const startupDiscovery = discoverStartupWorkflowsSync();
2578
- const runtimeRef: { current: ExtensionRuntime } = {
2579
- current: createExtensionRuntime({
2580
- registry: startupDiscovery.registry,
2581
- cwd: process.cwd(),
2582
- adapters,
2583
- cancellation: cancellationRegistry,
2584
- persistence: persistenceRef.current,
2585
- mcp: mcpPort,
2586
- intercom: intercomPort,
2587
- config: runtimeConfigRef.current,
2588
- resolveDefaultStageSessionDir,
2589
- }),
2590
- };
2591
- const discoveryRef: { current: DiscoveryResult | null } = { current: null };
2592
- const configLoadRef: { current: ConfigLoadResult | null } = { current: null };
2593
-
2594
- /** Stable proxy — all registrations close over this; delegates to runtimeRef.current. */
2595
- const runtimeProxy: ExtensionRuntime = {
2596
- get registry() {
2597
- return runtimeRef.current.registry;
2598
- },
2599
- dispatch(args, options) {
2600
- return runtimeRef.current.dispatch(args, options);
2601
- },
2602
- runDirect(args, options) {
2603
- return runtimeRef.current.runDirect(args, options);
2604
- },
2605
- resumeFailedRun(sourceRunId, stageId, options) {
2606
- return runtimeRef.current.resumeFailedRun(sourceRunId, stageId, options);
2607
- },
2608
- };
2609
-
2610
- function modelFullId(model: PiRuntimeModel): string {
2611
- return `${String(model.provider)}/${model.id}`;
2612
- }
2613
-
2614
- function workflowModelCatalogFromContext(
2615
- ctx?: PiModelContext,
2616
- ): WorkflowModelCatalogPort | undefined {
2617
- if (ctx?.modelRegistry === undefined && ctx?.model === undefined)
2618
- return undefined;
2619
- return {
2620
- listModels: async (): Promise<readonly WorkflowModelInfo[]> => {
2621
- const available =
2622
- ctx.modelRegistry?.getAvailable() ??
2623
- (ctx.model === undefined ? [] : [ctx.model]);
2624
- return available.map((model) => ({
2625
- provider: String(model.provider),
2626
- id: model.id,
2627
- fullId: modelFullId(model),
2628
- model: model as NonNullable<CreateAgentSessionOptions["model"]>,
2629
- }));
2630
- },
2631
- ...(ctx.model !== undefined
2632
- ? {
2633
- currentModel: ctx.model as NonNullable<
2634
- CreateAgentSessionOptions["model"]
2635
- >,
2636
- preferredProvider: String(ctx.model.provider),
2637
- }
2638
- : {}),
2639
- };
2640
- }
2641
-
2642
- function runtimeWithModels(
2643
- models: WorkflowModelCatalogPort | undefined,
2644
- ): ExtensionRuntime {
2645
- if (models === undefined) return runtimeProxy;
2646
- return createExtensionRuntime({
2647
- registry: runtimeRef.current.registry,
2648
- cwd: process.cwd(),
2649
- adapters,
2650
- cancellation: cancellationRegistry,
2651
- persistence: persistenceRef.current,
2652
- mcp: mcpPort,
2653
- intercom: intercomPort,
2654
- config: runtimeConfigRef.current,
2655
- models,
2656
- resolveDefaultStageSessionDir,
2657
- });
2658
- }
2659
-
2660
- // The runtime normally does not depend on per-command UI, but model fallback
2661
- // resolution uses the live command/tool context when pi exposes modelRegistry.
2662
- function runtimeForContext(
2663
- ctx?: { ui?: PiUISurface } & PiModelContext,
2664
- ): ExtensionRuntime {
2665
- return runtimeWithModels(workflowModelCatalogFromContext(ctx));
2666
- }
2667
-
2668
- let intercomControlUnsubscribe: (() => void) | null = null;
2669
- let workflowReloadQueue: Promise<void> = Promise.resolve();
2670
-
2671
- async function reloadWorkflowResources(options?: { allowInFlight?: boolean }): Promise<void> {
2672
- const reload = workflowReloadQueue.then(() => reloadWorkflowResourcesNow(options));
2673
- workflowReloadQueue = reload.catch(() => {});
2674
- await reload;
2675
- }
2676
-
2677
- async function loadPackageWorkflowPaths(): Promise<string[]> {
2678
- const packageResources =
2679
- (await pi.refreshWorkflowResources?.()) ??
2680
- pi.getWorkflowResources?.() ??
2681
- [];
2682
- return packageResources
2683
- .filter((resource) => resource.enabled !== false)
2684
- .map((resource) => resource.path);
2685
- }
2686
-
2687
- async function reloadWorkflowResourcesNow(options?: { allowInFlight?: boolean }): Promise<void> {
2688
- const activeRuns = inFlightRunCount();
2689
- if (options?.allowInFlight !== true) {
2690
- if (activeRuns > 0) {
2691
- throw new WorkflowReloadBlockedError(reloadBlockedMessage(activeRuns));
2692
- }
2693
- } else if (activeRuns > 0 && process.env.ATOMIC_WORKFLOW_DEBUG === "1") {
2694
- console.warn(
2695
- `Workflow reload bypassed in-flight guard with ${activeRuns} active run(s).`,
2696
- );
2697
- }
2698
-
2699
- const configResult = await loadWorkflowConfig();
2700
- configLoadRef.current = configResult;
2701
-
2702
- // Build scope-aware DiscoveryConfig: global entries → globalWorkflows (resolved
2703
- // under <homeDir>/.atomic/agent), project entries → projectWorkflows (resolved under
2704
- // projectRoot). Project keys override global keys. Paths pre-resolved to absolute.
2705
- const { homedir } = await import("node:os");
2706
- const hasGlobal = configResult.globalConfig != null;
2707
- const hasProject = configResult.projectConfig != null;
2708
- const discoveryConfig =
2709
- hasGlobal || hasProject
2710
- ? toScopedDiscoveryConfig(
2711
- configResult.globalConfig ?? null,
2712
- configResult.projectConfig ?? null,
2713
- { projectRoot: process.cwd(), homeDir: homedir() },
2714
- )
2715
- : undefined;
2716
-
2717
- const packageWorkflowPaths = await loadPackageWorkflowPaths();
2718
- const result = await discoverWorkflows({ config: discoveryConfig, packageWorkflowPaths });
2719
- discoveryRef.current = result;
2720
-
2721
- // Resolve effective config (fills in all defaults) and build WorkflowRuntimeConfig.
2722
- const effectiveConfig = withWorkflowDefaults(configResult.config ?? {});
2723
- runtimeConfigRef.current = {
2724
- maxDepth: effectiveConfig.maxDepth,
2725
- defaultConcurrency: effectiveConfig.defaultConcurrency,
2726
- persistRuns: effectiveConfig.persistRuns,
2727
- statusFile: effectiveConfig.statusFile,
2728
- resumeInFlight: effectiveConfig.resumeInFlight,
2729
- };
2730
- lifecycleNotificationConfigRef.current = effectiveConfig.workflowNotifications;
2731
- reinstallLifecycleNotifications();
2732
-
2733
- // Replace status writer with one that reflects the resolved config.
2734
- // Unsubscribe the prior (no-op) writer before creating the new one.
2735
- statusWriterRef.unsubscribe();
2736
- statusWriterRef = createStatusWriter(store, runtimeConfigRef.current);
2737
-
2738
- persistenceRef.current = makePersistencePort(
2739
- pi,
2740
- effectiveConfig.persistRuns,
2741
- );
2742
- runtimeRef.current = createExtensionRuntime({
2743
- registry: result.registry,
2744
- cwd: process.cwd(),
2745
- adapters,
2746
- cancellation: cancellationRegistry,
2747
- persistence: persistenceRef.current,
2748
- mcp: mcpPort,
2749
- intercom: intercomPort,
2750
- config: runtimeConfigRef.current,
2751
- resolveDefaultStageSessionDir,
2752
- });
2753
- }
2754
-
2755
- const executeWorkflowTool = makeExecuteWorkflowTool(
2756
- (ctx) => runtimeForContext(ctx),
2757
- () => persistenceRef.current,
2758
- reloadWorkflowResources,
2759
- );
2760
- let storeWidgetUnsubscribe: (() => void) | null = null;
2761
-
2762
- // Start unified async discovery immediately.
2763
- // On resolve: swap runtime ref so /workflow completions and dispatch see
2764
- // project-local, user-global, and settings-provided workflows.
2765
- // Load startup config before discovery so workflow paths and tunables are applied.
2766
- const discoveryPromise = pi.disableAsyncDiscovery
2767
- ? Promise.resolve()
2768
- : reloadWorkflowResources({ allowInFlight: true });
2769
-
2770
- // -------------------------------------------------------------------------
2771
- // 1. Register the `workflow` tool
2772
- // Pi's ToolDefinition.execute is positional: (toolCallId, params, signal,
2773
- // onUpdate, ctx) → Promise<AgentToolResult<TDetails>>. The internal
2774
- // `executeWorkflowTool` keeps its (args, ctx) shape for test ergonomics;
2775
- // we adapt here at the registration boundary only.
2776
- // cross-ref: pi-coding-agent dist/core/extensions/types.d.ts ToolDefinition
2777
- // -------------------------------------------------------------------------
2778
- if (typeof pi.registerTool === "function") {
2779
- pi.registerTool<WorkflowToolArgs, WorkflowToolResult>({
2780
- name: "workflow",
2781
- label: "workflow",
2782
- description: WORKFLOW_TOOL_DESCRIPTION,
2783
- parameters: workflowParameters,
2784
- promptGuidelines: DEFAULT_PROMPT_GUIDANCE,
2785
- renderShell: "self",
2786
- execute: async (_toolCallId, params, _signal, _onUpdate, ctx) => {
2787
- // Overlay is opt-in via F2 / ctrl+h; do not auto-open from a
2788
- // tool-call dispatch path. Awaited non-interactive runs suppress
2789
- // lifecycle steer notices until the terminal tool result is ready.
2790
- const policy = workflowPolicyFromContext(ctx);
2791
- const details = (params.action ?? "run") === "run"
2792
- ? await runWithLifecycleSuppressedForPolicy(policy, () =>
2793
- executeWorkflowTool(params, ctx),
2794
- )
2795
- : await executeWorkflowTool(params, ctx);
2796
- return {
2797
- content: [{ type: "text", text: renderWorkflowToolContent(details, params) }],
2798
- details,
2799
- };
2800
- },
2801
- renderCall: (args, _theme, _context) =>
2802
- dynamicTextRenderComponent((width) => renderCall(args, { width })),
2803
- renderResult: (result, opts, _theme, context) => {
2804
- // Capture wall-clock ONCE per chat entry. The lambda below is
2805
- // invoked on every TUI re-render; without a captured `now`, every
2806
- // tick would recompute elapsed/running durations and trigger
2807
- // pi-tui's full-redraw path for any entry above the viewport —
2808
- // visible as whole-screen flicker on terminals without
2809
- // synchronized output support (e.g. mosh).
2810
- const capturedNow = Date.now();
2811
- return dynamicTextRenderComponent((width) =>
2812
- renderResult(result.details, {
2813
- ...opts,
2814
- width,
2815
- now: capturedNow,
2816
- runInputs: (context as { args?: WorkflowToolArgs }).args?.inputs,
2817
- }),
2818
- );
2819
- },
2820
- });
2821
- }
2822
-
2823
- // -------------------------------------------------------------------------
2824
- // 2. Register /workflow slash command
2825
- // -------------------------------------------------------------------------
2826
- /**
2827
- * Shared top-level run-control handler.
2828
- *
2829
- * connect [runId|prefix] no arg → picker overlay; arg → attach to graph
2830
- * attach [runId|prefix [stageId]] open the in-place attach pane on a stage
2831
- * interrupt [runId|prefix|--all] [-y] confirmation overlay unless -y
2832
- * kill [runId|prefix|--all] [-y] kill and retain for inspection
2833
- * pause [runId|prefix [stageId]] pause a run or specific stage
2834
- * resume [runId|prefix [stageId] …] resume paused work or reopen snapshot
2835
- */
2836
- async function handleRunControlCommand(
2837
- action: "connect" | "interrupt" | "kill" | "attach" | "pause" | "resume",
2838
- rest: string[],
2839
- ctx: PiCommandContext,
2840
- reporter: WorkflowCommandReporter = createWorkflowCommandReporter(ctx),
2841
- ): Promise<boolean> {
2842
- const policy = workflowPolicyFromContext(ctx);
2843
- const print = (msg: string): void => reporter.info(msg);
2844
- const fail = (msg: string): void => reporter.error(msg);
2845
- const canOpenPicker = (ui: PiCommandContext["ui"] | undefined): boolean =>
2846
- policy.allowInputPicker && typeof ui?.custom === "function";
2847
- const confirmationPrompt = policy.allowHumanInput && typeof ctx.ui?.confirm === "function"
2848
- ? ctx.ui.confirm.bind(ctx.ui)
2849
- : undefined;
2850
- const theme = deriveGraphTheme({});
2851
- const failHeadlessAttachCommand = (
2852
- targetAction: "connect" | "attach",
2853
- runId: string,
2854
- stageId?: string,
2855
- ): boolean => {
2856
- if (policy.allowInputPicker) return false;
2857
- const displayTarget = stageId
2858
- ? `${runId.slice(0, 8)} stage ${stageId.slice(0, 8)}`
2859
- : runId.slice(0, 8);
2860
- fail(
2861
- `/workflow ${targetAction} requires an interactive UI surface and cannot attach in non-interactive mode. ` +
2862
- `Target: ${displayTarget}. Use /workflow status ${runId.slice(0, 8)} or the workflow tool's status/stages/transcript actions for non-interactive inspection.`,
2863
- );
2864
- return true;
2865
- };
2866
-
2867
- if (action === "connect") {
2868
- const target = rest.find((t) => !t.startsWith("--"));
2869
- if (!target) {
2870
- // Picker mode — mount the overlay and route the resolved action.
2871
- const ui = ctx.ui;
2872
- if (!canOpenPicker(ui)) {
2873
- fail(
2874
- `${renderSessionList(store.runs(), { theme, includeAll: true })}\n\nPicker requires an interactive UI surface. Pass a runId: /workflow connect <id>`,
2875
- );
2876
- return true;
2877
- }
2878
- const result = await openSessionPicker(ui, store, theme, "connect");
2879
- if (result.kind === "close") return true;
2880
- if (result.kind === "connect") {
2881
- overlay.open(result.runId, overlaySurfaceFromContext(ctx));
2882
- return true;
2883
- }
2884
- if (result.kind === "kill") {
2885
- const run = store.runs().find((r) => r.id === result.runId);
2886
- if (!run) {
2887
- fail(`Run not found: ${result.runId}`);
2888
- return true;
2889
- }
2890
- if (run.endedAt !== undefined) {
2891
- print(formatAlreadyEndedRetainedMessage(result.runId));
2892
- return true;
2893
- }
2894
- const confirmed = await openKillConfirm(ui, run, theme);
2895
- if (!confirmed) {
2896
- print(
2897
- `Cancelled. Run ${result.runId.slice(0, 8)} is still active.`,
2898
- );
2899
- return true;
2900
- }
2901
- const killed = killRun(result.runId, {
2902
- cancellation: cancellationRegistry,
2903
- persistence: persistenceRef.current,
2904
- });
2905
- if (killed.ok) {
2906
- emitChatSurface(pi, {
2907
- kind: "killed",
2908
- run,
2909
- previousStatus: killed.previousStatus,
2910
- });
2911
- print(`Run ${killed.runId.slice(0, 8)} killed and retained for inspection.`);
2912
- } else if (killed.reason === "already_ended") {
2913
- print(formatAlreadyEndedRetainedMessage(killed.runId));
2914
- } else {
2915
- fail(`Run not found: ${result.runId.slice(0, 8)}.`);
2916
- }
2917
- return true;
2918
- }
2919
- return true;
2920
- }
2921
- const resolved = resolveRunIdPrefix(target);
2922
- if (resolved.kind === "not_found") {
2923
- fail(
2924
- `Run not found: ${target}\n\n${renderSessionList(store.runs(), { theme, includeAll: true })}`,
2925
- );
2926
- return true;
2927
- }
2928
- if (resolved.kind === "ambiguous") {
2929
- fail(
2930
- `Ambiguous run prefix "${target}" matches: ${resolved.matches
2931
- .map((id) => id.slice(0, 12))
2932
- .join(", ")}`,
2933
- );
2934
- return true;
2935
- }
2936
- if (failHeadlessAttachCommand("connect", resolved.runId)) {
2937
- return true;
2938
- }
2939
- if (policy.allowInputPicker) {
2940
- overlay.open(resolved.runId, overlaySurfaceFromContext(ctx));
2941
- }
2942
- print(
2943
- `Attached to ${resolved.runId.slice(0, 8)}. h/ctrl+d hide · q kill · esc close.`,
2944
- );
2945
- return true;
2946
- }
2947
-
2948
- if (action === "interrupt") {
2949
- const { tokens: interruptArgs, yes } = stripYesFlag(rest);
2950
- let target = interruptArgs.find((t) => !t.startsWith("--"));
2951
- const wantsAll = interruptArgs.includes("--all");
2952
- if (!target && !wantsAll) {
2953
- target = store.activeRunId() ?? undefined;
2954
- if (!target) {
2955
- fail("No in-flight runs to interrupt.");
2956
- return true;
2957
- }
2958
- }
2959
- if (wantsAll) {
2960
- const inFlight = topLevelWorkflowRuns(store.runs()).filter((r) => r.endedAt === undefined);
2961
- if (inFlight.length === 0) {
2962
- fail("No in-flight runs to interrupt.");
2963
- return true;
2964
- }
2965
- if (!yes && confirmationPrompt) {
2966
- const ok = await confirmationPrompt(
2967
- `Interrupt all ${inFlight.length} in-flight workflow runs?`,
2968
- `Pauses: ${inFlight.map((r) => `${r.name} (${r.id.slice(0, 8)})`).join(", ")}`,
2969
- );
2970
- if (!ok) {
2971
- print("Cancelled.");
2972
- return true;
2973
- }
2974
- }
2975
- const results = interruptAllRuns();
2976
- const interrupted = results.filter((r) => r.ok).length;
2977
- if (interrupted > 0) {
2978
- print(`Interrupted ${interrupted} run(s).`);
2979
- } else {
2980
- fail("No in-flight runs to interrupt.");
2981
- }
2982
- return true;
2983
- }
2984
- const resolved = resolveRunIdPrefix(target!);
2985
- if (resolved.kind === "not_found") {
2986
- fail(`Run not found: ${target}`);
2987
- return true;
2988
- }
2989
- if (resolved.kind === "ambiguous") {
2990
- fail(
2991
- `Ambiguous run prefix "${target}" matches multiple runs: ${resolved.matches
2992
- .map((id) => id.slice(0, 12))
2993
- .join(", ")}`,
2994
- );
2995
- return true;
2996
- }
2997
- const run = store.runs().find((r) => r.id === resolved.runId);
2998
- if (!yes && run && run.endedAt === undefined && confirmationPrompt) {
2999
- const confirmed = await confirmationPrompt(
3000
- `Interrupt workflow run ${run.name} (${run.id.slice(0, 8)})?`,
3001
- "Pauses live work so it can be resumed later.",
3002
- );
3003
- if (!confirmed) {
3004
- print(
3005
- `Cancelled. Run ${resolved.runId.slice(0, 8)} is still active.`,
3006
- );
3007
- return true;
3008
- }
3009
- }
3010
- const result = interruptRun(resolved.runId);
3011
- if (result.ok) {
3012
- print(
3013
- `Run ${result.runId.slice(0, 8)} interrupted and can be resumed.`,
3014
- );
3015
- } else {
3016
- fail(
3017
- result.reason === "not_found"
3018
- ? `Run not found: ${target}`
3019
- : result.reason === "already_ended"
3020
- ? `Run already ended: ${target}`
3021
- : result.reason === "stage_not_found"
3022
- ? `Stage not found for run ${resolved.runId.slice(0, 8)}.`
3023
- : `No active stages to interrupt on run ${resolved.runId.slice(0, 8)}.`,
3024
- );
3025
- }
3026
- return true;
3027
- }
3028
-
3029
- if (action === "kill") {
3030
- const { tokens: killArgs, yes } = stripYesFlag(rest);
3031
- let target = killArgs.find((t) => !t.startsWith("--"));
3032
- const wantsAll = killArgs.includes("--all");
3033
- if (!target && !wantsAll) {
3034
- target = store.activeRunId() ?? undefined;
3035
- if (!target) {
3036
- fail("No in-flight runs to kill.");
3037
- return true;
3038
- }
3039
- }
3040
- if (wantsAll) {
3041
- const inFlight = topLevelWorkflowRuns(store.runs()).filter((r) => r.endedAt === undefined);
3042
- if (inFlight.length === 0) {
3043
- fail("No in-flight runs to kill.");
3044
- return true;
3045
- }
3046
- if (!yes && confirmationPrompt) {
3047
- const ok = await confirmationPrompt(
3048
- `Kill ${inFlight.length} in-flight workflow runs? Killed runs are retained for inspection.`,
3049
- `Aborts: ${inFlight.map((r) => `${r.name} (${r.id.slice(0, 8)})`).join(", ")}`,
3050
- );
3051
- if (!ok) {
3052
- print("Cancelled.");
3053
- return true;
3054
- }
3055
- }
3056
- const results = killAllRuns({
3057
- cancellation: cancellationRegistry,
3058
- persistence: persistenceRef.current,
3059
- });
3060
- const killed = results.filter((r) => r.ok).length;
3061
- if (killed > 0) {
3062
- print(`Killed and retained ${killed} run(s) for inspection.`);
3063
- } else {
3064
- fail("No in-flight runs to kill.");
3065
- }
3066
- return true;
3067
- }
3068
- const resolved = resolveRunIdPrefix(target!);
3069
- if (resolved.kind === "not_found") {
3070
- fail(`Run not found: ${target}`);
3071
- return true;
3072
- }
3073
- if (resolved.kind === "ambiguous") {
3074
- fail(
3075
- `Ambiguous run prefix "${target}" matches multiple runs: ${resolved.matches
3076
- .map((id) => id.slice(0, 12))
3077
- .join(", ")}`,
3078
- );
3079
- return true;
3080
- }
3081
- const run = store.runs().find((r) => r.id === resolved.runId);
3082
- if (run?.endedAt !== undefined) {
3083
- print(formatAlreadyEndedRetainedMessage(resolved.runId));
3084
- return true;
3085
- }
3086
- if (!yes && run && confirmationPrompt) {
3087
- const confirmed = await openKillConfirm(ctx.ui, run, theme);
3088
- if (!confirmed) {
3089
- print(
3090
- `Cancelled. Run ${resolved.runId.slice(0, 8)} is still in history/status.`,
3091
- );
3092
- return true;
3093
- }
3094
- }
3095
- const result = killRun(resolved.runId, {
3096
- cancellation: cancellationRegistry,
3097
- persistence: persistenceRef.current,
3098
- });
3099
- if (result.ok) {
3100
- if (run) {
3101
- emitChatSurface(pi, {
3102
- kind: "killed",
3103
- run,
3104
- previousStatus: result.previousStatus,
3105
- });
3106
- }
3107
- print(
3108
- `Run ${result.runId.slice(0, 8)} killed and retained for inspection (was ${result.previousStatus}).`,
3109
- );
3110
- } else if (result.reason === "already_ended") {
3111
- print(formatAlreadyEndedRetainedMessage(result.runId));
3112
- } else {
3113
- fail(`Run not found: ${target}`);
3114
- }
3115
- return true;
3116
- }
3117
-
3118
- if (action === "attach") {
3119
- const target = rest[0];
3120
- const stageTarget = rest[1];
3121
- let runId: string;
3122
- if (!target) {
3123
- const ui = ctx.ui;
3124
- if (!canOpenPicker(ui)) {
3125
- fail(
3126
- `${renderSessionList(store.runs(), { theme, includeAll: true })}\n\nPicker requires an interactive UI surface. Pass a runId: /workflow attach <id> [stageId]`,
3127
- );
3128
- return true;
3129
- }
3130
- const picked = await openSessionPicker(ui, store, theme, "connect");
3131
- if (picked.kind === "close") return true;
3132
- if (picked.kind !== "connect") {
3133
- // The picker may have surfaced interrupt from the `x` shortcut.
3134
- // Forward through the existing interrupt flow for clarity.
3135
- if (picked.kind === "kill") {
3136
- return handleRunControlCommand(
3137
- "kill",
3138
- [picked.runId, "-y"],
3139
- ctx,
3140
- reporter,
3141
- );
3142
- }
3143
- return true;
3144
- }
3145
- runId = picked.runId;
3146
- } else {
3147
- const resolved = resolveRunIdPrefix(target);
3148
- if (resolved.kind === "not_found") {
3149
- fail(`Run not found: ${target}`);
3150
- return true;
3151
- }
3152
- if (resolved.kind === "ambiguous") {
3153
- fail(
3154
- `Ambiguous run prefix "${target}" matches: ${resolved.matches.map((id) => id.slice(0, 12)).join(", ")}`,
3155
- );
3156
- return true;
3157
- }
3158
- runId = resolved.runId;
3159
- }
3160
- const run = store.runs().find((r) => r.id === runId);
3161
- let stageId: string | undefined;
3162
- if (stageTarget && run) {
3163
- const exact = run.stages.find((s) => s.id === stageTarget);
3164
- const prefix =
3165
- exact ?? run.stages.find((s) => s.id.startsWith(stageTarget));
3166
- const byName = prefix ?? run.stages.find((s) => s.name === stageTarget);
3167
- if (!byName) {
3168
- fail(`Stage not found in run ${runId.slice(0, 8)}: ${stageTarget}`);
3169
- return true;
3170
- }
3171
- stageId = byName.id;
3172
- }
3173
- if (failHeadlessAttachCommand("attach", runId, stageId)) {
3174
- return true;
3175
- }
3176
- if (policy.allowInputPicker) {
3177
- overlay.open(runId, overlaySurfaceFromContext(ctx), stageId);
3178
- }
3179
- print(
3180
- stageId
3181
- ? `Attached to ${runId.slice(0, 8)} stage ${stageId.slice(0, 8)}. ctrl+d return to graph · esc close.`
3182
- : `Attached to ${runId.slice(0, 8)}. ↵ chat · ctrl+d detach.`,
3183
- );
3184
- return true;
3185
- }
3186
-
3187
- if (action === "pause") {
3188
- const target = rest[0];
3189
- const stageTarget = rest[1];
3190
- let runId: string;
3191
- if (!target) {
3192
- const ui = ctx.ui;
3193
- if (!canOpenPicker(ui)) {
3194
- const active = topLevelWorkflowRuns(store.runs()).filter((r) => r.endedAt === undefined);
3195
- if (active.length === 0) {
3196
- fail("No active runs to pause.");
3197
- return true;
3198
- }
3199
- fail(
3200
- `Picker requires an interactive UI surface. Active runs:\n${active.map((r) => ` ${r.id.slice(0, 8)} ${r.name}`).join("\n")}\n\nUsage: /workflow pause <runId> [stageId]`,
3201
- );
3202
- return true;
3203
- }
3204
- const picked = await openSessionPicker(ui, store, theme, "pause");
3205
- if (picked.kind !== "pause") return true;
3206
- runId = picked.runId;
3207
- } else {
3208
- const resolved = resolveRunIdPrefix(target);
3209
- if (resolved.kind === "not_found") {
3210
- fail(`Run not found: ${target}`);
3211
- return true;
3212
- }
3213
- if (resolved.kind === "ambiguous") {
3214
- fail(
3215
- `Ambiguous run prefix "${target}" matches: ${resolved.matches.map((id) => id.slice(0, 12)).join(", ")}`,
3216
- );
3217
- return true;
3218
- }
3219
- runId = resolved.runId;
3220
- }
3221
- let stageId: string | undefined;
3222
- let stageRunId = runId;
3223
- if (stageTarget) {
3224
- const resolvedStage = resolveStageTarget(runId, stageTarget);
3225
- if (!resolvedStage.ok) {
3226
- fail(resolvedStage.message);
3227
- return true;
3228
- }
3229
- stageId = resolvedStage.stageId;
3230
- stageRunId = resolvedStage.runId ?? runId;
3231
- }
3232
- const result = pauseRun(stageRunId, { stageId });
3233
- if (!result.ok) {
3234
- const why =
3235
- result.reason === "not_found"
3236
- ? `Run not found: ${stageRunId.slice(0, 8)}`
3237
- : result.reason === "already_ended"
3238
- ? `Run ${stageRunId.slice(0, 8)} already ended.`
3239
- : result.reason === "no_active_stages"
3240
- ? `No pausable stages on run ${stageRunId.slice(0, 8)}.`
3241
- : `Stage not found: ${stageTarget ?? "(unknown)"}`;
3242
- fail(why);
3243
- return true;
3244
- }
3245
- // Open the orchestrator overlay (graph for run-level pause, stage
3246
- // chat when a stage was named). This mirrors connect/attach/resume:
3247
- // the full-screen overlay hides Pi's "Working… (esc to interrupt)"
3248
- // spinner, which otherwise stays visible because the host session
3249
- // is still streaming whatever was happening before the pause hit.
3250
- if (policy.allowInputPicker) {
3251
- overlay.open(runId, overlaySurfaceFromContext(ctx), stageId);
3252
- }
3253
- print(
3254
- result.paused.length === 0
3255
- ? `No stages were paused on run ${stageRunId.slice(0, 8)}.`
3256
- : `Paused ${result.paused.length} stage(s) on run ${stageRunId.slice(0, 8)}: ${result.paused.map((s) => s.name).join(", ")}`,
3257
- );
3258
- return true;
3259
- }
3260
-
3261
- if (action === "resume") {
3262
- const target = rest[0];
3263
- const stageTarget = rest[1];
3264
- const message = rest.slice(2).join(" ").trim() || undefined;
3265
- let runId: string;
3266
- if (!target) {
3267
- const ui = ctx.ui;
3268
- if (!canOpenPicker(ui)) {
3269
- fail(`Usage: /workflow resume <runId> [stageId] [message…]`);
3270
- return true;
3271
- }
3272
- const picked = await openSessionPicker(ui, store, theme, "resume");
3273
- if (picked.kind !== "resume") return true;
3274
- runId = picked.runId;
3275
- } else {
3276
- const resolved = resolveRunIdPrefix(target);
3277
- if (resolved.kind === "not_found") {
3278
- fail(`Run not found: ${target}`);
3279
- return true;
3280
- }
3281
- if (resolved.kind === "ambiguous") {
3282
- fail(
3283
- `Ambiguous run prefix "${target}" matches: ${resolved.matches.map((id) => id.slice(0, 12)).join(", ")}`,
3284
- );
3285
- return true;
3286
- }
3287
- runId = resolved.runId;
3288
- }
3289
- let stageId: string | undefined;
3290
- const resolvedStage = resolveStageTarget(runId, stageTarget);
3291
- if (!resolvedStage.ok) {
3292
- fail(resolvedStage.message);
3293
- return true;
3294
- }
3295
- stageId = resolvedStage.stageId;
3296
- const stageRunId = resolvedStage.runId ?? runId;
3297
- const run = store.runs().find((r) => r.id === stageRunId);
3298
- const isPaused =
3299
- run?.status === "paused" ||
3300
- (run?.stages.some((s) => s.status === "paused") ?? false);
3301
- const isResumableContinuation = run !== undefined && !isPaused && (
3302
- (run.status === "failed" && run.endedAt !== undefined && run.resumable !== false) ||
3303
- (run.endedAt === undefined && run.resumable === true && run.failureRecoverability === "recoverable")
3304
- );
3305
- if (isResumableContinuation) {
3306
- const continuation = runtimeForContext(ctx).resumeFailedRun(stageRunId, stageId, { policy });
3307
- if (continuation.ok) {
3308
- print(continuation.message);
3309
- } else {
3310
- fail(continuation.message);
3311
- }
3312
- return true;
3313
- }
3314
- const result = resumeRun(stageRunId, { stageId, message });
3315
- if (!result.ok) {
3316
- fail(`Run not found: ${stageRunId.slice(0, 8)}`);
3317
- return true;
3318
- }
3319
- if (!isPaused) {
3320
- // Non-paused fallback: reopen the orchestrator overlay as before when interactive.
3321
- if (policy.allowInputPicker) {
3322
- overlay.open(result.runId, overlaySurfaceFromContext(ctx));
3323
- }
3324
- print(
3325
- result.message ?? `Snapshot available: run ${result.runId} (${result.snapshot.name}) \u2014 status: ${result.snapshot.status}, stages: ${result.snapshot.stages.length}`,
3326
- );
3327
- return true;
3328
- }
3329
- // Paused live resume: when no message was provided and the picker
3330
- // is available, open the attached chat so the user can talk to
3331
- // the freshly-resumed stage.
3332
- if (!message && stageId && policy.allowInputPicker) {
3333
- overlay.open(runId, overlaySurfaceFromContext(ctx), stageId);
3334
- }
3335
- if (result.resumed.length === 0) {
3336
- fail(`No paused stages on run ${stageRunId.slice(0, 8)}.`);
3337
- } else {
3338
- print(`Resumed ${result.resumed.length} stage(s) on run ${stageRunId.slice(0, 8)}${message ? ` with message: "${message}"` : ""}.`);
3339
- }
3340
- return true;
3341
- }
3342
-
3343
- return false;
3344
- }
3345
-
3346
- registerWorkflowCommand(
3347
- pi,
3348
- "workflow",
3349
- {
3350
- description:
3351
- "Run or inspect Atomic workflows. Usage: /workflow <name> [key=value…] | /workflow [list|status|connect|attach|interrupt|kill|pause|resume|inputs|reload] [args]",
3352
- handler: async (args: string, ctx: PiCommandContext) => {
3353
- const policy = workflowPolicyFromContext(ctx);
3354
- const reporter = createWorkflowCommandReporter(ctx, policy, pi);
3355
- const print = (msg: string): void => reporter.info(msg);
3356
- const fail = (msg: string): void => reporter.error(msg);
3357
- const withImplicitYesFlag = (tokens: string[]): string[] =>
3358
- tokens.some((t) => t === "--yes" || t === "-y") ? tokens : [...tokens, "-y"];
3359
- const showWorkflowInputs = async (
3360
- workflowName: string,
3361
- command: WorkflowCommandOutputDetails["command"] = "inputs",
3362
- ): Promise<void> => {
3363
- const result = await runtimeForContext(ctx).dispatch({
3364
- workflow: workflowName,
3365
- inputs: {},
3366
- action: "inputs",
3367
- }, { policy });
3368
- if (result.action === "inputs" && "inputs" in result) {
3369
- const r = result as Extract<
3370
- WorkflowToolResult,
3371
- { action: "inputs" }
3372
- >;
3373
- if (r.error) {
3374
- const available = runtimeProxy.registry.names();
3375
- fail(
3376
- `${r.error}\nAvailable: ${formatAvailableWorkflowNames(available)}`,
3377
- );
3378
- } else {
3379
- const schemaText = renderInputsSchema(workflowName, r.inputs, {
3380
- theme: deriveGraphTheme({}),
3381
- });
3382
- if (policy.mode === "non_interactive") {
3383
- emitWorkflowCommandOutput(pi, schemaText, {
3384
- command,
3385
- workflowName,
3386
- });
3387
- } else {
3388
- print(schemaText);
3389
- }
3390
- }
3391
- }
3392
- };
3393
- // Quote-aware split so `prompt="map the codebase"` stays a single
3394
- // token. Plain `.split(/\s+/)` would mangle quoted multi-word values
3395
- // into `prompt="map`, `the`, `codebase"` — the dispatch confirm then
3396
- // renders `prompt=""map"` (see ui/qa-current-render-2.png).
3397
- const parts = tokenizeWorkflowArgs(args);
3398
- const subcommand = parts[0] ?? "";
3399
-
3400
- // -----------------------------------------------------------------------
3401
- // connect — open the orchestrator pane (picker if no id).
3402
- // attach — open the in-place attach pane on a stage (or pick run).
3403
- // pause — pause a run or specific stage.
3404
- // -----------------------------------------------------------------------
3405
- if (subcommand === "connect") {
3406
- await handleRunControlCommand("connect", parts.slice(1), ctx, reporter);
3407
- return;
3408
- }
3409
- if (subcommand === "attach") {
3410
- await handleRunControlCommand("attach", parts.slice(1), ctx, reporter);
3411
- return;
3412
- }
3413
- if (subcommand === "pause") {
3414
- await handleRunControlCommand("pause", parts.slice(1), ctx, reporter);
3415
- return;
3416
- }
3417
-
3418
- // -----------------------------------------------------------------------
3419
- // list (default when no subcommand) — render the workflow catalogue
3420
- // via the same renderer used by the LLM tool path.
3421
- // -----------------------------------------------------------------------
3422
- if (!subcommand || subcommand === "list") {
3423
- const items = runtimeProxy.registry.all().map((def) => ({
3424
- name: def.normalizedName,
3425
- description: def.description,
3426
- inputs: Object.entries(def.inputs).map(([iname, schema]) => ({
3427
- name: iname,
3428
- required: schemaIsRequired(schema),
3429
- })),
3430
- }));
3431
- emitChatSurface(pi, { kind: "list", entries: items });
3432
- return;
3433
- }
3434
-
3435
- // -----------------------------------------------------------------------
3436
- // status — band-header rich list, or per-run detail when an id is
3437
- // supplied. `/workflow status` lists all retained snapshots; `/workflow
3438
- // status <id>` drills into a single run via the inspectRun detail block.
3439
- // -----------------------------------------------------------------------
3440
- if (subcommand === "status") {
3441
- const target = parts[1];
3442
- if (target && !target.startsWith("--")) {
3443
- const resolved = resolveRunIdPrefix(target);
3444
- if (resolved.kind === "not_found") {
3445
- fail(`Run not found: ${target}`);
3446
- return;
3447
- }
3448
- if (resolved.kind === "ambiguous") {
3449
- fail(
3450
- `Ambiguous run prefix "${target}" matches: ${resolved.matches
3451
- .map((id) => id.slice(0, 12))
3452
- .join(", ")}`,
3453
- );
3454
- return;
3455
- }
3456
- const inspected = inspectRun(resolved.runId);
3457
- if (!inspected.ok) {
3458
- fail(`Run not found: ${target}`);
3459
- return;
3460
- }
3461
- emitChatSurface(pi, { kind: "detail", detail: inspected.detail });
3462
- return;
3463
- }
3464
- // Status lists all retained snapshots by default; --all remains
3465
- // accepted as a compatibility no-op.
3466
- const rows = selectRunsForPicker(
3467
- store.runs(),
3468
- "",
3469
- true,
3470
- Date.now(),
3471
- );
3472
- emitChatSurface(pi, { kind: "status", runs: rows.map((r) => r.run) });
3473
- return;
3474
- }
3475
-
3476
- // -----------------------------------------------------------------------
3477
- // reload — refresh workflow resources in-process when no workflows are
3478
- // currently running. Reload swaps runtime/persistence wiring, so doing it
3479
- // mid-flight would split active runs across old and new resources.
3480
- // -----------------------------------------------------------------------
3481
- if (subcommand === "reload") {
3482
- const activeRuns = inFlightRunCount();
3483
- if (activeRuns > 0) {
3484
- fail(reloadBlockedMessage(activeRuns));
3485
- return;
3486
- }
3487
- try {
3488
- await reloadWorkflowResources();
3489
- print("Reloaded workflow resources.");
3490
- } catch (error) {
3491
- fail(reloadFailureMessage(error));
3492
- }
3493
- return;
3494
- }
3495
-
3496
- // -----------------------------------------------------------------------
3497
- // interrupt — top-level chat fast path (no confirmation overlay).
3498
- // -----------------------------------------------------------------------
3499
- if (subcommand === "interrupt") {
3500
- // The top-level chat command is the fast interrupt path surfaced by the
3501
- // widget hint (`/workflow interrupt <id>`). The user's explicit slash
3502
- // command should pause immediately, even when a confirm surface is
3503
- // unavailable or would steal focus from the running workflow.
3504
- const interruptArgs = parts.slice(1);
3505
- await handleRunControlCommand(
3506
- "interrupt",
3507
- withImplicitYesFlag(interruptArgs),
3508
- ctx,
3509
- reporter,
3510
- );
3511
- return;
3512
- }
3513
-
3514
- // -----------------------------------------------------------------------
3515
- // kill — abort in-flight work, mark killed, and retain for inspection.
3516
- // -----------------------------------------------------------------------
3517
- if (subcommand === "kill") {
3518
- const killArgs = parts.slice(1);
3519
- await handleRunControlCommand(
3520
- "kill",
3521
- withImplicitYesFlag(killArgs),
3522
- ctx,
3523
- reporter,
3524
- );
3525
- return;
3526
- }
3527
-
3528
- // -----------------------------------------------------------------------
3529
- // resume — non-paused runs reopen the orchestrator pane (legacy
3530
- // behaviour); paused runs resume live work through the registry.
3531
- // -----------------------------------------------------------------------
3532
- if (subcommand === "resume") {
3533
- await handleRunControlCommand("resume", parts.slice(1), ctx, reporter);
3534
- return;
3535
- }
3536
-
3537
- // -----------------------------------------------------------------------
3538
- // inputs — pretty-printed via theme; falls back to plain in non-TTY tests.
3539
- // -----------------------------------------------------------------------
3540
- if (subcommand === "inputs") {
3541
- const workflowName = parts[1] ?? "";
3542
- if (!workflowName) {
3543
- fail("Usage: /workflow inputs <name>");
3544
- return;
3545
- }
3546
- await showWorkflowInputs(workflowName);
3547
- return;
3548
- }
3549
-
3550
- // -----------------------------------------------------------------------
3551
- // Workflow name dispatch — workflows always run as background tasks.
3552
- // The chat editor remains usable; HIL prompts surface through the graph
3553
- // viewer overlay (F2 / `/workflow connect`).
3554
- // -----------------------------------------------------------------------
3555
- const workflowName = subcommand;
3556
- const inputTokens = parts.slice(1);
3557
-
3558
- if (inputTokens.includes("--help")) {
3559
- await showWorkflowInputs(workflowName, "help");
3560
- return;
3561
- }
3562
-
3563
- const inputs = parseWorkflowArgs(inputTokens);
3564
- // -----------------------------------------------------------------------
3565
- // Interactive argument picker.
3566
- //
3567
- // Triggers when:
3568
- // - the workflow has at least one declared input (zero-input
3569
- // workflows go straight to dispatch — there's nothing to ask),
3570
- // - the user did not pass `--no-picker`,
3571
- // - an interactive TUI surface is available,
3572
- // - AND either no key=value was supplied or one of the required
3573
- // inputs is still missing after parsing.
3574
- //
3575
- // The picker is seeded with whatever the user *did* type, so a
3576
- // partial invocation like `/workflow gen-spec research_doc=notes.md`
3577
- // pre-fills that field and focuses the next unfilled required one.
3578
- // -----------------------------------------------------------------------
3579
- const wantsPickerSkip = inputTokens.includes("--no-picker");
3580
- let mergedInputs = inputs;
3581
- // Track whether the inputs picker actually showed a UI to the user.
3582
- // We use this below to mount the orchestrator overlay on dispatch
3583
- // success — same UX as `/workflow connect|attach|pause|resume`,
3584
- // which all cover Pi's `⠴ Working… (esc to interrupt)` spinner
3585
- // with the full-screen overlay instead of leaving it visible in
3586
- // the chat while the workflow runs in the background.
3587
- let pickerWasShown = false;
3588
- // Prefer the sticky inline form when the host can install a custom
3589
- // editor. If the host rejects that editor contract at runtime, fall
3590
- // back to the supported overlay picker rather than surfacing the host
3591
- // exception as a workflow command error.
3592
- const canOpenPicker =
3593
- policy.allowInputPicker &&
3594
- !wantsPickerSkip &&
3595
- (typeof ctx.ui?.setEditorComponent === "function" ||
3596
- typeof ctx.ui?.custom === "function");
3597
- if (canOpenPicker) {
3598
- const schemaResult = await runtimeForContext(ctx).dispatch({
3599
- workflow: workflowName,
3600
- inputs: {},
3601
- action: "inputs",
3602
- }, { policy });
3603
- const schema =
3604
- schemaResult.action === "inputs" && "inputs" in schemaResult
3605
- ? (schemaResult as Extract<
3606
- WorkflowToolResult,
3607
- { action: "inputs" }
3608
- >)
3609
- : undefined;
3610
- const fields = schema?.inputs ?? [];
3611
- const hasFields = fields.length > 0;
3612
- const missingRequired = fields.some(
3613
- (f: WorkflowInputEntry) =>
3614
- f.required === true &&
3615
- (inputs[f.name] === undefined ||
3616
- (typeof inputs[f.name] === "string" &&
3617
- (inputs[f.name] as string).trim() === "")),
3618
- );
3619
- const noTokensAtAll = inputTokens.length === 0;
3620
- if (hasFields && (noTokensAtAll || missingRequired)) {
3621
- pickerWasShown = true;
3622
- const pickerTheme = deriveGraphTheme({});
3623
- let pickerResult =
3624
- typeof ctx.ui?.setEditorComponent === "function"
3625
- ? await openInlineInputsForm(pi, ctx, {
3626
- workflowName,
3627
- fields,
3628
- prefilled: inputs,
3629
- theme: pickerTheme,
3630
- })
3631
- : { kind: "unsupported" as const };
3632
- if (
3633
- pickerResult.kind === "unsupported" &&
3634
- typeof ctx.ui?.custom === "function"
3635
- ) {
3636
- pickerResult = await openInputsPicker(ctx.ui, {
3637
- workflowName,
3638
- fields,
3639
- prefilled: inputs,
3640
- theme: pickerTheme,
3641
- });
3642
- }
3643
- if (pickerResult.kind === "cancel") {
3644
- return;
3645
- }
3646
- if (pickerResult.kind === "run") {
3647
- mergedInputs = pickerResult.values;
3648
- }
3649
- }
3650
- }
3651
-
3652
- const result = await runWithLifecycleSuppressedForPolicy(policy, () =>
3653
- runtimeForContext(ctx).dispatch({
3654
- workflow: workflowName,
3655
- inputs: mergedInputs,
3656
- action: "run",
3657
- }, { policy }),
3658
- );
3659
- if (result.action === "run" && "runId" in result) {
3660
- const r = result as Extract<
3661
- WorkflowToolResult,
3662
- { action: "run"; runId: string }
3663
- >;
3664
- if (r.status === "failed" && r.runId === "") {
3665
- if (r.error?.toLowerCase().includes("not found")) {
3666
- const available = runtimeProxy.registry.names();
3667
- fail(
3668
- `Workflow not found: ${workflowName}\nAvailable: ${formatAvailableWorkflowNames(available)}`,
3669
- );
3670
- } else {
3671
- fail(
3672
- `Workflow "${workflowName}" failed: ${r.error ?? "unknown error"}`,
3673
- );
3674
- }
3675
- } else if (r.status === "failed") {
3676
- fail(
3677
- `Workflow "${workflowName}" failed: ${r.error ?? "unknown error"}`,
3678
- );
3679
- } else {
3680
- if (policy.mode === "non_interactive") {
3681
- emitTerminalRunDetailSurface(pi, workflowName, mergedInputs, r);
3682
- return;
3683
- }
3684
- // Always-background — the run is alive, the chat is free.
3685
- // Route via emitChatSurface so the band+card chrome receives the
3686
- // real chat content width via pi-tui's Component contract
3687
- // (registered renderer returns `{ render(width): string[] }`),
3688
- // not a `process.stdout.columns - 2` heuristic.
3689
- emitChatSurface(pi, {
3690
- kind: "dispatch",
3691
- workflowName,
3692
- runId: r.runId,
3693
- inputs: mergedInputs,
3694
- });
3695
- // When the user reached this path via the inputs picker (i.e.
3696
- // they didn't pre-supply all required args), open the
3697
- // orchestrator overlay. The full-screen overlay covers the
3698
- // chat statusContainer so Pi's working spinner is not left
3699
- // visible behind the dispatch card. Direct invocations with
3700
- // complete args remain opt-in via F2 / `/workflow connect`.
3701
- if (pickerWasShown && typeof ctx.ui?.custom === "function") {
3702
- overlay.open(r.runId, overlaySurfaceFromContext(ctx));
3703
- }
3704
- }
3705
- }
3706
- return;
3707
- },
3708
- getArgumentCompletions: (partial: string): PiArgumentCompletionResult => {
3709
- const completeToken = (
3710
- argumentText: string,
3711
- candidates: PiArgumentCompletion[],
3712
- ): PiArgumentCompletionResult => {
3713
- const tokenStart = /\s$/.test(argumentText)
3714
- ? argumentText.length
3715
- : Math.max(
3716
- argumentText.lastIndexOf(" "),
3717
- argumentText.lastIndexOf("\t"),
3718
- ) + 1;
3719
- const head = argumentText.slice(0, tokenStart);
3720
- const token = argumentText.slice(tokenStart);
3721
- const filtered = candidates
3722
- .filter((candidate) => candidate.value.startsWith(token))
3723
- .map((candidate) => ({
3724
- ...candidate,
3725
- value: `${head}${candidate.value}`,
3726
- }));
3727
- return filtered.length > 0 ? filtered : null;
3728
- };
3729
-
3730
- const workflowNameItems = (): PiArgumentCompletion[] =>
3731
- runtimeProxy.registry.names().map((name) => ({
3732
- value: `${name} `,
3733
- label: name,
3734
- description: `Run workflow: ${name}`,
3735
- }));
3736
-
3737
- const runIdItems = (): PiArgumentCompletion[] =>
3738
- topLevelWorkflowRuns(store.runs()).map((run) => ({
3739
- value: `${run.id} `,
3740
- label: run.id.slice(0, 8),
3741
- description: `${run.name} — ${run.status}`,
3742
- }));
3743
-
3744
- const adminCompletions: PiArgumentCompletion[] = [
3745
- {
3746
- value: "connect ",
3747
- label: "connect",
3748
- description: "Attach to a run (picker if no id)",
3749
- },
3750
- {
3751
- value: "attach ",
3752
- label: "attach",
3753
- description: "Open the in-place attach pane on a node",
3754
- },
3755
- {
3756
- value: "list ",
3757
- label: "list",
3758
- description: "List registered workflows",
3759
- },
3760
- {
3761
- value: "status ",
3762
- label: "status",
3763
- description: "List current-session active and retained terminal runs",
3764
- },
3765
- {
3766
- value: "interrupt ",
3767
- label: "interrupt",
3768
- description: "Interrupt a run",
3769
- },
3770
- {
3771
- value: "kill ",
3772
- label: "kill",
3773
- description: "Kill and retain a run for inspection",
3774
- },
3775
- {
3776
- value: "pause ",
3777
- label: "pause",
3778
- description: "Pause a run or stage",
3779
- },
3780
- {
3781
- value: "resume ",
3782
- label: "resume",
3783
- description: "Re-open overlay for a run",
3784
- },
3785
- {
3786
- value: "inputs ",
3787
- label: "inputs",
3788
- description: "Show a workflow's input schema",
3789
- },
3790
- {
3791
- value: "reload ",
3792
- label: "reload",
3793
- description: "Reload workflow resources",
3794
- },
3795
- ];
3796
-
3797
- const parts = partial.trim().split(/\s+/).filter(Boolean);
3798
- const subcommand = parts[0] ?? "";
3799
- if (!partial.includes(" ")) {
3800
- return completeToken(partial, [
3801
- ...adminCompletions,
3802
- ...workflowNameItems(),
3803
- ]);
3804
- }
3805
-
3806
- if (subcommand === "inputs") {
3807
- return completeToken(partial, workflowNameItems());
3808
- }
3809
-
3810
- if (subcommand === "status") {
3811
- return completeToken(partial, runIdItems());
3812
- }
3813
-
3814
- if (subcommand === "connect") {
3815
- return completeToken(partial, runIdItems());
3816
- }
3817
-
3818
- if (subcommand === "resume") {
3819
- return completeToken(partial, runIdItems());
3820
- }
3821
-
3822
- if (subcommand === "attach" || subcommand === "pause") {
3823
- return completeToken(partial, runIdItems());
3824
- }
3825
-
3826
- if (subcommand === "interrupt" || subcommand === "kill") {
3827
- const verb = subcommand === "kill" ? "Kill and retain" : "Interrupt";
3828
- return completeToken(partial, [
3829
- {
3830
- value: "--all ",
3831
- label: "--all",
3832
- description: `${verb} all in-flight runs`,
3833
- },
3834
- {
3835
- value: "--yes ",
3836
- label: "--yes",
3837
- description: "Skip confirmation",
3838
- },
3839
- { value: "-y ", label: "-y", description: "Skip confirmation" },
3840
- ...runIdItems(),
3841
- ]);
3842
- }
3843
-
3844
- // `partial` ends with whitespace and no subcommand was typed yet
3845
- // (e.g. `/workflow `). pi's autocomplete is asking what to suggest
3846
- // after the trailing space; offer the same admin + workflow-name
3847
- // menu as the no-space branch above. Skipping this guard would call
3848
- // `registry.get("")`, which throws TypeError from normalizeWorkflowName.
3849
- if (!subcommand) {
3850
- return completeToken(partial, [
3851
- ...adminCompletions,
3852
- ...workflowNameItems(),
3853
- ]);
3854
- }
3855
-
3856
- const workflow = runtimeProxy.registry.get(subcommand);
3857
- if (!workflow) return null;
3858
-
3859
- const tokenStart = /\s$/.test(partial)
3860
- ? partial.length
3861
- : Math.max(partial.lastIndexOf(" "), partial.lastIndexOf("\t")) + 1;
3862
- const token = partial.slice(tokenStart);
3863
- const equalsIndex = token.indexOf("=");
3864
- if (equalsIndex > 0) {
3865
- const inputName = token.slice(0, equalsIndex);
3866
- const schema = workflow.inputs[inputName];
3867
- const schemaChoiceValues = schema === undefined ? undefined : schemaChoices(schema);
3868
- const schemaKind = schema === undefined ? undefined : schemaFieldKind(schema);
3869
- if (schemaChoiceValues !== undefined) {
3870
- return completeToken(
3871
- partial,
3872
- schemaChoiceValues.map((choice) => ({
3873
- value: `${inputName}=${choice} `,
3874
- label: choice,
3875
- description: inputName,
3876
- })),
3877
- );
3878
- }
3879
- if (schemaKind === "boolean") {
3880
- return completeToken(partial, [
3881
- {
3882
- value: `${inputName}=true `,
3883
- label: "true",
3884
- description: inputName,
3885
- },
3886
- {
3887
- value: `${inputName}=false `,
3888
- label: "false",
3889
- description: inputName,
3890
- },
3891
- ]);
3892
- }
3893
- return null;
3894
- }
3895
-
3896
- const inputCompletions: PiArgumentCompletion[] = Object.entries(
3897
- workflow.inputs,
3898
- ).map(([name, schema]) => ({
3899
- value: `${name}=`,
3900
- label: name,
3901
- description: schemaDescription(schema),
3902
- }));
3903
- return completeToken(partial, [
3904
- {
3905
- value: "--no-picker ",
3906
- label: "--no-picker",
3907
- description: "Skip interactive input picker",
3908
- },
3909
- {
3910
- value: "--help ",
3911
- label: "--help",
3912
- description: "Show this workflow's input schema",
3913
- },
3914
- ...inputCompletions,
3915
- ]);
3916
- },
3917
- },
3918
- workflowCommands,
3919
- );
3920
-
3921
- // -------------------------------------------------------------------------
3922
- // 3. Register message renderers for lifecycle events (§5.6)
3923
- // -------------------------------------------------------------------------
3924
- // Chat-scroll renderers are deliberately limited to run-level events
3925
- // (start + end). Per-stage chatter is owned by the orchestrator pane —
3926
- // duplicating it into chat scroll just creates visual noise and pushes
3927
- // older chat content out of view every time a stage transitions.
3928
- if (typeof pi.registerMessageRenderer === "function") {
3929
- // Wrap the string-producing banners in a render component: the host adds a
3930
- // renderer's result directly as a TUI child, so a bare string would crash
3931
- // `Container.render()` with "child.render is not a function".
3932
- pi.registerMessageRenderer("workflow.run.start", (payload) =>
3933
- dynamicTextRenderComponent(() => renderRunBanner(payload as RunStartPayload)),
3934
- );
3935
- pi.registerMessageRenderer("workflow.run.end", (payload) =>
3936
- dynamicTextRenderComponent(() => renderRunSummary(payload as RunEndPayload)),
3937
- );
3938
- // Inline workflow-input form (Option C in the design conversation):
3939
- // a sticky chat-history card driven by a custom EditorComponent. The
3940
- // renderer reads form state from the module-level store keyed by
3941
- // `details.formId`. Registered once; openInlineInputsForm() emits the
3942
- // card via pi.sendMessage on each invocation.
3943
- registerInlineFormRenderer(pi, deriveGraphTheme({}));
3944
-
3945
- // Chat-scroll surfaces for /workflow run|list|status|status <id>. Bypasses
3946
- // the default `notify`/`Text(paddingX=1)` path so band+card chrome
3947
- // receives the *real* chat content width instead of a `cols - 2` heuristic.
3948
- // See src/tui/chat-surface-message.ts for the contract.
3949
- registerChatSurfaceRenderer(pi, deriveGraphTheme({}));
3950
- }
3951
-
3952
- // -------------------------------------------------------------------------
3953
- // 4. Persistence: session_start restore + session_before_compact hook (§5.6, Phase D)
3954
- // -------------------------------------------------------------------------
3955
- if (typeof pi.on === "function") {
3956
- pi.on("session_before_switch", async (event, ctx) => {
3957
- const reason = typeof event === "object" && event !== null && "reason" in event
3958
- ? (event as { readonly reason?: string }).reason
3959
- : undefined;
3960
- if (reason !== "new" && reason !== "resume") return undefined;
3961
-
3962
- // "In-flight" intentionally includes paused runs: session_start kills any run
3963
- // without endedAt, so warn for the same set that would be stopped by the switch.
3964
- const inFlightWorkflowCount = inFlightRunCount();
3965
- if (inFlightWorkflowCount === 0) return undefined;
3966
-
3967
- const confirmSessionSwitch = ctx?.ui?.confirm;
3968
- // Headless/non-interactive callers intentionally fail open so automation cannot wedge.
3969
- if (typeof confirmSessionSwitch !== "function") return undefined;
3970
-
3971
- const workflowNoun = inFlightWorkflowCount === 1 ? "workflow" : "workflows";
3972
- const actionLabel = reason === "new" ? "Start a new session" : "Resume another session";
3973
- const messageLabel = reason === "new" ? "Starting a new session" : "Resuming another session";
3974
- const promptTitle = `${actionLabel} and stop ${inFlightWorkflowCount} in-flight ${workflowNoun}?`;
3975
- const promptMessage =
3976
- `${messageLabel} will stop/kill ${inFlightWorkflowCount} in-flight ${workflowNoun} and clear workflow history tied to the current session.`;
3977
- let shouldSwitchSession: boolean | undefined;
3978
- try {
3979
- shouldSwitchSession = await confirmSessionSwitch(promptTitle, promptMessage);
3980
- } catch {
3981
- // Keep headless/failed UI behavior fail-open so session automation cannot wedge.
3982
- return undefined;
3983
- }
3984
- if (shouldSwitchSession) return undefined;
3985
-
3986
- const cancelledLabel = reason === "new" ? "New session" : "Resume";
3987
- ctx?.ui?.notify?.(`${cancelledLabel} cancelled; in-flight workflows were left unchanged.`, "info");
3988
- return { cancel: true };
3989
- });
3990
-
3991
- pi.on("session_start", async (_event, ctx) => {
3992
- // Non-interactive (`-p` / `--mode json`) sessions keep the workflow tool
3993
- // available for deterministic automation. Policy gates disable pickers
3994
- // and make runtime human-input APIs unavailable.
3995
- // Defense-in-depth for older/nonstandard hosts: remove only the
3996
- // unavailable human-input tool from the active tool set.
3997
- deAdvertiseAskUserQuestionWhenHeadless(pi, ctx?.hasUI);
3998
-
3999
- // Workflow lifecycle is scoped to the originating chat session.
4000
- // A new session inherits a clean store; any leftover live runs from a
4001
- // previous session in the same pi process are killed (subprocess
4002
- // aborted), then all stale snapshots are cleared. `restoreOnSessionStart`
4003
- // below loads *this* session's persisted runs from disk.
4004
- killAllRuns({
4005
- store,
4006
- cancellation: cancellationRegistry,
4007
- persistence: persistenceRef.current,
4008
- });
4009
- store.clear();
4010
- // Drop any inline input-form state from a previous session in this pi
4011
- // process. A resumed/replaced session must not render a stale live form,
4012
- // and rehydrated `workflows:input-form` cards then resolve to no backing
4013
- // state so their renderer suppresses output (input widget hidden after
4014
- // /resume).
4015
- clearForms();
4016
- resetWorkflowLifecycleNotificationState(lifecycleNotificationState);
4017
- resetWorkflowHilAnswerNotificationState(hilAnswerNotificationState);
4018
- stageControlRegistry.clear();
4019
-
4020
- // pi-intercom session naming lives here so we don't trip the
4021
- // loader's "Action methods cannot be called during extension
4022
- // loading" guard.
4023
- intercomParentSession = registerIntercomParentSession(pi);
4024
-
4025
- // Ensure config+discovery are ready before restoring in-flight runs —
4026
- // tunables must be resolved first.
4027
- await discoveryPromise;
4028
- lifecycleNotificationsActive = true;
4029
- hilAnswerNotificationsActive = true;
4030
- reinstallLifecycleNotifications();
4031
- reinstallHilAnswerNotifications();
4032
- if (ctx?.ui) {
4033
- const diagnostics = formatStartupDiagnostics(configLoadRef.current, discoveryRef.current);
4034
- if (diagnostics !== null) {
4035
- ctx.ui.notify?.(diagnostics, "warning");
4036
- }
4037
- storeWidgetUnsubscribe?.();
4038
- storeWidgetUnsubscribe = installStoreWidget({ ui: ctx.ui }, store);
4039
- }
4040
-
4041
- const sessionManager = ctx?.sessionManager ?? pi.sessionManager;
4042
- updateHostStageSessionDir(sessionManager);
4043
- if (sessionManager) {
4044
- const cfg = configLoadRef.current?.config;
4045
- withWorkflowLifecycleNotificationsSuppressed(
4046
- lifecycleNotificationState,
4047
- () => {
4048
- restoreOnSessionStart(
4049
- sessionManager,
4050
- {
4051
- resumeInFlight: cfg?.resumeInFlight ?? "ask",
4052
- persistRuns: cfg?.persistRuns ?? true,
4053
- },
4054
- store,
4055
- );
4056
- // The suppressed subscriber observes restore replay and marks matching
4057
- // notices delivered. Seed explicitly as a defensive backstop for
4058
- // runtimes without a lifecycle-notification subscriber installed.
4059
- seedWorkflowLifecycleNotificationState(
4060
- lifecycleNotificationState,
4061
- store.snapshot(),
4062
- );
4063
- },
4064
- );
4065
- }
4066
- });
4067
-
4068
- installCompactionHook(pi, store);
4069
- pi.on("session_shutdown", (event) => {
4070
- // Only application exit owns workflow teardown. Session replacement
4071
- // paths (reload/new/resume/fork) are handled by session_start restore
4072
- // logic so they do not masquerade as app-exit kills.
4073
- const reason = typeof event === "object" && event !== null && "reason" in event
4074
- ? (event as { readonly reason?: string }).reason
4075
- : undefined;
4076
- intercomControlUnsubscribe?.();
4077
- intercomControlUnsubscribe = null;
4078
- if (reason === "quit") {
4079
- killAllRuns({
4080
- store,
4081
- cancellation: cancellationRegistry,
4082
- persistence: persistenceRef.current,
4083
- });
4084
- stageControlRegistry.clear();
4085
- }
4086
- storeWidgetUnsubscribe?.();
4087
- storeWidgetUnsubscribe = null;
4088
- lifecycleNotificationsActive = false;
4089
- hilAnswerNotificationsActive = false;
4090
- lifecycleNotificationsUnsubscribe?.();
4091
- lifecycleNotificationsUnsubscribe = null;
4092
- hilAnswerNotificationsUnsubscribe?.();
4093
- hilAnswerNotificationsUnsubscribe = null;
4094
- });
4095
- }
4096
-
4097
- storeWidgetUnsubscribe = installStoreWidget(pi, store);
4098
- installToolExecutionHooks(pi, store);
4099
-
4100
- // -------------------------------------------------------------------------
4101
- // 5. Register F2 keyboard shortcut — open graph overlay for active run.
4102
- // Falls back to noop when pi.registerShortcut is absent (degraded runtime).
4103
- // Existing API shape: (key, { description, handler }).
4104
- //
4105
- // Note: the historical `ctrl+h` toggle was removed when workflow runs
4106
- // became background-by-default — a global toggle is no longer the
4107
- // primary way to manage visibility. Inside the pane, press `h` to
4108
- // hide (calls setHidden(true) on the overlay handle); re-open via
4109
- // `F2` or `/workflow connect <id>`.
4110
- // -------------------------------------------------------------------------
4111
- if (typeof pi.registerShortcut === "function") {
4112
- // Prefer the in-flight run; if nothing's active, fall back to the
4113
- // most recently observed run so users can still review what just
4114
- // finished without typing `/workflow resume <id>`.
4115
- const openPane = (ctx?: PiCommandContext): void => {
4116
- const activeRunId = store.activeRunId();
4117
- const fallback = activeRunId ?? store.runs().at(-1)?.id ?? null;
4118
- overlay.open(fallback, overlaySurfaceFromContext(ctx));
4119
- };
4120
-
4121
- pi.registerShortcut("F2", {
4122
- description: "Open workflow orchestrator pane",
4123
- handler: openPane,
4124
- });
4125
- }
4126
-
4127
- // -------------------------------------------------------------------------
4128
- // 6. Register sibling integrations (Phase G — §5.8, §5.9, §5.10)
4129
- // All registration calls are guarded; no throw when sibling is absent.
4130
- // Note: registerIntercomParentSession (pi-intercom session naming) calls
4131
- // pi.setSessionName which is an action method — see session_start handler
4132
- // above for that registration.
4133
- // -------------------------------------------------------------------------
4134
-
4135
- // pi-intercom: route subagent:control-intercom events to overlay/store callbacks.
4136
- // buildIntercomCallbacks wires store.recordNotice, pi.ui.confirm (when present),
4137
- // and pi.events.emit (when present) so escalations are never silently dropped.
4138
- intercomControlUnsubscribe = subscribeIntercomControl(
4139
- pi,
4140
- buildIntercomCallbacks({
4141
- store,
4142
- emit:
4143
- typeof pi.events?.emit === "function"
4144
- ? (event, payload) => pi.events!.emit!(event, payload)
4145
- : undefined,
4146
- confirm:
4147
- typeof pi.ui?.confirm === "function"
4148
- ? (title, message) => pi.ui!.confirm!(title, message)
4149
- : undefined,
4150
- }),
4151
- );
4152
-
4153
- // -------------------------------------------------------------------------
4154
- // 7. Suppress pi's optimistic "Working… (esc to interrupt)" loader
4155
- // for our slash commands. Workflow commands are synchronous picker /
4156
- // connect / inspect UIs, not streaming turns — the loader is noise
4157
- // that pads chrome above the picker. The `on("input")` hook fires
4158
- // BEFORE `startPendingSubmission`, so returning `{ action: "handled" }`
4159
- // short-circuits the host before the loader starts. We dispatch the
4160
- // registered handler ourselves. See `installInputInterceptor` for
4161
- // the full rationale and host pipeline reference.
4162
- // -------------------------------------------------------------------------
4163
- installInputInterceptor(pi, workflowCommands);
4164
- }
4165
-
4166
- export default factory;
1
+ export { default } from "./extension-factory.js";
2
+ export {
3
+ DEFAULT_PROMPT_GUIDANCE,
4
+ WORKFLOW_TOOL_DESCRIPTION,
5
+ } from "./workflow-prompts.js";
6
+ export {
7
+ WORKFLOW_NON_INTERACTIVE_MESSAGE,
8
+ workflowPolicyFromContext,
9
+ } from "./workflow-policy.js";
10
+ export { makeExecuteWorkflowTool } from "./workflow-tool.js";
11
+ export {
12
+ WORKFLOW_COMMAND_OUTPUT_CUSTOM_TYPE,
13
+ parseWorkflowArgs,
14
+ stripYesFlag,
15
+ tokenizeWorkflowArgs,
16
+ } from "./workflow-command-utils.js";
17
+ export { makeMcpPort, makePersistencePort } from "./workflow-ports.js";
18
+ export type {
19
+ ExtensionAPI,
20
+ PiAgentToolResult,
21
+ PiArgumentCompletion,
22
+ PiArgumentCompletionResult,
23
+ PiCommandContext,
24
+ PiCommandOptions,
25
+ PiExecuteContext,
26
+ PiFlagNamedOpts,
27
+ PiMessageRenderComponent,
28
+ PiMessageRenderOptions,
29
+ PiMessageRenderer,
30
+ PiMessageRendererResult,
31
+ PiModelContext,
32
+ PiRenderComponent,
33
+ PiRenderContext,
34
+ PiRenderResultOpts,
35
+ PiRuntimeModel,
36
+ PiRuntimeModelRegistry,
37
+ PiTheme,
38
+ PiToolOpts,
39
+ WorkflowExecuteToolResult,
40
+ WorkflowResourceInfo,
41
+ WorkflowToolArgs,
42
+ } from "./public-types.js";