@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,116 +0,0 @@
1
- // lifecycle-predicates 单测(v4 B-1)。
2
- // 验证 isIdle/isResumable/hasLiveProcessHandle 在两态收敛后的判定逻辑。
3
- // 依赖 lifecycle-manager 模块级 idleTimers 与 session-runner.spawnedChildren(单例 Map),
4
- // beforeEach 重置隔离。
5
-
6
- import { describe, it, expect, beforeEach } from "vitest";
7
-
8
- import {
9
- armIdleTimer,
10
- disarmIdleTimer,
11
- _resetLifecycleState,
12
- } from "../lifecycle-manager.ts";
13
- import { spawnedChildren } from "../session-runner.ts";
14
- import type { ChildProcess } from "node:child_process";
15
- import type { ExecutionRecord } from "../types.ts";
16
-
17
- import { hasLiveProcessHandle, isIdle, isResumable } from "../lifecycle-predicates.ts";
18
-
19
- /** 构造最小 ExecutionRecord(status 默认 running)。 */
20
- function makeRecord(overrides: Partial<ExecutionRecord> = {}): ExecutionRecord {
21
- return {
22
- id: "sa-test",
23
- agent: "general-purpose",
24
- model: "test/model",
25
- thinkingLevel: undefined,
26
- mode: "background",
27
- task: "test",
28
- slug: "test",
29
- startedAt: Date.now(),
30
- rootSessionId: "root",
31
- parentRecordId: undefined,
32
- depth: 0,
33
- status: "running",
34
- turns: [],
35
- turnCount: 0,
36
- totalTokens: 0,
37
- lastError: undefined,
38
- round: 0,
39
- endedAt: undefined,
40
- result: undefined,
41
- error: undefined,
42
- agentResult: undefined,
43
- controller: undefined,
44
- ...overrides,
45
- } as ExecutionRecord;
46
- }
47
-
48
- /** 构造最小 ChildProcess fake(hasLiveProcessHandle 只读 .killed)。 */
49
- function fakeChild(killed: boolean): ChildProcess {
50
- // 测试 fake:被测代码仅读 .killed,其余字段不可达,用 unknown 中转满足 Map 类型。
51
- return { killed } as unknown as ChildProcess;
52
- }
53
-
54
- describe("lifecycle-predicates (v4 B-1)", () => {
55
- beforeEach(() => {
56
- _resetLifecycleState();
57
- spawnedChildren.clear();
58
- });
59
-
60
- describe("isIdle (= hasIdleTimer)", () => {
61
- it("armed idle timer → true", () => {
62
- const rec = makeRecord();
63
- armIdleTimer(rec.id, () => {});
64
- expect(isIdle(rec)).toBe(true);
65
- });
66
-
67
- it("no idle timer → false", () => {
68
- expect(isIdle(makeRecord())).toBe(false);
69
- });
70
-
71
- it("disarmed timer → false", () => {
72
- const rec = makeRecord();
73
- armIdleTimer(rec.id, () => {});
74
- disarmIdleTimer(rec.id);
75
- expect(isIdle(rec)).toBe(false);
76
- });
77
- });
78
-
79
- describe("hasLiveProcessHandle", () => {
80
- it("no child in map → false", () => {
81
- expect(hasLiveProcessHandle("sa-test")).toBe(false);
82
- });
83
-
84
- it("child present and not killed → true", () => {
85
- spawnedChildren.set("sa-test", fakeChild(false));
86
- expect(hasLiveProcessHandle("sa-test")).toBe(true);
87
- });
88
-
89
- it("child present but killed → false", () => {
90
- spawnedChildren.set("sa-test", fakeChild(true));
91
- expect(hasLiveProcessHandle("sa-test")).toBe(false);
92
- });
93
- });
94
-
95
- describe("isResumable (= running && !hasLiveProcessHandle)", () => {
96
- it("running + no live process → true (Path B / 跨重启)", () => {
97
- expect(isResumable(makeRecord({ status: "running" }))).toBe(true);
98
- });
99
-
100
- it("running + live process → false (Path A 保活 / 正在执行)", () => {
101
- const rec = makeRecord({ status: "running" });
102
- spawnedChildren.set(rec.id, fakeChild(false));
103
- expect(isResumable(rec)).toBe(false);
104
- });
105
-
106
- it("closed + no live process → false (终态不可 resume)", () => {
107
- expect(isResumable(makeRecord({ status: "closed" }))).toBe(false);
108
- });
109
-
110
- it("closed + live process → false (终态优先)", () => {
111
- const rec = makeRecord({ status: "closed" });
112
- spawnedChildren.set(rec.id, fakeChild(false));
113
- expect(isResumable(rec)).toBe(false);
114
- });
115
- });
116
- });
@@ -1,401 +0,0 @@
1
- // src/__tests__/list-component.test.ts
2
- //
3
- // SubagentsListComponent 单元测试(循环依赖消除后的新结构)。
4
- //
5
- // 被测组件 list-component.ts 不再 import list-view——按键处理经第 7 个构造函数参数
6
- // keyHandler 注入(list-view factory 的 processKey),状态经第 4 参数 ViewState 注入。
7
- // 本测试覆盖 render 三分支调度 / hasRunning / 左列视口窗口 / 右列预览兜底链 /
8
- // handleInput exit|changed|none 分支 / render 缓存 / detailMode 切换。
9
- //
10
- // Mock 策略:theme 透传为纯文本(断言业务文本而非 ANSI 码),service 只 stub collectRecords,
11
- // keyHandler 由各用例注入返回 KeyResult。spinner 帧 Date.now() 驱动 → fake timers 锁定。
12
-
13
- import { afterEach,beforeEach, describe, expect, it, vi } from "vitest";
14
-
15
- import type { ThemeLike } from "../../interface/format.ts";
16
- import { SubagentsListComponent } from "../../interface/list-component.ts";
17
- import type { KeyHandler, KeyResult, TuiLike, ViewState } from "../../interface/list-shared.ts";
18
- import type { SubagentService } from "../subagent-service.ts";
19
- import type { SubagentRecord } from "../types.ts";
20
-
21
- // ── KeyResult 常量(语义清晰,避到处写字面量对象) ──
22
-
23
- const KEY_NONE: KeyResult = { changed: false, exit: false };
24
- const KEY_CHANGED: KeyResult = { changed: true, exit: false };
25
- const KEY_EXIT: KeyResult = { changed: false, exit: true };
26
-
27
- // ── stub 工厂 ──
28
-
29
- /** 透传 theme(list-component 经 format.ts 调用 fg/bold,ThemeLike 要求 4 方法齐全)。 */
30
- function makeTheme(): ThemeLike {
31
- return {
32
- fg: (_tag: string, text: string) => text,
33
- bg: (_color: string, text: string) => text,
34
- bold: (text: string) => text,
35
- underline: (text: string) => text,
36
- } as ThemeLike;
37
- }
38
-
39
- /** service stub:list-component 只调 collectRecords(limit) 单参数 + getFullRecord([perf]
40
- * 选中项详情懒加载,mock 回 undefined → fullRecordOf 回退 light record,与旧行为一致)。
41
- * 与 tool-action.test.ts 同模式:部分对象直接断言为 SubagentService(duck-type)。 */
42
- function makeService(records: SubagentRecord[] = []): SubagentService {
43
- return {
44
- collectRecords: vi.fn(() => records),
45
- getFullRecord: vi.fn(() => undefined as SubagentRecord | undefined),
46
- } as SubagentService;
47
- }
48
-
49
- /** record fixture(参考 tool-action.test.ts,字段见 types.ts SubagentRecord)。 */
50
- function makeRecord(over: Partial<SubagentRecord> = {}): SubagentRecord {
51
- return {
52
- id: "run-1",
53
- agent: "worker",
54
- task: "do the thing",
55
- status: "closed",
56
- mode: "sync",
57
- startedAt: 1000,
58
- endedAt: 2000,
59
- rootSessionId: undefined,
60
- parentRecordId: undefined,
61
- depth: 0,
62
- turns: 1,
63
- totalTokens: 10,
64
- model: "test/model",
65
- thinkingLevel: undefined,
66
- eventLog: [],
67
- displayItems: [],
68
- result: "ok",
69
- error: undefined,
70
- sessionFile: undefined,
71
- ...over,
72
- };
73
- }
74
-
75
- /** 构造 N 条 records(agent/task 含索引便于断言可见性)。 */
76
- function makeRecords(n: number): SubagentRecord[] {
77
- return Array.from({ length: n }, (_, i) =>
78
- makeRecord({ id: `run-${i}`, agent: `agent-${i}`, task: `task-${i}` }),
79
- );
80
- }
81
-
82
- interface MakeOpts {
83
- records?: SubagentRecord[];
84
- rows?: number;
85
- selectedIdx?: number;
86
- detailMode?: boolean;
87
- keyHandler?: KeyHandler;
88
- }
89
-
90
- /** 构造组件 + 暴露 service/tui/state 供断言。 */
91
- function makeComponent(opts: MakeOpts = {}) {
92
- const records = opts.records ?? [];
93
- const service = makeService(records);
94
- const theme = makeTheme();
95
- const tui = {
96
- requestRender: vi.fn(),
97
- terminal: { rows: opts.rows ?? 24 },
98
- };
99
- const state: ViewState = {
100
- selectedIdx: opts.selectedIdx ?? 0,
101
- scrollOffset: 0,
102
- filterText: "",
103
- detailMode: opts.detailMode ?? false,
104
- disposed: false,
105
- syncCancelHint: false,
106
- };
107
- const keyHandler: KeyHandler = opts.keyHandler ?? (() => KEY_NONE);
108
- const comp = new SubagentsListComponent(
109
- service,
110
- theme,
111
- tui as TuiLike,
112
- state,
113
- () => {},
114
- () => {},
115
- keyHandler,
116
- );
117
- return { comp, service, theme, tui, state };
118
- }
119
-
120
- // ============================================================
121
- // SubagentsListComponent
122
- // ============================================================
123
- describe("SubagentsListComponent", () => {
124
- beforeEach(() => {
125
- // spinner 帧由 Math.floor(Date.now()/250) 选取,锁定时间避免 flaky。
126
- vi.useFakeTimers();
127
- vi.setSystemTime(new Date("2025-01-01T00:00:00Z"));
128
- });
129
- afterEach(() => {
130
- vi.useRealTimers();
131
- });
132
-
133
- // ── render 三分支调度 ──────────────────────────────────
134
- describe("render 分支调度", () => {
135
- it("rows < MIN_TERM_ROWS(8) → too small 提示", () => {
136
- const { comp } = makeComponent({ records: [], rows: 5 });
137
- const joined = comp.render(80).join("\n");
138
- expect(joined).toContain("too small");
139
- expect(joined).toContain("need >=");
140
- });
141
-
142
- it("空 records → emptyBox(含 (no subagent records) 文案)", () => {
143
- const { comp } = makeComponent({ records: [], rows: 24 });
144
- const joined = comp.render(80).join("\n");
145
- expect(joined).toContain("(no subagent records)");
146
- // 紧凑小框不渲染分屏分区线
147
- expect(joined).not.toContain("Records");
148
- });
149
-
150
- it("有 records → splitBox(含 record 的 task + agent 文本)", () => {
151
- const rec = makeRecord({ agent: "researcher", task: "investigate bug" });
152
- const { comp } = makeComponent({ records: [rec], rows: 24 });
153
- const joined = comp.render(80).join("\n");
154
- expect(joined).toContain("researcher"); // 左列 agent
155
- expect(joined).toContain("investigate bug"); // 右列 task 首行
156
- expect(joined).toContain("Records"); // 分区线标题
157
- expect(joined).toContain("Detail");
158
- });
159
- });
160
-
161
- // ── hasRunning ────────────────────────────────────────
162
- describe("hasRunning", () => {
163
- it("records 全是 closed(终态)→ false", () => {
164
- const { comp } = makeComponent({
165
- // v4 B-1:done/failed 等旧终态已收敛为 closed(fixture 同步迁移)
166
- records: [makeRecord({ status: "closed" }), makeRecord({ status: "closed" })],
167
- });
168
- expect(comp.hasRunning()).toBe(false);
169
- });
170
-
171
- it("records 含一个 running → true", () => {
172
- const { comp } = makeComponent({
173
- records: [
174
- makeRecord({ id: "a", status: "closed" }),
175
- makeRecord({ id: "b", status: "running" }),
176
- ],
177
- });
178
- expect(comp.hasRunning()).toBe(true);
179
- });
180
- });
181
-
182
- // ── 左列视口窗口 ──────────────────────────────────────
183
- describe("左列视口窗口", () => {
184
- it("records 数 > bodyH → render 行数 ≤ rows(不溢出终端)", () => {
185
- // rows=24 → 内框高 innerRows = 24 - PAD_ROWS(2) = 22;bodyH = 22 - SPLIT_FIXED_LINES(6) = 16。
186
- // 30 条 records 远超 bodyH,选中行在中间。断言输出总行数 == rows(overlay 填满全屏),
187
- // 且左列只渲染 bodyH 条(不溢出导致底框被推出终端)。
188
- const records = makeRecords(30);
189
- const { comp } = makeComponent({ records, rows: 24, selectedIdx: 15 });
190
- const lines = comp.render(80);
191
- expect(lines.length).toBe(24); // 填满全屏,不溢出
192
- // 中间 record 的 agent 不在视口窗口外应仍可见(窗口居中显示 selectedIdx 附近)。
193
- const joined = lines.join("\n");
194
- expect(joined).toContain("agent-15"); // 选中行在视口内
195
- });
196
-
197
- it("selectedIdx 在尾部 → 视口贴底(最后一条可见)", () => {
198
- const records = makeRecords(30);
199
- const { comp } = makeComponent({ records, rows: 24, selectedIdx: 29 });
200
- const joined = comp.render(80).join("\n");
201
- expect(joined).toContain("agent-29"); // 尾部 record 仍可见(视口贴底)
202
- });
203
- });
204
-
205
- // ── 右列预览兜底链 ────────────────────────────────────
206
- describe("右列预览兜底链 (renderRightPreview)", () => {
207
- it("record 有 displayItems → 输出含 displayItems 内容", () => {
208
- const rec = makeRecord({
209
- displayItems: [{ type: "text", text: "partial analysis output" }],
210
- });
211
- const { comp } = makeComponent({ records: [rec], rows: 24 });
212
- const joined = comp.render(80).join("\n");
213
- expect(joined).toContain("partial analysis output");
214
- });
215
-
216
- it("record 无 displayItems 但有 eventLog → 回退 eventLog(输出含 event 标签)", () => {
217
- const rec = makeRecord({
218
- displayItems: [],
219
- eventLog: [{ type: "tool_start", label: "Read file.ts", ts: 1500 }],
220
- });
221
- const { comp } = makeComponent({ records: [rec], rows: 24 });
222
- const joined = comp.render(80).join("\n");
223
- // formatEventLine 的 tool_start 输出 "tool: <label>"
224
- expect(joined).toContain("tool:");
225
- expect(joined).toContain("Read file.ts");
226
- });
227
-
228
- it("record 两者都无 → 输出 (no output) 兜底文案", () => {
229
- const rec = makeRecord({ displayItems: [], eventLog: [] });
230
- const { comp } = makeComponent({ records: [rec], rows: 24 });
231
- const joined = comp.render(80).join("\n");
232
- expect(joined).toContain("(no output)");
233
- });
234
- });
235
-
236
- // ── handleInput ───────────────────────────────────────
237
- describe("handleInput", () => {
238
- it("disposed → 直接返回,不调用 keyHandler", () => {
239
- const keyHandler = vi.fn(() => KEY_NONE);
240
- const { comp, state } = makeComponent({ keyHandler });
241
- state.disposed = true;
242
- comp.handleInput("x");
243
- expect(keyHandler).not.toHaveBeenCalled();
244
- });
245
-
246
- it("keyHandler 返回 exit → 调用 closeFn 关闭 overlay", () => {
247
- const keyHandler = vi.fn(() => KEY_EXIT);
248
- const { comp } = makeComponent({ keyHandler });
249
- const closeFn = vi.fn();
250
- comp.setCloseFn(closeFn);
251
- comp.handleInput("\x1b"); // Esc
252
- expect(closeFn).toHaveBeenCalledTimes(1);
253
- });
254
-
255
- it("keyHandler 返回 changed → invalidate + requestRender", () => {
256
- const keyHandler = vi.fn(() => KEY_CHANGED);
257
- const { comp, tui } = makeComponent({ keyHandler });
258
- comp.handleInput("\x1b[B"); // Down
259
- expect(tui.requestRender).toHaveBeenCalledTimes(1);
260
- });
261
-
262
- it("keyHandler 返回 none → 不 invalidate / 不 close / 不 requestRender", () => {
263
- const keyHandler = vi.fn(() => KEY_NONE);
264
- const closeFn = vi.fn();
265
- const { comp, tui } = makeComponent({ keyHandler });
266
- comp.setCloseFn(closeFn);
267
- comp.handleInput("x");
268
- expect(closeFn).not.toHaveBeenCalled();
269
- expect(tui.requestRender).not.toHaveBeenCalled();
270
- });
271
-
272
- it("exit 优先于 changed(exit=true 时只 close,不 requestRender)", () => {
273
- const keyHandler = vi.fn(() => ({ changed: true, exit: true }));
274
- const closeFn = vi.fn();
275
- const { comp, tui } = makeComponent({ keyHandler });
276
- comp.setCloseFn(closeFn);
277
- comp.handleInput("\x1b");
278
- expect(closeFn).toHaveBeenCalledTimes(1);
279
- expect(tui.requestRender).not.toHaveBeenCalled();
280
- });
281
- });
282
-
283
- // ── render 缓存 ───────────────────────────────────────
284
- describe("render 缓存", () => {
285
- it("相同 width 连续两次 render → 返回相同结果(缓存命中)", () => {
286
- const records = [makeRecord({ agent: "cached-agent" })];
287
- const { comp } = makeComponent({ records, rows: 24 });
288
- const first = comp.render(80);
289
- const second = comp.render(80);
290
- // 缓存命中:返回同一引用(buildLines 未重新执行)。
291
- expect(second).toBe(first);
292
- });
293
-
294
- it("invalidate 后再 render → 重建(结果内容相同但引用不同)", () => {
295
- const records = [makeRecord()];
296
- const { comp } = makeComponent({ records, rows: 24 });
297
- const first = comp.render(80);
298
- comp.invalidate();
299
- const second = comp.render(80);
300
- expect(second).not.toBe(first); // 引用不同 → 重建
301
- expect(second).toEqual(first); // 内容相同
302
- });
303
-
304
- it("不同 width → 不命中缓存(重新构建)", () => {
305
- const records = [makeRecord()];
306
- const { comp } = makeComponent({ records, rows: 24 });
307
- const w80 = comp.render(80);
308
- const w100 = comp.render(100);
309
- // 宽度不同 → 不同 key → 重建。行数应随宽度变化内容(至少引用不同)。
310
- expect(w100).not.toBe(w80);
311
- });
312
- });
313
-
314
- // ── detailMode 切换 ───────────────────────────────────
315
- describe("detailMode 切换", () => {
316
- it("detailMode=true → footer 含 Esc back + 右侧锚定提示 Pinned", () => {
317
- const rec = makeRecord({ agent: "pinned-agent" });
318
- const { comp } = makeComponent({ records: [rec], rows: 24, detailMode: true });
319
- const joined = comp.render(80).join("\n");
320
- expect(joined).toContain("Esc back to list");
321
- expect(joined).toContain("Pinned:");
322
- expect(joined).toContain("pinned-agent");
323
- });
324
-
325
- it("detailMode=false → footer 含 navigate / Enter detail(非锚定文案)", () => {
326
- const rec = makeRecord();
327
- const { comp } = makeComponent({ records: [rec], rows: 24, detailMode: false });
328
- const joined = comp.render(80).join("\n");
329
- expect(joined).toContain("Enter detail");
330
- expect(joined).not.toContain("Pinned:");
331
- });
332
-
333
- it("detailMode 下完整详情含 result + sessionFile(预览阶段不显示 sessionFile)", () => {
334
- const rec = makeRecord({
335
- result: "final report content",
336
- sessionFile: "/tmp/session-abc.jsonl",
337
- });
338
- // 预览阶段
339
- const previewComp = makeComponent({ records: [rec], rows: 24, detailMode: false });
340
- const previewJoined = previewComp.comp.render(80).join("\n");
341
- expect(previewJoined).toContain("Enter for full detail"); // 预览阶段提示
342
- // 详情阶段
343
- const detailComp = makeComponent({ records: [rec], rows: 24, detailMode: true });
344
- const detailJoined = detailComp.comp.render(80).join("\n");
345
- expect(detailJoined).toContain("final report content"); // Result 段
346
- expect(detailJoined).toContain("Result:");
347
- expect(detailJoined).toContain("session-abc.jsonl"); // sessionFile
348
- });
349
- });
350
-
351
- // ── 帧缓存 collectRecordsFrame(TC3/IF3/DM5)──────────
352
- describe("帧缓存 collectRecordsFrame", () => {
353
- it("同一帧(TTL 50ms 内)hasRunning + render 只触发 1 次 service.collectRecords", () => {
354
- // fake timers 已锁 Date.now()(beforeEach)→ 帧内多次消费共享同一份 records
355
- const rec = makeRecord({ id: "a", status: "running" });
356
- const { comp, service } = makeComponent({ records: [rec], rows: 24 });
357
- expect(comp.hasRunning()).toBe(true); // 第 1 次扫描
358
- comp.render(80); // buildLines 消费(帧命中,不重扫)
359
- comp.handleInput("x"); // handleInput 消费(帧命中)
360
- expect(vi.mocked(service.collectRecords)).toHaveBeenCalledTimes(1);
361
- });
362
-
363
- it("advance 100ms 后 TTL 过期 → 重扫(collectRecords 递增)", () => {
364
- const rec = makeRecord({ id: "a", status: "running" });
365
- const { comp, service } = makeComponent({ records: [rec], rows: 24 });
366
- comp.render(80);
367
- expect(vi.mocked(service.collectRecords)).toHaveBeenCalledTimes(1);
368
- vi.advanceTimersByTime(100); // > FRAME_TTL_MS(50)
369
- // 镜像 animTimer 真实序列:hasRunning(帧消费点)→ invalidate → render。
370
- // hasRunning 直接走帧缓存(不经 render 行缓存),TTL 过期 → 重扫
371
- expect(comp.hasRunning()).toBe(true);
372
- expect(vi.mocked(service.collectRecords)).toHaveBeenCalledTimes(2);
373
- comp.invalidate();
374
- comp.render(80); // 重建行,但帧刚刷新(100ms 后的同一时刻)→ 不再重扫
375
- expect(vi.mocked(service.collectRecords)).toHaveBeenCalledTimes(2);
376
- });
377
-
378
- it("invalidate 不清帧缓存:invalidate 后同帧 render 仍命中(不重扫)", () => {
379
- // timer 序列 hasRunning → invalidate → requestRender 的共享前提:
380
- // invalidate 只清渲染行缓存(cachedKey/cachedLines),帧缓存由 TTL 独立保证
381
- const rec = makeRecord({ id: "a", status: "running" });
382
- const { comp, service } = makeComponent({ records: [rec], rows: 24 });
383
- const first = comp.render(80);
384
- expect(vi.mocked(service.collectRecords)).toHaveBeenCalledTimes(1);
385
- comp.invalidate();
386
- const second = comp.render(80);
387
- expect(second).not.toBe(first); // 渲染行缓存已清 → 重建
388
- expect(vi.mocked(service.collectRecords)).toHaveBeenCalledTimes(1); // 帧缓存未清 → 不重扫
389
- });
390
-
391
- it("detailMode 渲染路径(buildDetailContent children)同帧共享:render 仍只 1 次扫描", () => {
392
- // 选中项有子 record → buildDetailContent 内 children 计算消费 collectRecordsFrame
393
- const parent = makeRecord({ id: "p", status: "closed" });
394
- const child = makeRecord({ id: "c", parentRecordId: "p" });
395
- const { comp, service } = makeComponent({ records: [parent, child], rows: 24, detailMode: true });
396
- const joined = comp.render(80).join("\n");
397
- expect(joined).toContain("children:");
398
- expect(vi.mocked(service.collectRecords)).toHaveBeenCalledTimes(1); // buildLines + children 同帧合一
399
- });
400
- });
401
- });
@@ -1,140 +0,0 @@
1
- // src/execution/__tests__/list-fields.test.ts
2
- //
3
- // [v4 A-6] recordToListItem 字段派生单测;[U3 C-outcome] closedReason 改锚 outcome。
4
- //
5
- // 验证 list 输出的字段派生正确:
6
- // - parent:从 record.parentRecordId 派生(顶层 record → undefined)
7
- // - resumable:从 isResumable 派生(running && 无活进程句柄)
8
- // - outcome:一等终态语义(projectOutcome 唯一出口);closedReason 退出对外 JSON,
9
- // 存量/重建 record(无 outcome 字段)由 deriveOutcome(closedReason, error) 兜底
10
- //
11
- // Mock 策略:vi.mock lifecycle-predicates 的 isResumable,控制其返回值模拟「有/无
12
- // 活进程句柄」两种 running 子态。isResumable 真实逻辑(running && !hasLiveProcessHandle)
13
- // 由 lifecycle-predicates.test.ts 覆盖;本测试聚焦 recordToListItem 的字段派生与透传。
14
-
15
- import { describe, expect, it, vi } from "vitest";
16
-
17
- // mock lifecycle-predicates:控制 isResumable 返回值。
18
- // recordToListItem 内部 import 的 isResumable 经 vitest 自动接线拿到此 mock 版本。
19
- vi.mock("../../execution/lifecycle-predicates.ts", () => ({
20
- isResumable: vi.fn(),
21
- }));
22
-
23
- import { recordToListItem } from "../../interface/subagent-actions.ts";
24
- import { isResumable } from "../../execution/lifecycle-predicates.ts";
25
- import type { SubagentRecord } from "../types.ts";
26
-
27
- // ── SubagentRecord stub 工厂(最小合法 record) ──
28
-
29
- function makeRecord(over: Partial<SubagentRecord> = {}): SubagentRecord {
30
- return {
31
- id: "sa-test",
32
- agent: "general-purpose",
33
- task: "test task",
34
- slug: "test-slug",
35
- status: "running",
36
- mode: "background",
37
- startedAt: Date.now(),
38
- rootSessionId: "session-main",
39
- parentRecordId: undefined,
40
- depth: 0,
41
- endedAt: undefined,
42
- turns: 0,
43
- totalTokens: 0,
44
- model: "test/model",
45
- thinkingLevel: undefined,
46
- eventLog: [],
47
- displayItems: [],
48
- result: undefined,
49
- error: undefined,
50
- sessionFile: undefined,
51
- ...over,
52
- };
53
- }
54
-
55
- describe("recordToListItem — parent/resumable (v4 A-6)", () => {
56
- // ═══ parent:从 record.parentRecordId 派生 ═══
57
-
58
- it("parent:嵌套 record(parentRecordId='sa-A')→ parent='sa-A'", () => {
59
- const rec = makeRecord({ parentRecordId: "sa-A" });
60
- expect(recordToListItem(rec).parent).toBe("sa-A");
61
- });
62
-
63
- it("parent:根层 record(parentRecordId=undefined)→ parent=undefined", () => {
64
- const rec = makeRecord({ parentRecordId: undefined });
65
- expect(recordToListItem(rec).parent).toBeUndefined();
66
- });
67
-
68
- // ═══ resumable:isResumable 透传(mock 模拟有/无活进程句柄) ═══
69
-
70
- it("resumable:running + 无活进程句柄(isResumable=true)→ true(B-1 续聊态)", () => {
71
- vi.mocked(isResumable).mockReturnValue(true);
72
- const rec = makeRecord({ status: "running" });
73
- expect(recordToListItem(rec).resumable).toBe(true);
74
- });
75
-
76
- it("resumable:running + 有活进程句柄(isResumable=false)→ false(正在执行)", () => {
77
- vi.mocked(isResumable).mockReturnValue(false);
78
- const rec = makeRecord({ status: "running" });
79
- expect(recordToListItem(rec).resumable).toBe(false);
80
- });
81
-
82
- it("resumable:closed(isResumable=false)→ false(终态不可续聊)", () => {
83
- vi.mocked(isResumable).mockReturnValue(false);
84
- const rec = makeRecord({ status: "closed" });
85
- expect(recordToListItem(rec).resumable).toBe(false);
86
- });
87
-
88
- // ═══ outcome:一等终态披露(U3 C-outcome,projectOutcome 唯一出口)═══
89
-
90
- it("outcome:closed + closedReason='parent-fork' + 合成 error → 'failed'(D6 显式取舍:父进程关闭未完成即失败,勿改 cancelled)", () => {
91
- const rec = makeRecord({
92
- status: "closed",
93
- closedReason: "parent-fork",
94
- error: "closed due to parent-fork",
95
- });
96
- expect(recordToListItem(rec).outcome).toBe("failed");
97
- });
98
-
99
- it("outcome:closed + closedReason='cancelled' → 'cancelled'(取消优先于 error)", () => {
100
- const rec = makeRecord({
101
- status: "closed",
102
- closedReason: "cancelled",
103
- error: "aborted",
104
- });
105
- expect(recordToListItem(rec).outcome).toBe("cancelled");
106
- });
107
-
108
- it("outcome:closed + gc 正常完成(存量形态,无 outcome 字段、无 error)→ 兑底派生 'completed'", () => {
109
- const rec = makeRecord({ status: "closed", closedReason: "gc" });
110
- expect(recordToListItem(rec).outcome).toBe("completed");
111
- });
112
-
113
- it("outcome:closed + gc + error(存量失败形态)→ 兑底派生 'failed'", () => {
114
- const rec = makeRecord({ status: "closed", closedReason: "gc", error: "spawn EPIPE" });
115
- expect(recordToListItem(rec).outcome).toBe("failed");
116
- });
117
-
118
- it("outcome:一等字段存在时直读透传(不重推导)", () => {
119
- const rec = makeRecord({ status: "closed", outcome: "failed", closedReason: "gc" });
120
- expect(recordToListItem(rec).outcome).toBe("failed");
121
- });
122
-
123
- it("outcome:running record → undefined(终态语义不适用活跃态)", () => {
124
- const rec = makeRecord({ status: "running" });
125
- expect(recordToListItem(rec).outcome).toBeUndefined();
126
- });
127
-
128
- it("closedReason 退出对外 JSON:list item 不再携带(内部诊断字段),outcome 字段在位", () => {
129
- const rec = makeRecord({ status: "closed", closedReason: "gc", error: "boom" });
130
- const item = recordToListItem(rec);
131
- expect("closedReason" in item).toBe(false);
132
- const parsed = JSON.parse(JSON.stringify(item)) as Record<string, unknown>;
133
- expect("closedReason" in parsed).toBe(false);
134
- expect(parsed.outcome).toBe("failed");
135
- // 旧字段保留(向后兼容)
136
- expect(parsed.status).toBe("closed");
137
- expect(parsed.state).toBe("ended");
138
- expect(parsed.mode).toBe("background");
139
- });
140
- });