@zhushanwen/pi-subagent-workflow 8.6.0 → 8.7.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 (347) hide show
  1. package/package.json +9 -13
  2. package/relay/relay.mjs +1 -1
  3. package/src/host/__tests__/pi-host.test.ts +214 -0
  4. package/src/host/pi-host.ts +109 -0
  5. package/src/index.ts +89 -32
  6. package/src/injectors/__tests__/engine-awareness.test.ts +292 -0
  7. package/src/injectors/__tests__/engine-section-stability.test.ts +341 -0
  8. package/src/injectors/__tests__/subagent-list-injector.test.ts +5 -5
  9. package/src/injectors/__tests__/workflow-list-injector.test.ts +5 -5
  10. package/src/injectors/engine-awareness.ts +123 -0
  11. package/src/injectors/model-list-injector.ts +1 -1
  12. package/src/injectors/subagent-list-injector.ts +8 -8
  13. package/src/injectors/workflow-list-injector.ts +8 -8
  14. package/src/interface/__tests__/detectors.test.ts +3 -3
  15. package/src/interface/__tests__/subagent-tool-path-guard.test.ts +2 -2
  16. package/src/interface/__tests__/tool-workflow-script-generate.test.ts +2 -2
  17. package/src/interface/__tests__/tool-workflow-throw-paths.test.ts +1 -1
  18. package/src/interface/bg-notify-render.ts +4 -4
  19. package/src/interface/commands.ts +3 -3
  20. package/src/interface/format.ts +2 -2
  21. package/src/interface/helpers.ts +1 -1
  22. package/src/interface/list-component.ts +4 -4
  23. package/src/interface/list-shared.ts +2 -2
  24. package/src/interface/list-view.ts +2 -2
  25. package/src/interface/subagent-actions.ts +263 -11
  26. package/src/interface/subagent-tool-schema.ts +20 -13
  27. package/src/interface/subagent-tool.ts +11 -6
  28. package/src/interface/subagents.ts +3 -3
  29. package/src/interface/tool-render.ts +34 -2
  30. package/src/interface/tool-workflow-script.ts +4 -4
  31. package/src/interface/tool-workflow.ts +6 -6
  32. package/src/interface/views/WorkflowsView.ts +5 -5
  33. package/src/interface/views/__tests__/WorkflowsView-signature.test.ts +3 -3
  34. package/src/interface/views/__tests__/detail-content-session-file.test.ts +2 -2
  35. package/src/interface/views/detail-content.ts +4 -4
  36. package/src/interface/views/format.ts +4 -4
  37. package/src/{orchestration/jsonl-run-store.ts → jsonl-run-store.ts} +11 -11
  38. package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +0 -53
  39. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +0 -1
  40. package/src/execution/__tests__/agent-registry.test.ts +0 -363
  41. package/src/execution/__tests__/agent-result-mapper.test.ts +0 -150
  42. package/src/execution/__tests__/alive-store.test.ts +0 -147
  43. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
  44. package/src/execution/__tests__/before-agent-start-injection.test.ts +0 -132
  45. package/src/execution/__tests__/bg-notify-render.test.ts +0 -329
  46. package/src/execution/__tests__/channel-registry-handshake.test.ts +0 -243
  47. package/src/execution/__tests__/chat-engine-routing.test.ts +0 -601
  48. package/src/execution/__tests__/chatmode-first-round-closure-service.test.ts +0 -365
  49. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -190
  50. package/src/execution/__tests__/chatmode-round-notify-real-chain.test.ts +0 -215
  51. package/src/execution/__tests__/concurrency-pool.test.ts +0 -250
  52. package/src/execution/__tests__/config.test.ts +0 -110
  53. package/src/execution/__tests__/conversation-wiring.test.ts +0 -198
  54. package/src/execution/__tests__/crash-recovery.test.ts +0 -320
  55. package/src/execution/__tests__/delivery-methods.test.ts +0 -422
  56. package/src/execution/__tests__/dialog-queue.test.ts +0 -299
  57. package/src/execution/__tests__/epipe-fallback.test.ts +0 -241
  58. package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -243
  59. package/src/execution/__tests__/execute-nesting.test.ts +0 -323
  60. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  61. package/src/execution/__tests__/execution-record.test.ts +0 -1394
  62. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +0 -171
  63. package/src/execution/__tests__/finalize-record.test.ts +0 -368
  64. package/src/execution/__tests__/finalized-marker.test.ts +0 -82
  65. package/src/execution/__tests__/format-schema-instruction.test.ts +0 -169
  66. package/src/execution/__tests__/format.test.ts +0 -458
  67. package/src/execution/__tests__/gc-timer.test.ts +0 -184
  68. package/src/execution/__tests__/get-record-for-action-restart.test.ts +0 -254
  69. package/src/execution/__tests__/gui-mode-dispatch.test.ts +0 -59
  70. package/src/execution/__tests__/helpers/mock-extension-api.ts +0 -30
  71. package/src/execution/__tests__/helpers/spawn-mock.ts +0 -242
  72. package/src/execution/__tests__/host-mode.test.ts +0 -87
  73. package/src/execution/__tests__/index-session-start-identity.test.ts +0 -371
  74. package/src/execution/__tests__/index-session-start.test.ts +0 -672
  75. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +0 -211
  76. package/src/execution/__tests__/lifecycle-manager.test.ts +0 -383
  77. package/src/execution/__tests__/lifecycle-predicates.test.ts +0 -116
  78. package/src/execution/__tests__/list-component.test.ts +0 -401
  79. package/src/execution/__tests__/list-fields.test.ts +0 -140
  80. package/src/execution/__tests__/manifest-parentid.test.ts +0 -117
  81. package/src/execution/__tests__/model-resolver.test.ts +0 -465
  82. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +0 -287
  83. package/src/execution/__tests__/nested-visibility.test.ts +0 -325
  84. package/src/execution/__tests__/notifier-flush.test.ts +0 -612
  85. package/src/execution/__tests__/notifier-golden-snapshot.test.ts +0 -261
  86. package/src/execution/__tests__/notify-ledger.test.ts +0 -826
  87. package/src/execution/__tests__/one-shot-upgrade.test.ts +0 -205
  88. package/src/execution/__tests__/output-collector.test.ts +0 -358
  89. package/src/execution/__tests__/parent-child-matrix.test.ts +0 -336
  90. package/src/execution/__tests__/path-encoding.test.ts +0 -104
  91. package/src/execution/__tests__/pi-invocation.test.ts +0 -134
  92. package/src/execution/__tests__/record-store.test.ts +0 -1057
  93. package/src/execution/__tests__/records-cwd-isolation.test.ts +0 -91
  94. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +0 -339
  95. package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -273
  96. package/src/execution/__tests__/relay-agent.test.ts +0 -448
  97. package/src/execution/__tests__/relay-env.test.ts +0 -42
  98. package/src/execution/__tests__/resource-policy.test.ts +0 -109
  99. package/src/execution/__tests__/rpc-mode.test.ts +0 -89
  100. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -267
  101. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -253
  102. package/src/execution/__tests__/run-spawn-edges.test.ts +0 -687
  103. package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
  104. package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
  105. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
  106. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +0 -199
  107. package/src/execution/__tests__/sdk-contract.test.ts +0 -273
  108. package/src/execution/__tests__/session-context-resolver.test.ts +0 -167
  109. package/src/execution/__tests__/session-file-gc.test.ts +0 -293
  110. package/src/execution/__tests__/session-pending.test.ts +0 -197
  111. package/src/execution/__tests__/session-reconstructor.test.ts +0 -379
  112. package/src/execution/__tests__/session-runner-epipe.test.ts +0 -178
  113. package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -350
  114. package/src/execution/__tests__/session-start-reaper.test.ts +0 -233
  115. package/src/execution/__tests__/spawn-args.test.ts +0 -445
  116. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -189
  117. package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
  118. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -207
  119. package/src/execution/__tests__/spawned-children.test.ts +0 -92
  120. package/src/execution/__tests__/start-sync-model-guard.test.ts +0 -150
  121. package/src/execution/__tests__/startup-config-declaration.test.ts +0 -35
  122. package/src/execution/__tests__/status-refactor.test.ts +0 -345
  123. package/src/execution/__tests__/stdin-writer.test.ts +0 -463
  124. package/src/execution/__tests__/stream-sink-retirement.test.ts +0 -261
  125. package/src/execution/__tests__/subagent-service-abort.test.ts +0 -60
  126. package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -629
  127. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +0 -180
  128. package/src/execution/__tests__/subagent-service.test.ts +0 -788
  129. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +0 -310
  130. package/src/execution/__tests__/subprocess-agent-runner.test.ts +0 -599
  131. package/src/execution/__tests__/temp-prompt.test.ts +0 -53
  132. package/src/execution/__tests__/timeout-integration.test.ts +0 -615
  133. package/src/execution/__tests__/tombstone-store.test.ts +0 -73
  134. package/src/execution/__tests__/tool-action.test.ts +0 -476
  135. package/src/execution/__tests__/truncline-snapshot.test.ts +0 -81
  136. package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
  137. package/src/execution/__tests__/turn-limiter.test.ts +0 -65
  138. package/src/execution/__tests__/ui-channels.test.ts +0 -187
  139. package/src/execution/__tests__/ui-interaction-model.test.ts +0 -67
  140. package/src/execution/__tests__/ui-request-handler-factory.test.ts +0 -370
  141. package/src/execution/__tests__/ui-request-handler.test.ts +0 -204
  142. package/src/execution/__tests__/ui-request-observability.test.ts +0 -114
  143. package/src/execution/__tests__/ui-request-queue.test.ts +0 -133
  144. package/src/execution/__tests__/worktree-manager.test.ts +0 -633
  145. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -229
  146. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +0 -181
  147. package/src/execution/__tests__/worktree-registry.test.ts +0 -199
  148. package/src/execution/agent-registry.ts +0 -199
  149. package/src/execution/agent-result-mapper.ts +0 -90
  150. package/src/execution/alive-store.ts +0 -92
  151. package/src/execution/argv-mirror.ts +0 -113
  152. package/src/execution/best-effort.ts +0 -38
  153. package/src/execution/channel-registry-access.ts +0 -144
  154. package/src/execution/concurrency-pool.ts +0 -116
  155. package/src/execution/config.ts +0 -96
  156. package/src/execution/dialog-queue.ts +0 -330
  157. package/src/execution/engine/__tests__/common/data-dir.test.ts +0 -53
  158. package/src/execution/engine/__tests__/common/errors.test.ts +0 -132
  159. package/src/execution/engine/__tests__/common/event-journal.test.ts +0 -177
  160. package/src/execution/engine/__tests__/common/kill-chain.test.ts +0 -192
  161. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +0 -81
  162. package/src/execution/engine/__tests__/common/persona-router.test.ts +0 -123
  163. package/src/execution/engine/__tests__/common/pool-manager.test.ts +0 -154
  164. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
  165. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
  166. package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +0 -141
  167. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +0 -109
  168. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +0 -101
  169. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +0 -77
  170. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +0 -104
  171. package/src/execution/engine/__tests__/conformance/contract.relay.test.ts +0 -342
  172. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +0 -201
  173. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +0 -76
  174. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +0 -79
  175. package/src/execution/engine/__tests__/engine-discovery.test.ts +0 -87
  176. package/src/execution/engine/__tests__/engines-declaration.test.ts +0 -36
  177. package/src/execution/engine/__tests__/model-prompt.test.ts +0 -85
  178. package/src/execution/engine/__tests__/paths.test.ts +0 -39
  179. package/src/execution/engine/__tests__/registry.test.ts +0 -120
  180. package/src/execution/engine/__tests__/routing.test.ts +0 -231
  181. package/src/execution/engine/common/data-dir.ts +0 -62
  182. package/src/execution/engine/common/errors.ts +0 -183
  183. package/src/execution/engine/common/event-journal.ts +0 -254
  184. package/src/execution/engine/common/journal-replay.ts +0 -62
  185. package/src/execution/engine/common/kill-chain.ts +0 -221
  186. package/src/execution/engine/common/nesting-guard.ts +0 -50
  187. package/src/execution/engine/common/persona-router.ts +0 -108
  188. package/src/execution/engine/common/pool-manager.ts +0 -226
  189. package/src/execution/engine/common/schema-emulation.ts +0 -189
  190. package/src/execution/engine/common/session-view-projection.ts +0 -51
  191. package/src/execution/engine/engine-discovery.ts +0 -65
  192. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -469
  193. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
  194. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  195. package/src/execution/engine/engines/pi/pi-engine.ts +0 -415
  196. package/src/execution/engine/engines/pi/reader.ts +0 -48
  197. package/src/execution/engine/engines/pi/registration.ts +0 -35
  198. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  199. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  200. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  201. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -246
  202. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -228
  203. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
  204. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -64
  205. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -127
  206. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -580
  207. package/src/execution/engine/engines/zcode/constants.ts +0 -43
  208. package/src/execution/engine/engines/zcode/golden-sample.ts +0 -39
  209. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  210. package/src/execution/engine/engines/zcode/parser.ts +0 -436
  211. package/src/execution/engine/engines/zcode/preparer.ts +0 -363
  212. package/src/execution/engine/engines/zcode/reader.ts +0 -381
  213. package/src/execution/engine/engines/zcode/registration.ts +0 -37
  214. package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -658
  215. package/src/execution/engine/host-task-spec.ts +0 -47
  216. package/src/execution/engine/model-prompt.ts +0 -59
  217. package/src/execution/engine/paths.ts +0 -42
  218. package/src/execution/engine/port.ts +0 -153
  219. package/src/execution/engine/registry.ts +0 -123
  220. package/src/execution/engine/routing.ts +0 -218
  221. package/src/execution/engine/types.ts +0 -309
  222. package/src/execution/execute-options-mapper.ts +0 -112
  223. package/src/execution/execution-record.ts +0 -965
  224. package/src/execution/finalize-record.ts +0 -251
  225. package/src/execution/finalized-marker.ts +0 -51
  226. package/src/execution/get-state-handshake.ts +0 -104
  227. package/src/execution/host-mode.ts +0 -56
  228. package/src/execution/idle-gc.ts +0 -47
  229. package/src/execution/lifecycle-manager.ts +0 -513
  230. package/src/execution/lifecycle-predicates.ts +0 -65
  231. package/src/execution/manifest-store.ts +0 -256
  232. package/src/execution/model-config-service.ts +0 -219
  233. package/src/execution/model-resolver.ts +0 -248
  234. package/src/execution/notifier.ts +0 -330
  235. package/src/execution/notify-ledger.ts +0 -580
  236. package/src/execution/output-collector.ts +0 -228
  237. package/src/execution/path-encoding.ts +0 -60
  238. package/src/execution/pi-invocation.ts +0 -120
  239. package/src/execution/record-entry.ts +0 -132
  240. package/src/execution/record-store.ts +0 -1234
  241. package/src/execution/relay-env.ts +0 -37
  242. package/src/execution/session-context-resolver.ts +0 -64
  243. package/src/execution/session-file-gc.ts +0 -120
  244. package/src/execution/session-pending.ts +0 -164
  245. package/src/execution/session-reconstructor.ts +0 -678
  246. package/src/execution/session-runner.ts +0 -1781
  247. package/src/execution/sessions-index.ts +0 -304
  248. package/src/execution/spawn-event-adapter.ts +0 -363
  249. package/src/execution/stdin-writer.ts +0 -198
  250. package/src/execution/stream-sink.ts +0 -126
  251. package/src/execution/subagent-service.ts +0 -2141
  252. package/src/execution/subprocess-agent-runner.ts +0 -317
  253. package/src/execution/temp-prompt.ts +0 -62
  254. package/src/execution/tombstone-store.ts +0 -72
  255. package/src/execution/turn-limiter.ts +0 -102
  256. package/src/execution/types.ts +0 -973
  257. package/src/execution/ui-channels.ts +0 -216
  258. package/src/execution/ui-interaction-model.ts +0 -48
  259. package/src/execution/ui-request-handler-factory.ts +0 -212
  260. package/src/execution/ui-request-observability.ts +0 -81
  261. package/src/execution/ui-request-queue.ts +0 -184
  262. package/src/execution/worktree-manager.ts +0 -688
  263. package/src/execution/worktree-registry.ts +0 -222
  264. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +0 -349
  265. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +0 -202
  266. package/src/orchestration/__tests__/agent-call-stream.test.ts +0 -152
  267. package/src/orchestration/__tests__/args-validator.test.ts +0 -143
  268. package/src/orchestration/__tests__/config-loader.test.ts +0 -503
  269. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +0 -809
  270. package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +0 -405
  271. package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +0 -56
  272. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +0 -166
  273. package/src/orchestration/__tests__/execute-agent-call.test.ts +0 -451
  274. package/src/orchestration/__tests__/jsonl-run-store-corrupt-entry.test.ts +0 -150
  275. package/src/orchestration/__tests__/jsonl-run-store-loadall-sources.test.ts +0 -171
  276. package/src/orchestration/__tests__/jsonl-run-store-retention.test.ts +0 -202
  277. package/src/orchestration/__tests__/jsonl-run-store-session-file.test.ts +0 -1030
  278. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +0 -600
  279. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +0 -96
  280. package/src/orchestration/__tests__/lifecycle.test.ts +0 -659
  281. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +0 -95
  282. package/src/orchestration/__tests__/review-fix-loop-e2e.test.ts +0 -2025
  283. package/src/orchestration/__tests__/script-lint.test.ts +0 -831
  284. package/src/orchestration/__tests__/skill-discovery.test.ts +0 -201
  285. package/src/orchestration/__tests__/test-mocks.ts +0 -197
  286. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +0 -368
  287. package/src/orchestration/__tests__/worker-host.test.ts +0 -120
  288. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +0 -164
  289. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +0 -563
  290. package/src/orchestration/__tests__/worker-script-builder.test.ts +0 -309
  291. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +0 -129
  292. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +0 -317
  293. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +0 -110
  294. package/src/orchestration/__tests__/workflows-e2e.test.ts +0 -537
  295. package/src/orchestration/agent-opts-resolver.ts +0 -174
  296. package/src/orchestration/args-validator.ts +0 -127
  297. package/src/orchestration/config-loader.ts +0 -315
  298. package/src/orchestration/error-recovery.ts +0 -1018
  299. package/src/orchestration/execute-agent-call.ts +0 -256
  300. package/src/orchestration/launcher.ts +0 -455
  301. package/src/orchestration/lifecycle.ts +0 -399
  302. package/src/orchestration/models/__tests__/budget.test.ts +0 -307
  303. package/src/orchestration/models/__tests__/trace.test.ts +0 -408
  304. package/src/orchestration/models/agent-call.ts +0 -83
  305. package/src/orchestration/models/budget.ts +0 -118
  306. package/src/orchestration/models/ports.ts +0 -164
  307. package/src/orchestration/models/run-runtime.ts +0 -104
  308. package/src/orchestration/models/run-spec.ts +0 -83
  309. package/src/orchestration/models/run-state.ts +0 -44
  310. package/src/orchestration/models/trace.ts +0 -183
  311. package/src/orchestration/models/types.ts +0 -301
  312. package/src/orchestration/models/workflow-run.ts +0 -254
  313. package/src/orchestration/models/workflow-script-registry.ts +0 -35
  314. package/src/orchestration/models/workflow-script.ts +0 -117
  315. package/src/orchestration/script-lint.ts +0 -766
  316. package/src/orchestration/skill-discovery.ts +0 -115
  317. package/src/orchestration/worker-handle.ts +0 -115
  318. package/src/orchestration/worker-host.ts +0 -98
  319. package/src/orchestration/worker-script-builder.ts +0 -421
  320. package/src/orchestration/workflow-files.ts +0 -85
  321. package/src/orchestration/workflow-script-registry-impl.ts +0 -133
  322. package/src/shared/__tests__/agent-ref.test.ts +0 -34
  323. package/src/shared/__tests__/meta-parser.test.ts +0 -304
  324. package/src/shared/__tests__/model-ref.test.ts +0 -306
  325. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -280
  326. package/src/shared/__tests__/resource-discovery.test.ts +0 -736
  327. package/src/shared/__tests__/resource-meta.test.ts +0 -51
  328. package/src/shared/__tests__/schema-jsonify.test.ts +0 -81
  329. package/src/shared/__tests__/timer-delay.test.ts +0 -61
  330. package/src/shared/agent-event.ts +0 -13
  331. package/src/shared/agent-ref.ts +0 -57
  332. package/src/shared/meta-parser.ts +0 -261
  333. package/src/shared/model-ref.ts +0 -286
  334. package/src/shared/resource-discovery.ts +0 -811
  335. package/src/shared/resource-meta.ts +0 -65
  336. package/src/shared/schema-env.ts +0 -44
  337. package/src/shared/schema-jsonify.ts +0 -58
  338. package/src/shared/timer-delay.ts +0 -54
  339. package/src/shared/xml-injection.ts +0 -35
  340. package/workflows/README.md +0 -81
  341. package/workflows/_shared/agent-refs.cjs +0 -40
  342. package/workflows/chain.js +0 -131
  343. package/workflows/map-reduce.js +0 -174
  344. package/workflows/parallel.js +0 -148
  345. package/workflows/review-fix-loop-utils.cjs +0 -1309
  346. package/workflows/review-fix-loop.js +0 -1404
  347. 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
- });