@zhushanwen/pi-subagent-workflow 8.6.0 → 8.8.0

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 (364) hide show
  1. package/README.md +5 -11
  2. package/package.json +13 -20
  3. package/relay/relay.mjs +1 -1
  4. package/skills/workflow-script-format/SKILL.md +32 -13
  5. package/src/host/__tests__/pi-host.test.ts +235 -0
  6. package/src/host/pi-host.ts +163 -0
  7. package/src/index.ts +141 -138
  8. package/src/injectors/__tests__/engine-awareness.test.ts +292 -0
  9. package/src/injectors/__tests__/engine-section-stability.test.ts +343 -0
  10. package/src/injectors/__tests__/model-list-injector.test.ts +18 -21
  11. package/src/injectors/__tests__/subagent-list-injector.test.ts +59 -19
  12. package/src/injectors/__tests__/workflow-list-injector.test.ts +31 -17
  13. package/src/injectors/engine-awareness.ts +119 -0
  14. package/src/injectors/model-list-injector.ts +15 -58
  15. package/src/injectors/subagent-list-injector.ts +56 -114
  16. package/src/injectors/workflow-list-injector.ts +37 -70
  17. package/src/interface/__tests__/detectors.test.ts +48 -37
  18. package/src/interface/__tests__/subagent-tool-path-guard.test.ts +2 -2
  19. package/src/interface/__tests__/subagent-tool-prompt.test.ts +6 -3
  20. package/src/interface/__tests__/tool-workflow-run-builtin-name.test.ts +216 -0
  21. package/src/interface/__tests__/tool-workflow-script-generate.test.ts +17 -6
  22. package/src/interface/__tests__/tool-workflow-throw-paths.test.ts +38 -2
  23. package/src/interface/bg-notify-render.ts +7 -17
  24. package/src/interface/command-actions.ts +5 -15
  25. package/src/interface/commands.ts +4 -4
  26. package/src/interface/format.ts +17 -6
  27. package/src/interface/gui-mappers.ts +18 -22
  28. package/src/interface/helpers.ts +9 -130
  29. package/src/interface/list-component.ts +5 -5
  30. package/src/interface/list-shared.ts +3 -3
  31. package/src/interface/list-view.ts +3 -3
  32. package/src/interface/subagent-actions.ts +66 -439
  33. package/src/interface/subagent-tool-schema.ts +21 -17
  34. package/src/interface/subagent-tool.ts +12 -7
  35. package/src/interface/subagents.ts +4 -4
  36. package/src/interface/tool-render.ts +37 -15
  37. package/src/interface/tool-workflow-script.ts +34 -76
  38. package/src/interface/tool-workflow.ts +57 -94
  39. package/src/interface/views/WorkflowsView.ts +8 -16
  40. package/src/interface/views/__tests__/WorkflowsView-signature.test.ts +3 -3
  41. package/src/interface/views/__tests__/detail-content-session-file.test.ts +2 -2
  42. package/src/interface/views/detail-content.ts +4 -4
  43. package/src/interface/views/format.ts +23 -62
  44. package/src/{orchestration/jsonl-run-store.ts → jsonl-run-store.ts} +137 -225
  45. package/agents/analyst.md +0 -61
  46. package/agents/coder.md +0 -70
  47. package/agents/debugger.md +0 -67
  48. package/agents/doc-reviewer.md +0 -50
  49. package/agents/explorer.md +0 -64
  50. package/agents/general-purpose.md +0 -32
  51. package/agents/orchestrator.md +0 -63
  52. package/agents/planner.md +0 -54
  53. package/agents/researcher.md +0 -65
  54. package/agents/reviewer.md +0 -74
  55. package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +0 -53
  56. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +0 -1
  57. package/src/execution/__tests__/agent-registry.test.ts +0 -363
  58. package/src/execution/__tests__/agent-result-mapper.test.ts +0 -150
  59. package/src/execution/__tests__/alive-store.test.ts +0 -147
  60. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
  61. package/src/execution/__tests__/before-agent-start-injection.test.ts +0 -132
  62. package/src/execution/__tests__/bg-notify-render.test.ts +0 -329
  63. package/src/execution/__tests__/channel-registry-handshake.test.ts +0 -243
  64. package/src/execution/__tests__/chat-engine-routing.test.ts +0 -601
  65. package/src/execution/__tests__/chatmode-first-round-closure-service.test.ts +0 -365
  66. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -190
  67. package/src/execution/__tests__/chatmode-round-notify-real-chain.test.ts +0 -215
  68. package/src/execution/__tests__/concurrency-pool.test.ts +0 -250
  69. package/src/execution/__tests__/config.test.ts +0 -110
  70. package/src/execution/__tests__/conversation-wiring.test.ts +0 -198
  71. package/src/execution/__tests__/crash-recovery.test.ts +0 -320
  72. package/src/execution/__tests__/delivery-methods.test.ts +0 -422
  73. package/src/execution/__tests__/dialog-queue.test.ts +0 -299
  74. package/src/execution/__tests__/epipe-fallback.test.ts +0 -241
  75. package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -243
  76. package/src/execution/__tests__/execute-nesting.test.ts +0 -323
  77. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  78. package/src/execution/__tests__/execution-record.test.ts +0 -1394
  79. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +0 -171
  80. package/src/execution/__tests__/finalize-record.test.ts +0 -368
  81. package/src/execution/__tests__/finalized-marker.test.ts +0 -82
  82. package/src/execution/__tests__/format-schema-instruction.test.ts +0 -169
  83. package/src/execution/__tests__/format.test.ts +0 -458
  84. package/src/execution/__tests__/gc-timer.test.ts +0 -184
  85. package/src/execution/__tests__/get-record-for-action-restart.test.ts +0 -254
  86. package/src/execution/__tests__/gui-mode-dispatch.test.ts +0 -59
  87. package/src/execution/__tests__/helpers/mock-extension-api.ts +0 -30
  88. package/src/execution/__tests__/helpers/spawn-mock.ts +0 -242
  89. package/src/execution/__tests__/host-mode.test.ts +0 -87
  90. package/src/execution/__tests__/index-session-start-identity.test.ts +0 -371
  91. package/src/execution/__tests__/index-session-start.test.ts +0 -672
  92. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +0 -211
  93. package/src/execution/__tests__/lifecycle-manager.test.ts +0 -383
  94. package/src/execution/__tests__/lifecycle-predicates.test.ts +0 -116
  95. package/src/execution/__tests__/list-component.test.ts +0 -401
  96. package/src/execution/__tests__/list-fields.test.ts +0 -140
  97. package/src/execution/__tests__/manifest-parentid.test.ts +0 -117
  98. package/src/execution/__tests__/model-resolver.test.ts +0 -465
  99. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +0 -287
  100. package/src/execution/__tests__/nested-visibility.test.ts +0 -325
  101. package/src/execution/__tests__/notifier-flush.test.ts +0 -612
  102. package/src/execution/__tests__/notifier-golden-snapshot.test.ts +0 -261
  103. package/src/execution/__tests__/notify-ledger.test.ts +0 -826
  104. package/src/execution/__tests__/one-shot-upgrade.test.ts +0 -205
  105. package/src/execution/__tests__/output-collector.test.ts +0 -358
  106. package/src/execution/__tests__/parent-child-matrix.test.ts +0 -336
  107. package/src/execution/__tests__/path-encoding.test.ts +0 -104
  108. package/src/execution/__tests__/pi-invocation.test.ts +0 -134
  109. package/src/execution/__tests__/record-store.test.ts +0 -1057
  110. package/src/execution/__tests__/records-cwd-isolation.test.ts +0 -91
  111. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +0 -339
  112. package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -273
  113. package/src/execution/__tests__/relay-agent.test.ts +0 -448
  114. package/src/execution/__tests__/relay-env.test.ts +0 -42
  115. package/src/execution/__tests__/resource-policy.test.ts +0 -109
  116. package/src/execution/__tests__/rpc-mode.test.ts +0 -89
  117. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -267
  118. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -253
  119. package/src/execution/__tests__/run-spawn-edges.test.ts +0 -687
  120. package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
  121. package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
  122. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
  123. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +0 -199
  124. package/src/execution/__tests__/sdk-contract.test.ts +0 -273
  125. package/src/execution/__tests__/session-context-resolver.test.ts +0 -167
  126. package/src/execution/__tests__/session-file-gc.test.ts +0 -293
  127. package/src/execution/__tests__/session-pending.test.ts +0 -197
  128. package/src/execution/__tests__/session-reconstructor.test.ts +0 -379
  129. package/src/execution/__tests__/session-runner-epipe.test.ts +0 -178
  130. package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -350
  131. package/src/execution/__tests__/session-start-reaper.test.ts +0 -233
  132. package/src/execution/__tests__/spawn-args.test.ts +0 -445
  133. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -189
  134. package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
  135. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -207
  136. package/src/execution/__tests__/spawned-children.test.ts +0 -92
  137. package/src/execution/__tests__/start-sync-model-guard.test.ts +0 -150
  138. package/src/execution/__tests__/startup-config-declaration.test.ts +0 -35
  139. package/src/execution/__tests__/status-refactor.test.ts +0 -345
  140. package/src/execution/__tests__/stdin-writer.test.ts +0 -463
  141. package/src/execution/__tests__/stream-sink-retirement.test.ts +0 -261
  142. package/src/execution/__tests__/subagent-service-abort.test.ts +0 -60
  143. package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -629
  144. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +0 -180
  145. package/src/execution/__tests__/subagent-service.test.ts +0 -788
  146. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +0 -310
  147. package/src/execution/__tests__/subprocess-agent-runner.test.ts +0 -599
  148. package/src/execution/__tests__/temp-prompt.test.ts +0 -53
  149. package/src/execution/__tests__/timeout-integration.test.ts +0 -615
  150. package/src/execution/__tests__/tombstone-store.test.ts +0 -73
  151. package/src/execution/__tests__/tool-action.test.ts +0 -476
  152. package/src/execution/__tests__/truncline-snapshot.test.ts +0 -81
  153. package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
  154. package/src/execution/__tests__/turn-limiter.test.ts +0 -65
  155. package/src/execution/__tests__/ui-channels.test.ts +0 -187
  156. package/src/execution/__tests__/ui-interaction-model.test.ts +0 -67
  157. package/src/execution/__tests__/ui-request-handler-factory.test.ts +0 -370
  158. package/src/execution/__tests__/ui-request-handler.test.ts +0 -204
  159. package/src/execution/__tests__/ui-request-observability.test.ts +0 -114
  160. package/src/execution/__tests__/ui-request-queue.test.ts +0 -133
  161. package/src/execution/__tests__/worktree-manager.test.ts +0 -633
  162. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -229
  163. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +0 -181
  164. package/src/execution/__tests__/worktree-registry.test.ts +0 -199
  165. package/src/execution/agent-registry.ts +0 -199
  166. package/src/execution/agent-result-mapper.ts +0 -90
  167. package/src/execution/alive-store.ts +0 -92
  168. package/src/execution/argv-mirror.ts +0 -113
  169. package/src/execution/best-effort.ts +0 -38
  170. package/src/execution/channel-registry-access.ts +0 -144
  171. package/src/execution/concurrency-pool.ts +0 -116
  172. package/src/execution/config.ts +0 -96
  173. package/src/execution/dialog-queue.ts +0 -330
  174. package/src/execution/engine/__tests__/common/data-dir.test.ts +0 -53
  175. package/src/execution/engine/__tests__/common/errors.test.ts +0 -132
  176. package/src/execution/engine/__tests__/common/event-journal.test.ts +0 -177
  177. package/src/execution/engine/__tests__/common/kill-chain.test.ts +0 -192
  178. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +0 -81
  179. package/src/execution/engine/__tests__/common/persona-router.test.ts +0 -123
  180. package/src/execution/engine/__tests__/common/pool-manager.test.ts +0 -154
  181. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
  182. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
  183. package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +0 -141
  184. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +0 -109
  185. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +0 -101
  186. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +0 -77
  187. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +0 -104
  188. package/src/execution/engine/__tests__/conformance/contract.relay.test.ts +0 -342
  189. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +0 -201
  190. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +0 -76
  191. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +0 -79
  192. package/src/execution/engine/__tests__/engine-discovery.test.ts +0 -87
  193. package/src/execution/engine/__tests__/engines-declaration.test.ts +0 -36
  194. package/src/execution/engine/__tests__/model-prompt.test.ts +0 -85
  195. package/src/execution/engine/__tests__/paths.test.ts +0 -39
  196. package/src/execution/engine/__tests__/registry.test.ts +0 -120
  197. package/src/execution/engine/__tests__/routing.test.ts +0 -231
  198. package/src/execution/engine/common/data-dir.ts +0 -62
  199. package/src/execution/engine/common/errors.ts +0 -183
  200. package/src/execution/engine/common/event-journal.ts +0 -254
  201. package/src/execution/engine/common/journal-replay.ts +0 -62
  202. package/src/execution/engine/common/kill-chain.ts +0 -221
  203. package/src/execution/engine/common/nesting-guard.ts +0 -50
  204. package/src/execution/engine/common/persona-router.ts +0 -108
  205. package/src/execution/engine/common/pool-manager.ts +0 -226
  206. package/src/execution/engine/common/schema-emulation.ts +0 -189
  207. package/src/execution/engine/common/session-view-projection.ts +0 -51
  208. package/src/execution/engine/engine-discovery.ts +0 -65
  209. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -469
  210. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
  211. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  212. package/src/execution/engine/engines/pi/pi-engine.ts +0 -415
  213. package/src/execution/engine/engines/pi/reader.ts +0 -48
  214. package/src/execution/engine/engines/pi/registration.ts +0 -35
  215. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  216. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  217. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  218. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -246
  219. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -228
  220. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
  221. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -64
  222. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -127
  223. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -580
  224. package/src/execution/engine/engines/zcode/constants.ts +0 -43
  225. package/src/execution/engine/engines/zcode/golden-sample.ts +0 -39
  226. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  227. package/src/execution/engine/engines/zcode/parser.ts +0 -436
  228. package/src/execution/engine/engines/zcode/preparer.ts +0 -363
  229. package/src/execution/engine/engines/zcode/reader.ts +0 -381
  230. package/src/execution/engine/engines/zcode/registration.ts +0 -37
  231. package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -658
  232. package/src/execution/engine/host-task-spec.ts +0 -47
  233. package/src/execution/engine/model-prompt.ts +0 -59
  234. package/src/execution/engine/paths.ts +0 -42
  235. package/src/execution/engine/port.ts +0 -153
  236. package/src/execution/engine/registry.ts +0 -123
  237. package/src/execution/engine/routing.ts +0 -218
  238. package/src/execution/engine/types.ts +0 -309
  239. package/src/execution/execute-options-mapper.ts +0 -112
  240. package/src/execution/execution-record.ts +0 -965
  241. package/src/execution/finalize-record.ts +0 -251
  242. package/src/execution/finalized-marker.ts +0 -51
  243. package/src/execution/get-state-handshake.ts +0 -104
  244. package/src/execution/host-mode.ts +0 -56
  245. package/src/execution/idle-gc.ts +0 -47
  246. package/src/execution/lifecycle-manager.ts +0 -513
  247. package/src/execution/lifecycle-predicates.ts +0 -65
  248. package/src/execution/manifest-store.ts +0 -256
  249. package/src/execution/model-config-service.ts +0 -219
  250. package/src/execution/model-resolver.ts +0 -248
  251. package/src/execution/notifier.ts +0 -330
  252. package/src/execution/notify-ledger.ts +0 -580
  253. package/src/execution/output-collector.ts +0 -228
  254. package/src/execution/path-encoding.ts +0 -60
  255. package/src/execution/pi-invocation.ts +0 -120
  256. package/src/execution/record-entry.ts +0 -132
  257. package/src/execution/record-store.ts +0 -1234
  258. package/src/execution/relay-env.ts +0 -37
  259. package/src/execution/session-context-resolver.ts +0 -64
  260. package/src/execution/session-file-gc.ts +0 -120
  261. package/src/execution/session-pending.ts +0 -164
  262. package/src/execution/session-reconstructor.ts +0 -678
  263. package/src/execution/session-runner.ts +0 -1781
  264. package/src/execution/sessions-index.ts +0 -304
  265. package/src/execution/spawn-event-adapter.ts +0 -363
  266. package/src/execution/stdin-writer.ts +0 -198
  267. package/src/execution/stream-sink.ts +0 -126
  268. package/src/execution/subagent-service.ts +0 -2141
  269. package/src/execution/subprocess-agent-runner.ts +0 -317
  270. package/src/execution/temp-prompt.ts +0 -62
  271. package/src/execution/tombstone-store.ts +0 -72
  272. package/src/execution/turn-limiter.ts +0 -102
  273. package/src/execution/types.ts +0 -973
  274. package/src/execution/ui-channels.ts +0 -216
  275. package/src/execution/ui-interaction-model.ts +0 -48
  276. package/src/execution/ui-request-handler-factory.ts +0 -212
  277. package/src/execution/ui-request-observability.ts +0 -81
  278. package/src/execution/ui-request-queue.ts +0 -184
  279. package/src/execution/worktree-manager.ts +0 -688
  280. package/src/execution/worktree-registry.ts +0 -222
  281. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +0 -349
  282. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +0 -202
  283. package/src/orchestration/__tests__/agent-call-stream.test.ts +0 -152
  284. package/src/orchestration/__tests__/args-validator.test.ts +0 -143
  285. package/src/orchestration/__tests__/config-loader.test.ts +0 -503
  286. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +0 -809
  287. package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +0 -405
  288. package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +0 -56
  289. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +0 -166
  290. package/src/orchestration/__tests__/execute-agent-call.test.ts +0 -451
  291. package/src/orchestration/__tests__/jsonl-run-store-corrupt-entry.test.ts +0 -150
  292. package/src/orchestration/__tests__/jsonl-run-store-loadall-sources.test.ts +0 -171
  293. package/src/orchestration/__tests__/jsonl-run-store-retention.test.ts +0 -202
  294. package/src/orchestration/__tests__/jsonl-run-store-session-file.test.ts +0 -1030
  295. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +0 -600
  296. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +0 -96
  297. package/src/orchestration/__tests__/lifecycle.test.ts +0 -659
  298. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +0 -95
  299. package/src/orchestration/__tests__/review-fix-loop-e2e.test.ts +0 -2025
  300. package/src/orchestration/__tests__/script-lint.test.ts +0 -831
  301. package/src/orchestration/__tests__/skill-discovery.test.ts +0 -201
  302. package/src/orchestration/__tests__/test-mocks.ts +0 -197
  303. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +0 -368
  304. package/src/orchestration/__tests__/worker-host.test.ts +0 -120
  305. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +0 -164
  306. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +0 -563
  307. package/src/orchestration/__tests__/worker-script-builder.test.ts +0 -309
  308. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +0 -129
  309. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +0 -317
  310. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +0 -110
  311. package/src/orchestration/__tests__/workflows-e2e.test.ts +0 -537
  312. package/src/orchestration/agent-opts-resolver.ts +0 -174
  313. package/src/orchestration/args-validator.ts +0 -127
  314. package/src/orchestration/config-loader.ts +0 -315
  315. package/src/orchestration/error-recovery.ts +0 -1018
  316. package/src/orchestration/execute-agent-call.ts +0 -256
  317. package/src/orchestration/launcher.ts +0 -455
  318. package/src/orchestration/lifecycle.ts +0 -399
  319. package/src/orchestration/models/__tests__/budget.test.ts +0 -307
  320. package/src/orchestration/models/__tests__/trace.test.ts +0 -408
  321. package/src/orchestration/models/agent-call.ts +0 -83
  322. package/src/orchestration/models/budget.ts +0 -118
  323. package/src/orchestration/models/ports.ts +0 -164
  324. package/src/orchestration/models/run-runtime.ts +0 -104
  325. package/src/orchestration/models/run-spec.ts +0 -83
  326. package/src/orchestration/models/run-state.ts +0 -44
  327. package/src/orchestration/models/trace.ts +0 -183
  328. package/src/orchestration/models/types.ts +0 -301
  329. package/src/orchestration/models/workflow-run.ts +0 -254
  330. package/src/orchestration/models/workflow-script-registry.ts +0 -35
  331. package/src/orchestration/models/workflow-script.ts +0 -117
  332. package/src/orchestration/script-lint.ts +0 -766
  333. package/src/orchestration/skill-discovery.ts +0 -115
  334. package/src/orchestration/worker-handle.ts +0 -115
  335. package/src/orchestration/worker-host.ts +0 -98
  336. package/src/orchestration/worker-script-builder.ts +0 -421
  337. package/src/orchestration/workflow-files.ts +0 -85
  338. package/src/orchestration/workflow-script-registry-impl.ts +0 -133
  339. package/src/shared/__tests__/agent-ref.test.ts +0 -34
  340. package/src/shared/__tests__/meta-parser.test.ts +0 -304
  341. package/src/shared/__tests__/model-ref.test.ts +0 -306
  342. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -280
  343. package/src/shared/__tests__/resource-discovery.test.ts +0 -736
  344. package/src/shared/__tests__/resource-meta.test.ts +0 -51
  345. package/src/shared/__tests__/schema-jsonify.test.ts +0 -81
  346. package/src/shared/__tests__/timer-delay.test.ts +0 -61
  347. package/src/shared/agent-event.ts +0 -13
  348. package/src/shared/agent-ref.ts +0 -57
  349. package/src/shared/meta-parser.ts +0 -261
  350. package/src/shared/model-ref.ts +0 -286
  351. package/src/shared/resource-discovery.ts +0 -811
  352. package/src/shared/resource-meta.ts +0 -65
  353. package/src/shared/schema-env.ts +0 -44
  354. package/src/shared/schema-jsonify.ts +0 -58
  355. package/src/shared/timer-delay.ts +0 -54
  356. package/src/shared/xml-injection.ts +0 -35
  357. package/workflows/README.md +0 -81
  358. package/workflows/_shared/agent-refs.cjs +0 -40
  359. package/workflows/chain.js +0 -131
  360. package/workflows/map-reduce.js +0 -174
  361. package/workflows/parallel.js +0 -148
  362. package/workflows/review-fix-loop-utils.cjs +0 -1309
  363. package/workflows/review-fix-loop.js +0 -1404
  364. package/workflows/scatter-gather.js +0 -178
@@ -1,405 +0,0 @@
1
- // src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts
2
- //
3
- // W2: 主线程层 postMessage 防御测试。
4
- //
5
- // 背景:主线程有 3 处 run.runtime?.worker.postMessage(...) 调用(经 helper 函数),
6
- // 全部没有 try/catch。若 result 对象含不可克隆成员(function/Symbol/循环引用),
7
- // postMessage 同步抛 DataCloneError:
8
- // - postAgentResult:result 是 agent 返回值,不可克隆概率最高。DataCloneError 冒泡到
9
- // dispatchAgentCall 的 .then 回调,中断后续 postBudgetUpdate/store.save/budget 检查,
10
- // run 卡在 running。
11
- // - postBudgetUpdate:payload 是 number,风险低但无兜底。
12
- // - dispatchWorkflowCall 的 postResult:result 是子 workflow 任意返回值。
13
- //
14
- // 修复后三处均包 try/catch + fallback。本测试通过 mock worker.postMessage 抛
15
- // DataCloneError,验证:
16
- // 1. 调用方不抛错(流程不中断)
17
- // 2. fallback result(纯字符串,必可克隆)被发送
18
- // 3. console.error 记录诊断
19
-
20
- import { readFileSync } from "node:fs";
21
- import { dirname, join } from "node:path";
22
- import { fileURLToPath } from "node:url";
23
-
24
- import { describe, expect, it, vi } from "vitest";
25
-
26
- // Mock 共享 logger,让 logger.error 可被 spy(源码已从 console.error 改为 logger.error)
27
- const { loggerMock } = vi.hoisted(() => ({
28
- loggerMock: {
29
- debug: vi.fn(),
30
- warn: vi.fn(),
31
- error: vi.fn(),
32
- info: vi.fn(),
33
- },
34
- }));
35
- vi.mock("@zhushanwen/pi-extension-logger", () => ({
36
- getLogger: () => loggerMock,
37
- }));
38
-
39
- import { handleWorkerMessage, postBudgetUpdate } from "../error-recovery.ts";
40
- import type { LifecycleDeps, WorkerHandlers } from "../models/ports.ts";
41
- import type { WorkflowRun } from "../models/workflow-run.ts";
42
-
43
- const __dirname = dirname(fileURLToPath(import.meta.url));
44
- const ERROR_RECOVERY_SRC = readFileSync(
45
- join(__dirname, "../error-recovery.ts"),
46
- "utf-8",
47
- );
48
-
49
- // ── helpers ──────────────────────────────────────────────────
50
-
51
- /** flush microtask 队列,让 void .then().catch() 链路跑完。 */
52
- async function flushMicrotasks(): Promise<void> {
53
- await new Promise((resolve) => setTimeout(resolve, 0));
54
- }
55
-
56
- /** 构造一个 postMessage mock:前 n 次抛 DataCloneError,之后正常(模拟 fallback 成功)。 */
57
- function makeFailingPostMessage(failTimes: number): ReturnType<typeof vi.fn> {
58
- let calls = 0;
59
- return vi.fn(() => {
60
- calls += 1;
61
- if (calls <= failTimes) {
62
- const err = new Error("Could not clone object: function found");
63
- err.name = "DataCloneError";
64
- throw err;
65
- }
66
- // fallback 成功路径:no-op
67
- });
68
- }
69
-
70
- /** 构造一个永远抛 DataCloneError 的 postMessage mock(fallback 也失败)。 */
71
- function makeAlwaysFailingPostMessage(): ReturnType<typeof vi.fn> {
72
- return vi.fn(() => {
73
- const err = new Error("Could not clone object");
74
- err.name = "DataCloneError";
75
- throw err;
76
- });
77
- }
78
-
79
- /** 构造 status="running" 的 mock WorkflowRun,postMessage 由调用方注入。 */
80
- function makeRunningRun(postMessage: ReturnType<typeof vi.fn>): WorkflowRun {
81
- return {
82
- state: { status: "running" },
83
- runtime: { worker: { postMessage } },
84
- } as unknown as WorkflowRun;
85
- }
86
-
87
- /** LifecycleDeps 只需 onWorkflowCall(dispatchWorkflowCall 唯一消费的 dep)。 */
88
- function makeDeps(onWorkflowCall?: LifecycleDeps["onWorkflowCall"]): LifecycleDeps {
89
- return { onWorkflowCall } as unknown as LifecycleDeps;
90
- }
91
-
92
- /** WorkerHandlers 占位(workflow-call 路径不触发 handler 回调)。 */
93
- function makeHandlers(): WorkerHandlers {
94
- return {
95
- onMessage: vi.fn(async () => {}),
96
- onError: vi.fn(async () => {}),
97
- onExit: vi.fn(async () => {}),
98
- } as unknown as WorkerHandlers;
99
- }
100
-
101
- interface PostedMsg {
102
- type: string;
103
- callId?: number;
104
- result?: { content: string; error?: string };
105
- budget?: { usedTokens: number; usedCost: number };
106
- cached?: boolean;
107
- }
108
-
109
- /** 从 postMessage mock 取第 idx 次调用的第 0 参。 */
110
- function postedAt(postMessage: ReturnType<typeof vi.fn>, idx: number): PostedMsg {
111
- return postMessage.mock.calls[idx]![0] as PostedMsg;
112
- }
113
-
114
- /** 清空 logger.error 调用记录(防御路径会打印诊断,避免污染跨用例断言)。 */
115
- function silenceConsoleError(): () => void {
116
- loggerMock.error.mockClear();
117
- return () => {
118
- loggerMock.error.mockClear();
119
- };
120
- }
121
-
122
- // ── W2a: postBudgetUpdate try/catch ──
123
-
124
- describe("W2a: postBudgetUpdate 防御 DataCloneError", () => {
125
- it("postMessage 抛错时不向上传播(流程不中断)", () => {
126
- const restore = silenceConsoleError();
127
- try {
128
- const postMessage = makeAlwaysFailingPostMessage();
129
- const run = {
130
- state: {
131
- status: "running",
132
- budget: { usedTokens: 42, usedCost: 0.5 },
133
- },
134
- runtime: { worker: { postMessage } },
135
- } as unknown as WorkflowRun;
136
-
137
- // 不应抛错——防御性兜底
138
- expect(() => postBudgetUpdate(run)).not.toThrow();
139
- } finally {
140
- restore();
141
- }
142
- });
143
-
144
- it("postMessage 失败时记录 console.error 诊断", () => {
145
- const restore = silenceConsoleError();
146
- try {
147
- const postMessage = makeAlwaysFailingPostMessage();
148
- const run = {
149
- state: {
150
- status: "running",
151
- budget: { usedTokens: 42, usedCost: 0.5 },
152
- },
153
- runtime: { worker: { postMessage } },
154
- } as unknown as WorkflowRun;
155
-
156
- postBudgetUpdate(run);
157
-
158
- expect(loggerMock.error).toHaveBeenCalledTimes(1);
159
- const diag = loggerMock.error.mock.calls[0]![0] as string;
160
- expect(diag).toContain("postBudgetUpdate failed");
161
- expect(diag).toContain("Could not clone object");
162
- } finally {
163
- restore();
164
- }
165
- });
166
-
167
- it("正常 payload(纯 number)成功发送", () => {
168
- const postMessage = vi.fn();
169
- const run = {
170
- state: {
171
- status: "running",
172
- budget: { usedTokens: 42, usedCost: 0.5 },
173
- },
174
- runtime: { worker: { postMessage } },
175
- } as unknown as WorkflowRun;
176
-
177
- postBudgetUpdate(run);
178
-
179
- expect(postMessage).toHaveBeenCalledTimes(1);
180
- expect(postedAt(postMessage, 0)).toEqual({
181
- type: "budget-update",
182
- budget: { usedTokens: 42, usedCost: 0.5 },
183
- });
184
- });
185
- });
186
-
187
- // ── W2b: dispatchWorkflowCall postResult 闭包防御 ──
188
-
189
- describe("W2b: dispatchWorkflowCall postResult 防御 DataCloneError", () => {
190
- it("result 不可克隆 → 回发纯字符串 fallback result", async () => {
191
- const restore = silenceConsoleError();
192
- try {
193
- // 第 1 次 postMessage 抛 DataCloneError(原始 result 不可克隆),
194
- // 第 2 次(fallback)成功。
195
- const postMessage = makeFailingPostMessage(1);
196
- const onWorkflowCall = vi.fn(async () => ({ nonCloneable: () => {} }));
197
- const run = makeRunningRun(postMessage);
198
- const deps = makeDeps(onWorkflowCall);
199
-
200
- await handleWorkerMessage(
201
- run,
202
- { type: "workflow-call", callId: 9, name: "sub", args: {} },
203
- deps,
204
- makeHandlers(),
205
- );
206
- await flushMicrotasks();
207
-
208
- // 调用两次:1 原始(失败)+ 1 fallback(成功)
209
- expect(postMessage).toHaveBeenCalledTimes(2);
210
- const fallback = postedAt(postMessage, 1);
211
- expect(fallback.type).toBe("workflow-result");
212
- expect(fallback.callId).toBe(9);
213
- expect(fallback.result?.content).toBe("");
214
- expect(fallback.result?.error).toContain("Workflow result serialization failed");
215
- } finally {
216
- restore();
217
- }
218
- });
219
-
220
- it("postResult 不抛错到调用方(不中断 onWorkflowCall 链路)", async () => {
221
- const restore = silenceConsoleError();
222
- try {
223
- const postMessage = makeAlwaysFailingPostMessage();
224
- const onWorkflowCall = vi.fn(async () => ({ bad: () => {} }));
225
- const run = makeRunningRun(postMessage);
226
- const deps = makeDeps(onWorkflowCall);
227
-
228
- // handleWorkerMessage 自身不应抛——postResult 内部已 catch
229
- await expect(
230
- handleWorkerMessage(
231
- run,
232
- { type: "workflow-call", callId: 10, name: "sub", args: {} },
233
- deps,
234
- makeHandlers(),
235
- ),
236
- ).resolves.toBeUndefined();
237
- await flushMicrotasks();
238
- } finally {
239
- restore();
240
- }
241
- });
242
-
243
- it("fallback 也失败 → console.error 记录 worker pending 将挂起", async () => {
244
- const restore = silenceConsoleError();
245
- try {
246
- const postMessage = makeAlwaysFailingPostMessage();
247
- const onWorkflowCall = vi.fn(async () => ({ bad: () => {} }));
248
- const run = makeRunningRun(postMessage);
249
- const deps = makeDeps(onWorkflowCall);
250
-
251
- await handleWorkerMessage(
252
- run,
253
- { type: "workflow-call", callId: 11, name: "sub", args: {} },
254
- deps,
255
- makeHandlers(),
256
- );
257
- await flushMicrotasks();
258
-
259
- // 至少 2 次尝试(原始 + fallback),fallback 失败也记日志
260
- expect(postMessage.mock.calls.length).toBeGreaterThanOrEqual(2);
261
- const errorCalls = loggerMock.error.mock.calls.map((c) => c[0] as string);
262
- expect(errorCalls.some((s) => s.includes("fallback also failed"))).toBe(true);
263
- } finally {
264
- restore();
265
- }
266
- });
267
- });
268
-
269
- // ── W2c: postAgentResult 防御(经 handleWorkerMessage 触发) ──
270
- //
271
- // postAgentResult 是私有函数,通过 workflow-call 路径无法触发。但它可经 agent-call
272
- // 路径的「cached replay」分支触发:dispatchAgentCall 发现 run.state.calls.get(callId)
273
- // 已是 done 时,直接 postAgentResult(run, callId, cached.result, true)(无需 spawn
274
- // 子进程)。利用这一点构造行为测试——往 cached.result 里塞不可克隆值(function),
275
- // mock postMessage 在首次发送 agent-result 时抛 DataCloneError,验证 fallback 路径。
276
- //
277
- // 另外补充:验证 error-recovery.ts 源码中三处 postMessage 调用点都有 try/catch 包裹,
278
- // 防止未来重构误删防御(类似 worker-script-builder.test.ts 的源码字符串断言模式)。
279
-
280
- /** 构造 status="running" 且 calls 已含一个 done 结果(含不可克隆成员)的 mock run。
281
- * 触发 dispatchAgentCall 的 cached replay 分支(line ~234),直接走 postAgentResult。 */
282
- function makeRunningRunWithCachedDone(
283
- postMessage: ReturnType<typeof vi.fn>,
284
- callId: number,
285
- result: unknown,
286
- ): WorkflowRun {
287
- const calls = new Map();
288
- calls.set(callId, { status: "done", result });
289
- return {
290
- state: {
291
- status: "running",
292
- calls,
293
- trace: { append: vi.fn(), update: vi.fn() },
294
- budget: { isExceeded: vi.fn(() => false) },
295
- },
296
- runtime: { worker: { postMessage } },
297
- } as unknown as WorkflowRun;
298
- }
299
-
300
- describe("W2c: postAgentResult 行为测试(cached replay 路径)", () => {
301
- it("result 不可克隆 → 回发纯字符串 fallback result(cached: false)", async () => {
302
- const restore = silenceConsoleError();
303
- try {
304
- // 第 1 次 postMessage 抛 DataCloneError(原始 cached.result 含 function 不可克隆),
305
- // 第 2 次(fallback)成功。
306
- const postMessage = makeFailingPostMessage(1);
307
- // cached.result 含 function 成员 → 模拟 agent 返回不可克隆值({ bad: () => {} })
308
- const run = makeRunningRunWithCachedDone(postMessage, 7, { bad: () => {} });
309
- const deps = makeDeps();
310
-
311
- await handleWorkerMessage(
312
- run,
313
- { type: "agent-call", callId: 7, opts: { prompt: "noop" } },
314
- deps,
315
- makeHandlers(),
316
- );
317
- await flushMicrotasks();
318
-
319
- // 调用两次:1 原始 agent-result(失败)+ 1 fallback(成功)
320
- expect(postMessage).toHaveBeenCalledTimes(2);
321
-
322
- // 第 1 次:原始 agent-result,result 透传原值,cached 为 replay 的 true
323
- const original = postedAt(postMessage, 0);
324
- expect(original.type).toBe("agent-result");
325
- expect(original.callId).toBe(7);
326
- expect(original.cached).toBe(true);
327
-
328
- // 第 2 次:fallback agent-result,result 形状为 {content:"", error:"Result serialization failed: ..."},
329
- // 且 cached 固定为 false(fallback result 非缓存命中,透传原值含义失真)
330
- const fallback = postedAt(postMessage, 1);
331
- expect(fallback.type).toBe("agent-result");
332
- expect(fallback.callId).toBe(7);
333
- expect(fallback.result?.content).toBe("");
334
- expect(fallback.result?.error).toContain("Result serialization failed");
335
- expect(fallback.result?.error).toContain("Could not clone object");
336
- expect(fallback.cached).toBe(false);
337
- } finally {
338
- restore();
339
- }
340
- });
341
-
342
- it("fallback 也失败 → 不向上抛错,记录 worker pending 将挂起", async () => {
343
- const restore = silenceConsoleError();
344
- try {
345
- // postMessage 永远抛 DataCloneError(原始 + fallback 均失败)
346
- const postMessage = makeAlwaysFailingPostMessage();
347
- const run = makeRunningRunWithCachedDone(postMessage, 8, { bad: () => {} });
348
- const deps = makeDeps();
349
-
350
- // handleWorkerMessage 自身不应抛——postAgentResult 内部已 catch
351
- await expect(
352
- handleWorkerMessage(
353
- run,
354
- { type: "agent-call", callId: 8, opts: { prompt: "noop" } },
355
- deps,
356
- makeHandlers(),
357
- ),
358
- ).resolves.toBeUndefined();
359
- await flushMicrotasks();
360
-
361
- // 至少 2 次尝试(原始 + fallback),fallback 失败也记日志
362
- expect(postMessage.mock.calls.length).toBeGreaterThanOrEqual(2);
363
- const errorCalls = loggerMock.error.mock.calls.map((c) => c[0] as string);
364
- expect(errorCalls.some((s) => s.includes("postAgentResult failed"))).toBe(true);
365
- expect(errorCalls.some((s) => s.includes("fallback also failed"))).toBe(true);
366
- } finally {
367
- restore();
368
- }
369
- });
370
- });
371
-
372
- describe("W2c: postAgentResult 防御(源码结构断言)", () => {
373
- /** 校验:给定函数体内的 postMessage 调用被 try/catch 包裹。
374
- * 简化策略——在函数体片段中确认存在 try { ... postMessage ... } catch。 */
375
- function hasTryCatchAroundPostMessage(funcBody: string): boolean {
376
- return /try\s*\{[\s\S]*?postMessage[\s\S]*?\}\s*catch/.test(funcBody);
377
- }
378
-
379
- it("postAgentResult 包含 try/catch + fallback result", () => {
380
- const match = ERROR_RECOVERY_SRC.match(/function postAgentResult\([\s\S]*?\n\}/);
381
- expect(match, "postAgentResult 函数定义应存在").toBeTruthy();
382
- expect(hasTryCatchAroundPostMessage(match![0])).toBe(true);
383
- // fallback 通过共享工厂 makeSerializeFailedResult 构造纯字符串 result(必可克隆)
384
- expect(match![0]).toContain('result: makeSerializeFailedResult("Result serialization failed"');
385
- expect(match![0]).toContain("Result serialization failed");
386
- // 原 result 不可克隆时 cached 透传原值含义失真 → fallback 固定 cached: false
387
- expect(match![0]).toContain("cached: false");
388
- });
389
-
390
- it("postBudgetUpdate 包含 try/catch", () => {
391
- const match = ERROR_RECOVERY_SRC.match(/export function postBudgetUpdate\([\s\S]*?\n\}/);
392
- expect(match, "postBudgetUpdate 函数定义应存在").toBeTruthy();
393
- expect(hasTryCatchAroundPostMessage(match![0])).toBe(true);
394
- });
395
-
396
- it("dispatchWorkflowCall postResult 闭包包含 try/catch + fallback", () => {
397
- // postResult 是 const 闭包,匹配到下一个 }; 结尾
398
- const match = ERROR_RECOVERY_SRC.match(/const postResult = \(result[\s\S]*?\n \};/);
399
- expect(match, "postResult 闭包定义应存在").toBeTruthy();
400
- expect(hasTryCatchAroundPostMessage(match![0])).toBe(true);
401
- expect(match![0]).toContain("Workflow result serialization failed");
402
- // 防御变量名遮蔽:错误变量用 err 而非 msg(外层参数名 msg)
403
- expect(match![0]).toMatch(/catch \(err\)/);
404
- });
405
- });
@@ -1,56 +0,0 @@
1
- // src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts
2
- //
3
- // makeSerializeFailedResult 独立单测(W2 防御关键纯函数)。
4
- //
5
- // 背景:postMessage 序列化失败时,主线程需回发「必可克隆」的 fallback result
6
- // 让 worker 内 pending Promise resolve(否则 agent()/workflow() 永久挂起,只能靠
7
- // timeout 兜底)。两条 fallback 路径(postAgentResult / dispatchWorkflowCall.postResult)
8
- // 共享 makeSerializeFailedResult 构造逻辑——本测试锁住其返回 shape,确保两条路径
9
- // 不漂移。
10
- //
11
- // 验证点:
12
- // 1. content 恒为 ""(纯字符串 fallback,必可克隆——不含 function/Symbol/循环引用)
13
- // 2. error 形如 "<prefix>: <errMsg>"(前缀区分调用方,便于诊断定位)
14
- // 3. prefix / errMsg 各自原样透传(含空串、特殊字符、多行)
15
-
16
- import { describe, expect, it } from "vitest";
17
-
18
- import { makeSerializeFailedResult } from "../error-recovery.ts";
19
-
20
- describe("makeSerializeFailedResult", () => {
21
- it("返回 {content:'', error:'<prefix>: <errMsg>'} 形状(必可克隆 fallback)", () => {
22
- const result = makeSerializeFailedResult("Result serialization failed", "DataCloneError: ...");
23
- expect(result).toEqual({
24
- content: "",
25
- error: "Result serialization failed: DataCloneError: ...",
26
- });
27
- });
28
-
29
- it("content 恒为空串(纯字符串 fallback,不含不可克隆成员)", () => {
30
- // 无论入参如何,content 必为 ""——postMessage 必须能克隆这个 fallback result。
31
- const result = makeSerializeFailedResult("any prefix", "any error");
32
- expect(result.content).toBe("");
33
- });
34
-
35
- it("error 由 prefix + ': ' + errMsg 拼接(前缀区分调用方,便于诊断)", () => {
36
- const result = makeSerializeFailedResult("Workflow result serialization failed", "boom");
37
- expect(result.error).toBe("Workflow result serialization failed: boom");
38
- // 分隔符固定为 ": "——两条 fallback 路径共享同一构造逻辑。
39
- expect(result.error).toContain(": ");
40
- });
41
-
42
- it("prefix 与 errMsg 原样透传(含空串、特殊字符、多行)", () => {
43
- // 空串 prefix
44
- expect(makeSerializeFailedResult("", "err").error).toBe(": err");
45
- // 空串 errMsg
46
- expect(makeSerializeFailedResult("prefix", "").error).toBe("prefix: ");
47
- // 含冒号 / 换行 / unicode 的 errMsg(原样透传,不做转义)
48
- const weird = "err: with: colons\nand newline 中文 🚀";
49
- expect(makeSerializeFailedResult("P", weird).error).toBe(`P: ${weird}`);
50
- });
51
-
52
- it("返回对象字段仅 content + error(无多余字段,shape 稳定不漂移)", () => {
53
- const result = makeSerializeFailedResult("p", "e");
54
- expect(Object.keys(result).sort()).toEqual(["content", "error"]);
55
- });
56
- });
@@ -1,166 +0,0 @@
1
- /**
2
- * dispatchWorkflowCall — workflow-call 消息路由测试。
3
- *
4
- * 通过 handleWorkerMessage 触发 workflow-call case,验证:
5
- * - onWorkflowCall 回调被正确调用(name + args + parentRun)
6
- * - 成功时 postMessage(workflow-result, result)
7
- * - onWorkflowCall reject 时 postMessage 含 error
8
- * - onWorkflowCall 未注入时 postMessage 含 error(向后兼容)
9
- * - stale 完成守卫(resolve 前 run 已终态 → 不 postMessage)
10
- */
11
- import { describe, expect, it, vi } from "vitest";
12
-
13
- import { handleWorkerMessage } from "../error-recovery.ts";
14
- import type { LifecycleDeps, WorkerHandlers } from "../models/ports.ts";
15
- import type { WorkflowRun } from "../models/workflow-run.ts";
16
-
17
- // ── helpers ──────────────────────────────────────────────────
18
-
19
- /** flush microtask 队列,让 void .then().catch() 链路跑完。 */
20
- async function flushMicrotasks(): Promise<void> {
21
- await new Promise((resolve) => setTimeout(resolve, 0));
22
- }
23
-
24
- /** 构造一个 status="running" 的 mock WorkflowRun,postMessage 可观测。 */
25
- function makeRunningRun(postMessage: ReturnType<typeof vi.fn>): WorkflowRun {
26
- return {
27
- state: { status: "running" },
28
- runtime: { worker: { postMessage } },
29
- } as unknown as WorkflowRun;
30
- }
31
-
32
- /** LifecycleDeps 只需 onWorkflowCall(dispatchWorkflowCall 唯一消费的 dep)。 */
33
- function makeDeps(onWorkflowCall?: LifecycleDeps["onWorkflowCall"]): LifecycleDeps {
34
- return { onWorkflowCall } as unknown as LifecycleDeps;
35
- }
36
-
37
- /** WorkerHandlers 占位(workflow-call 路径不触发 handler 回调)。 */
38
- function makeHandlers(): WorkerHandlers {
39
- return {
40
- onMessage: vi.fn(async () => {}),
41
- onError: vi.fn(async () => {}),
42
- onExit: vi.fn(async () => {}),
43
- } as unknown as WorkerHandlers;
44
- }
45
-
46
- interface PostedMsg {
47
- type: string;
48
- callId: number;
49
- result: { content: string; error?: string };
50
- }
51
-
52
- /** 从 postMessage mock 取第 0 次调用的第 0 参,类型安全窄化。 */
53
- function firstPosted(postMessage: ReturnType<typeof vi.fn>): PostedMsg {
54
- return postMessage.mock.calls[0]![0] as PostedMsg;
55
- }
56
-
57
- // ── tests ────────────────────────────────────────────────────
58
-
59
- describe("dispatchWorkflowCall (workflow-call routing)", () => {
60
- it("calls onWorkflowCall with name and args", async () => {
61
- const postMessage = vi.fn();
62
- const onWorkflowCall = vi.fn(async () => ({ content: "ok" }));
63
- const run = makeRunningRun(postMessage);
64
- const deps = makeDeps(onWorkflowCall);
65
-
66
- await handleWorkerMessage(
67
- run,
68
- { type: "workflow-call", callId: 1, name: "sub", args: { k: 1 } },
69
- deps,
70
- makeHandlers(),
71
- );
72
- await flushMicrotasks();
73
-
74
- expect(onWorkflowCall).toHaveBeenCalledTimes(1);
75
- expect(onWorkflowCall).toHaveBeenCalledWith("sub", { k: 1 }, run);
76
- });
77
-
78
- it("posts workflow-result on success", async () => {
79
- const postMessage = vi.fn();
80
- const onWorkflowCall = vi.fn(async () => ({ content: "result-data" }));
81
- const run = makeRunningRun(postMessage);
82
- const deps = makeDeps(onWorkflowCall);
83
-
84
- await handleWorkerMessage(
85
- run,
86
- { type: "workflow-call", callId: 2, name: "sub", args: {} },
87
- deps,
88
- makeHandlers(),
89
- );
90
- await flushMicrotasks();
91
-
92
- expect(postMessage).toHaveBeenCalledWith({
93
- type: "workflow-result",
94
- callId: 2,
95
- result: { content: "result-data" },
96
- });
97
- });
98
-
99
- it("posts error result when onWorkflowCall rejects", async () => {
100
- const postMessage = vi.fn();
101
- const onWorkflowCall = vi.fn(async () => {
102
- throw new Error("boom");
103
- });
104
- const run = makeRunningRun(postMessage);
105
- const deps = makeDeps(onWorkflowCall);
106
-
107
- await handleWorkerMessage(
108
- run,
109
- { type: "workflow-call", callId: 3, name: "sub", args: {} },
110
- deps,
111
- makeHandlers(),
112
- );
113
- await flushMicrotasks();
114
-
115
- expect(postMessage).toHaveBeenCalledTimes(1);
116
- const sent = firstPosted(postMessage);
117
- expect(sent.type).toBe("workflow-result");
118
- expect(sent.callId).toBe(3);
119
- expect(sent.result.error).toBe("boom");
120
- });
121
-
122
- it("posts error result when onWorkflowCall not injected", async () => {
123
- const postMessage = vi.fn();
124
- const run = makeRunningRun(postMessage);
125
- const deps = makeDeps(undefined);
126
-
127
- await handleWorkerMessage(
128
- run,
129
- { type: "workflow-call", callId: 4, name: "sub", args: {} },
130
- deps,
131
- makeHandlers(),
132
- );
133
- await flushMicrotasks();
134
-
135
- expect(postMessage).toHaveBeenCalledTimes(1);
136
- const sent = firstPosted(postMessage);
137
- expect(sent.type).toBe("workflow-result");
138
- expect(sent.result.error).toContain("onWorkflowCall not injected");
139
- });
140
-
141
- it("does not post when run reaches terminal state before result arrives", async () => {
142
- const postMessage = vi.fn();
143
- let resolveWorkflow: (value: unknown) => void = () => {};
144
- const workflowPromise = new Promise<unknown>((r) => {
145
- resolveWorkflow = r;
146
- });
147
- const onWorkflowCall = vi.fn(() => workflowPromise);
148
- const run = makeRunningRun(postMessage);
149
- const deps = makeDeps(onWorkflowCall);
150
-
151
- await handleWorkerMessage(
152
- run,
153
- { type: "workflow-call", callId: 5, name: "sub", args: {} },
154
- deps,
155
- makeHandlers(),
156
- );
157
-
158
- // dispatchWorkflowCall 已触发,onWorkflowCall pending。
159
- // 在 resolve 前终止 run(转终态 done)—— stale 完成守卫应阻止 postMessage。
160
- run.state.status = "done";
161
- resolveWorkflow({ content: "late" });
162
- await flushMicrotasks();
163
-
164
- expect(postMessage).not.toHaveBeenCalled();
165
- });
166
- });