@zhushanwen/pi-subagent-workflow 8.5.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 (336) hide show
  1. package/package.json +13 -16
  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 +142 -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 +157 -0
  16. package/src/interface/__tests__/subagent-tool-prompt.test.ts +12 -0
  17. package/src/interface/__tests__/tool-workflow-script-generate.test.ts +2 -2
  18. package/src/interface/__tests__/tool-workflow-throw-paths.test.ts +1 -1
  19. package/src/interface/bg-notify-render.ts +34 -13
  20. package/src/interface/commands.ts +3 -3
  21. package/src/interface/format.ts +2 -2
  22. package/src/interface/helpers.ts +3 -3
  23. package/src/interface/list-component.ts +4 -4
  24. package/src/interface/list-shared.ts +2 -2
  25. package/src/interface/list-view.ts +2 -2
  26. package/src/interface/subagent-actions.ts +288 -19
  27. package/src/interface/subagent-tool-schema.ts +163 -0
  28. package/src/interface/subagent-tool.ts +65 -129
  29. package/src/interface/subagents.ts +5 -5
  30. package/src/interface/tool-render.ts +34 -2
  31. package/src/interface/tool-workflow-script.ts +4 -4
  32. package/src/interface/tool-workflow.ts +6 -6
  33. package/src/interface/views/WorkflowsView.ts +5 -5
  34. package/src/interface/views/__tests__/WorkflowsView-signature.test.ts +3 -3
  35. package/src/interface/views/__tests__/detail-content-session-file.test.ts +2 -2
  36. package/src/interface/views/detail-content.ts +4 -4
  37. package/src/interface/views/format.ts +4 -4
  38. package/src/{orchestration/jsonl-run-store.ts → jsonl-run-store.ts} +132 -18
  39. package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +0 -53
  40. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +0 -1
  41. package/src/execution/__tests__/agent-registry.test.ts +0 -363
  42. package/src/execution/__tests__/agent-result-mapper.test.ts +0 -150
  43. package/src/execution/__tests__/alive-store.test.ts +0 -147
  44. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
  45. package/src/execution/__tests__/before-agent-start-injection.test.ts +0 -132
  46. package/src/execution/__tests__/bg-notify-render.test.ts +0 -256
  47. package/src/execution/__tests__/channel-registry-handshake.test.ts +0 -243
  48. package/src/execution/__tests__/chat-engine-routing.test.ts +0 -597
  49. package/src/execution/__tests__/chatmode-first-round-closure-service.test.ts +0 -365
  50. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -190
  51. package/src/execution/__tests__/chatmode-round-notify-real-chain.test.ts +0 -215
  52. package/src/execution/__tests__/concurrency-pool.test.ts +0 -250
  53. package/src/execution/__tests__/config.test.ts +0 -110
  54. package/src/execution/__tests__/conversation-wiring.test.ts +0 -198
  55. package/src/execution/__tests__/crash-recovery.test.ts +0 -320
  56. package/src/execution/__tests__/delivery-methods.test.ts +0 -385
  57. package/src/execution/__tests__/dialog-queue.test.ts +0 -299
  58. package/src/execution/__tests__/epipe-fallback.test.ts +0 -241
  59. package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -243
  60. package/src/execution/__tests__/execute-nesting.test.ts +0 -323
  61. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -189
  62. package/src/execution/__tests__/execution-record.test.ts +0 -1284
  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 -138
  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 -238
  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 -593
  75. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +0 -211
  76. package/src/execution/__tests__/lifecycle-manager.test.ts +0 -337
  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 -109
  80. package/src/execution/__tests__/manifest-parentid.test.ts +0 -117
  81. package/src/execution/__tests__/model-resolver.test.ts +0 -413
  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 -574
  85. package/src/execution/__tests__/notifier-golden-snapshot.test.ts +0 -261
  86. package/src/execution/__tests__/one-shot-upgrade.test.ts +0 -205
  87. package/src/execution/__tests__/output-collector.test.ts +0 -61
  88. package/src/execution/__tests__/parent-child-matrix.test.ts +0 -336
  89. package/src/execution/__tests__/path-encoding.test.ts +0 -104
  90. package/src/execution/__tests__/pi-invocation.test.ts +0 -134
  91. package/src/execution/__tests__/record-store.test.ts +0 -1057
  92. package/src/execution/__tests__/records-cwd-isolation.test.ts +0 -91
  93. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +0 -339
  94. package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -273
  95. package/src/execution/__tests__/relay-agent.test.ts +0 -448
  96. package/src/execution/__tests__/relay-env.test.ts +0 -42
  97. package/src/execution/__tests__/resource-policy.test.ts +0 -109
  98. package/src/execution/__tests__/rpc-mode.test.ts +0 -89
  99. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -267
  100. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -253
  101. package/src/execution/__tests__/run-spawn-edges.test.ts +0 -644
  102. package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
  103. package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
  104. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
  105. package/src/execution/__tests__/sdk-contract.test.ts +0 -273
  106. package/src/execution/__tests__/session-context-resolver.test.ts +0 -167
  107. package/src/execution/__tests__/session-file-gc.test.ts +0 -293
  108. package/src/execution/__tests__/session-pending.test.ts +0 -197
  109. package/src/execution/__tests__/session-reconstructor.test.ts +0 -379
  110. package/src/execution/__tests__/session-runner-epipe.test.ts +0 -178
  111. package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -311
  112. package/src/execution/__tests__/session-start-reaper.test.ts +0 -233
  113. package/src/execution/__tests__/spawn-args.test.ts +0 -434
  114. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -189
  115. package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
  116. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -207
  117. package/src/execution/__tests__/spawned-children.test.ts +0 -92
  118. package/src/execution/__tests__/startup-config-declaration.test.ts +0 -35
  119. package/src/execution/__tests__/status-refactor.test.ts +0 -345
  120. package/src/execution/__tests__/stdin-writer.test.ts +0 -463
  121. package/src/execution/__tests__/stream-sink-retirement.test.ts +0 -261
  122. package/src/execution/__tests__/subagent-service-abort.test.ts +0 -60
  123. package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -629
  124. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +0 -180
  125. package/src/execution/__tests__/subagent-service.test.ts +0 -788
  126. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +0 -310
  127. package/src/execution/__tests__/subprocess-agent-runner.test.ts +0 -506
  128. package/src/execution/__tests__/temp-prompt.test.ts +0 -53
  129. package/src/execution/__tests__/timeout-integration.test.ts +0 -397
  130. package/src/execution/__tests__/tombstone-store.test.ts +0 -73
  131. package/src/execution/__tests__/tool-action.test.ts +0 -385
  132. package/src/execution/__tests__/truncline-snapshot.test.ts +0 -81
  133. package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
  134. package/src/execution/__tests__/turn-limiter.test.ts +0 -65
  135. package/src/execution/__tests__/ui-channels.test.ts +0 -187
  136. package/src/execution/__tests__/ui-interaction-model.test.ts +0 -67
  137. package/src/execution/__tests__/ui-request-handler-factory.test.ts +0 -370
  138. package/src/execution/__tests__/ui-request-handler.test.ts +0 -204
  139. package/src/execution/__tests__/ui-request-observability.test.ts +0 -114
  140. package/src/execution/__tests__/ui-request-queue.test.ts +0 -133
  141. package/src/execution/__tests__/worktree-manager.test.ts +0 -633
  142. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -229
  143. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +0 -181
  144. package/src/execution/__tests__/worktree-registry.test.ts +0 -199
  145. package/src/execution/agent-registry.ts +0 -193
  146. package/src/execution/agent-result-mapper.ts +0 -90
  147. package/src/execution/alive-store.ts +0 -92
  148. package/src/execution/argv-mirror.ts +0 -109
  149. package/src/execution/best-effort.ts +0 -38
  150. package/src/execution/channel-registry-access.ts +0 -144
  151. package/src/execution/concurrency-pool.ts +0 -116
  152. package/src/execution/config.ts +0 -96
  153. package/src/execution/dialog-queue.ts +0 -330
  154. package/src/execution/engine/__tests__/common/data-dir.test.ts +0 -53
  155. package/src/execution/engine/__tests__/common/errors.test.ts +0 -132
  156. package/src/execution/engine/__tests__/common/event-journal.test.ts +0 -177
  157. package/src/execution/engine/__tests__/common/kill-chain.test.ts +0 -192
  158. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +0 -81
  159. package/src/execution/engine/__tests__/common/persona-router.test.ts +0 -123
  160. package/src/execution/engine/__tests__/common/pool-manager.test.ts +0 -154
  161. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
  162. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
  163. package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +0 -141
  164. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +0 -109
  165. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +0 -101
  166. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +0 -77
  167. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +0 -104
  168. package/src/execution/engine/__tests__/conformance/contract.relay.test.ts +0 -342
  169. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +0 -201
  170. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +0 -76
  171. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +0 -79
  172. package/src/execution/engine/__tests__/engine-discovery.test.ts +0 -87
  173. package/src/execution/engine/__tests__/engines-declaration.test.ts +0 -36
  174. package/src/execution/engine/__tests__/model-prompt.test.ts +0 -85
  175. package/src/execution/engine/__tests__/paths.test.ts +0 -39
  176. package/src/execution/engine/__tests__/registry.test.ts +0 -120
  177. package/src/execution/engine/__tests__/routing.test.ts +0 -231
  178. package/src/execution/engine/common/data-dir.ts +0 -62
  179. package/src/execution/engine/common/errors.ts +0 -183
  180. package/src/execution/engine/common/event-journal.ts +0 -254
  181. package/src/execution/engine/common/journal-replay.ts +0 -62
  182. package/src/execution/engine/common/kill-chain.ts +0 -221
  183. package/src/execution/engine/common/nesting-guard.ts +0 -50
  184. package/src/execution/engine/common/persona-router.ts +0 -108
  185. package/src/execution/engine/common/pool-manager.ts +0 -226
  186. package/src/execution/engine/common/schema-emulation.ts +0 -189
  187. package/src/execution/engine/common/session-view-projection.ts +0 -51
  188. package/src/execution/engine/engine-discovery.ts +0 -65
  189. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -469
  190. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
  191. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  192. package/src/execution/engine/engines/pi/pi-engine.ts +0 -415
  193. package/src/execution/engine/engines/pi/reader.ts +0 -48
  194. package/src/execution/engine/engines/pi/registration.ts +0 -35
  195. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  196. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  197. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  198. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -246
  199. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -228
  200. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
  201. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -64
  202. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -127
  203. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -567
  204. package/src/execution/engine/engines/zcode/constants.ts +0 -43
  205. package/src/execution/engine/engines/zcode/golden-sample.ts +0 -39
  206. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  207. package/src/execution/engine/engines/zcode/parser.ts +0 -436
  208. package/src/execution/engine/engines/zcode/preparer.ts +0 -363
  209. package/src/execution/engine/engines/zcode/reader.ts +0 -381
  210. package/src/execution/engine/engines/zcode/registration.ts +0 -37
  211. package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -648
  212. package/src/execution/engine/host-task-spec.ts +0 -47
  213. package/src/execution/engine/model-prompt.ts +0 -59
  214. package/src/execution/engine/paths.ts +0 -42
  215. package/src/execution/engine/port.ts +0 -153
  216. package/src/execution/engine/registry.ts +0 -123
  217. package/src/execution/engine/routing.ts +0 -218
  218. package/src/execution/engine/types.ts +0 -304
  219. package/src/execution/execute-options-mapper.ts +0 -111
  220. package/src/execution/execution-record.ts +0 -906
  221. package/src/execution/finalize-record.ts +0 -251
  222. package/src/execution/finalized-marker.ts +0 -51
  223. package/src/execution/get-state-handshake.ts +0 -104
  224. package/src/execution/host-mode.ts +0 -56
  225. package/src/execution/idle-gc.ts +0 -47
  226. package/src/execution/lifecycle-manager.ts +0 -491
  227. package/src/execution/lifecycle-predicates.ts +0 -65
  228. package/src/execution/manifest-store.ts +0 -256
  229. package/src/execution/model-config-service.ts +0 -204
  230. package/src/execution/model-resolver.ts +0 -276
  231. package/src/execution/notifier.ts +0 -260
  232. package/src/execution/output-collector.ts +0 -88
  233. package/src/execution/path-encoding.ts +0 -60
  234. package/src/execution/pi-invocation.ts +0 -120
  235. package/src/execution/record-entry.ts +0 -132
  236. package/src/execution/record-store.ts +0 -1234
  237. package/src/execution/relay-env.ts +0 -37
  238. package/src/execution/session-context-resolver.ts +0 -64
  239. package/src/execution/session-file-gc.ts +0 -120
  240. package/src/execution/session-pending.ts +0 -164
  241. package/src/execution/session-reconstructor.ts +0 -678
  242. package/src/execution/session-runner.ts +0 -1548
  243. package/src/execution/sessions-index.ts +0 -304
  244. package/src/execution/spawn-event-adapter.ts +0 -363
  245. package/src/execution/stdin-writer.ts +0 -198
  246. package/src/execution/stream-sink.ts +0 -126
  247. package/src/execution/subagent-service.ts +0 -2119
  248. package/src/execution/subprocess-agent-runner.ts +0 -303
  249. package/src/execution/temp-prompt.ts +0 -62
  250. package/src/execution/tombstone-store.ts +0 -72
  251. package/src/execution/turn-limiter.ts +0 -102
  252. package/src/execution/types.ts +0 -910
  253. package/src/execution/ui-channels.ts +0 -216
  254. package/src/execution/ui-interaction-model.ts +0 -48
  255. package/src/execution/ui-request-handler-factory.ts +0 -212
  256. package/src/execution/ui-request-observability.ts +0 -81
  257. package/src/execution/ui-request-queue.ts +0 -174
  258. package/src/execution/worktree-manager.ts +0 -688
  259. package/src/execution/worktree-registry.ts +0 -222
  260. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +0 -336
  261. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +0 -208
  262. package/src/orchestration/__tests__/agent-call-stream.test.ts +0 -157
  263. package/src/orchestration/__tests__/args-validator.test.ts +0 -143
  264. package/src/orchestration/__tests__/concurrency-gate.test.ts +0 -125
  265. package/src/orchestration/__tests__/config-loader.test.ts +0 -503
  266. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +0 -724
  267. package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +0 -405
  268. package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +0 -56
  269. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +0 -166
  270. package/src/orchestration/__tests__/execute-agent-call.test.ts +0 -314
  271. package/src/orchestration/__tests__/jsonl-run-store-loadall-sources.test.ts +0 -171
  272. package/src/orchestration/__tests__/jsonl-run-store-session-file.test.ts +0 -1030
  273. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +0 -277
  274. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +0 -96
  275. package/src/orchestration/__tests__/lifecycle.test.ts +0 -625
  276. package/src/orchestration/__tests__/review-fix-loop-e2e.test.ts +0 -1971
  277. package/src/orchestration/__tests__/script-lint.test.ts +0 -831
  278. package/src/orchestration/__tests__/skill-discovery.test.ts +0 -157
  279. package/src/orchestration/__tests__/test-mocks.ts +0 -197
  280. package/src/orchestration/__tests__/worker-host.test.ts +0 -120
  281. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +0 -164
  282. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +0 -520
  283. package/src/orchestration/__tests__/worker-script-builder.test.ts +0 -309
  284. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +0 -110
  285. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +0 -317
  286. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +0 -110
  287. package/src/orchestration/__tests__/workflows-e2e.test.ts +0 -537
  288. package/src/orchestration/agent-opts-resolver.ts +0 -93
  289. package/src/orchestration/args-validator.ts +0 -127
  290. package/src/orchestration/concurrency-gate.ts +0 -69
  291. package/src/orchestration/config-loader.ts +0 -315
  292. package/src/orchestration/error-recovery.ts +0 -862
  293. package/src/orchestration/execute-agent-call.ts +0 -217
  294. package/src/orchestration/launcher.ts +0 -410
  295. package/src/orchestration/lifecycle.ts +0 -396
  296. package/src/orchestration/models/__tests__/budget.test.ts +0 -367
  297. package/src/orchestration/models/__tests__/trace.test.ts +0 -408
  298. package/src/orchestration/models/agent-call.ts +0 -83
  299. package/src/orchestration/models/budget.ts +0 -148
  300. package/src/orchestration/models/ports.ts +0 -164
  301. package/src/orchestration/models/run-runtime.ts +0 -89
  302. package/src/orchestration/models/run-spec.ts +0 -83
  303. package/src/orchestration/models/run-state.ts +0 -44
  304. package/src/orchestration/models/trace.ts +0 -183
  305. package/src/orchestration/models/types.ts +0 -292
  306. package/src/orchestration/models/workflow-run.ts +0 -254
  307. package/src/orchestration/models/workflow-script-registry.ts +0 -35
  308. package/src/orchestration/models/workflow-script.ts +0 -117
  309. package/src/orchestration/script-lint.ts +0 -766
  310. package/src/orchestration/skill-discovery.ts +0 -92
  311. package/src/orchestration/worker-handle.ts +0 -115
  312. package/src/orchestration/worker-host.ts +0 -98
  313. package/src/orchestration/worker-script-builder.ts +0 -408
  314. package/src/orchestration/workflow-files.ts +0 -85
  315. package/src/orchestration/workflow-script-registry-impl.ts +0 -133
  316. package/src/shared/__tests__/agent-ref.test.ts +0 -34
  317. package/src/shared/__tests__/meta-parser.test.ts +0 -304
  318. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -280
  319. package/src/shared/__tests__/resource-discovery.test.ts +0 -736
  320. package/src/shared/__tests__/resource-meta.test.ts +0 -51
  321. package/src/shared/__tests__/schema-jsonify.test.ts +0 -81
  322. package/src/shared/agent-event.ts +0 -13
  323. package/src/shared/agent-ref.ts +0 -57
  324. package/src/shared/meta-parser.ts +0 -261
  325. package/src/shared/resource-discovery.ts +0 -811
  326. package/src/shared/resource-meta.ts +0 -65
  327. package/src/shared/schema-jsonify.ts +0 -56
  328. package/src/shared/xml-injection.ts +0 -35
  329. package/workflows/README.md +0 -81
  330. package/workflows/_shared/agent-refs.cjs +0 -40
  331. package/workflows/chain.js +0 -131
  332. package/workflows/map-reduce.js +0 -174
  333. package/workflows/parallel.js +0 -148
  334. package/workflows/review-fix-loop-utils.cjs +0 -1307
  335. package/workflows/review-fix-loop.js +0 -1396
  336. package/workflows/scatter-gather.js +0 -178
@@ -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,109 +0,0 @@
1
- // src/execution/__tests__/list-fields.test.ts
2
- //
3
- // [v4 A-6] recordToListItem 字段派生单测。
4
- //
5
- // 验证 list 输出的新增字段派生正确:
6
- // - parent:从 record.parentRecordId 派生(顶层 record → undefined)
7
- // - resumable:从 isResumable 派生(running && 无活进程句柄)
8
- // - closedReason:透传 record.closedReason(SP-4 级联关闭告知替代)
9
- //
10
- // Mock 策略:vi.mock lifecycle-predicates 的 isResumable,控制其返回值模拟「有/无
11
- // 活进程句柄」两种 running 子态。isResumable 真实逻辑(running && !hasLiveProcessHandle)
12
- // 由 lifecycle-predicates.test.ts 覆盖;本测试聚焦 recordToListItem 的字段派生与透传。
13
-
14
- import { describe, expect, it, vi } from "vitest";
15
-
16
- // mock lifecycle-predicates:控制 isResumable 返回值。
17
- // recordToListItem 内部 import 的 isResumable 经 vitest 自动接线拿到此 mock 版本。
18
- vi.mock("../../execution/lifecycle-predicates.ts", () => ({
19
- isResumable: vi.fn(),
20
- }));
21
-
22
- import { recordToListItem } from "../../interface/subagent-actions.ts";
23
- import { isResumable } from "../../execution/lifecycle-predicates.ts";
24
- import type { ClosedReason, SubagentRecord } from "../types.ts";
25
-
26
- // ── SubagentRecord stub 工厂(最小合法 record) ──
27
-
28
- function makeRecord(over: Partial<SubagentRecord> = {}): SubagentRecord {
29
- return {
30
- id: "sa-test",
31
- agent: "general-purpose",
32
- task: "test task",
33
- slug: "test-slug",
34
- status: "running",
35
- mode: "background",
36
- startedAt: Date.now(),
37
- rootSessionId: "session-main",
38
- parentRecordId: undefined,
39
- depth: 0,
40
- endedAt: undefined,
41
- turns: 0,
42
- totalTokens: 0,
43
- model: "test/model",
44
- thinkingLevel: undefined,
45
- eventLog: [],
46
- displayItems: [],
47
- result: undefined,
48
- error: undefined,
49
- sessionFile: undefined,
50
- ...over,
51
- };
52
- }
53
-
54
- describe("recordToListItem — parent/resumable/closedReason (v4 A-6)", () => {
55
- // ═══ parent:从 record.parentRecordId 派生 ═══
56
-
57
- it("parent:嵌套 record(parentRecordId='sa-A')→ parent='sa-A'", () => {
58
- const rec = makeRecord({ parentRecordId: "sa-A" });
59
- expect(recordToListItem(rec).parent).toBe("sa-A");
60
- });
61
-
62
- it("parent:根层 record(parentRecordId=undefined)→ parent=undefined", () => {
63
- const rec = makeRecord({ parentRecordId: undefined });
64
- expect(recordToListItem(rec).parent).toBeUndefined();
65
- });
66
-
67
- // ═══ resumable:isResumable 透传(mock 模拟有/无活进程句柄) ═══
68
-
69
- it("resumable:running + 无活进程句柄(isResumable=true)→ true(B-1 续聊态)", () => {
70
- vi.mocked(isResumable).mockReturnValue(true);
71
- const rec = makeRecord({ status: "running" });
72
- expect(recordToListItem(rec).resumable).toBe(true);
73
- });
74
-
75
- it("resumable:running + 有活进程句柄(isResumable=false)→ false(正在执行)", () => {
76
- vi.mocked(isResumable).mockReturnValue(false);
77
- const rec = makeRecord({ status: "running" });
78
- expect(recordToListItem(rec).resumable).toBe(false);
79
- });
80
-
81
- it("resumable:closed(isResumable=false)→ false(终态不可续聊)", () => {
82
- vi.mocked(isResumable).mockReturnValue(false);
83
- const rec = makeRecord({ status: "closed" });
84
- expect(recordToListItem(rec).resumable).toBe(false);
85
- });
86
-
87
- // ═══ closedReason:透传 record.closedReason ═══
88
-
89
- it("closedReason:closed + closedReason='parent-fork' → 透传", () => {
90
- const rec = makeRecord({
91
- status: "closed",
92
- closedReason: "parent-fork" as ClosedReason,
93
- });
94
- expect(recordToListItem(rec).closedReason).toBe("parent-fork");
95
- });
96
-
97
- it("closedReason:closed + closedReason='parent-new' → 透传(SP-4 级联关闭场景)", () => {
98
- const rec = makeRecord({
99
- status: "closed",
100
- closedReason: "parent-new" as ClosedReason,
101
- });
102
- expect(recordToListItem(rec).closedReason).toBe("parent-new");
103
- });
104
-
105
- it("closedReason:running record(无 closedReason)→ undefined", () => {
106
- const rec = makeRecord({ status: "running" });
107
- expect(recordToListItem(rec).closedReason).toBeUndefined();
108
- });
109
- });
@@ -1,117 +0,0 @@
1
- // ManifestStore — parentRecordId 落盘测试(M3a)。
2
- //
3
- // 验证 M3a 三条契约:
4
- // 1. 新 record 落盘含 parentRecordId(depth>=1 subagent 读回直接父 record id)
5
- // 2. 旧 manifest JSON(无 parentRecordId 字段)readManifest 仍有效(向后兼容)
6
- // 3. isValidManifest 校验不改(5 必填不变,parentRecordId optional)
7
- //
8
- // isValidManifest 私有未 export——通过 readManifest 等价验证:readManifest 内部
9
- // `isValidManifest(parsed) ? parsed : null`,非 null ⟺ 校验通过。不 export 私有函数
10
- // 避免扩大公共 API 表面(M3a C1 约束:不改 isValidManifest,仅 2 行代码改动)。
11
-
12
- import * as fs from "node:fs";
13
- import * as os from "node:os";
14
- import * as path from "node:path";
15
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
16
-
17
- import { ManifestStore, type ManifestRecord } from "../manifest-store.ts";
18
-
19
- /** 构造最小合法 ManifestRecord(5 必填),optional 字段按 overrides 传入。 */
20
- function makeBaseManifest(overrides: Partial<ManifestRecord> = {}): ManifestRecord {
21
- return {
22
- id: "rec-test",
23
- rootSessionId: "session-main",
24
- agentName: "worker",
25
- status: "completed",
26
- createdAt: 1000,
27
- ...overrides,
28
- };
29
- }
30
-
31
- describe("ManifestStore — parentRecordId 落盘 (M3a)", () => {
32
- let tmpDir: string;
33
- let store: ManifestStore;
34
-
35
- beforeEach(() => {
36
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "manifest-parentid-"));
37
- store = new ManifestStore(tmpDir);
38
- });
39
-
40
- afterEach(() => {
41
- fs.rmSync(tmpDir, { recursive: true, force: true });
42
- });
43
-
44
- // ── TC-m3a-new-record-parentid ──
45
- it("新 record 落盘含 parentRecordId(depth>=1 读回直接父 record id)", async () => {
46
- const record = makeBaseManifest({
47
- id: "rec-child",
48
- parentRecordId: "sa-parent-1",
49
- });
50
- await store.writeManifest(record);
51
-
52
- const readBack = await store.readManifest("rec-child");
53
- expect(readBack).not.toBeNull();
54
- expect(readBack?.parentRecordId).toBe("sa-parent-1");
55
- });
56
-
57
- it("顶层 record(parentRecordId 缺失)落盘读回仍 undefined", async () => {
58
- // 顶层 subagent parentRecordId=undefined(父是 main,main 无 record)
59
- const record = makeBaseManifest({ id: "rec-top" });
60
- await store.writeManifest(record);
61
-
62
- const readBack = await store.readManifest("rec-top");
63
- expect(readBack).not.toBeNull();
64
- expect(readBack?.parentRecordId).toBeUndefined();
65
- });
66
-
67
- // ── TC-m3a-old-manifest-compat ──
68
- it("旧 manifest JSON(无 parentRecordId)readManifest 返有效(isValidManifest 通过)", async () => {
69
- // 手写旧版本格式 manifest(无 parentRecordId 字段),模拟旧 subagent-workflow 写的磁盘文件
70
- const oldManifest = {
71
- id: "rec-old",
72
- rootSessionId: "session-main",
73
- agentName: "worker",
74
- status: "completed",
75
- createdAt: 2000,
76
- // 无 parentRecordId —— 旧版本写的
77
- };
78
- fs.writeFileSync(
79
- path.join(tmpDir, "rec-old.json"),
80
- JSON.stringify(oldManifest),
81
- "utf-8",
82
- );
83
-
84
- const readBack = await store.readManifest("rec-old");
85
- // readManifest 内 isValidManifest(parsed) ? parsed : null —— 非 null 即 5 必填校验通过
86
- expect(readBack).not.toBeNull();
87
- expect(readBack?.id).toBe("rec-old");
88
- expect(readBack?.parentRecordId).toBeUndefined();
89
- });
90
-
91
- // ── TC-m3a-isvalidmanifest-unchanged ──
92
- it("isValidManifest 不改:含/不含 parentRecordId 均通过(5 必填不变)", async () => {
93
- // isValidManifest 私有,通过 readManifest 等价验证(非 null ⟺ 校验通过)。
94
- // 含 parentRecordId —— 新格式
95
- const withParent = makeBaseManifest({
96
- id: "rec-with-parent",
97
- parentRecordId: "sa-x",
98
- });
99
- await store.writeManifest(withParent);
100
- expect(await store.readManifest("rec-with-parent")).not.toBeNull();
101
-
102
- // 不含 parentRecordId —— 仅 5 必填(旧格式 / 顶层 record)
103
- const minimal = {
104
- id: "rec-minimal",
105
- rootSessionId: "session-main",
106
- agentName: "worker",
107
- status: "completed",
108
- createdAt: 3000,
109
- };
110
- fs.writeFileSync(
111
- path.join(tmpDir, "rec-minimal.json"),
112
- JSON.stringify(minimal),
113
- "utf-8",
114
- );
115
- expect(await store.readManifest("rec-minimal")).not.toBeNull();
116
- });
117
- });