@xopcai/xopc 0.0.86 → 0.0.88

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 (658) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/feishu/src/adapters/cli-login.js +3 -3
  3. package/dist/extensions/feishu/src/adapters/cli-login.js.map +1 -1
  4. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  5. package/dist/extensions/feishu/src/workflow-progress.js +1 -1
  6. package/dist/extensions/telegram/src/delivery-chat-id.d.ts +1 -1
  7. package/dist/extensions/telegram/src/delivery-chat-id.js +1 -1
  8. package/dist/extensions/telegram/src/delivery-chat-id.js.map +1 -1
  9. package/dist/extensions/telegram/src/plugin.js +1 -1
  10. package/dist/extensions/telegram/src/routing-integration.js +3 -2
  11. package/dist/extensions/telegram/src/routing-integration.js.map +1 -1
  12. package/dist/extensions/telegram/src/workflow-progress.js +1 -1
  13. package/dist/extensions/telegram/xopc.extension.json +1 -1
  14. package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js +2 -2
  15. package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js.map +1 -1
  16. package/dist/extensions/weixin/src/api/api.js +3 -3
  17. package/dist/extensions/weixin/src/api/api.js.map +1 -1
  18. package/dist/extensions/weixin/src/auth/accounts.js +12 -12
  19. package/dist/extensions/weixin/src/auth/accounts.js.map +1 -1
  20. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  21. package/dist/extensions/weixin/src/delivery-to.js +2 -2
  22. package/dist/extensions/weixin/src/delivery-to.js.map +1 -1
  23. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  24. package/dist/extensions/weixin/src/messaging/debug-mode.js +5 -5
  25. package/dist/extensions/weixin/src/messaging/debug-mode.js.map +1 -1
  26. package/dist/extensions/weixin/src/messaging/inbound.js +11 -11
  27. package/dist/extensions/weixin/src/messaging/inbound.js.map +1 -1
  28. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  29. package/dist/extensions/weixin/src/plugin.js +1 -1
  30. package/dist/extensions/weixin/src/storage/sync-buf.js +4 -4
  31. package/dist/extensions/weixin/src/storage/sync-buf.js.map +1 -1
  32. package/dist/extensions/weixin/src/workflow-progress.d.ts +1 -1
  33. package/dist/extensions/weixin/src/workflow-progress.js +1 -1
  34. package/dist/extensions/weixin/src/workflow-progress.js.map +1 -1
  35. package/dist/gateway/static/root/assets/agents-CRxETUZx.js +222 -0
  36. package/dist/gateway/static/root/assets/{apps-page-DrfytjOb.js → apps-page-wKWf3l57.js} +1 -1
  37. package/dist/gateway/static/root/assets/channels-settings-DDbqVNkx.js +1 -0
  38. package/dist/gateway/static/root/assets/{channels-status-swr-Bs5kMCMI.js → channels-status-swr-DIsl75Y3.js} +1 -1
  39. package/dist/gateway/static/root/assets/copy-SxMW6Xpc.js +1 -0
  40. package/dist/gateway/static/root/assets/{cron-api-BuVcZ5zR.js → cron-api-N9hvuRrn.js} +1 -1
  41. package/dist/gateway/static/root/assets/{cron-page-BMrloeFH.js → cron-page-tlNGNxhP.js} +1 -1
  42. package/dist/gateway/static/root/assets/{dist-CKU1OOTf.js → dist-CJwfHYvT.js} +1 -1
  43. package/dist/gateway/static/root/assets/{extension-debug-page-BdW_46sN.js → extension-debug-page-BVJohZoZ.js} +1 -1
  44. package/dist/gateway/static/root/assets/{extension-page-DW47KI82.js → extension-page-BT2tmElC.js} +1 -1
  45. package/dist/gateway/static/root/assets/extension-settings-page-BSS47c2j.js +1 -0
  46. package/dist/gateway/static/root/assets/{fetch-B2MYHbWg.js → fetch-BaFNUtkE.js} +1 -1
  47. package/dist/gateway/static/root/assets/{field-primitives-DPG-oJmx.js → field-primitives-QwYEq6Hz.js} +1 -1
  48. package/dist/gateway/static/root/assets/{heartbeat-config-api-C8dNts9i.js → heartbeat-config-api-BVSidEDJ.js} +1 -1
  49. package/dist/gateway/static/root/assets/index-CqZzHNEg.css +1 -0
  50. package/dist/gateway/static/root/assets/{index-BmVYculr.js → index-qNrVJp-y.js} +97 -95
  51. package/dist/gateway/static/root/assets/{logs-page-sTsVWz0X.js → logs-page-DDonPVLn.js} +1 -1
  52. package/dist/gateway/static/root/assets/sessions-page-DKt-Wmib.js +1 -0
  53. package/dist/gateway/static/root/assets/{settings-form-section-DuvRQW--.js → settings-form-section-B8N3A3Zo.js} +1 -1
  54. package/dist/gateway/static/root/assets/settings-page-DcJjvvw4.js +3 -0
  55. package/dist/gateway/static/root/assets/{share-preview-page-BtG2kLDh.js → share-preview-page-Q7KqkO-u.js} +1 -1
  56. package/dist/gateway/static/root/assets/skills-page-DuJ4BTO3.js +2 -0
  57. package/dist/gateway/static/root/assets/{theme-store-DryYl3qD.js → theme-store-BbRc5ugR.js} +1 -1
  58. package/dist/gateway/static/root/assets/url-D6jvVYIA.js +7 -0
  59. package/dist/gateway/static/root/assets/{utils-BY7bU1DT.js → utils-CxDGduqK.js} +1 -1
  60. package/dist/gateway/static/root/assets/voice-api-key-field-CTyHz7L_.js +1 -0
  61. package/dist/gateway/static/root/assets/workflows-page-GacJ41Fv.js +27 -0
  62. package/dist/gateway/static/root/index.html +6 -5
  63. package/dist/package.js +1 -1
  64. package/dist/src/agent/agent-manager.js +7 -7
  65. package/dist/src/agent/agent-scope.d.ts +4 -0
  66. package/dist/src/agent/agent-scope.js +53 -10
  67. package/dist/src/agent/agent-scope.js.map +1 -1
  68. package/dist/src/agent/bootstrap/filter-bootstrap-files.js +2 -1
  69. package/dist/src/agent/bootstrap/filter-bootstrap-files.js.map +1 -1
  70. package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
  71. package/dist/src/agent/child-agent-factory.d.ts +15 -0
  72. package/dist/src/agent/child-agent-factory.js +35 -2
  73. package/dist/src/agent/child-agent-factory.js.map +1 -1
  74. package/dist/src/agent/client-error-format.d.ts +20 -0
  75. package/dist/src/agent/client-error-format.js +97 -0
  76. package/dist/src/agent/client-error-format.js.map +1 -0
  77. package/dist/src/agent/context/workspace-seed.js +2 -2
  78. package/dist/src/agent/embedded/run-turn.js +23 -4
  79. package/dist/src/agent/embedded/run-turn.js.map +1 -1
  80. package/dist/src/agent/embedded/session-tool-result-guard.js +2 -1
  81. package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
  82. package/dist/src/agent/embedded/tool-result-truncation.js +2 -1
  83. package/dist/src/agent/embedded/tool-result-truncation.js.map +1 -1
  84. package/dist/src/agent/fallback/candidates.js +2 -2
  85. package/dist/src/agent/fallback/candidates.js.map +1 -1
  86. package/dist/src/agent/goals/goal-locale.d.ts +1 -1
  87. package/dist/src/agent/goals/goal-run-store.js +4 -4
  88. package/dist/src/agent/goals/persistent-goal-apis.d.ts +0 -2
  89. package/dist/src/agent/goals/persistent-goal-service.js +1 -2
  90. package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
  91. package/dist/src/agent/goals/post-turn.js +2 -2
  92. package/dist/src/agent/image/generation/normalization.js +2 -12
  93. package/dist/src/agent/image/generation/normalization.js.map +1 -1
  94. package/dist/src/agent/image/generation/provider-registry.d.ts +4 -8
  95. package/dist/src/agent/image/generation/provider-registry.js.map +1 -1
  96. package/dist/src/agent/image/generation/runtime.d.ts +2 -2
  97. package/dist/src/agent/image/generation/runtime.js.map +1 -1
  98. package/dist/src/agent/image/generation/types.d.ts +0 -18
  99. package/dist/src/agent/image/image-helpers.js +6 -1
  100. package/dist/src/agent/image/image-helpers.js.map +1 -1
  101. package/dist/src/agent/image/index.d.ts +1 -1
  102. package/dist/src/agent/image/load-image-media.js +2 -2
  103. package/dist/src/agent/inbound/inbound-loop.d.ts +5 -0
  104. package/dist/src/agent/inbound/inbound-loop.js +41 -10
  105. package/dist/src/agent/inbound/inbound-loop.js.map +1 -1
  106. package/dist/src/agent/inbound/turn-dispatcher.d.ts +4 -0
  107. package/dist/src/agent/inbound/turn-dispatcher.js +7 -5
  108. package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
  109. package/dist/src/agent/ipc/bus.js +1 -1
  110. package/dist/src/agent/ipc/inbox.js +2 -2
  111. package/dist/src/agent/ipc/socket.js +1 -1
  112. package/dist/src/agent/mcp/bundle-mcp-materialize.js +2 -1
  113. package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
  114. package/dist/src/agent/mcp/bundle-mcp-names.js +2 -1
  115. package/dist/src/agent/mcp/bundle-mcp-names.js.map +1 -1
  116. package/dist/src/agent/mcp/bundle-mcp-runtime.js +2 -1
  117. package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
  118. package/dist/src/agent/mcp/mcp-transport-config.js +2 -1
  119. package/dist/src/agent/mcp/mcp-transport-config.js.map +1 -1
  120. package/dist/src/agent/mcp/mcp-transport.js +2 -1
  121. package/dist/src/agent/mcp/mcp-transport.js.map +1 -1
  122. package/dist/src/agent/media-generation/runtime-shared.js +2 -9
  123. package/dist/src/agent/media-generation/runtime-shared.js.map +1 -1
  124. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  125. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  126. package/dist/src/agent/memory/dreaming/events.js +1 -1
  127. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  128. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  129. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  130. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  131. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  132. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  133. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  134. package/dist/src/agent/messaging/command-handler.d.ts +6 -0
  135. package/dist/src/agent/messaging/command-handler.js +5 -0
  136. package/dist/src/agent/messaging/command-handler.js.map +1 -1
  137. package/dist/src/agent/models/manager.js +1 -1
  138. package/dist/src/agent/orchestration/llm-turn-retry.d.ts +2 -0
  139. package/dist/src/agent/orchestration/llm-turn-retry.js +9 -1
  140. package/dist/src/agent/orchestration/llm-turn-retry.js.map +1 -1
  141. package/dist/src/agent/prompt/safety.d.ts +0 -7
  142. package/dist/src/agent/prompt/safety.js +1 -20
  143. package/dist/src/agent/prompt/safety.js.map +1 -1
  144. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  145. package/dist/src/agent/reply/post-compaction-context.js +1 -1
  146. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  147. package/dist/src/agent/sandbox/path-policy.js +2 -2
  148. package/dist/src/agent/service/build-direct-message-content.js +2 -2
  149. package/dist/src/agent/service/build-direct-message-content.js.map +1 -1
  150. package/dist/src/agent/service/direct-turn-helpers.d.ts +3 -1
  151. package/dist/src/agent/service/direct-turn-helpers.js +6 -1
  152. package/dist/src/agent/service/direct-turn-helpers.js.map +1 -1
  153. package/dist/src/agent/service/process-direct-one-shot.d.ts +4 -0
  154. package/dist/src/agent/service/process-direct-one-shot.js +15 -2
  155. package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
  156. package/dist/src/agent/service/process-direct-streaming.d.ts +4 -0
  157. package/dist/src/agent/service/process-direct-streaming.js +53 -7
  158. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  159. package/dist/src/agent/service/webchat-tts.d.ts +1 -2
  160. package/dist/src/agent/service/webchat-tts.js +2 -2
  161. package/dist/src/agent/service/webchat-tts.js.map +1 -1
  162. package/dist/src/agent/service.d.ts +8 -0
  163. package/dist/src/agent/service.js +25 -5
  164. package/dist/src/agent/service.js.map +1 -1
  165. package/dist/src/agent/session/session-inspector.js +1 -1
  166. package/dist/src/agent/skills/config.js +1 -1
  167. package/dist/src/agent/skills/hub-hash.js +2 -2
  168. package/dist/src/agent/skills/hub-lock.js +1 -1
  169. package/dist/src/agent/skills/hub-pull.js +2 -2
  170. package/dist/src/agent/skills/index.js +1 -1
  171. package/dist/src/agent/skills/managed-store.js +1 -1
  172. package/dist/src/agent/skills/scanner.js +1 -1
  173. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  174. package/dist/src/agent/skills/skill-manager.js +1 -1
  175. package/dist/src/agent/tools/create-share-tool.js +27 -20
  176. package/dist/src/agent/tools/create-share-tool.js.map +1 -1
  177. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  178. package/dist/src/agent/tools/factory.js +2 -2
  179. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  180. package/dist/src/agent/tools/index.d.ts +0 -1
  181. package/dist/src/agent/tools/index.js +4 -5
  182. package/dist/src/agent/tools/send-media.js +1 -1
  183. package/dist/src/agent/tools/shell.js +0 -13
  184. package/dist/src/agent/tools/shell.js.map +1 -1
  185. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  186. package/dist/src/agent/tools/workflow-tool.js +70 -16
  187. package/dist/src/agent/tools/workflow-tool.js.map +1 -1
  188. package/dist/src/agent/tools/write.js +1 -1
  189. package/dist/src/agent/workflow/agent-progress.d.ts +5 -0
  190. package/dist/src/agent/workflow/agent-progress.js +65 -0
  191. package/dist/src/agent/workflow/agent-progress.js.map +1 -0
  192. package/dist/src/agent/workflow/builtins/audit-repo.d.ts +1 -1
  193. package/dist/src/agent/workflow/builtins/audit-repo.js +14 -0
  194. package/dist/src/agent/workflow/builtins/audit-repo.js.map +1 -1
  195. package/dist/src/agent/workflow/builtins/debug-incident.d.ts +1 -1
  196. package/dist/src/agent/workflow/builtins/debug-incident.js +14 -0
  197. package/dist/src/agent/workflow/builtins/debug-incident.js.map +1 -1
  198. package/dist/src/agent/workflow/builtins/implementation-plan.d.ts +12 -0
  199. package/dist/src/agent/workflow/builtins/implementation-plan.js +175 -0
  200. package/dist/src/agent/workflow/builtins/implementation-plan.js.map +1 -0
  201. package/dist/src/agent/workflow/builtins/index.d.ts +3 -1
  202. package/dist/src/agent/workflow/builtins/index.js +11 -1
  203. package/dist/src/agent/workflow/builtins/index.js.map +1 -1
  204. package/dist/src/agent/workflow/builtins/multi-perspective-review.d.ts +1 -1
  205. package/dist/src/agent/workflow/builtins/multi-perspective-review.js +14 -0
  206. package/dist/src/agent/workflow/builtins/multi-perspective-review.js.map +1 -1
  207. package/dist/src/agent/workflow/builtins/pr-review.d.ts +1 -1
  208. package/dist/src/agent/workflow/builtins/pr-review.js +14 -0
  209. package/dist/src/agent/workflow/builtins/pr-review.js.map +1 -1
  210. package/dist/src/agent/workflow/builtins/release-check.d.ts +11 -0
  211. package/dist/src/agent/workflow/builtins/release-check.js +165 -0
  212. package/dist/src/agent/workflow/builtins/release-check.js.map +1 -0
  213. package/dist/src/agent/workflow/builtins/research.d.ts +1 -1
  214. package/dist/src/agent/workflow/builtins/research.js +14 -0
  215. package/dist/src/agent/workflow/builtins/research.js.map +1 -1
  216. package/dist/src/agent/workflow/catalog.js +1 -1
  217. package/dist/src/agent/workflow/channel-capability.d.ts +3 -3
  218. package/dist/src/agent/workflow/index.d.ts +2 -1
  219. package/dist/src/agent/workflow/index.js +3 -2
  220. package/dist/src/agent/workflow/lint.d.ts +38 -0
  221. package/dist/src/agent/workflow/lint.js +74 -0
  222. package/dist/src/agent/workflow/lint.js.map +1 -0
  223. package/dist/src/agent/workflow/meta-locale.d.ts +12 -0
  224. package/dist/src/agent/workflow/meta-locale.js +62 -0
  225. package/dist/src/agent/workflow/meta-locale.js.map +1 -0
  226. package/dist/src/agent/workflow/parser.js +7 -1
  227. package/dist/src/agent/workflow/parser.js.map +1 -1
  228. package/dist/src/agent/workflow/runtime.d.ts +4 -1
  229. package/dist/src/agent/workflow/runtime.js +88 -8
  230. package/dist/src/agent/workflow/runtime.js.map +1 -1
  231. package/dist/src/agent/workflow/snapshot.js +2 -12
  232. package/dist/src/agent/workflow/snapshot.js.map +1 -1
  233. package/dist/src/agent/workflow/step-labels.d.ts +8 -0
  234. package/dist/src/agent/workflow/step-labels.js +48 -0
  235. package/dist/src/agent/workflow/step-labels.js.map +1 -0
  236. package/dist/src/agent/workflow/subagent-runner.js +46 -1
  237. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  238. package/dist/src/agent/workflow/types.d.ts +76 -1
  239. package/dist/src/auth/credentials.d.ts +5 -0
  240. package/dist/src/auth/credentials.js +12 -3
  241. package/dist/src/auth/credentials.js.map +1 -1
  242. package/dist/src/auth/profiles/store.js +1 -1
  243. package/dist/src/auth/sync-provider-auth.js +1 -1
  244. package/dist/src/browser/cache-dir-policy.js +1 -1
  245. package/dist/src/browser/cdp-local-launcher.js +2 -2
  246. package/dist/src/browser/index.js +4 -4
  247. package/dist/src/browser/manager.d.ts +1 -3
  248. package/dist/src/browser/manager.js +0 -6
  249. package/dist/src/browser/manager.js.map +1 -1
  250. package/dist/src/browser/providers/browser-ext-install.d.ts +4 -4
  251. package/dist/src/browser/providers/browser-ext-install.js +41 -88
  252. package/dist/src/browser/providers/browser-ext-install.js.map +1 -1
  253. package/dist/src/browser/providers/cloakbrowser.d.ts +0 -5
  254. package/dist/src/browser/providers/cloakbrowser.js +6 -59
  255. package/dist/src/browser/providers/cloakbrowser.js.map +1 -1
  256. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  257. package/dist/src/browser/stealth.js +1 -1
  258. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  259. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  260. package/dist/src/channels/attachments/voice-stt-webchat.js +10 -8
  261. package/dist/src/channels/attachments/voice-stt-webchat.js.map +1 -1
  262. package/dist/src/channels/outbound/persist-store.js +1 -1
  263. package/dist/src/channels/pairing/allow-from-file.js +9 -9
  264. package/dist/src/channels/pairing/allow-from-file.js.map +1 -1
  265. package/dist/src/channels/pairing/pairing-store.js +7 -7
  266. package/dist/src/channels/pairing/pairing-store.js.map +1 -1
  267. package/dist/src/chat-commands/builtins/config.js +2 -2
  268. package/dist/src/chat-commands/builtins/session.js +1 -1
  269. package/dist/src/chat-commands/builtins/session.js.map +1 -1
  270. package/dist/src/chat-commands/builtins/tts.js +2 -2
  271. package/dist/src/chat-commands/builtins/tts.js.map +1 -1
  272. package/dist/src/chat-commands/context.d.ts +3 -0
  273. package/dist/src/chat-commands/context.js +22 -4
  274. package/dist/src/chat-commands/context.js.map +1 -1
  275. package/dist/src/chat-commands/session-key.d.ts +4 -37
  276. package/dist/src/chat-commands/session-key.js +49 -85
  277. package/dist/src/chat-commands/session-key.js.map +1 -1
  278. package/dist/src/chat-commands/types.d.ts +2 -0
  279. package/dist/src/cli/commands/agent/interactive.js +2 -2
  280. package/dist/src/cli/commands/agent/interactive.js.map +1 -1
  281. package/dist/src/cli/commands/agent/sessions.js +2 -2
  282. package/dist/src/cli/commands/agent/sessions.js.map +1 -1
  283. package/dist/src/cli/commands/agent.js +4 -5
  284. package/dist/src/cli/commands/agent.js.map +1 -1
  285. package/dist/src/cli/commands/channels.js +1 -5
  286. package/dist/src/cli/commands/channels.js.map +1 -1
  287. package/dist/src/cli/commands/config.js +1 -1
  288. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  289. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  290. package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
  291. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  292. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  293. package/dist/src/cli/commands/extension-dev.js +1 -1
  294. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  295. package/dist/src/cli/commands/extension-pack.js +1 -1
  296. package/dist/src/cli/commands/gateway/lifecycle-core.js +1 -1
  297. package/dist/src/cli/commands/gateway/lifecycle-core.js.map +1 -1
  298. package/dist/src/cli/commands/gateway/logs.d.ts +9 -0
  299. package/dist/src/cli/commands/gateway/logs.js +50 -17
  300. package/dist/src/cli/commands/gateway/logs.js.map +1 -1
  301. package/dist/src/cli/commands/image.js +23 -22
  302. package/dist/src/cli/commands/image.js.map +1 -1
  303. package/dist/src/cli/commands/init.js +4 -4
  304. package/dist/src/cli/commands/onboard.js +1 -1
  305. package/dist/src/cli/commands/session/utils.js +2 -2
  306. package/dist/src/cli/commands/session/utils.js.map +1 -1
  307. package/dist/src/cli/commands/update.js +26 -46
  308. package/dist/src/cli/commands/update.js.map +1 -1
  309. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  310. package/dist/src/cli/utils/session.d.ts +0 -5
  311. package/dist/src/cli/utils/session.js +1 -6
  312. package/dist/src/cli/utils/session.js.map +1 -1
  313. package/dist/src/commands/agents.config.js +1 -1
  314. package/dist/src/commands/agents.config.js.map +1 -1
  315. package/dist/src/config/agent-profile.js +6 -28
  316. package/dist/src/config/agent-profile.js.map +1 -1
  317. package/dist/src/config/agent-typed-models.d.ts +18 -0
  318. package/dist/src/config/agent-typed-models.js +53 -0
  319. package/dist/src/config/agent-typed-models.js.map +1 -0
  320. package/dist/src/config/gateway-bind.js +1 -1
  321. package/dist/src/config/index.js +6 -6
  322. package/dist/src/config/loader.js +2 -2
  323. package/dist/src/config/model-input.js +2 -5
  324. package/dist/src/config/model-input.js.map +1 -1
  325. package/dist/src/config/models-json.js +2 -2
  326. package/dist/src/config/paths-state.js +1 -1
  327. package/dist/src/config/profile.js +2 -2
  328. package/dist/src/config/schema.d.ts +253 -217
  329. package/dist/src/config/schema.js +91 -40
  330. package/dist/src/config/schema.js.map +1 -1
  331. package/dist/src/config/voice.d.ts +3 -28
  332. package/dist/src/config/voice.js +27 -261
  333. package/dist/src/config/voice.js.map +1 -1
  334. package/dist/src/config/workspace-path-helpers.d.ts +1 -2
  335. package/dist/src/config/workspace-path-helpers.js.map +1 -1
  336. package/dist/src/config/workspace-path.js +1 -1
  337. package/dist/src/cron/executor.js +2 -2
  338. package/dist/src/cron/persistence.js +1 -1
  339. package/dist/src/cron/run-log-store.js +1 -1
  340. package/dist/src/daemon/constants.js +1 -1
  341. package/dist/src/daemon/install-plan.js +27 -3
  342. package/dist/src/daemon/install-plan.js.map +1 -1
  343. package/dist/src/daemon/launchd.d.ts +8 -0
  344. package/dist/src/daemon/launchd.js +7 -14
  345. package/dist/src/daemon/launchd.js.map +1 -1
  346. package/dist/src/daemon/schtasks.d.ts +25 -0
  347. package/dist/src/daemon/schtasks.js +168 -48
  348. package/dist/src/daemon/schtasks.js.map +1 -1
  349. package/dist/src/daemon/service.js +5 -4
  350. package/dist/src/daemon/service.js.map +1 -1
  351. package/dist/src/daemon/systemd.d.ts +6 -0
  352. package/dist/src/daemon/systemd.js +20 -5
  353. package/dist/src/daemon/systemd.js.map +1 -1
  354. package/dist/src/extensions/activation-context.js +0 -1
  355. package/dist/src/extensions/activation-context.js.map +1 -1
  356. package/dist/src/extensions/bundle-mcp.js +1 -1
  357. package/dist/src/extensions/discover-extensions.js +1 -1
  358. package/dist/src/extensions/health.js +1 -1
  359. package/dist/src/extensions/loader.js +1 -1
  360. package/dist/src/extensions/lockfile.js +2 -2
  361. package/dist/src/extensions/normalize-manifest.js +0 -1
  362. package/dist/src/extensions/normalize-manifest.js.map +1 -1
  363. package/dist/src/extensions/types/manifest.d.ts +0 -2
  364. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  365. package/dist/src/gateway/agent-builtin-tools.js +1 -0
  366. package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
  367. package/dist/src/gateway/agents-admin.d.ts +9 -0
  368. package/dist/src/gateway/agents-admin.js +28 -4
  369. package/dist/src/gateway/agents-admin.js.map +1 -1
  370. package/dist/src/gateway/config-tools-web.js +3 -2
  371. package/dist/src/gateway/config-tools-web.js.map +1 -1
  372. package/dist/src/gateway/file-path-classifier.js +2 -2
  373. package/dist/src/gateway/heartbeat/service.js +2 -2
  374. package/dist/src/gateway/heartbeat/service.js.map +1 -1
  375. package/dist/src/gateway/hono/app.js +1 -1
  376. package/dist/src/gateway/hono/lib/agent-model.d.ts +25 -10
  377. package/dist/src/gateway/hono/lib/agent-model.js +60 -36
  378. package/dist/src/gateway/hono/lib/agent-model.js.map +1 -1
  379. package/dist/src/gateway/hono/lib/config-payload.js +29 -6
  380. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  381. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  382. package/dist/src/gateway/hono/lib/mask-secret-length.d.ts +6 -0
  383. package/dist/src/gateway/hono/lib/mask-secret-length.js +16 -0
  384. package/dist/src/gateway/hono/lib/mask-secret-length.js.map +1 -0
  385. package/dist/src/gateway/hono/lib/safe-providers-config.d.ts +1 -1
  386. package/dist/src/gateway/hono/lib/safe-providers-config.js +2 -1
  387. package/dist/src/gateway/hono/lib/safe-providers-config.js.map +1 -1
  388. package/dist/src/gateway/hono/lib/safe-voice-config.js +16 -54
  389. package/dist/src/gateway/hono/lib/safe-voice-config.js.map +1 -1
  390. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  391. package/dist/src/gateway/hono/oauth.js +1 -1
  392. package/dist/src/gateway/hono/routes/agents.js +2 -2
  393. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  394. package/dist/src/gateway/hono/routes/config-patch/agents.js +25 -7
  395. package/dist/src/gateway/hono/routes/config-patch/agents.js.map +1 -1
  396. package/dist/src/gateway/hono/routes/config-patch/channels.js +0 -11
  397. package/dist/src/gateway/hono/routes/config-patch/channels.js.map +1 -1
  398. package/dist/src/gateway/hono/routes/config-patch/gateway.js +3 -2
  399. package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
  400. package/dist/src/gateway/hono/routes/config-patch/misc.js +8 -3
  401. package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -1
  402. package/dist/src/gateway/hono/routes/config.js +59 -0
  403. package/dist/src/gateway/hono/routes/config.js.map +1 -1
  404. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  405. package/dist/src/gateway/hono/routes/goals.js +1 -1
  406. package/dist/src/gateway/hono/routes/goals.js.map +1 -1
  407. package/dist/src/gateway/hono/routes/host-fs.js +2 -2
  408. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  409. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  410. package/dist/src/gateway/hono/routes/models.js +75 -12
  411. package/dist/src/gateway/hono/routes/models.js.map +1 -1
  412. package/dist/src/gateway/hono/routes/sessions.js +28 -7
  413. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  414. package/dist/src/gateway/hono/routes/shares.js +15 -13
  415. package/dist/src/gateway/hono/routes/shares.js.map +1 -1
  416. package/dist/src/gateway/hono/routes/tunnel.js +1 -1
  417. package/dist/src/gateway/hono/routes/update.js +4 -2
  418. package/dist/src/gateway/hono/routes/update.js.map +1 -1
  419. package/dist/src/gateway/hono/routes/voice.js +75 -0
  420. package/dist/src/gateway/hono/routes/voice.js.map +1 -1
  421. package/dist/src/gateway/hono/routes/workflows.d.ts +3 -0
  422. package/dist/src/gateway/hono/routes/workflows.js +347 -0
  423. package/dist/src/gateway/hono/routes/workflows.js.map +1 -0
  424. package/dist/src/gateway/hono/routes/workspace.js +4 -4
  425. package/dist/src/gateway/hono/sse.js +16 -33
  426. package/dist/src/gateway/hono/sse.js.map +1 -1
  427. package/dist/src/gateway/lock.js +11 -11
  428. package/dist/src/gateway/lock.js.map +1 -1
  429. package/dist/src/gateway/ports.js +6 -6
  430. package/dist/src/gateway/ports.js.map +1 -1
  431. package/dist/src/gateway/resolve-webchat-session-key.d.ts +19 -0
  432. package/dist/src/gateway/resolve-webchat-session-key.js +46 -0
  433. package/dist/src/gateway/resolve-webchat-session-key.js.map +1 -0
  434. package/dist/src/gateway/service/agent-runner.js +2 -2
  435. package/dist/src/gateway/service/marketplace-service.js +2 -2
  436. package/dist/src/gateway/service/run-gateway-agent.js +9 -11
  437. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  438. package/dist/src/gateway/service/sessions-api.d.ts +3 -0
  439. package/dist/src/gateway/service/sessions-api.js +8 -0
  440. package/dist/src/gateway/service/sessions-api.js.map +1 -1
  441. package/dist/src/gateway/service.d.ts +3 -2
  442. package/dist/src/gateway/service.js +9 -8
  443. package/dist/src/gateway/service.js.map +1 -1
  444. package/dist/src/gateway/session-reset-service.d.ts +20 -0
  445. package/dist/src/gateway/session-reset-service.js +54 -0
  446. package/dist/src/gateway/session-reset-service.js.map +1 -0
  447. package/dist/src/gateway/startup-readiness.d.ts +1 -1
  448. package/dist/src/gateway/startup-readiness.js +1 -0
  449. package/dist/src/gateway/startup-readiness.js.map +1 -1
  450. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  451. package/dist/src/heartbeat/index.js +1 -1
  452. package/dist/src/infra/gateway-processes.js +2 -2
  453. package/dist/src/infra/gateway-processes.js.map +1 -1
  454. package/dist/src/infra/restart.js +2 -2
  455. package/dist/src/infra/run-command.d.ts +16 -0
  456. package/dist/src/infra/run-command.js +67 -0
  457. package/dist/src/infra/run-command.js.map +1 -0
  458. package/dist/src/infra/update-check.js +1 -1
  459. package/dist/src/infra/update-global.d.ts +45 -0
  460. package/dist/src/infra/update-global.js +224 -0
  461. package/dist/src/infra/update-global.js.map +1 -0
  462. package/dist/src/infra/update-lock.js +3 -3
  463. package/dist/src/infra/update-runner.js +1 -1
  464. package/dist/src/infra/update-startup.js +2 -2
  465. package/dist/src/infra/write-file-atomic.js +2 -2
  466. package/dist/src/mcp/channel-shared.js +2 -1
  467. package/dist/src/mcp/channel-shared.js.map +1 -1
  468. package/dist/src/providers/auth-runtime/auth-profile-store.js +2 -2
  469. package/dist/src/providers/auth-runtime/auth-profile-store.js.map +1 -1
  470. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -12
  471. package/dist/src/providers/auth-runtime/resolve-auth.js.map +1 -1
  472. package/dist/src/providers/auth-runtime/types.d.ts +6 -12
  473. package/dist/src/providers/index.js +2 -2
  474. package/dist/src/providers/model-registry.js +1 -1
  475. package/dist/src/routing/agent-session-key.d.ts +58 -0
  476. package/dist/src/routing/agent-session-key.js +164 -0
  477. package/dist/src/routing/agent-session-key.js.map +1 -0
  478. package/dist/src/routing/index.d.ts +1 -1
  479. package/dist/src/routing/index.js +4 -2
  480. package/dist/src/routing/index.js.map +1 -1
  481. package/dist/src/routing/resolve-route.d.ts +15 -0
  482. package/dist/src/routing/resolve-route.js +41 -20
  483. package/dist/src/routing/resolve-route.js.map +1 -1
  484. package/dist/src/routing/resolve-tui-session-key.d.ts +25 -0
  485. package/dist/src/routing/resolve-tui-session-key.js +54 -0
  486. package/dist/src/routing/resolve-tui-session-key.js.map +1 -0
  487. package/dist/src/routing/session-key-utils.d.ts +24 -0
  488. package/dist/src/routing/session-key-utils.js +92 -0
  489. package/dist/src/routing/session-key-utils.js.map +1 -0
  490. package/dist/src/routing/session-key.d.ts +19 -49
  491. package/dist/src/routing/session-key.js +143 -116
  492. package/dist/src/routing/session-key.js.map +1 -1
  493. package/dist/src/session/config-store.js +2 -2
  494. package/dist/src/session/index.d.ts +6 -0
  495. package/dist/src/session/index.js +7 -1
  496. package/dist/src/session/init-session-turn.d.ts +30 -0
  497. package/dist/src/session/init-session-turn.js +102 -0
  498. package/dist/src/session/init-session-turn.js.map +1 -0
  499. package/dist/src/session/lifecycle-timestamps.d.ts +8 -0
  500. package/dist/src/session/lifecycle-timestamps.js +16 -0
  501. package/dist/src/session/lifecycle-timestamps.js.map +1 -0
  502. package/dist/src/session/manager.d.ts +7 -1
  503. package/dist/src/session/manager.js +8 -1
  504. package/dist/src/session/manager.js.map +1 -1
  505. package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
  506. package/dist/src/session/parity/sessions-json-file.js +1 -1
  507. package/dist/src/session/parity/transcript-file-lock.js +2 -2
  508. package/dist/src/session/parity/transcript-paths.js +2 -2
  509. package/dist/src/session/parity/transcript-paths.js.map +1 -1
  510. package/dist/src/session/parity/xopc-session-disk-entry.d.ts +6 -0
  511. package/dist/src/session/reset-policy.d.ts +32 -0
  512. package/dist/src/session/reset-policy.js +65 -0
  513. package/dist/src/session/reset-policy.js.map +1 -0
  514. package/dist/src/session/reset-triggers.d.ts +20 -0
  515. package/dist/src/session/reset-triggers.js +63 -0
  516. package/dist/src/session/reset-triggers.js.map +1 -0
  517. package/dist/src/session/reset-type.d.ts +12 -0
  518. package/dist/src/session/reset-type.js +25 -0
  519. package/dist/src/session/reset-type.js.map +1 -0
  520. package/dist/src/session/resolve-session.d.ts +30 -0
  521. package/dist/src/session/resolve-session.js +93 -0
  522. package/dist/src/session/resolve-session.js.map +1 -0
  523. package/dist/src/session/search-index-cache.js +1 -1
  524. package/dist/src/session/search-index.js +1 -1
  525. package/dist/src/session/session-title.js +3 -2
  526. package/dist/src/session/session-title.js.map +1 -1
  527. package/dist/src/session/store.d.ts +11 -4
  528. package/dist/src/session/store.js +62 -11
  529. package/dist/src/session/store.js.map +1 -1
  530. package/dist/src/session/transcript-events.js +2 -1
  531. package/dist/src/session/transcript-events.js.map +1 -1
  532. package/dist/src/share/share-auto.js +2 -2
  533. package/dist/src/share/share-store.js +3 -3
  534. package/dist/src/share/share-thumbnail.js +2 -2
  535. package/dist/src/share/share-url.d.ts +33 -0
  536. package/dist/src/share/share-url.js +56 -14
  537. package/dist/src/share/share-url.js.map +1 -1
  538. package/dist/src/share/share-zip.js +1 -1
  539. package/dist/src/share/site-share-store.js +3 -3
  540. package/dist/src/share/site-static-serve.js +1 -1
  541. package/dist/src/tui/backends/embedded-backend.js +4 -9
  542. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  543. package/dist/src/tui/backends/gateway-sse-backend.js +1 -1
  544. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  545. package/dist/src/tui/clipboard-image.js +3 -3
  546. package/dist/src/tui/components/chat-log.js +3 -3
  547. package/dist/src/tui/components/chat-log.js.map +1 -1
  548. package/dist/src/tui/theme-manager.js +1 -1
  549. package/dist/src/tui/theme.d.ts +0 -2
  550. package/dist/src/tui/theme.js +1 -3
  551. package/dist/src/tui/theme.js.map +1 -1
  552. package/dist/src/tui/tui-agent-events.js +2 -1
  553. package/dist/src/tui/tui-agent-events.js.map +1 -1
  554. package/dist/src/tui/tui-commands.d.ts +3 -0
  555. package/dist/src/tui/tui-commands.js +45 -10
  556. package/dist/src/tui/tui-commands.js.map +1 -1
  557. package/dist/src/tui/tui-keybindings-file.js +2 -22
  558. package/dist/src/tui/tui-keybindings-file.js.map +1 -1
  559. package/dist/src/tui/tui-scoped-models.js +2 -2
  560. package/dist/src/tui/tui-session-actions.d.ts +28 -0
  561. package/dist/src/tui/tui-session-actions.js +88 -0
  562. package/dist/src/tui/tui-session-actions.js.map +1 -0
  563. package/dist/src/tui/tui-settings.js +1 -1
  564. package/dist/src/tui/tui.js +54 -49
  565. package/dist/src/tui/tui.js.map +1 -1
  566. package/dist/src/tunnel/frpc-binary.js +3 -3
  567. package/dist/src/tunnel/frpc-config.js +1 -1
  568. package/dist/src/tunnel/frpc-extract.js +1 -1
  569. package/dist/src/tunnel/tunnel-state.js +1 -1
  570. package/dist/src/utils/logger/audit.js +1 -1
  571. package/dist/src/utils/logger/log-store.js +1 -1
  572. package/dist/src/utils/logger/rotation.js +1 -1
  573. package/dist/src/utils/string-coerce.d.ts +2 -0
  574. package/dist/src/utils/string-coerce.js +10 -1
  575. package/dist/src/utils/string-coerce.js.map +1 -1
  576. package/dist/src/voice/metadata/builtin.d.ts +2 -0
  577. package/dist/src/voice/metadata/builtin.js +420 -0
  578. package/dist/src/voice/metadata/builtin.js.map +1 -0
  579. package/dist/src/voice/metadata/index.d.ts +4 -0
  580. package/dist/src/voice/metadata/index.js +3 -0
  581. package/dist/src/voice/metadata/registry.d.ts +5 -0
  582. package/dist/src/voice/metadata/registry.js +34 -0
  583. package/dist/src/voice/metadata/registry.js.map +1 -0
  584. package/dist/src/voice/metadata/types.d.ts +41 -0
  585. package/dist/src/voice/metadata/types.js +1 -0
  586. package/dist/src/voice/stt/config-slice.d.ts +2 -5
  587. package/dist/src/voice/stt/config-slice.js +5 -26
  588. package/dist/src/voice/stt/config-slice.js.map +1 -1
  589. package/dist/src/voice/stt/list-providers.d.ts +3 -3
  590. package/dist/src/voice/stt/list-providers.js +41 -6
  591. package/dist/src/voice/stt/list-providers.js.map +1 -1
  592. package/dist/src/voice/stt/types.d.ts +1 -18
  593. package/dist/src/voice/stt/types.js +4 -2
  594. package/dist/src/voice/stt/types.js.map +1 -1
  595. package/dist/src/voice/tts/audio.js +1 -1
  596. package/dist/src/voice/tts/config-slice.d.ts +3 -7
  597. package/dist/src/voice/tts/config-slice.js +7 -38
  598. package/dist/src/voice/tts/config-slice.js.map +1 -1
  599. package/dist/src/voice/tts/list-providers.d.ts +3 -3
  600. package/dist/src/voice/tts/list-providers.js +41 -6
  601. package/dist/src/voice/tts/list-providers.js.map +1 -1
  602. package/dist/src/voice/tts/merge-config.js +2 -48
  603. package/dist/src/voice/tts/merge-config.js.map +1 -1
  604. package/dist/src/voice/tts/providers/alibaba-speech.js +1 -1
  605. package/dist/src/voice/tts/providers/alibaba-speech.js.map +1 -1
  606. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  607. package/dist/src/voice/tts/types.d.ts +1 -29
  608. package/dist/src/voice/tts/types.js +19 -17
  609. package/dist/src/voice/tts/types.js.map +1 -1
  610. package/dist/src/workflows/domain/command.d.ts +18 -0
  611. package/dist/src/workflows/domain/command.js +1 -0
  612. package/dist/src/workflows/domain/definition.d.ts +62 -0
  613. package/dist/src/workflows/domain/definition.js +1 -0
  614. package/dist/src/workflows/domain/event.d.ts +67 -0
  615. package/dist/src/workflows/domain/event.js +1 -0
  616. package/dist/src/workflows/domain/index.d.ts +5 -0
  617. package/dist/src/workflows/domain/index.js +2 -0
  618. package/dist/src/workflows/domain/result.d.ts +65 -0
  619. package/dist/src/workflows/domain/result.js +1 -0
  620. package/dist/src/workflows/domain/run.d.ts +120 -0
  621. package/dist/src/workflows/domain/run.js +14 -0
  622. package/dist/src/workflows/domain/run.js.map +1 -0
  623. package/dist/src/workflows/engine/index.d.ts +2 -0
  624. package/dist/src/workflows/engine/index.js +3 -0
  625. package/dist/src/workflows/engine/projector.d.ts +3 -0
  626. package/dist/src/workflows/engine/projector.js +205 -0
  627. package/dist/src/workflows/engine/projector.js.map +1 -0
  628. package/dist/src/workflows/engine/workflow-engine.d.ts +31 -0
  629. package/dist/src/workflows/engine/workflow-engine.js +188 -0
  630. package/dist/src/workflows/engine/workflow-engine.js.map +1 -0
  631. package/dist/src/workflows/index.d.ts +6 -0
  632. package/dist/src/workflows/index.js +11 -0
  633. package/dist/src/workflows/runtime/index.d.ts +1 -0
  634. package/dist/src/workflows/runtime/index.js +4 -0
  635. package/dist/src/workflows/runtime/script-runtime.d.ts +3 -0
  636. package/dist/src/workflows/runtime/script-runtime.js +3 -0
  637. package/dist/src/workflows/store/event-store.d.ts +17 -0
  638. package/dist/src/workflows/store/event-store.js +83 -0
  639. package/dist/src/workflows/store/event-store.js.map +1 -0
  640. package/dist/src/workflows/store/paths.d.ts +7 -0
  641. package/dist/src/workflows/store/paths.js +26 -0
  642. package/dist/src/workflows/store/paths.js.map +1 -0
  643. package/dist/src/workflows/store/run-store.d.ts +13 -0
  644. package/dist/src/workflows/store/run-store.js +68 -0
  645. package/dist/src/workflows/store/run-store.js.map +1 -0
  646. package/package.json +5 -8
  647. package/dist/gateway/static/root/assets/agents-mS3_HpRI.js +0 -222
  648. package/dist/gateway/static/root/assets/channels-settings-BG6b9KrW.js +0 -1
  649. package/dist/gateway/static/root/assets/extension-settings-page-B-W4x2xP.js +0 -1
  650. package/dist/gateway/static/root/assets/index-ew_2L2We.css +0 -1
  651. package/dist/gateway/static/root/assets/sessions-page-FaG_Vlkb.js +0 -1
  652. package/dist/gateway/static/root/assets/settings-page-Bet1OerL.js +0 -3
  653. package/dist/gateway/static/root/assets/skills-page-DhUO235y.js +0 -2
  654. package/dist/gateway/static/root/assets/url-BwNL6Rgk.js +0 -3
  655. package/dist/gateway/static/root/assets/voice-api-key-field-CGEydndO.js +0 -1
  656. package/dist/src/agent/tools/browser-legacy-tools.d.ts +0 -17
  657. package/dist/src/agent/tools/browser-legacy-tools.js +0 -766
  658. package/dist/src/agent/tools/browser-legacy-tools.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"parser.js","names":[],"sources":["../../../../src/agent/workflow/parser.ts"],"sourcesContent":["/**\n * Workflow script parser.\n *\n * Responsibilities:\n * 1. Parse the script with acorn (latest ECMA, top-level await + return allowed).\n * 2. Enforce determinism — reject `Date.now()`, `Math.random()`, `new Date()`,\n * `require`, `import`, dynamic eval. This keeps future resume/replay possible\n * and surfaces non-deterministic mistakes early.\n * 3. Require the first statement to be `export const meta = <literal>`, validate\n * the literal shape, and strip that line from the body returned to the runtime.\n *\n * Returning a `{ meta, body }` pair means the runtime can `vm.Script(body)` without\n * any further AST work.\n */\n\nimport { parse } from 'acorn';\nimport type { Node } from 'acorn';\n\nimport type { WorkflowMeta, WorkflowMetaPhase } from './types.js';\n\ntype AnyNode = Node & { [key: string]: any; start: number; end: number };\n\nconst NONDETERMINISM_ERROR =\n 'Workflow scripts must be deterministic: Date.now()/Math.random()/new Date() are unavailable. ' +\n 'Pass timestamps via args or stamp them after the workflow returns.';\n\nexport interface ParsedWorkflow {\n meta: WorkflowMeta;\n body: string;\n}\n\nexport function parseWorkflowScript(script: string): ParsedWorkflow {\n let ast: AnyNode;\n try {\n ast = parse(script, {\n ecmaVersion: 'latest',\n sourceType: 'module',\n allowAwaitOutsideFunction: true,\n allowReturnOutsideFunction: true,\n ranges: false,\n }) as AnyNode;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n throw new Error(`Workflow script parse error: ${msg}`);\n }\n\n assertDeterministicAst(ast);\n assertNoDangerousImports(ast);\n\n const first = ast.body?.[0] as AnyNode | undefined;\n if (first?.type !== 'ExportNamedDeclaration') {\n throw new Error(\n '`export const meta = { name, description }` must be the first statement in the script',\n );\n }\n\n const declaration = first.declaration as AnyNode | null;\n if (declaration?.type !== 'VariableDeclaration' || declaration.kind !== 'const') {\n throw new Error('meta export must be `export const meta = ...`');\n }\n if (declaration.declarations.length !== 1) {\n throw new Error('meta export must declare only `meta`');\n }\n const declarator = declaration.declarations[0] as AnyNode;\n if (declarator.id?.type !== 'Identifier' || declarator.id.name !== 'meta') {\n throw new Error('meta export must declare `meta`');\n }\n if (!declarator.init) {\n throw new Error('meta must have a literal value');\n }\n\n const meta = evaluateLiteral(declarator.init, 'meta');\n validateMeta(meta);\n\n return {\n meta,\n body: script.slice(0, first.start) + script.slice(first.end),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Determinism / safety guards\n// ---------------------------------------------------------------------------\n\nfunction assertDeterministicAst(node: AnyNode): void {\n if (isDateNowCall(node) || isMathRandomCall(node) || isNewDateExpression(node)) {\n throw new Error(NONDETERMINISM_ERROR);\n }\n for (const child of astChildren(node)) {\n assertDeterministicAst(child);\n }\n}\n\nfunction assertNoDangerousImports(node: AnyNode): void {\n if (node.type === 'ImportDeclaration' || node.type === 'ImportExpression') {\n throw new Error(\n \"Workflow scripts cannot use `import` — only the exposed globals (agent, parallel, pipeline, phase, log, args, cwd, budget) are available.\",\n );\n }\n if (node.type === 'CallExpression') {\n const callee = node.callee as AnyNode | undefined;\n if (callee?.type === 'Identifier' && (callee.name === 'require' || callee.name === 'eval')) {\n throw new Error(`Workflow scripts cannot call \\`${callee.name}\\`.`);\n }\n }\n for (const child of astChildren(node)) {\n assertNoDangerousImports(child);\n }\n}\n\nfunction astChildren(node: AnyNode): AnyNode[] {\n const children: AnyNode[] = [];\n for (const value of Object.values(node)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n if (isAstNode(v)) children.push(v);\n }\n } else if (isAstNode(value)) {\n children.push(value);\n }\n }\n return children;\n}\n\nfunction isAstNode(value: unknown): value is AnyNode {\n return !!value && typeof value === 'object' && typeof (value as AnyNode).type === 'string';\n}\n\nfunction isDateNowCall(node: AnyNode): boolean {\n return node.type === 'CallExpression' && isMemberExpression(node.callee, 'Date', 'now');\n}\n\nfunction isMathRandomCall(node: AnyNode): boolean {\n return node.type === 'CallExpression' && isMemberExpression(node.callee, 'Math', 'random');\n}\n\nfunction isNewDateExpression(node: AnyNode): boolean {\n return (\n node.type === 'NewExpression' &&\n (node.callee as AnyNode | undefined)?.type === 'Identifier' &&\n (node.callee as AnyNode).name === 'Date'\n );\n}\n\nfunction isMemberExpression(\n node: AnyNode | undefined,\n objectName: string,\n propertyName: string,\n): boolean {\n if (\n node?.type !== 'MemberExpression' ||\n (node.object as AnyNode | undefined)?.type !== 'Identifier' ||\n (node.object as AnyNode).name !== objectName\n ) {\n return false;\n }\n const prop = node.property as AnyNode | undefined;\n if (!node.computed && prop?.type === 'Identifier') return prop.name === propertyName;\n if (prop?.type === 'Literal' && typeof prop.value === 'string') return prop.value === propertyName;\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Literal evaluator (meta must be a pure literal)\n// ---------------------------------------------------------------------------\n\nfunction evaluateLiteral(node: AnyNode, path: string): any {\n switch (node.type) {\n case 'ObjectExpression': {\n const out: Record<string, unknown> = {};\n for (const prop of node.properties as AnyNode[]) {\n if (prop.type === 'SpreadElement') {\n throw new Error(`spread not allowed in ${path}`);\n }\n if (prop.type !== 'Property') {\n throw new Error(`only plain properties allowed in ${path}`);\n }\n if (prop.computed) {\n throw new Error(`computed keys not allowed in ${path}`);\n }\n if (prop.kind !== 'init' || prop.method) {\n throw new Error(`methods/accessors not allowed in ${path}`);\n }\n const key = propertyKey(prop.key as AnyNode, path);\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') {\n throw new Error(`reserved key name not allowed in ${path}: ${key}`);\n }\n out[key] = evaluateLiteral(prop.value as AnyNode, `${path}.${key}`);\n }\n return out;\n }\n case 'ArrayExpression':\n return (node.elements as Array<AnyNode | null>).map((element, index) => {\n if (!element) throw new Error(`sparse arrays not allowed in ${path}`);\n if (element.type === 'SpreadElement') {\n throw new Error(`spread not allowed in ${path}`);\n }\n return evaluateLiteral(element, `${path}[${index}]`);\n });\n case 'Literal':\n return node.value;\n case 'TemplateLiteral':\n if (node.expressions.length > 0) {\n throw new Error(`template interpolation not allowed in ${path}`);\n }\n return node.quasis\n .map((quasi: AnyNode) => quasi.value.cooked ?? quasi.value.raw)\n .join('');\n case 'UnaryExpression':\n if (\n node.operator === '-' &&\n node.argument?.type === 'Literal' &&\n typeof node.argument.value === 'number'\n ) {\n return -node.argument.value;\n }\n throw new Error(`only negative-number unary allowed in ${path}`);\n default:\n throw new Error(`non-literal node type in ${path}: ${node.type}`);\n }\n}\n\nfunction propertyKey(node: AnyNode, path: string): string {\n if (node.type === 'Identifier') return node.name;\n if (node.type === 'Literal' && (typeof node.value === 'string' || typeof node.value === 'number')) {\n return String(node.value);\n }\n throw new Error(`unsupported key type in ${path}: ${node.type}`);\n}\n\nfunction validateMeta(meta: unknown): asserts meta is WorkflowMeta {\n if (!meta || typeof meta !== 'object') {\n throw new Error('meta must be an object');\n }\n const value = meta as WorkflowMeta;\n if (typeof value.name !== 'string' || !value.name.trim()) {\n throw new Error('meta.name must be a non-empty string');\n }\n if (!/^[a-z][a-z0-9_-]*$/.test(value.name)) {\n throw new Error(\n `meta.name must be lowercase snake_case (got \"${value.name}\"). Example: \"audit_repo\".`,\n );\n }\n if (typeof value.description !== 'string' || !value.description.trim()) {\n throw new Error('meta.description must be a non-empty string');\n }\n if (value.whenToUse !== undefined && typeof value.whenToUse !== 'string') {\n throw new Error('meta.whenToUse must be a string');\n }\n if (value.phases !== undefined) {\n if (!Array.isArray(value.phases)) {\n throw new Error('meta.phases must be an array');\n }\n for (const phase of value.phases) {\n if (!phase || typeof phase !== 'object' || typeof (phase as WorkflowMetaPhase).title !== 'string') {\n throw new Error('each meta phase must have a title string');\n }\n }\n }\n if (value.tags !== undefined) {\n if (!Array.isArray(value.tags) || value.tags.some((tag) => typeof tag !== 'string' || !tag.trim())) {\n throw new Error('meta.tags must be an array of non-empty strings');\n }\n }\n if (value.estimatedAgents !== undefined) {\n const est = value.estimatedAgents;\n if (!est || typeof est !== 'object') {\n throw new Error('meta.estimatedAgents must be an object');\n }\n if (typeof est.min !== 'number' || typeof est.max !== 'number' || !Number.isFinite(est.min) || !Number.isFinite(est.max)) {\n throw new Error('meta.estimatedAgents.min and .max must be finite numbers');\n }\n if (est.min < 1 || est.max < est.min) {\n throw new Error('meta.estimatedAgents requires min >= 1 and max >= min');\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAsBA,MAAM,uBACJ;AAQF,SAAgB,oBAAoB,QAAgC;CAClE,IAAI;AACJ,KAAI;AACF,QAAM,MAAM,QAAQ;GAClB,aAAa;GACb,YAAY;GACZ,2BAA2B;GAC3B,4BAA4B;GAC5B,QAAQ;GACT,CAAC;UACK,GAAG;EACV,MAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;AACtD,QAAM,IAAI,MAAM,gCAAgC,MAAM;;AAGxD,wBAAuB,IAAI;AAC3B,0BAAyB,IAAI;CAE7B,MAAM,QAAQ,IAAI,OAAO;AACzB,KAAI,OAAO,SAAS,yBAClB,OAAM,IAAI,MACR,wFACD;CAGH,MAAM,cAAc,MAAM;AAC1B,KAAI,aAAa,SAAS,yBAAyB,YAAY,SAAS,QACtE,OAAM,IAAI,MAAM,gDAAgD;AAElE,KAAI,YAAY,aAAa,WAAW,EACtC,OAAM,IAAI,MAAM,uCAAuC;CAEzD,MAAM,aAAa,YAAY,aAAa;AAC5C,KAAI,WAAW,IAAI,SAAS,gBAAgB,WAAW,GAAG,SAAS,OACjE,OAAM,IAAI,MAAM,kCAAkC;AAEpD,KAAI,CAAC,WAAW,KACd,OAAM,IAAI,MAAM,iCAAiC;CAGnD,MAAM,OAAO,gBAAgB,WAAW,MAAM,OAAO;AACrD,cAAa,KAAK;AAElB,QAAO;EACL;EACA,MAAM,OAAO,MAAM,GAAG,MAAM,MAAM,GAAG,OAAO,MAAM,MAAM,IAAI;EAC7D;;AAOH,SAAS,uBAAuB,MAAqB;AACnD,KAAI,cAAc,KAAK,IAAI,iBAAiB,KAAK,IAAI,oBAAoB,KAAK,CAC5E,OAAM,IAAI,MAAM,qBAAqB;AAEvC,MAAK,MAAM,SAAS,YAAY,KAAK,CACnC,wBAAuB,MAAM;;AAIjC,SAAS,yBAAyB,MAAqB;AACrD,KAAI,KAAK,SAAS,uBAAuB,KAAK,SAAS,mBACrD,OAAM,IAAI,MACR,4IACD;AAEH,KAAI,KAAK,SAAS,kBAAkB;EAClC,MAAM,SAAS,KAAK;AACpB,MAAI,QAAQ,SAAS,iBAAiB,OAAO,SAAS,aAAa,OAAO,SAAS,QACjF,OAAM,IAAI,MAAM,kCAAkC,OAAO,KAAK,KAAK;;AAGvE,MAAK,MAAM,SAAS,YAAY,KAAK,CACnC,0BAAyB,MAAM;;AAInC,SAAS,YAAY,MAA0B;CAC7C,MAAM,WAAsB,EAAE;AAC9B,MAAK,MAAM,SAAS,OAAO,OAAO,KAAK,CACrC,KAAI,MAAM,QAAQ,MAAM;OACjB,MAAM,KAAK,MACd,KAAI,UAAU,EAAE,CAAE,UAAS,KAAK,EAAE;YAE3B,UAAU,MAAM,CACzB,UAAS,KAAK,MAAM;AAGxB,QAAO;;AAGT,SAAS,UAAU,OAAkC;AACnD,QAAO,CAAC,CAAC,SAAS,OAAO,UAAU,YAAY,OAAQ,MAAkB,SAAS;;AAGpF,SAAS,cAAc,MAAwB;AAC7C,QAAO,KAAK,SAAS,oBAAoB,mBAAmB,KAAK,QAAQ,QAAQ,MAAM;;AAGzF,SAAS,iBAAiB,MAAwB;AAChD,QAAO,KAAK,SAAS,oBAAoB,mBAAmB,KAAK,QAAQ,QAAQ,SAAS;;AAG5F,SAAS,oBAAoB,MAAwB;AACnD,QACE,KAAK,SAAS,mBACb,KAAK,QAAgC,SAAS,gBAC9C,KAAK,OAAmB,SAAS;;AAItC,SAAS,mBACP,MACA,YACA,cACS;AACT,KACE,MAAM,SAAS,sBACd,KAAK,QAAgC,SAAS,gBAC9C,KAAK,OAAmB,SAAS,WAElC,QAAO;CAET,MAAM,OAAO,KAAK;AAClB,KAAI,CAAC,KAAK,YAAY,MAAM,SAAS,aAAc,QAAO,KAAK,SAAS;AACxE,KAAI,MAAM,SAAS,aAAa,OAAO,KAAK,UAAU,SAAU,QAAO,KAAK,UAAU;AACtF,QAAO;;AAOT,SAAS,gBAAgB,MAAe,MAAmB;AACzD,SAAQ,KAAK,MAAb;EACE,KAAK,oBAAoB;GACvB,MAAM,MAA+B,EAAE;AACvC,QAAK,MAAM,QAAQ,KAAK,YAAyB;AAC/C,QAAI,KAAK,SAAS,gBAChB,OAAM,IAAI,MAAM,yBAAyB,OAAO;AAElD,QAAI,KAAK,SAAS,WAChB,OAAM,IAAI,MAAM,oCAAoC,OAAO;AAE7D,QAAI,KAAK,SACP,OAAM,IAAI,MAAM,gCAAgC,OAAO;AAEzD,QAAI,KAAK,SAAS,UAAU,KAAK,OAC/B,OAAM,IAAI,MAAM,oCAAoC,OAAO;IAE7D,MAAM,MAAM,YAAY,KAAK,KAAgB,KAAK;AAClD,QAAI,QAAQ,eAAe,QAAQ,iBAAiB,QAAQ,YAC1D,OAAM,IAAI,MAAM,oCAAoC,KAAK,IAAI,MAAM;AAErE,QAAI,OAAO,gBAAgB,KAAK,OAAkB,GAAG,KAAK,GAAG,MAAM;;AAErE,UAAO;;EAET,KAAK,kBACH,QAAQ,KAAK,SAAmC,KAAK,SAAS,UAAU;AACtE,OAAI,CAAC,QAAS,OAAM,IAAI,MAAM,gCAAgC,OAAO;AACrE,OAAI,QAAQ,SAAS,gBACnB,OAAM,IAAI,MAAM,yBAAyB,OAAO;AAElD,UAAO,gBAAgB,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG;IACpD;EACJ,KAAK,UACH,QAAO,KAAK;EACd,KAAK;AACH,OAAI,KAAK,YAAY,SAAS,EAC5B,OAAM,IAAI,MAAM,yCAAyC,OAAO;AAElE,UAAO,KAAK,OACT,KAAK,UAAmB,MAAM,MAAM,UAAU,MAAM,MAAM,IAAI,CAC9D,KAAK,GAAG;EACb,KAAK;AACH,OACE,KAAK,aAAa,OAClB,KAAK,UAAU,SAAS,aACxB,OAAO,KAAK,SAAS,UAAU,SAE/B,QAAO,CAAC,KAAK,SAAS;AAExB,SAAM,IAAI,MAAM,yCAAyC,OAAO;EAClE,QACE,OAAM,IAAI,MAAM,4BAA4B,KAAK,IAAI,KAAK,OAAO;;;AAIvE,SAAS,YAAY,MAAe,MAAsB;AACxD,KAAI,KAAK,SAAS,aAAc,QAAO,KAAK;AAC5C,KAAI,KAAK,SAAS,cAAc,OAAO,KAAK,UAAU,YAAY,OAAO,KAAK,UAAU,UACtF,QAAO,OAAO,KAAK,MAAM;AAE3B,OAAM,IAAI,MAAM,2BAA2B,KAAK,IAAI,KAAK,OAAO;;AAGlE,SAAS,aAAa,MAA6C;AACjE,KAAI,CAAC,QAAQ,OAAO,SAAS,SAC3B,OAAM,IAAI,MAAM,yBAAyB;CAE3C,MAAM,QAAQ;AACd,KAAI,OAAO,MAAM,SAAS,YAAY,CAAC,MAAM,KAAK,MAAM,CACtD,OAAM,IAAI,MAAM,uCAAuC;AAEzD,KAAI,CAAC,qBAAqB,KAAK,MAAM,KAAK,CACxC,OAAM,IAAI,MACR,gDAAgD,MAAM,KAAK,4BAC5D;AAEH,KAAI,OAAO,MAAM,gBAAgB,YAAY,CAAC,MAAM,YAAY,MAAM,CACpE,OAAM,IAAI,MAAM,8CAA8C;AAEhE,KAAI,MAAM,cAAc,KAAA,KAAa,OAAO,MAAM,cAAc,SAC9D,OAAM,IAAI,MAAM,kCAAkC;AAEpD,KAAI,MAAM,WAAW,KAAA,GAAW;AAC9B,MAAI,CAAC,MAAM,QAAQ,MAAM,OAAO,CAC9B,OAAM,IAAI,MAAM,+BAA+B;AAEjD,OAAK,MAAM,SAAS,MAAM,OACxB,KAAI,CAAC,SAAS,OAAO,UAAU,YAAY,OAAQ,MAA4B,UAAU,SACvF,OAAM,IAAI,MAAM,2CAA2C;;AAIjE,KAAI,MAAM,SAAS,KAAA;MACb,CAAC,MAAM,QAAQ,MAAM,KAAK,IAAI,MAAM,KAAK,MAAM,QAAQ,OAAO,QAAQ,YAAY,CAAC,IAAI,MAAM,CAAC,CAChG,OAAM,IAAI,MAAM,kDAAkD;;AAGtE,KAAI,MAAM,oBAAoB,KAAA,GAAW;EACvC,MAAM,MAAM,MAAM;AAClB,MAAI,CAAC,OAAO,OAAO,QAAQ,SACzB,OAAM,IAAI,MAAM,yCAAyC;AAE3D,MAAI,OAAO,IAAI,QAAQ,YAAY,OAAO,IAAI,QAAQ,YAAY,CAAC,OAAO,SAAS,IAAI,IAAI,IAAI,CAAC,OAAO,SAAS,IAAI,IAAI,CACtH,OAAM,IAAI,MAAM,2DAA2D;AAE7E,MAAI,IAAI,MAAM,KAAK,IAAI,MAAM,IAAI,IAC/B,OAAM,IAAI,MAAM,wDAAwD"}
1
+ {"version":3,"file":"parser.js","names":[],"sources":["../../../../src/agent/workflow/parser.ts"],"sourcesContent":["/**\n * Workflow script parser.\n *\n * Responsibilities:\n * 1. Parse the script with acorn (latest ECMA, top-level await + return allowed).\n * 2. Enforce determinism — reject `Date.now()`, `Math.random()`, `new Date()`,\n * `require`, `import`, dynamic eval. This keeps future resume/replay possible\n * and surfaces non-deterministic mistakes early.\n * 3. Require the first statement to be `export const meta = <literal>`, validate\n * the literal shape, and strip that line from the body returned to the runtime.\n *\n * Returning a `{ meta, body }` pair means the runtime can `vm.Script(body)` without\n * any further AST work.\n */\n\nimport { parse } from 'acorn';\nimport type { Node } from 'acorn';\n\nimport { lintAwaits } from './lint.js';\nimport { validateExamplePrompts, validateMetaI18n } from './meta-locale.js';\nimport type { WorkflowMeta, WorkflowMetaPhase } from './types.js';\n\ntype AnyNode = Node & { [key: string]: any; start: number; end: number };\n\nconst NONDETERMINISM_ERROR =\n 'Workflow scripts must be deterministic: Date.now()/Math.random()/new Date() are unavailable. ' +\n 'Pass timestamps via args or stamp them after the workflow returns.';\n\nexport interface ParsedWorkflow {\n meta: WorkflowMeta;\n body: string;\n}\n\nexport function parseWorkflowScript(script: string): ParsedWorkflow {\n let ast: AnyNode;\n try {\n ast = parse(script, {\n ecmaVersion: 'latest',\n sourceType: 'module',\n allowAwaitOutsideFunction: true,\n allowReturnOutsideFunction: true,\n ranges: false,\n locations: true,\n }) as AnyNode;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n throw new Error(`Workflow script parse error: ${msg}`);\n }\n\n assertDeterministicAst(ast);\n assertNoDangerousImports(ast);\n lintAwaits(ast);\n\n const first = ast.body?.[0] as AnyNode | undefined;\n if (first?.type !== 'ExportNamedDeclaration') {\n throw new Error(\n '`export const meta = { name, description }` must be the first statement in the script',\n );\n }\n\n const declaration = first.declaration as AnyNode | null;\n if (declaration?.type !== 'VariableDeclaration' || declaration.kind !== 'const') {\n throw new Error('meta export must be `export const meta = ...`');\n }\n if (declaration.declarations.length !== 1) {\n throw new Error('meta export must declare only `meta`');\n }\n const declarator = declaration.declarations[0] as AnyNode;\n if (declarator.id?.type !== 'Identifier' || declarator.id.name !== 'meta') {\n throw new Error('meta export must declare `meta`');\n }\n if (!declarator.init) {\n throw new Error('meta must have a literal value');\n }\n\n const meta = evaluateLiteral(declarator.init, 'meta');\n validateMeta(meta);\n\n return {\n meta,\n body: script.slice(0, first.start) + script.slice(first.end),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Determinism / safety guards\n// ---------------------------------------------------------------------------\n\nfunction assertDeterministicAst(node: AnyNode): void {\n if (isDateNowCall(node) || isMathRandomCall(node) || isNewDateExpression(node)) {\n throw new Error(NONDETERMINISM_ERROR);\n }\n for (const child of astChildren(node)) {\n assertDeterministicAst(child);\n }\n}\n\nfunction assertNoDangerousImports(node: AnyNode): void {\n if (node.type === 'ImportDeclaration' || node.type === 'ImportExpression') {\n throw new Error(\n \"Workflow scripts cannot use `import` — only the exposed globals (agent, parallel, pipeline, phase, log, args, cwd, budget) are available.\",\n );\n }\n if (node.type === 'CallExpression') {\n const callee = node.callee as AnyNode | undefined;\n if (callee?.type === 'Identifier' && (callee.name === 'require' || callee.name === 'eval')) {\n throw new Error(`Workflow scripts cannot call \\`${callee.name}\\`.`);\n }\n }\n for (const child of astChildren(node)) {\n assertNoDangerousImports(child);\n }\n}\n\nfunction astChildren(node: AnyNode): AnyNode[] {\n const children: AnyNode[] = [];\n for (const value of Object.values(node)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n if (isAstNode(v)) children.push(v);\n }\n } else if (isAstNode(value)) {\n children.push(value);\n }\n }\n return children;\n}\n\nfunction isAstNode(value: unknown): value is AnyNode {\n return !!value && typeof value === 'object' && typeof (value as AnyNode).type === 'string';\n}\n\nfunction isDateNowCall(node: AnyNode): boolean {\n return node.type === 'CallExpression' && isMemberExpression(node.callee, 'Date', 'now');\n}\n\nfunction isMathRandomCall(node: AnyNode): boolean {\n return node.type === 'CallExpression' && isMemberExpression(node.callee, 'Math', 'random');\n}\n\nfunction isNewDateExpression(node: AnyNode): boolean {\n return (\n node.type === 'NewExpression' &&\n (node.callee as AnyNode | undefined)?.type === 'Identifier' &&\n (node.callee as AnyNode).name === 'Date'\n );\n}\n\nfunction isMemberExpression(\n node: AnyNode | undefined,\n objectName: string,\n propertyName: string,\n): boolean {\n if (\n node?.type !== 'MemberExpression' ||\n (node.object as AnyNode | undefined)?.type !== 'Identifier' ||\n (node.object as AnyNode).name !== objectName\n ) {\n return false;\n }\n const prop = node.property as AnyNode | undefined;\n if (!node.computed && prop?.type === 'Identifier') return prop.name === propertyName;\n if (prop?.type === 'Literal' && typeof prop.value === 'string') return prop.value === propertyName;\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Literal evaluator (meta must be a pure literal)\n// ---------------------------------------------------------------------------\n\nfunction evaluateLiteral(node: AnyNode, path: string): any {\n switch (node.type) {\n case 'ObjectExpression': {\n const out: Record<string, unknown> = {};\n for (const prop of node.properties as AnyNode[]) {\n if (prop.type === 'SpreadElement') {\n throw new Error(`spread not allowed in ${path}`);\n }\n if (prop.type !== 'Property') {\n throw new Error(`only plain properties allowed in ${path}`);\n }\n if (prop.computed) {\n throw new Error(`computed keys not allowed in ${path}`);\n }\n if (prop.kind !== 'init' || prop.method) {\n throw new Error(`methods/accessors not allowed in ${path}`);\n }\n const key = propertyKey(prop.key as AnyNode, path);\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') {\n throw new Error(`reserved key name not allowed in ${path}: ${key}`);\n }\n out[key] = evaluateLiteral(prop.value as AnyNode, `${path}.${key}`);\n }\n return out;\n }\n case 'ArrayExpression':\n return (node.elements as Array<AnyNode | null>).map((element, index) => {\n if (!element) throw new Error(`sparse arrays not allowed in ${path}`);\n if (element.type === 'SpreadElement') {\n throw new Error(`spread not allowed in ${path}`);\n }\n return evaluateLiteral(element, `${path}[${index}]`);\n });\n case 'Literal':\n return node.value;\n case 'TemplateLiteral':\n if (node.expressions.length > 0) {\n throw new Error(`template interpolation not allowed in ${path}`);\n }\n return node.quasis\n .map((quasi: AnyNode) => quasi.value.cooked ?? quasi.value.raw)\n .join('');\n case 'UnaryExpression':\n if (\n node.operator === '-' &&\n node.argument?.type === 'Literal' &&\n typeof node.argument.value === 'number'\n ) {\n return -node.argument.value;\n }\n throw new Error(`only negative-number unary allowed in ${path}`);\n default:\n throw new Error(`non-literal node type in ${path}: ${node.type}`);\n }\n}\n\nfunction propertyKey(node: AnyNode, path: string): string {\n if (node.type === 'Identifier') return node.name;\n if (node.type === 'Literal' && (typeof node.value === 'string' || typeof node.value === 'number')) {\n return String(node.value);\n }\n throw new Error(`unsupported key type in ${path}: ${node.type}`);\n}\n\nfunction validateMeta(meta: unknown): asserts meta is WorkflowMeta {\n if (!meta || typeof meta !== 'object') {\n throw new Error('meta must be an object');\n }\n const value = meta as WorkflowMeta;\n if (typeof value.name !== 'string' || !value.name.trim()) {\n throw new Error('meta.name must be a non-empty string');\n }\n if (!/^[a-z][a-z0-9_-]*$/.test(value.name)) {\n throw new Error(\n `meta.name must be lowercase snake_case (got \"${value.name}\"). Example: \"audit_repo\".`,\n );\n }\n if (typeof value.description !== 'string' || !value.description.trim()) {\n throw new Error('meta.description must be a non-empty string');\n }\n if (value.whenToUse !== undefined && typeof value.whenToUse !== 'string') {\n throw new Error('meta.whenToUse must be a string');\n }\n if (value.phases !== undefined) {\n if (!Array.isArray(value.phases)) {\n throw new Error('meta.phases must be an array');\n }\n for (const phase of value.phases) {\n if (!phase || typeof phase !== 'object' || typeof (phase as WorkflowMetaPhase).title !== 'string') {\n throw new Error('each meta phase must have a title string');\n }\n }\n }\n if (value.tags !== undefined) {\n if (!Array.isArray(value.tags) || value.tags.some((tag) => typeof tag !== 'string' || !tag.trim())) {\n throw new Error('meta.tags must be an array of non-empty strings');\n }\n }\n if (value.estimatedAgents !== undefined) {\n const est = value.estimatedAgents;\n if (!est || typeof est !== 'object') {\n throw new Error('meta.estimatedAgents must be an object');\n }\n if (typeof est.min !== 'number' || typeof est.max !== 'number' || !Number.isFinite(est.min) || !Number.isFinite(est.max)) {\n throw new Error('meta.estimatedAgents.min and .max must be finite numbers');\n }\n if (est.min < 1 || est.max < est.min) {\n throw new Error('meta.estimatedAgents requires min >= 1 and max >= min');\n }\n }\n validateExamplePrompts(value.examplePrompts, 'meta.examplePrompts');\n validateMetaI18n(value.i18n);\n}\n"],"mappings":"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"}
@@ -23,9 +23,12 @@
23
23
  * carries no LLM dependency, and is fully driven by injected callbacks — that
24
24
  * means the workflow tool, tests, and any future runner share one runtime.
25
25
  */
26
+ import type { Api, Model } from '@earendil-works/pi-ai';
26
27
  import type { SubagentRunner, WorkflowRunOptions, WorkflowRunResult, WorkflowSnapshot } from './types.js';
27
28
  export interface RunWorkflowDeps {
28
29
  runner: SubagentRunner;
30
+ /** Resolve a model ref (`provider/model` or configured typed id) to a {@link Model}. Throws on unknown ref. */
31
+ resolveModelId?: (modelId: string) => Model<Api>;
29
32
  }
30
33
  export declare function runWorkflow<T = unknown>(script: string, deps: RunWorkflowDeps, options: WorkflowRunOptions): Promise<WorkflowRunResult<T>>;
31
- export declare function emptySnapshotFor(name: string, description?: string): WorkflowSnapshot;
34
+ export declare function emptySnapshotFor(name: string, description?: string, phaseTitles?: string[]): WorkflowSnapshot;
@@ -43,6 +43,7 @@ async function runWorkflow(script, deps, options) {
43
43
  const maxSubagents = Math.max(1, options.maxSubagents ?? DEFAULT_MAX_SUBAGENTS);
44
44
  const limiter = createLimiter(concurrency);
45
45
  const pendingAgentRuns = /* @__PURE__ */ new Set();
46
+ const phaseDefaultModels = buildPhaseModelMap(meta.phases);
46
47
  const log = (message) => {
47
48
  const text = String(message);
48
49
  state.logs.push(text);
@@ -62,6 +63,20 @@ async function runWorkflow(script, deps, options) {
62
63
  const throwIfAborted = () => {
63
64
  if (options.signal?.aborted) throw new Error("workflow aborted");
64
65
  };
66
+ const resolveAgentModel = (normalized, assignedPhase) => {
67
+ const realId = normalized.model?.trim();
68
+ if (realId) {
69
+ if (!deps.resolveModelId) throw new Error("workflow runtime missing resolveModelId; cannot resolve real model id");
70
+ return deps.resolveModelId(realId);
71
+ }
72
+ if (assignedPhase) {
73
+ const phaseRef = phaseDefaultModels.get(assignedPhase);
74
+ if (phaseRef) {
75
+ if (!deps.resolveModelId) return void 0;
76
+ return deps.resolveModelId(phaseRef);
77
+ }
78
+ }
79
+ };
65
80
  const agent = async (prompt, agentOptions = {}) => {
66
81
  throwIfAborted();
67
82
  if (budget.total !== null && budget.remaining() <= 0) throw new Error("workflow token budget exhausted");
@@ -70,10 +85,16 @@ async function runWorkflow(script, deps, options) {
70
85
  const normalized = normalizeAgentOptions(agentOptions);
71
86
  const assignedPhase = normalized.phase ?? state.currentPhase;
72
87
  const requestedLabel = normalized.label?.trim();
88
+ state.agentCount += 1;
89
+ const id = state.agentCount;
90
+ const label = requestedLabel || defaultAgentLabel(assignedPhase, id);
91
+ options.onAgentQueued?.({
92
+ id,
93
+ label,
94
+ phase: assignedPhase,
95
+ prompt: taskPrompt
96
+ });
73
97
  const runPromise = limiter(async () => {
74
- state.agentCount += 1;
75
- const id = state.agentCount;
76
- const label = requestedLabel || defaultAgentLabel(assignedPhase, id);
77
98
  options.onAgentStart?.({
78
99
  id,
79
100
  label,
@@ -82,6 +103,13 @@ async function runWorkflow(script, deps, options) {
82
103
  });
83
104
  try {
84
105
  throwIfAborted();
106
+ const resolvedModel = resolveAgentModel(normalized, assignedPhase);
107
+ const enhanced = options.enhanceSubagentRun?.({
108
+ id,
109
+ label,
110
+ phase: assignedPhase,
111
+ prompt: taskPrompt
112
+ });
85
113
  const result = await deps.runner.run(taskPrompt, {
86
114
  label,
87
115
  schema: normalized.schema,
@@ -89,7 +117,8 @@ async function runWorkflow(script, deps, options) {
89
117
  maxIterations: normalized.maxIterations,
90
118
  phase: assignedPhase,
91
119
  signal: options.signal,
92
- instructions: normalized.model ? `The parent workflow requested model "${normalized.model}".` : void 0
120
+ model: resolvedModel,
121
+ ...enhanced
93
122
  });
94
123
  throwIfAborted();
95
124
  const status = result === null ? "error" : "done";
@@ -195,7 +224,7 @@ async function runWorkflow(script, deps, options) {
195
224
  await Promise.allSettled([...pendingAgentRuns]);
196
225
  } catch (e) {
197
226
  await Promise.allSettled([...pendingAgentRuns]);
198
- throw e;
227
+ throw rewriteScriptError(e);
199
228
  }
200
229
  assertStructuredCloneable(result, "workflow result");
201
230
  return {
@@ -207,11 +236,11 @@ async function runWorkflow(script, deps, options) {
207
236
  durationMs: Date.now() - started
208
237
  };
209
238
  }
210
- function emptySnapshotFor(name, description) {
239
+ function emptySnapshotFor(name, description, phaseTitles) {
211
240
  return {
212
241
  name,
213
242
  description,
214
- phases: [],
243
+ phases: phaseTitles ? [...phaseTitles] : [],
215
244
  logs: [],
216
245
  agents: [],
217
246
  agentCount: 0,
@@ -247,6 +276,12 @@ function createLimiter(limit) {
247
276
  }
248
277
  };
249
278
  }
279
+ function buildPhaseModelMap(phases) {
280
+ const out = /* @__PURE__ */ new Map();
281
+ if (!phases) return out;
282
+ for (const p of phases) if (p && typeof p.title === "string" && typeof p.model === "string" && p.model.trim()) out.set(p.title, p.model.trim());
283
+ return out;
284
+ }
250
285
  function requireString(value, name) {
251
286
  if (typeof value !== "string") throw new TypeError(`${name} must be a string`);
252
287
  return value;
@@ -267,11 +302,12 @@ function normalizeAgentOptions(value) {
267
302
  if (maxIterations !== void 0) {
268
303
  if (typeof maxIterations !== "number" || !Number.isFinite(maxIterations) || maxIterations < 1) throw new TypeError("agent maxIterations must be a positive number");
269
304
  }
305
+ const modelStr = optionalString(options.model, "agent model");
270
306
  return {
271
307
  label: optionalString(options.label, "agent label"),
272
308
  phase: optionalString(options.phase, "agent phase"),
273
309
  schema: options.schema,
274
- model: optionalString(options.model, "agent model"),
310
+ model: modelStr,
275
311
  toolset,
276
312
  maxIterations
277
313
  };
@@ -280,10 +316,54 @@ function assertStructuredCloneable(value, name) {
280
316
  try {
281
317
  structuredClone(value);
282
318
  } catch (e) {
319
+ const promisePath = findPromisePath(value, "");
320
+ if (promisePath !== null) throw new Error(`${name} contains a Promise at \`${promisePath || "<root>"}\` — missing 'await' before parallel()/pipeline()/agent(). Async return auto-unwraps a bare Promise, but a Promise nested in an object/array is returned as-is.`);
283
321
  const detail = e instanceof Error ? ` ${e.message}` : "";
284
322
  throw new Error(`${name} must be structured-cloneable; did you forget to await agent(), parallel(), or pipeline()?${detail}`);
285
323
  }
286
324
  }
325
+ /**
326
+ * Find the first Promise lurking in `value`, returning a JS-path like
327
+ * "results[0].pending". Returns null when no Promise is found. Bounded
328
+ * depth/breadth so it never explodes on weird user shapes.
329
+ */
330
+ function findPromisePath(value, path, depth = 0) {
331
+ if (depth > 4) return null;
332
+ if (isThenable(value)) return path;
333
+ if (Array.isArray(value)) {
334
+ for (let i = 0; i < Math.min(value.length, 32); i++) {
335
+ const inner = findPromisePath(value[i], `${path}[${i}]`, depth + 1);
336
+ if (inner !== null) return inner;
337
+ }
338
+ return null;
339
+ }
340
+ if (value !== null && typeof value === "object") {
341
+ let count = 0;
342
+ for (const [key, child] of Object.entries(value)) {
343
+ if (count++ > 32) break;
344
+ const inner = findPromisePath(child, path ? `${path}.${key}` : key, depth + 1);
345
+ if (inner !== null) return inner;
346
+ }
347
+ }
348
+ return null;
349
+ }
350
+ function isThenable(value) {
351
+ return value !== null && typeof value === "object" && typeof value.then === "function";
352
+ }
353
+ /**
354
+ * Rewrite TypeErrors that look like "called .map on a Promise" with an
355
+ * await-shaped hint. Static lint catches the obvious form at parse time;
356
+ * this is the safety net for cases lint can't see (dynamic indirection,
357
+ * values stashed in helper closures).
358
+ */
359
+ const PROMISE_METHOD_ERROR = /\.(map|filter|forEach|flat|flatMap|find|some|every|reduce|join|length|then)\b is not a function/;
360
+ function rewriteScriptError(error) {
361
+ const asError = error;
362
+ if (!(asError?.name === "TypeError" && typeof asError.message === "string")) return error instanceof Error ? error : new Error(String(error));
363
+ const message = asError.message;
364
+ if (!PROMISE_METHOD_ERROR.test(message)) return error instanceof Error ? error : new Error(message);
365
+ return /* @__PURE__ */ new Error(`${message}\n\nHint: parallel()/pipeline()/agent() return a Promise — 'await' the call before using its result.\n ❌ const r = parallel(...); r.map(...)\n ✅ const r = await parallel(...); r.map(...)`);
366
+ }
287
367
  function defaultAgentLabel(phase, index) {
288
368
  return phase ? `${phase} agent ${index}` : `agent ${index}`;
289
369
  }
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","names":[],"sources":["../../../../src/agent/workflow/runtime.ts"],"sourcesContent":["/**\n * Sandboxed workflow runtime.\n *\n * Parses the script via {@link parseWorkflowScript} (which strips the `meta`\n * export), wraps the remaining body in an async IIFE, and runs it inside a\n * Node `vm` context with a curated set of globals:\n *\n * - `agent(prompt, opts)` — spawns a subagent through the injected\n * {@link SubagentRunner} and returns its result (string, or schema-validated\n * object). Failures resolve to `null`.\n * - `parallel(thunks)` — concurrent fan-out; thunks (not promises!) so the\n * limiter sees each agent() call.\n * - `pipeline(items, ...stages)` — per-item sequential stages, items run\n * concurrently (no stage barrier). Each stage receives\n * `(prevResult, originalItem, index)`. A stage that throws drops that item\n * to `null` and skips remaining stages.\n * - `phase(title)` — marks the current phase; surfaces through `onPhase`.\n * - `log(message)` — appends to the workflow log.\n * - `budget` — `{ total, spent(), remaining() }` for self-pacing scripts.\n * - `args`, `cwd`, `process.cwd()`.\n *\n * The runtime is the only code that touches `vm`. It exposes no IO surface,\n * carries no LLM dependency, and is fully driven by injected callbacks — that\n * means the workflow tool, tests, and any future runner share one runtime.\n */\n\nimport { availableParallelism } from 'node:os';\nimport { createContext, Script } from 'node:vm';\n\nimport { parseWorkflowScript } from './parser.js';\nimport type {\n AgentScriptOptions,\n SubagentRunner,\n WorkflowRunOptions,\n WorkflowRunResult,\n WorkflowSnapshot,\n WorkflowAgentStatus,\n} from './types.js';\n\nconst DEFAULT_CONCURRENCY_FLOOR = 1;\nconst DEFAULT_CONCURRENCY_CEILING = 16;\nconst DEFAULT_MAX_SUBAGENTS = 1000;\n\ninterface RuntimeState {\n currentPhase?: string;\n logs: string[];\n phases: string[];\n agentCount: number;\n spent: number;\n}\n\nexport interface RunWorkflowDeps {\n runner: SubagentRunner;\n}\n\nexport async function runWorkflow<T = unknown>(\n script: string,\n deps: RunWorkflowDeps,\n options: WorkflowRunOptions,\n): Promise<WorkflowRunResult<T>> {\n const started = Date.now();\n const { meta, body } = parseWorkflowScript(script);\n\n const state: RuntimeState = { logs: [], phases: [], agentCount: 0, spent: 0 };\n const concurrency = clampConcurrency(options.concurrency);\n const maxSubagents = Math.max(1, options.maxSubagents ?? DEFAULT_MAX_SUBAGENTS);\n const limiter = createLimiter(concurrency);\n const pendingAgentRuns = new Set<Promise<unknown>>();\n\n const log = (message: unknown) => {\n const text = String(message);\n state.logs.push(text);\n options.onLog?.(text);\n };\n\n const phase = (title: unknown) => {\n const text = requireString(title, 'phase title');\n state.currentPhase = text;\n if (!state.phases.includes(text)) state.phases.push(text);\n options.onPhase?.(text);\n };\n\n const budget = Object.freeze({\n total: options.tokenBudget ?? null,\n spent: () => state.spent,\n remaining: () =>\n options.tokenBudget == null\n ? Number.POSITIVE_INFINITY\n : Math.max(0, options.tokenBudget - state.spent),\n });\n\n const throwIfAborted = () => {\n if (options.signal?.aborted) throw new Error('workflow aborted');\n };\n\n const agent = async (prompt: unknown, agentOptions: unknown = {}) => {\n throwIfAborted();\n if (budget.total !== null && budget.remaining() <= 0) {\n throw new Error('workflow token budget exhausted');\n }\n if (state.agentCount >= maxSubagents) {\n throw new Error(`workflow agent quota exhausted (max ${maxSubagents})`);\n }\n\n const taskPrompt = requireString(prompt, 'agent prompt');\n const normalized = normalizeAgentOptions(agentOptions);\n const assignedPhase = normalized.phase ?? state.currentPhase;\n const requestedLabel = normalized.label?.trim();\n\n const runPromise = limiter(async () => {\n // Counter increments inside the limiter — id reflects start order, not enqueue order.\n state.agentCount += 1;\n const id = state.agentCount;\n const label = requestedLabel || defaultAgentLabel(assignedPhase, id);\n options.onAgentStart?.({ id, label, phase: assignedPhase, prompt: taskPrompt });\n\n try {\n throwIfAborted();\n const result = await deps.runner.run<unknown>(taskPrompt, {\n label,\n schema: normalized.schema,\n allowedToolNames: normalized.toolset,\n maxIterations: normalized.maxIterations,\n phase: assignedPhase,\n signal: options.signal,\n instructions: normalized.model\n ? `The parent workflow requested model \"${normalized.model}\".`\n : undefined,\n });\n throwIfAborted();\n\n const status: WorkflowAgentStatus = result === null ? 'error' : 'done';\n state.spent += estimateTokens(result);\n options.onAgentEnd?.({ id, label, phase: assignedPhase, result, status });\n return result;\n } catch (e) {\n if (options.signal?.aborted) {\n options.onAgentEnd?.({ id, label, phase: assignedPhase, result: null, status: 'skipped' });\n throw e;\n }\n const message = e instanceof Error ? e.message : String(e);\n log(`agent ${label} failed: ${message}`);\n options.onAgentEnd?.({ id, label, phase: assignedPhase, result: null, status: 'error' });\n return null;\n }\n });\n\n pendingAgentRuns.add(runPromise);\n // `then` (not `finally`) keeps the bookkeeping promise from re-throwing into\n // the unhandled-rejection channel when `runPromise` rejects on abort.\n runPromise.then(\n () => pendingAgentRuns.delete(runPromise),\n () => pendingAgentRuns.delete(runPromise),\n );\n return runPromise;\n };\n\n const parallel = async (thunks: unknown) => {\n throwIfAborted();\n if (!Array.isArray(thunks)) throw new TypeError('parallel() expects an array of functions');\n for (const t of thunks) {\n if (typeof t !== 'function') {\n throw new TypeError(\n 'parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)',\n );\n }\n }\n return Promise.all(\n thunks.map(async (thunk, index) => {\n try {\n return await (thunk as () => unknown)();\n } catch (e) {\n if (options.signal?.aborted) throw e;\n const message = e instanceof Error ? e.message : String(e);\n log(`parallel[${index}] failed: ${message}`);\n return null;\n }\n }),\n );\n };\n\n const pipeline = async (items: unknown, ...stages: Array<unknown>) => {\n throwIfAborted();\n if (!Array.isArray(items)) {\n throw new TypeError('pipeline() expects an array as the first argument');\n }\n for (const stage of stages) {\n if (typeof stage !== 'function') {\n throw new TypeError(\n 'pipeline() stages must be functions: pipeline(items, item => ..., result => ...)',\n );\n }\n }\n const typedStages = stages as Array<\n (prev: unknown, original: unknown, index: number) => unknown\n >;\n return Promise.all(\n items.map(async (item, index) => {\n let value: unknown = item;\n for (const stage of typedStages) {\n try {\n throwIfAborted();\n value = await stage(value, item, index);\n throwIfAborted();\n } catch (e) {\n if (options.signal?.aborted) throw e;\n const message = e instanceof Error ? e.message : String(e);\n log(`pipeline[${index}] failed: ${message}`);\n return null;\n }\n }\n return value;\n }),\n );\n };\n\n const context = createContext({\n agent,\n parallel,\n pipeline,\n log,\n phase,\n args: options.args,\n cwd: options.cwd,\n process: Object.freeze({ cwd: () => options.cwd }),\n budget,\n console: {\n log,\n info: log,\n warn: (m: unknown) => log(`[warn] ${String(m)}`),\n error: (m: unknown) => log(`[error] ${String(m)}`),\n },\n JSON,\n Math,\n Array,\n Object,\n String,\n Number,\n Boolean,\n Set,\n Map,\n Promise,\n });\n\n const wrapped = `(async () => {\\n${body}\\n})()`;\n const script$ = new Script(wrapped, { filename: `${meta.name}.workflow.js` });\n\n let result: unknown;\n try {\n result = await script$.runInContext(context);\n // Wait for any agent() runs the script forgot to await before declaring success.\n await Promise.allSettled([...pendingAgentRuns]);\n } catch (e) {\n // Drain pending agent calls before propagating, so the snapshot reflects final state.\n await Promise.allSettled([...pendingAgentRuns]);\n throw e;\n }\n\n assertStructuredCloneable(result, 'workflow result');\n\n return {\n meta,\n result: result as T,\n logs: state.logs,\n phases: state.phases,\n agentCount: state.agentCount,\n durationMs: Date.now() - started,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Initial snapshot helper — kept here so the runtime is the single source of\n// truth for \"what a fresh snapshot looks like for this workflow\".\n// ---------------------------------------------------------------------------\n\nexport function emptySnapshotFor(name: string, description?: string): WorkflowSnapshot {\n return {\n name,\n description,\n phases: [],\n logs: [],\n agents: [],\n agentCount: 0,\n runningCount: 0,\n doneCount: 0,\n errorCount: 0,\n skippedCount: 0,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------\n\nfunction clampConcurrency(requested?: number): number {\n if (typeof requested === 'number' && Number.isFinite(requested) && requested >= 1) {\n return Math.min(Math.floor(requested), DEFAULT_CONCURRENCY_CEILING);\n }\n let cpu = DEFAULT_CONCURRENCY_CEILING;\n try {\n cpu = availableParallelism();\n } catch {\n // Some sandboxes throw; fall back to the ceiling.\n }\n return Math.max(DEFAULT_CONCURRENCY_FLOOR, Math.min(DEFAULT_CONCURRENCY_CEILING, cpu - 2));\n}\n\nfunction createLimiter(limit: number) {\n let active = 0;\n const queue: Array<() => void> = [];\n const next = () => {\n active -= 1;\n const resume = queue.shift();\n if (resume) resume();\n };\n return async <T>(fn: () => Promise<T>): Promise<T> => {\n if (active >= limit) {\n await new Promise<void>((resolve) => queue.push(resolve));\n }\n active += 1;\n try {\n return await fn();\n } finally {\n next();\n }\n };\n}\n\nfunction requireString(value: unknown, name: string): string {\n if (typeof value !== 'string') throw new TypeError(`${name} must be a string`);\n return value;\n}\n\nfunction optionalString(value: unknown, name: string): string | undefined {\n if (value === undefined) return undefined;\n return requireString(value, name);\n}\n\nfunction normalizeAgentOptions(value: unknown): AgentScriptOptions {\n if (value === undefined || value === null) return {};\n if (typeof value !== 'object') throw new TypeError('agent options must be an object');\n const options = value as AgentScriptOptions;\n const toolset = options.toolset;\n if (toolset !== undefined) {\n if (!Array.isArray(toolset) || toolset.some((t) => typeof t !== 'string')) {\n throw new TypeError('agent toolset must be an array of strings');\n }\n }\n const maxIterations = options.maxIterations;\n if (maxIterations !== undefined) {\n if (typeof maxIterations !== 'number' || !Number.isFinite(maxIterations) || maxIterations < 1) {\n throw new TypeError('agent maxIterations must be a positive number');\n }\n }\n return {\n label: optionalString(options.label, 'agent label'),\n phase: optionalString(options.phase, 'agent phase'),\n schema: options.schema,\n model: optionalString(options.model, 'agent model'),\n toolset,\n maxIterations,\n };\n}\n\nfunction assertStructuredCloneable(value: unknown, name: string): void {\n try {\n structuredClone(value);\n } catch (e) {\n const detail = e instanceof Error ? ` ${e.message}` : '';\n throw new Error(\n `${name} must be structured-cloneable; did you forget to await agent(), parallel(), or pipeline()?${detail}`,\n );\n }\n}\n\nfunction defaultAgentLabel(phase: string | undefined, index: number): string {\n return phase ? `${phase} agent ${index}` : `agent ${index}`;\n}\n\nfunction estimateTokens(value: unknown): number {\n if (value === null || value === undefined) return 0;\n try {\n return Math.ceil(JSON.stringify(value).length / 4);\n } catch {\n return Math.ceil(String(value).length / 4);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"runtime.js","names":[],"sources":["../../../../src/agent/workflow/runtime.ts"],"sourcesContent":["/**\n * Sandboxed workflow runtime.\n *\n * Parses the script via {@link parseWorkflowScript} (which strips the `meta`\n * export), wraps the remaining body in an async IIFE, and runs it inside a\n * Node `vm` context with a curated set of globals:\n *\n * - `agent(prompt, opts)` — spawns a subagent through the injected\n * {@link SubagentRunner} and returns its result (string, or schema-validated\n * object). Failures resolve to `null`.\n * - `parallel(thunks)` — concurrent fan-out; thunks (not promises!) so the\n * limiter sees each agent() call.\n * - `pipeline(items, ...stages)` — per-item sequential stages, items run\n * concurrently (no stage barrier). Each stage receives\n * `(prevResult, originalItem, index)`. A stage that throws drops that item\n * to `null` and skips remaining stages.\n * - `phase(title)` — marks the current phase; surfaces through `onPhase`.\n * - `log(message)` — appends to the workflow log.\n * - `budget` — `{ total, spent(), remaining() }` for self-pacing scripts.\n * - `args`, `cwd`, `process.cwd()`.\n *\n * The runtime is the only code that touches `vm`. It exposes no IO surface,\n * carries no LLM dependency, and is fully driven by injected callbacks — that\n * means the workflow tool, tests, and any future runner share one runtime.\n */\n\nimport { availableParallelism } from 'node:os';\nimport { createContext, Script } from 'node:vm';\n\nimport type { Api, Model } from '@earendil-works/pi-ai';\n\nimport { parseWorkflowScript } from './parser.js';\nimport type {\n AgentScriptOptions,\n SubagentRunner,\n WorkflowMetaPhase,\n WorkflowRunOptions,\n WorkflowRunResult,\n WorkflowSnapshot,\n WorkflowAgentStatus,\n} from './types.js';\n\nconst DEFAULT_CONCURRENCY_FLOOR = 1;\nconst DEFAULT_CONCURRENCY_CEILING = 16;\nconst DEFAULT_MAX_SUBAGENTS = 1000;\n\ninterface RuntimeState {\n currentPhase?: string;\n logs: string[];\n phases: string[];\n agentCount: number;\n spent: number;\n}\n\nexport interface RunWorkflowDeps {\n runner: SubagentRunner;\n /** Resolve a model ref (`provider/model` or configured typed id) to a {@link Model}. Throws on unknown ref. */\n resolveModelId?: (modelId: string) => Model<Api>;\n}\n\nexport async function runWorkflow<T = unknown>(\n script: string,\n deps: RunWorkflowDeps,\n options: WorkflowRunOptions,\n): Promise<WorkflowRunResult<T>> {\n const started = Date.now();\n const { meta, body } = parseWorkflowScript(script);\n\n const state: RuntimeState = { logs: [], phases: [], agentCount: 0, spent: 0 };\n const concurrency = clampConcurrency(options.concurrency);\n const maxSubagents = Math.max(1, options.maxSubagents ?? DEFAULT_MAX_SUBAGENTS);\n const limiter = createLimiter(concurrency);\n const pendingAgentRuns = new Set<Promise<unknown>>();\n const phaseDefaultModels = buildPhaseModelMap(meta.phases);\n\n const log = (message: unknown) => {\n const text = String(message);\n state.logs.push(text);\n options.onLog?.(text);\n };\n\n const phase = (title: unknown) => {\n const text = requireString(title, 'phase title');\n state.currentPhase = text;\n if (!state.phases.includes(text)) state.phases.push(text);\n options.onPhase?.(text);\n };\n\n const budget = Object.freeze({\n total: options.tokenBudget ?? null,\n spent: () => state.spent,\n remaining: () =>\n options.tokenBudget == null\n ? Number.POSITIVE_INFINITY\n : Math.max(0, options.tokenBudget - state.spent),\n });\n\n const throwIfAborted = () => {\n if (options.signal?.aborted) throw new Error('workflow aborted');\n };\n\n const resolveAgentModel = (\n normalized: AgentScriptOptions,\n assignedPhase: string | undefined,\n ): Model<Api> | undefined => {\n const realId = normalized.model?.trim();\n if (realId) {\n if (!deps.resolveModelId) {\n throw new Error('workflow runtime missing resolveModelId; cannot resolve real model id');\n }\n return deps.resolveModelId(realId);\n }\n if (assignedPhase) {\n const phaseRef = phaseDefaultModels.get(assignedPhase);\n if (phaseRef) {\n if (!deps.resolveModelId) return undefined;\n return deps.resolveModelId(phaseRef);\n }\n }\n return undefined;\n };\n\n const agent = async (prompt: unknown, agentOptions: unknown = {}) => {\n throwIfAborted();\n if (budget.total !== null && budget.remaining() <= 0) {\n throw new Error('workflow token budget exhausted');\n }\n if (state.agentCount >= maxSubagents) {\n throw new Error(`workflow agent quota exhausted (max ${maxSubagents})`);\n }\n\n const taskPrompt = requireString(prompt, 'agent prompt');\n const normalized = normalizeAgentOptions(agentOptions);\n const assignedPhase = normalized.phase ?? state.currentPhase;\n const requestedLabel = normalized.label?.trim();\n\n state.agentCount += 1;\n const id = state.agentCount;\n const label = requestedLabel || defaultAgentLabel(assignedPhase, id);\n options.onAgentQueued?.({ id, label, phase: assignedPhase, prompt: taskPrompt });\n\n const runPromise = limiter(async () => {\n options.onAgentStart?.({ id, label, phase: assignedPhase, prompt: taskPrompt });\n\n try {\n throwIfAborted();\n const resolvedModel = resolveAgentModel(normalized, assignedPhase);\n const enhanced = options.enhanceSubagentRun?.({\n id,\n label,\n phase: assignedPhase,\n prompt: taskPrompt,\n });\n const result = await deps.runner.run<unknown>(taskPrompt, {\n label,\n schema: normalized.schema,\n allowedToolNames: normalized.toolset,\n maxIterations: normalized.maxIterations,\n phase: assignedPhase,\n signal: options.signal,\n model: resolvedModel,\n ...enhanced,\n });\n throwIfAborted();\n\n const status: WorkflowAgentStatus = result === null ? 'error' : 'done';\n state.spent += estimateTokens(result);\n options.onAgentEnd?.({ id, label, phase: assignedPhase, result, status });\n return result;\n } catch (e) {\n if (options.signal?.aborted) {\n options.onAgentEnd?.({ id, label, phase: assignedPhase, result: null, status: 'skipped' });\n throw e;\n }\n const message = e instanceof Error ? e.message : String(e);\n log(`agent ${label} failed: ${message}`);\n options.onAgentEnd?.({ id, label, phase: assignedPhase, result: null, status: 'error' });\n return null;\n }\n });\n\n pendingAgentRuns.add(runPromise);\n // `then` (not `finally`) keeps the bookkeeping promise from re-throwing into\n // the unhandled-rejection channel when `runPromise` rejects on abort.\n runPromise.then(\n () => pendingAgentRuns.delete(runPromise),\n () => pendingAgentRuns.delete(runPromise),\n );\n return runPromise;\n };\n\n const parallel = async (thunks: unknown) => {\n throwIfAborted();\n if (!Array.isArray(thunks)) throw new TypeError('parallel() expects an array of functions');\n for (const t of thunks) {\n if (typeof t !== 'function') {\n throw new TypeError(\n 'parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)',\n );\n }\n }\n return Promise.all(\n thunks.map(async (thunk, index) => {\n try {\n return await (thunk as () => unknown)();\n } catch (e) {\n if (options.signal?.aborted) throw e;\n const message = e instanceof Error ? e.message : String(e);\n log(`parallel[${index}] failed: ${message}`);\n return null;\n }\n }),\n );\n };\n\n const pipeline = async (items: unknown, ...stages: Array<unknown>) => {\n throwIfAborted();\n if (!Array.isArray(items)) {\n throw new TypeError('pipeline() expects an array as the first argument');\n }\n for (const stage of stages) {\n if (typeof stage !== 'function') {\n throw new TypeError(\n 'pipeline() stages must be functions: pipeline(items, item => ..., result => ...)',\n );\n }\n }\n const typedStages = stages as Array<\n (prev: unknown, original: unknown, index: number) => unknown\n >;\n return Promise.all(\n items.map(async (item, index) => {\n let value: unknown = item;\n for (const stage of typedStages) {\n try {\n throwIfAborted();\n value = await stage(value, item, index);\n throwIfAborted();\n } catch (e) {\n if (options.signal?.aborted) throw e;\n const message = e instanceof Error ? e.message : String(e);\n log(`pipeline[${index}] failed: ${message}`);\n return null;\n }\n }\n return value;\n }),\n );\n };\n\n const context = createContext({\n agent,\n parallel,\n pipeline,\n log,\n phase,\n args: options.args,\n cwd: options.cwd,\n process: Object.freeze({ cwd: () => options.cwd }),\n budget,\n console: {\n log,\n info: log,\n warn: (m: unknown) => log(`[warn] ${String(m)}`),\n error: (m: unknown) => log(`[error] ${String(m)}`),\n },\n JSON,\n Math,\n Array,\n Object,\n String,\n Number,\n Boolean,\n Set,\n Map,\n Promise,\n });\n\n const wrapped = `(async () => {\\n${body}\\n})()`;\n const script$ = new Script(wrapped, { filename: `${meta.name}.workflow.js` });\n\n let result: unknown;\n try {\n result = await script$.runInContext(context);\n // Wait for any agent() runs the script forgot to await before declaring success.\n await Promise.allSettled([...pendingAgentRuns]);\n } catch (e) {\n // Drain pending agent calls before propagating, so the snapshot reflects final state.\n await Promise.allSettled([...pendingAgentRuns]);\n throw rewriteScriptError(e);\n }\n\n assertStructuredCloneable(result, 'workflow result');\n\n return {\n meta,\n result: result as T,\n logs: state.logs,\n phases: state.phases,\n agentCount: state.agentCount,\n durationMs: Date.now() - started,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Initial snapshot helper — kept here so the runtime is the single source of\n// truth for \"what a fresh snapshot looks like for this workflow\".\n// ---------------------------------------------------------------------------\n\nexport function emptySnapshotFor(\n name: string,\n description?: string,\n phaseTitles?: string[],\n): WorkflowSnapshot {\n return {\n name,\n description,\n phases: phaseTitles ? [...phaseTitles] : [],\n logs: [],\n agents: [],\n agentCount: 0,\n runningCount: 0,\n doneCount: 0,\n errorCount: 0,\n skippedCount: 0,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------\n\nfunction clampConcurrency(requested?: number): number {\n if (typeof requested === 'number' && Number.isFinite(requested) && requested >= 1) {\n return Math.min(Math.floor(requested), DEFAULT_CONCURRENCY_CEILING);\n }\n let cpu = DEFAULT_CONCURRENCY_CEILING;\n try {\n cpu = availableParallelism();\n } catch {\n // Some sandboxes throw; fall back to the ceiling.\n }\n return Math.max(DEFAULT_CONCURRENCY_FLOOR, Math.min(DEFAULT_CONCURRENCY_CEILING, cpu - 2));\n}\n\nfunction createLimiter(limit: number) {\n let active = 0;\n const queue: Array<() => void> = [];\n const next = () => {\n active -= 1;\n const resume = queue.shift();\n if (resume) resume();\n };\n return async <T>(fn: () => Promise<T>): Promise<T> => {\n if (active >= limit) {\n await new Promise<void>((resolve) => queue.push(resolve));\n }\n active += 1;\n try {\n return await fn();\n } finally {\n next();\n }\n };\n}\n\nfunction buildPhaseModelMap(phases: WorkflowMetaPhase[] | undefined): Map<string, string> {\n const out = new Map<string, string>();\n if (!phases) return out;\n for (const p of phases) {\n if (p && typeof p.title === 'string' && typeof p.model === 'string' && p.model.trim()) {\n out.set(p.title, p.model.trim());\n }\n }\n return out;\n}\n\nfunction requireString(value: unknown, name: string): string {\n if (typeof value !== 'string') throw new TypeError(`${name} must be a string`);\n return value;\n}\n\nfunction optionalString(value: unknown, name: string): string | undefined {\n if (value === undefined) return undefined;\n return requireString(value, name);\n}\n\nfunction normalizeAgentOptions(value: unknown): AgentScriptOptions {\n if (value === undefined || value === null) return {};\n if (typeof value !== 'object') throw new TypeError('agent options must be an object');\n const options = value as AgentScriptOptions;\n const toolset = options.toolset;\n if (toolset !== undefined) {\n if (!Array.isArray(toolset) || toolset.some((t) => typeof t !== 'string')) {\n throw new TypeError('agent toolset must be an array of strings');\n }\n }\n const maxIterations = options.maxIterations;\n if (maxIterations !== undefined) {\n if (typeof maxIterations !== 'number' || !Number.isFinite(maxIterations) || maxIterations < 1) {\n throw new TypeError('agent maxIterations must be a positive number');\n }\n }\n const modelStr = optionalString(options.model, 'agent model');\n return {\n label: optionalString(options.label, 'agent label'),\n phase: optionalString(options.phase, 'agent phase'),\n schema: options.schema,\n model: modelStr,\n toolset,\n maxIterations,\n };\n}\n\nfunction assertStructuredCloneable(value: unknown, name: string): void {\n try {\n structuredClone(value);\n } catch (e) {\n const promisePath = findPromisePath(value, '');\n if (promisePath !== null) {\n throw new Error(\n `${name} contains a Promise at \\`${promisePath || '<root>'}\\` — missing 'await' before parallel()/pipeline()/agent(). ` +\n `Async return auto-unwraps a bare Promise, but a Promise nested in an object/array is returned as-is.`,\n );\n }\n const detail = e instanceof Error ? ` ${e.message}` : '';\n throw new Error(\n `${name} must be structured-cloneable; did you forget to await agent(), parallel(), or pipeline()?${detail}`,\n );\n }\n}\n\n/**\n * Find the first Promise lurking in `value`, returning a JS-path like\n * \"results[0].pending\". Returns null when no Promise is found. Bounded\n * depth/breadth so it never explodes on weird user shapes.\n */\nfunction findPromisePath(value: unknown, path: string, depth = 0): string | null {\n if (depth > 4) return null;\n if (isThenable(value)) return path;\n if (Array.isArray(value)) {\n for (let i = 0; i < Math.min(value.length, 32); i++) {\n const inner = findPromisePath(value[i], `${path}[${i}]`, depth + 1);\n if (inner !== null) return inner;\n }\n return null;\n }\n if (value !== null && typeof value === 'object') {\n let count = 0;\n for (const [key, child] of Object.entries(value as Record<string, unknown>)) {\n if (count++ > 32) break;\n const inner = findPromisePath(child, path ? `${path}.${key}` : key, depth + 1);\n if (inner !== null) return inner;\n }\n }\n return null;\n}\n\nfunction isThenable(value: unknown): boolean {\n return (\n value !== null &&\n typeof value === 'object' &&\n typeof (value as { then?: unknown }).then === 'function'\n );\n}\n\n/**\n * Rewrite TypeErrors that look like \"called .map on a Promise\" with an\n * await-shaped hint. Static lint catches the obvious form at parse time;\n * this is the safety net for cases lint can't see (dynamic indirection,\n * values stashed in helper closures).\n */\nconst PROMISE_METHOD_ERROR =\n /\\.(map|filter|forEach|flat|flatMap|find|some|every|reduce|join|length|then)\\b is not a function/;\n\nfunction rewriteScriptError(error: unknown): Error {\n // VM-context errors aren't `instanceof` host classes (the vm has its own\n // global constructors), so check by name + duck-typing message.\n const asError = error as { name?: string; message?: string } | null | undefined;\n const isTypeError = asError?.name === 'TypeError' && typeof asError.message === 'string';\n if (!isTypeError) {\n return error instanceof Error ? error : new Error(String(error));\n }\n const message = (asError as { message: string }).message;\n if (!PROMISE_METHOD_ERROR.test(message)) {\n return error instanceof Error ? error : new Error(message);\n }\n return new Error(\n `${message}\\n\\nHint: parallel()/pipeline()/agent() return a Promise — 'await' the call before using its result.\\n` +\n ` ❌ const r = parallel(...); r.map(...)\\n` +\n ` ✅ const r = await parallel(...); r.map(...)`,\n );\n}\n\nfunction defaultAgentLabel(phase: string | undefined, index: number): string {\n return phase ? `${phase} agent ${index}` : `agent ${index}`;\n}\n\nfunction estimateTokens(value: unknown): number {\n if (value === null || value === undefined) return 0;\n try {\n return Math.ceil(JSON.stringify(value).length / 4);\n } catch {\n return Math.ceil(String(value).length / 4);\n }\n}\n"],"mappings":"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"}
@@ -1,17 +1,7 @@
1
+ import { emptySnapshotFor } from "./runtime.js";
1
2
  //#region src/agent/workflow/snapshot.ts
2
3
  function createWorkflowSnapshot(meta) {
3
- return {
4
- name: meta.name,
5
- description: meta.description,
6
- phases: [],
7
- logs: [],
8
- agents: [],
9
- agentCount: 0,
10
- runningCount: 0,
11
- doneCount: 0,
12
- errorCount: 0,
13
- skippedCount: 0
14
- };
4
+ return emptySnapshotFor(meta.name, meta.description, meta.phases?.map((p) => p.title));
15
5
  }
16
6
  function recomputeCounts(snapshot) {
17
7
  let running = 0;
@@ -1 +1 @@
1
- {"version":3,"file":"snapshot.js","names":[],"sources":["../../../../src/agent/workflow/snapshot.ts"],"sourcesContent":["/**\n * Workflow progress snapshot model + text renderers.\n *\n * The runtime emits per-event callbacks (`onPhase`, `onAgentStart`, `onAgentEnd`,\n * `onLog`). The workflow tool wraps those callbacks to mutate a snapshot and push\n * a text rendering through `onUpdate` — keeping TUI / Gateway / IM consumers in\n * lock-step from a single source of truth.\n */\n\nimport type {\n WorkflowAgentSnapshot,\n WorkflowAgentStatus,\n WorkflowMeta,\n WorkflowSnapshot,\n} from './types.js';\n\nexport function createWorkflowSnapshot(meta: WorkflowMeta): WorkflowSnapshot {\n return {\n name: meta.name,\n description: meta.description,\n phases: [],\n logs: [],\n agents: [],\n agentCount: 0,\n runningCount: 0,\n doneCount: 0,\n errorCount: 0,\n skippedCount: 0,\n };\n}\n\nexport function recomputeCounts(snapshot: WorkflowSnapshot): void {\n let running = 0;\n let done = 0;\n let error = 0;\n let skipped = 0;\n for (const agent of snapshot.agents) {\n switch (agent.status) {\n case 'running':\n running++;\n break;\n case 'done':\n done++;\n break;\n case 'error':\n error++;\n break;\n case 'skipped':\n skipped++;\n break;\n }\n }\n snapshot.agentCount = snapshot.agents.length;\n snapshot.runningCount = running;\n snapshot.doneCount = done;\n snapshot.errorCount = error;\n snapshot.skippedCount = skipped;\n}\n\nexport interface RenderOptions {\n maxAgentsPerPhase?: number;\n maxLogs?: number;\n showResultPreviews?: boolean;\n}\n\nexport function renderWorkflowText(\n snapshot: WorkflowSnapshot,\n completed = false,\n options: RenderOptions = {},\n): string {\n const maxAgentsPerPhase = options.maxAgentsPerPhase ?? 6;\n const maxLogs = options.maxLogs ?? 2;\n const showPreviews = options.showResultPreviews ?? false;\n\n const state = stateSuffix(snapshot);\n const header = completed\n ? `◆ workflow ✓ ${snapshot.name} (${snapshot.doneCount}/${snapshot.agentCount} done${state})`\n : `◆ workflow: ${snapshot.name} (${snapshot.doneCount}/${snapshot.agentCount} done${state})`;\n const lines = [header];\n\n const phaseNames = uniqueOrdered([\n ...snapshot.phases,\n ...(snapshot.currentPhase ? [snapshot.currentPhase] : []),\n ...snapshot.agents.map((a) => a.phase).filter((p): p is string => Boolean(p)),\n ]);\n const rendered = new Set<WorkflowAgentSnapshot>();\n\n for (const phase of phaseNames) {\n const agents = snapshot.agents.filter((a) => a.phase === phase);\n if (agents.length === 0 && snapshot.currentPhase !== phase) continue;\n for (const a of agents) rendered.add(a);\n\n const counts = countAgents(agents);\n const completeHere = agents.length > 0 && counts.done + counts.error + counts.skipped === agents.length;\n const marker =\n counts.running > 0 || (!completeHere && snapshot.currentPhase === phase)\n ? '▶'\n : completeHere\n ? '✓'\n : ' ';\n\n const tail =\n (counts.running ? ` · ${counts.running} running` : '') +\n (counts.error ? ` · ${counts.error} errors` : '') +\n (counts.skipped ? ` · ${counts.skipped} skipped` : '');\n lines.push(` ${marker} ${phase} ${counts.done}/${agents.length}${tail}`);\n\n const visible = agents.slice(-maxAgentsPerPhase);\n for (const agent of visible) {\n const previewText = showPreviews && agent.resultPreview ? ` — ${agent.resultPreview}` : '';\n lines.push(\n ` #${agent.id} ${statusIcon(agent.status)} ${shorten(agent.label, 56)}${previewText}`,\n );\n }\n if (agents.length > visible.length) {\n lines.push(` … ${agents.length - visible.length} earlier agents`);\n }\n }\n\n const unphased = snapshot.agents.filter((a) => !rendered.has(a));\n if (unphased.length > 0) {\n lines.push(' unphased');\n for (const agent of unphased.slice(-maxAgentsPerPhase)) {\n const previewText = showPreviews && agent.resultPreview ? ` — ${agent.resultPreview}` : '';\n lines.push(\n ` #${agent.id} ${statusIcon(agent.status)} ${shorten(agent.label, 56)}${previewText}`,\n );\n }\n }\n\n const visibleLogs = snapshot.logs.slice(-maxLogs);\n if (visibleLogs.length > 0) {\n lines.push('');\n for (const log of visibleLogs) {\n lines.push(` log: ${shorten(log, 80)}`);\n }\n }\n return lines.join('\\n');\n}\n\nexport function previewValue(value: unknown, max = 80): string {\n if (value === null || value === undefined) return '';\n const text = typeof value === 'string' ? value : safeStringify(value);\n if (!text) return '';\n return text.length > max ? `${text.slice(0, max - 1)}…` : text;\n}\n\n// ---------------------------------------------------------------------------\n\nfunction countAgents(agents: WorkflowAgentSnapshot[]) {\n let done = 0;\n let running = 0;\n let error = 0;\n let skipped = 0;\n for (const a of agents) {\n if (a.status === 'done') done++;\n else if (a.status === 'running') running++;\n else if (a.status === 'error') error++;\n else if (a.status === 'skipped') skipped++;\n }\n return { done, running, error, skipped };\n}\n\nfunction statusIcon(status: WorkflowAgentStatus): string {\n switch (status) {\n case 'queued':\n return '○';\n case 'running':\n return '●';\n case 'done':\n return '✓';\n case 'error':\n return '✗';\n case 'skipped':\n return '-';\n }\n}\n\nfunction stateSuffix(snapshot: WorkflowSnapshot): string {\n if (snapshot.errorCount > 0) return `, ${snapshot.errorCount} errors`;\n if (snapshot.skippedCount > 0) return `, ${snapshot.skippedCount} skipped`;\n if (snapshot.runningCount > 0) return `, ${snapshot.runningCount} running`;\n return '';\n}\n\nfunction uniqueOrdered(values: string[]): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const v of values) {\n if (!seen.has(v)) {\n seen.add(v);\n out.push(v);\n }\n }\n return out;\n}\n\nfunction shorten(value: string, max: number): string {\n const text = value.replace(/\\s+/g, ' ').trim();\n return text.length > max ? `${text.slice(0, max - 1)}…` : text;\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"snapshot.js","names":[],"sources":["../../../../src/agent/workflow/snapshot.ts"],"sourcesContent":["/**\n * Workflow progress snapshot model + text renderers.\n *\n * The runtime emits per-event callbacks (`onPhase`, `onAgentStart`, `onAgentEnd`,\n * `onLog`). The workflow tool wraps those callbacks to mutate a snapshot and push\n * a text rendering through `onUpdate` — keeping TUI / Gateway / IM consumers in\n * lock-step from a single source of truth.\n */\n\nimport type {\n WorkflowAgentSnapshot,\n WorkflowAgentStatus,\n WorkflowMeta,\n WorkflowSnapshot,\n} from './types.js';\nimport { emptySnapshotFor } from './runtime.js';\n\nexport function createWorkflowSnapshot(meta: WorkflowMeta): WorkflowSnapshot {\n return emptySnapshotFor(\n meta.name,\n meta.description,\n meta.phases?.map((p) => p.title),\n );\n}\n\nexport function recomputeCounts(snapshot: WorkflowSnapshot): void {\n let running = 0;\n let done = 0;\n let error = 0;\n let skipped = 0;\n for (const agent of snapshot.agents) {\n switch (agent.status) {\n case 'running':\n running++;\n break;\n case 'done':\n done++;\n break;\n case 'error':\n error++;\n break;\n case 'skipped':\n skipped++;\n break;\n }\n }\n snapshot.agentCount = snapshot.agents.length;\n snapshot.runningCount = running;\n snapshot.doneCount = done;\n snapshot.errorCount = error;\n snapshot.skippedCount = skipped;\n}\n\nexport interface RenderOptions {\n maxAgentsPerPhase?: number;\n maxLogs?: number;\n showResultPreviews?: boolean;\n}\n\nexport function renderWorkflowText(\n snapshot: WorkflowSnapshot,\n completed = false,\n options: RenderOptions = {},\n): string {\n const maxAgentsPerPhase = options.maxAgentsPerPhase ?? 6;\n const maxLogs = options.maxLogs ?? 2;\n const showPreviews = options.showResultPreviews ?? false;\n\n const state = stateSuffix(snapshot);\n const header = completed\n ? `◆ workflow ✓ ${snapshot.name} (${snapshot.doneCount}/${snapshot.agentCount} done${state})`\n : `◆ workflow: ${snapshot.name} (${snapshot.doneCount}/${snapshot.agentCount} done${state})`;\n const lines = [header];\n\n const phaseNames = uniqueOrdered([\n ...snapshot.phases,\n ...(snapshot.currentPhase ? [snapshot.currentPhase] : []),\n ...snapshot.agents.map((a) => a.phase).filter((p): p is string => Boolean(p)),\n ]);\n const rendered = new Set<WorkflowAgentSnapshot>();\n\n for (const phase of phaseNames) {\n const agents = snapshot.agents.filter((a) => a.phase === phase);\n if (agents.length === 0 && snapshot.currentPhase !== phase) continue;\n for (const a of agents) rendered.add(a);\n\n const counts = countAgents(agents);\n const completeHere = agents.length > 0 && counts.done + counts.error + counts.skipped === agents.length;\n const marker =\n counts.running > 0 || (!completeHere && snapshot.currentPhase === phase)\n ? '▶'\n : completeHere\n ? '✓'\n : ' ';\n\n const tail =\n (counts.running ? ` · ${counts.running} running` : '') +\n (counts.error ? ` · ${counts.error} errors` : '') +\n (counts.skipped ? ` · ${counts.skipped} skipped` : '');\n lines.push(` ${marker} ${phase} ${counts.done}/${agents.length}${tail}`);\n\n const visible = agents.slice(-maxAgentsPerPhase);\n for (const agent of visible) {\n const previewText = showPreviews && agent.resultPreview ? ` — ${agent.resultPreview}` : '';\n lines.push(\n ` #${agent.id} ${statusIcon(agent.status)} ${shorten(agent.label, 56)}${previewText}`,\n );\n }\n if (agents.length > visible.length) {\n lines.push(` … ${agents.length - visible.length} earlier agents`);\n }\n }\n\n const unphased = snapshot.agents.filter((a) => !rendered.has(a));\n if (unphased.length > 0) {\n lines.push(' unphased');\n for (const agent of unphased.slice(-maxAgentsPerPhase)) {\n const previewText = showPreviews && agent.resultPreview ? ` — ${agent.resultPreview}` : '';\n lines.push(\n ` #${agent.id} ${statusIcon(agent.status)} ${shorten(agent.label, 56)}${previewText}`,\n );\n }\n }\n\n const visibleLogs = snapshot.logs.slice(-maxLogs);\n if (visibleLogs.length > 0) {\n lines.push('');\n for (const log of visibleLogs) {\n lines.push(` log: ${shorten(log, 80)}`);\n }\n }\n return lines.join('\\n');\n}\n\nexport function previewValue(value: unknown, max = 80): string {\n if (value === null || value === undefined) return '';\n const text = typeof value === 'string' ? value : safeStringify(value);\n if (!text) return '';\n return text.length > max ? `${text.slice(0, max - 1)}…` : text;\n}\n\n// ---------------------------------------------------------------------------\n\nfunction countAgents(agents: WorkflowAgentSnapshot[]) {\n let done = 0;\n let running = 0;\n let error = 0;\n let skipped = 0;\n for (const a of agents) {\n if (a.status === 'done') done++;\n else if (a.status === 'running') running++;\n else if (a.status === 'error') error++;\n else if (a.status === 'skipped') skipped++;\n }\n return { done, running, error, skipped };\n}\n\nfunction statusIcon(status: WorkflowAgentStatus): string {\n switch (status) {\n case 'queued':\n return '○';\n case 'running':\n return '●';\n case 'done':\n return '✓';\n case 'error':\n return '✗';\n case 'skipped':\n return '-';\n }\n}\n\nfunction stateSuffix(snapshot: WorkflowSnapshot): string {\n if (snapshot.errorCount > 0) return `, ${snapshot.errorCount} errors`;\n if (snapshot.skippedCount > 0) return `, ${snapshot.skippedCount} skipped`;\n if (snapshot.runningCount > 0) return `, ${snapshot.runningCount} running`;\n return '';\n}\n\nfunction uniqueOrdered(values: string[]): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const v of values) {\n if (!seen.has(v)) {\n seen.add(v);\n out.push(v);\n }\n }\n return out;\n}\n\nfunction shorten(value: string, max: number): string {\n const text = value.replace(/\\s+/g, ' ').trim();\n return text.length > max ? `${text.slice(0, max - 1)}…` : text;\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Human-readable labels for workflow subagent tool steps (server-side snapshot).
3
+ * Mirrors the web `tool-friendly-title` rules so IM/TUI and gateway stay aligned.
4
+ */
5
+ export declare function workflowStepLabel(toolName: string, args: Record<string, unknown>): {
6
+ label: string;
7
+ detail?: string;
8
+ };
@@ -0,0 +1,48 @@
1
+ //#region src/agent/workflow/step-labels.ts
2
+ /**
3
+ * Human-readable labels for workflow subagent tool steps (server-side snapshot).
4
+ * Mirrors the web `tool-friendly-title` rules so IM/TUI and gateway stay aligned.
5
+ */
6
+ const MAX_DETAIL_LEN = 120;
7
+ function workflowStepLabel(toolName, args) {
8
+ const n = toolName.toLowerCase().replace(/-/g, "_").trim();
9
+ let label = toolName.trim() || "tool";
10
+ if (n === "shell") label = "Run command";
11
+ else if (n === "list_dir" || n === "ls") label = "List directory";
12
+ else if (n === "write_file") label = "Write file";
13
+ else if (n === "edit_file") label = "Edit file";
14
+ else if (n === "web_fetch") label = "Fetch URL";
15
+ else if (n === "open_url") label = "Open URL";
16
+ else if (n === "web_search" || n === "brave_search" || n.includes("search")) label = "Search web";
17
+ else if (n === "read_file" || n.includes("read_file") || n.includes("file_read")) label = "Read file";
18
+ else if (n === "grep" || n === "rg") label = "Search files";
19
+ else if (n === "delegate_task" || n === "workflow") label = toolName;
20
+ const detail = extractStepDetail(n, args);
21
+ return detail ? {
22
+ label,
23
+ detail
24
+ } : { label };
25
+ }
26
+ function extractStepDetail(toolKey, args) {
27
+ for (const key of [
28
+ "path",
29
+ "file_path",
30
+ "filePath",
31
+ "target_file",
32
+ "targetFile"
33
+ ]) {
34
+ const v = args[key];
35
+ if (typeof v === "string" && v.trim()) return truncate(v.trim());
36
+ }
37
+ if (toolKey === "shell" && typeof args.command === "string" && args.command.trim()) return truncate(args.command.trim());
38
+ if ((toolKey.includes("search") || toolKey === "grep" || toolKey === "rg") && typeof args.query === "string" && args.query.trim()) return truncate(args.query.trim());
39
+ if (typeof args.url === "string" && args.url.trim()) return truncate(args.url.trim());
40
+ }
41
+ function truncate(text) {
42
+ if (text.length <= MAX_DETAIL_LEN) return text;
43
+ return `${text.slice(0, MAX_DETAIL_LEN - 1)}…`;
44
+ }
45
+ //#endregion
46
+ export { workflowStepLabel };
47
+
48
+ //# sourceMappingURL=step-labels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-labels.js","names":[],"sources":["../../../../src/agent/workflow/step-labels.ts"],"sourcesContent":["/**\n * Human-readable labels for workflow subagent tool steps (server-side snapshot).\n * Mirrors the web `tool-friendly-title` rules so IM/TUI and gateway stay aligned.\n */\n\nconst MAX_DETAIL_LEN = 120;\n\nexport function workflowStepLabel(\n toolName: string,\n args: Record<string, unknown>,\n): { label: string; detail?: string } {\n const n = toolName.toLowerCase().replace(/-/g, '_').trim();\n let label = toolName.trim() || 'tool';\n if (n === 'shell') label = 'Run command';\n else if (n === 'list_dir' || n === 'ls') label = 'List directory';\n else if (n === 'write_file') label = 'Write file';\n else if (n === 'edit_file') label = 'Edit file';\n else if (n === 'web_fetch') label = 'Fetch URL';\n else if (n === 'open_url') label = 'Open URL';\n else if (n === 'web_search' || n === 'brave_search' || n.includes('search')) label = 'Search web';\n else if (n === 'read_file' || n.includes('read_file') || n.includes('file_read')) label = 'Read file';\n else if (n === 'grep' || n === 'rg') label = 'Search files';\n else if (n === 'delegate_task' || n === 'workflow') label = toolName;\n\n const detail = extractStepDetail(n, args);\n return detail ? { label, detail } : { label };\n}\n\nfunction extractStepDetail(toolKey: string, args: Record<string, unknown>): string | undefined {\n const pathKeys = ['path', 'file_path', 'filePath', 'target_file', 'targetFile'];\n for (const key of pathKeys) {\n const v = args[key];\n if (typeof v === 'string' && v.trim()) return truncate(v.trim());\n }\n if (toolKey === 'shell' && typeof args.command === 'string' && args.command.trim()) {\n return truncate(args.command.trim());\n }\n if (\n (toolKey.includes('search') || toolKey === 'grep' || toolKey === 'rg') &&\n typeof args.query === 'string' &&\n args.query.trim()\n ) {\n return truncate(args.query.trim());\n }\n if (typeof args.url === 'string' && args.url.trim()) return truncate(args.url.trim());\n return undefined;\n}\n\nfunction truncate(text: string): string {\n if (text.length <= MAX_DETAIL_LEN) return text;\n return `${text.slice(0, MAX_DETAIL_LEN - 1)}…`;\n}\n"],"mappings":";;;;;AAKA,MAAM,iBAAiB;AAEvB,SAAgB,kBACd,UACA,MACoC;CACpC,MAAM,IAAI,SAAS,aAAa,CAAC,QAAQ,MAAM,IAAI,CAAC,MAAM;CAC1D,IAAI,QAAQ,SAAS,MAAM,IAAI;AAC/B,KAAI,MAAM,QAAS,SAAQ;UAClB,MAAM,cAAc,MAAM,KAAM,SAAQ;UACxC,MAAM,aAAc,SAAQ;UAC5B,MAAM,YAAa,SAAQ;UAC3B,MAAM,YAAa,SAAQ;UAC3B,MAAM,WAAY,SAAQ;UAC1B,MAAM,gBAAgB,MAAM,kBAAkB,EAAE,SAAS,SAAS,CAAE,SAAQ;UAC5E,MAAM,eAAe,EAAE,SAAS,YAAY,IAAI,EAAE,SAAS,YAAY,CAAE,SAAQ;UACjF,MAAM,UAAU,MAAM,KAAM,SAAQ;UACpC,MAAM,mBAAmB,MAAM,WAAY,SAAQ;CAE5D,MAAM,SAAS,kBAAkB,GAAG,KAAK;AACzC,QAAO,SAAS;EAAE;EAAO;EAAQ,GAAG,EAAE,OAAO;;AAG/C,SAAS,kBAAkB,SAAiB,MAAmD;AAE7F,MAAK,MAAM,OAAO;EADA;EAAQ;EAAa;EAAY;EAAe;EACxC,EAAE;EAC1B,MAAM,IAAI,KAAK;AACf,MAAI,OAAO,MAAM,YAAY,EAAE,MAAM,CAAE,QAAO,SAAS,EAAE,MAAM,CAAC;;AAElE,KAAI,YAAY,WAAW,OAAO,KAAK,YAAY,YAAY,KAAK,QAAQ,MAAM,CAChF,QAAO,SAAS,KAAK,QAAQ,MAAM,CAAC;AAEtC,MACG,QAAQ,SAAS,SAAS,IAAI,YAAY,UAAU,YAAY,SACjE,OAAO,KAAK,UAAU,YACtB,KAAK,MAAM,MAAM,CAEjB,QAAO,SAAS,KAAK,MAAM,MAAM,CAAC;AAEpC,KAAI,OAAO,KAAK,QAAQ,YAAY,KAAK,IAAI,MAAM,CAAE,QAAO,SAAS,KAAK,IAAI,MAAM,CAAC;;AAIvF,SAAS,SAAS,MAAsB;AACtC,KAAI,KAAK,UAAU,eAAgB,QAAO;AAC1C,QAAO,GAAG,KAAK,MAAM,GAAG,iBAAiB,EAAE,CAAC"}
@@ -25,6 +25,7 @@ var DelegateSubagentRunner = class {
25
25
  return null;
26
26
  }
27
27
  const fullPrompt = buildPrompt(prompt, opts, wantStructured);
28
+ const streamMode = resolveSubagentStreamMode(this.deps.getConfig);
28
29
  const handle = createDelegateChildHandle({
29
30
  workspace: this.deps.workspace,
30
31
  goal: fullPrompt,
@@ -41,7 +42,13 @@ var DelegateSubagentRunner = class {
41
42
  schema: opts.schema,
42
43
  capture
43
44
  })];
44
- }
45
+ },
46
+ progressHooks: opts.onProgress && streamMode !== "off" ? {
47
+ mode: streamMode === "full" ? "full" : "steps",
48
+ onProgress: (event) => {
49
+ opts.onProgress?.(mapChildProgressEvent(event));
50
+ }
51
+ } : void 0
45
52
  });
46
53
  const onAbort = () => handle.abort();
47
54
  opts.signal?.addEventListener("abort", onAbort, { once: true });
@@ -98,6 +105,44 @@ function safeResolveDefaultModel(get) {
98
105
  return null;
99
106
  }
100
107
  }
108
+ function resolveSubagentStreamMode(getConfig) {
109
+ const mode = getConfig()?.agents?.defaults?.workflow?.subagentStream;
110
+ if (mode === "off" || mode === "steps" || mode === "full") return mode;
111
+ return "steps";
112
+ }
113
+ function mapChildProgressEvent(event) {
114
+ switch (event.type) {
115
+ case "tool_start": return {
116
+ type: "tool_start",
117
+ toolCallId: event.toolCallId ?? "",
118
+ toolName: event.toolName ?? "tool",
119
+ args: event.args ?? {}
120
+ };
121
+ case "tool_end": return {
122
+ type: "tool_end",
123
+ toolCallId: event.toolCallId ?? "",
124
+ toolName: event.toolName ?? "tool",
125
+ isError: Boolean(event.isError)
126
+ };
127
+ case "iteration": return {
128
+ type: "iteration",
129
+ count: event.count ?? 0,
130
+ max: event.max ?? 0
131
+ };
132
+ case "text_delta": return {
133
+ type: "text_delta",
134
+ delta: event.delta ?? ""
135
+ };
136
+ case "thinking_delta": return {
137
+ type: "thinking_delta",
138
+ delta: event.delta ?? ""
139
+ };
140
+ default: return {
141
+ type: "text_delta",
142
+ delta: ""
143
+ };
144
+ }
145
+ }
101
146
  //#endregion
102
147
  export { DelegateSubagentRunner };
103
148