@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,469 +0,0 @@
1
- // src/execution/engine/engines/pi/__tests__/pi-engine.test.ts
2
- //
3
- // PiEngine 适配层测试(P1 回填):capabilities 链路接通口径(D3)、run 委托与
4
- // 中立声明→ExecuteOptions 映射、interact 三 action 直通、read 三级降级、probe 形状
5
- // (C1:ok=false 时 error.recovery 非空)。fake PiEngineService 注入,不 spawn 真进程。
6
-
7
- import * as fs from "node:fs";
8
- import * as os from "node:os";
9
- import * as path from "node:path";
10
-
11
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
12
-
13
- import { createRecord } from "../../../../execution-record.ts";
14
- import type { ExecuteOptions, SubagentRecord } from "../../../../types.ts";
15
- import { IDENTITY_CUSTOM_TYPE } from "../../../../session-reconstructor.ts";
16
- import { SubagentStream } from "../../../../stream-sink.ts";
17
- import type { RunContext } from "../../../port.ts";
18
- import type { AgentTaskSpec, EngineHandle } from "../../../types.ts";
19
- import {
20
- PI_ADAPTER_VERSION,
21
- PI_ENGINE_ID,
22
- PiEngine,
23
- type PiEngineService,
24
- } from "../pi-engine.ts";
25
-
26
- // ── fake 编排服务(结构子集,记录调用) ──
27
-
28
- interface ServiceCalls {
29
- executeOpts?: ExecuteOptions;
30
- signal?: AbortSignal;
31
- onEvent?: (event: unknown) => void;
32
- stream?: unknown;
33
- deliverMessage?: { recordId: string; text: string; interrupt: boolean };
34
- close?: { recordId: string; force: boolean };
35
- cancelId?: string;
36
- getRecordId?: string;
37
- }
38
-
39
- /** 构造最小完整 SubagentRecord(collectRecords 返回项——resolveRecordId 只读 id/sessionFile)。 */
40
- function makeListedRecord(id: string, sessionFile: string | undefined): SubagentRecord {
41
- return {
42
- id,
43
- agent: "reviewer",
44
- task: "t",
45
- slug: "s",
46
- status: "running",
47
- mode: "background",
48
- startedAt: 1,
49
- rootSessionId: undefined,
50
- parentRecordId: undefined,
51
- depth: 0,
52
- endedAt: undefined,
53
- turns: 0,
54
- totalTokens: 0,
55
- model: "p/m",
56
- thinkingLevel: undefined,
57
- eventLog: [],
58
- displayItems: [],
59
- ...(sessionFile !== undefined ? { sessionFile } : {}),
60
- };
61
- }
62
-
63
- function makeFakeService(overrides?: {
64
- executeResult?: Awaited<ReturnType<PiEngineService["executeAndAwait"]>>;
65
- executeReject?: Error;
66
- recordsById?: Map<string, ReturnType<typeof createRecord>>;
67
- listed?: Array<{ id: string; sessionFile?: string }>;
68
- cancelResult?: boolean;
69
- deliverReject?: Error;
70
- }): { service: PiEngineService; calls: ServiceCalls } {
71
- const calls: ServiceCalls = {};
72
- const record = createRecord("sa-fake", {
73
- agent: "reviewer",
74
- model: "p/m",
75
- thinkingLevel: "high",
76
- mode: "background",
77
- task: "t",
78
- slug: "s",
79
- startedAt: 1,
80
- controller: new AbortController(),
81
- });
82
- const service: PiEngineService = {
83
- executeAndAwait: async (opts, signal, onEvent, stream) => {
84
- calls.executeOpts = opts;
85
- calls.signal = signal;
86
- calls.onEvent = onEvent;
87
- calls.stream = stream;
88
- if (overrides?.executeReject) throw overrides.executeReject;
89
- return (
90
- overrides?.executeResult ?? {
91
- content: "done",
92
- durationMs: 42,
93
- toolCalls: [],
94
- }
95
- );
96
- },
97
- getRecordForAction: (id) => {
98
- calls.getRecordId = id;
99
- // recordsById 提供时严格查表(模拟「record 不存在 → throw」路径);缺省返回默认 record
100
- if (overrides?.recordsById) {
101
- const found = overrides.recordsById.get(id);
102
- if (!found) {
103
- throw new Error(`subagent not found or not owned: ${id}`);
104
- }
105
- return found;
106
- }
107
- return record;
108
- },
109
- deliverMessage: async (rec, text, interrupt) => {
110
- calls.deliverMessage = { recordId: rec.id, text, interrupt };
111
- if (overrides?.deliverReject) throw overrides.deliverReject;
112
- },
113
- closeSubagent: async (rec, force) => {
114
- calls.close = { recordId: rec.id, force };
115
- },
116
- cancel: (id) => {
117
- calls.cancelId = id;
118
- return overrides?.cancelResult ?? true;
119
- },
120
- collectRecords: () =>
121
- (overrides?.listed ?? []).map(({ id, sessionFile }) => makeListedRecord(id, sessionFile)),
122
- };
123
- return { service, calls };
124
- }
125
-
126
- /** 全字段任务声明(覆盖全部泛化点)。 */
127
- function makeSpec(): AgentTaskSpec {
128
- return {
129
- task: "do the thing",
130
- slug: "do-thing",
131
- agent: "reviewer",
132
- model: "zai-coding-cn/glm-5.2",
133
- effort: "high",
134
- persona: { skillPath: "/skills/r/SKILL.md", appendSystemPrompt: ["extra"] },
135
- schema: { type: "object", properties: { ok: { type: "boolean" } } },
136
- maxTurns: 5,
137
- graceTurns: 2,
138
- fork: true,
139
- worktree: false,
140
- cwd: "/work",
141
- conversation: true,
142
- idleTimeoutMs: 99,
143
- };
144
- }
145
-
146
- function makeHandle(sessionRef: Record<string, string>): EngineHandle {
147
- return { data: { v: 1, engineId: PI_ENGINE_ID, sessionRef, poolKey: "shared", adapterVersion: PI_ADAPTER_VERSION } };
148
- }
149
-
150
- function makeRunCtx(overrides?: Partial<RunContext>): RunContext {
151
- return { taskId: "sa-test", poolKey: "shared", ...overrides };
152
- }
153
-
154
- // ── capabilities ──
155
-
156
- describe("PiEngine.capabilities(D3 链路接通口径)", () => {
157
- it("id = 'pi';声明本仓 subagent 链路实际接通的能力(非 RPC 理论能力)", () => {
158
- const engine = new PiEngine({ getService: () => null });
159
- expect(engine.id).toBe(PI_ENGINE_ID);
160
- expect(engine.capabilities()).toEqual({
161
- schemaEnforcement: "native", // PI_WORKFLOW_SCHEMA env 注入链路(方案 A 唯一权威)
162
- steer: "unsupported", // RPC 有 steer 但 spawn 链路未接通(session-runner no-op)
163
- conversation: "native", // chatMode idle 复用 + message/close/cancel 已接通
164
- personaInjection: "flag", // --skill / --append-system-prompt
165
- eventGranularity: "stream", // 30+ 事件流
166
- sandbox: "emulated", // 无 OS sandbox;worktree 隔离
167
- sessionRead: "full", // pi JSONL 完整重建
168
- resume: "native", // 同进程 idle 复用 + --session 冷续写
169
- interrupt: "kill-only", // 现链路 abort = SIGTERM,rpc abort 未接通
170
- permissionMode: "native", // argv-mirror 镜像主进程 flag
171
- });
172
- });
173
- });
174
-
175
- // ── run ──
176
-
177
- describe("PiEngine.run", () => {
178
- it("中立声明 → ExecuteOptions 映射 + signal/onEvent/stream/ctxModel 直通(行为零变化)", async () => {
179
- const { service, calls } = makeFakeService();
180
- const engine = new PiEngine({ getService: () => service });
181
- const spec = makeSpec();
182
- const ctxModel = { id: "m", name: "M", provider: "p", reasoning: false };
183
- const onEvent = (e: unknown) => void e;
184
- const stream = new SubagentStream("sa-test", { setWidget: () => {} });
185
- const signal = new AbortController().signal;
186
-
187
- const { handle, outcome } = await engine.run(spec, makeRunCtx({ signal, onEvent, ctxModel, stream }));
188
-
189
- // 传参恒等(SAR 接线前的直接调用形态)
190
- expect(calls.signal).toBe(signal);
191
- expect(calls.onEvent).toBe(onEvent);
192
- expect(calls.stream).toBe(stream);
193
- expect(calls.executeOpts).toEqual({
194
- task: "do the thing",
195
- slug: "do-thing",
196
- agent: "reviewer",
197
- model: "zai-coding-cn/glm-5.2",
198
- thinkingLevel: "high", // effort 恒等映射回
199
- skillPath: "/skills/r/SKILL.md", // persona 还原
200
- appendSystemPrompt: ["extra"],
201
- schema: spec.schema,
202
- schemaEnv: JSON.stringify(spec.schema), // schema 派生(D-A6 bridge)
203
- maxTurns: 5,
204
- graceTurns: 2,
205
- ctxModel,
206
- fork: true,
207
- worktree: false,
208
- cwd: "/work",
209
- conversation: true,
210
- idleTimeoutMs: 99,
211
- engine: "pi", // P4 引擎留痕(D9①):实际执行引擎 id 进 record 投影链
212
- });
213
-
214
- // outcome 字段全集映射(缺字段在此转红——SAR outcomeToRunnerResult 的完整性依赖)
215
- expect(outcome).toEqual({
216
- content: "done",
217
- parsedOutput: undefined,
218
- usage: undefined,
219
- durationMs: 42,
220
- error: undefined,
221
- sessionId: undefined,
222
- sessionFile: undefined,
223
- worktreePath: undefined,
224
- toolCalls: [],
225
- engineId: "pi",
226
- });
227
-
228
- // handle 自描述(engineId + sessionRef + poolKey + adapter 版本)
229
- expect(handle.data).toMatchObject({
230
- v: 1,
231
- engineId: "pi",
232
- poolKey: "shared",
233
- adapterVersion: PI_ADAPTER_VERSION,
234
- });
235
- });
236
-
237
- it("sessionFile 回填进 handle.sessionRef;ctx.poolKey 透传(空串兜底 'shared')", async () => {
238
- const { service } = makeFakeService({
239
- executeResult: { content: "x", sessionFile: "/tmp/s.jsonl", sessionId: "sess-1", toolCalls: [] },
240
- });
241
- const engine = new PiEngine({ getService: () => service });
242
- const r1 = await engine.run({ task: "t", slug: "s" }, makeRunCtx({ poolKey: "agent-reviewer" }));
243
- expect(r1.handle.data.sessionRef).toEqual({ sessionFile: "/tmp/s.jsonl" });
244
- expect(r1.handle.data.poolKey).toBe("agent-reviewer");
245
- expect(r1.outcome.sessionId).toBe("sess-1");
246
- const r2 = await engine.run({ task: "t", slug: "s" }, makeRunCtx({ poolKey: "" }));
247
- expect(r2.handle.data.poolKey).toBe("shared");
248
- });
249
-
250
- it("服务不可用(prepare 期)→ reject 且不产生 handle", async () => {
251
- const engine = new PiEngine({ getService: () => null });
252
- await expect(engine.run({ task: "t", slug: "s" }, makeRunCtx())).rejects.toThrow(/SubagentService unavailable/);
253
- });
254
-
255
- it("executeAndAwait throw(嵌套超限等创建期异常)→ 向上传播(SAR catch 兜底不变)", async () => {
256
- const { service } = makeFakeService({ executeReject: new Error("nesting depth exceeded") });
257
- const engine = new PiEngine({ getService: () => service });
258
- await expect(engine.run({ task: "t", slug: "s" }, makeRunCtx())).rejects.toThrow("nesting depth exceeded");
259
- });
260
- });
261
-
262
- // ── interact ──
263
-
264
- describe("PiEngine.interact(chatMode 交互面直通)", () => {
265
- it("message → deliverMessage(record, text, false)(interrupt 中立 action 未携带,P1 恒 followUp)", async () => {
266
- const { service, calls } = makeFakeService();
267
- const engine = new PiEngine({ getService: () => service });
268
- const res = await engine.interact(makeHandle({ recordId: "sa-fake" }), { kind: "message", payload: "next round" });
269
- expect(res).toEqual({ ok: true, delivered: true });
270
- expect(calls.deliverMessage).toEqual({ recordId: "sa-fake", text: "next round", interrupt: false });
271
- });
272
-
273
- it("close → closeSubagent(record, force);payload 缺省 force=false", async () => {
274
- const { service, calls } = makeFakeService();
275
- const engine = new PiEngine({ getService: () => service });
276
- await engine.interact(makeHandle({ recordId: "sa-fake" }), { kind: "close", payload: { force: true } });
277
- expect(calls.close).toEqual({ recordId: "sa-fake", force: true });
278
- await engine.interact(makeHandle({ recordId: "sa-fake" }), { kind: "close" });
279
- expect(calls.close).toEqual({ recordId: "sa-fake", force: false });
280
- });
281
-
282
- it("cancel → service.cancel(recordId)", async () => {
283
- const { service, calls } = makeFakeService();
284
- const engine = new PiEngine({ getService: () => service });
285
- const res = await engine.interact(makeHandle({ recordId: "sa-fake" }), { kind: "cancel" });
286
- expect(res).toEqual({ ok: true, delivered: true });
287
- expect(calls.cancelId).toBe("sa-fake");
288
- });
289
-
290
- it("cancel 返回 false → engine_interact_failed", async () => {
291
- const { service } = makeFakeService({ cancelResult: false });
292
- const engine = new PiEngine({ getService: () => service });
293
- const res = await engine.interact(makeHandle({ recordId: "sa-fake" }), { kind: "cancel" });
294
- expect(res.ok).toBe(false);
295
- if (!res.ok) {
296
- expect(res.code).toBe("engine_interact_failed");
297
- expect(res.message).toContain("sa-fake");
298
- }
299
- });
300
-
301
- it("recordId 缺席时按 sessionFile 扫描兜底定位(collectRecords 匹配)", async () => {
302
- const { service, calls } = makeFakeService({ listed: [{ id: "sa-scan-hit", sessionFile: "/x/s.jsonl" }] });
303
- const engine = new PiEngine({ getService: () => service });
304
- await engine.interact(makeHandle({ sessionFile: "/x/s.jsonl" }), { kind: "message", payload: "hi" });
305
- expect(calls.getRecordId).toBe("sa-scan-hit");
306
- });
307
-
308
- it("死 handle(无定位符 / record 不存在)→ engine_session_not_resumable(含 cold resume 指引)", async () => {
309
- const { service } = makeFakeService();
310
- const engine = new PiEngine({ getService: () => service });
311
- const res = await engine.interact(makeHandle({}), { kind: "message", payload: "hi" });
312
- expect(res.ok).toBe(false);
313
- if (!res.ok) {
314
- expect(res.code).toBe("engine_session_not_resumable");
315
- expect(res.message).toContain("--session");
316
- }
317
- });
318
-
319
- it("交互面 throw → engine_interact_failed(message 文案透传行动语言)", async () => {
320
- const { service } = makeFakeService({
321
- deliverReject: new Error("subagent sa-fake is not ready for a new message"),
322
- });
323
- const engine = new PiEngine({ getService: () => service });
324
- const res = await engine.interact(makeHandle({ recordId: "sa-fake" }), { kind: "message", payload: "hi" });
325
- expect(res).toEqual({
326
- ok: false,
327
- code: "engine_interact_failed",
328
- message: "subagent sa-fake is not ready for a new message",
329
- });
330
- });
331
-
332
- it("服务不可用 → reject", async () => {
333
- const engine = new PiEngine({ getService: () => null });
334
- await expect(
335
- engine.interact(makeHandle({ recordId: "x" }), { kind: "message", payload: "hi" }),
336
- ).rejects.toThrow(/SubagentService unavailable/);
337
- });
338
- });
339
-
340
- // ── read ──
341
-
342
- describe("PiEngine.read(D6 降级链)", () => {
343
- let tmpDir: string;
344
-
345
- beforeEach(() => {
346
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-engine-read-"));
347
- });
348
- afterEach(() => {
349
- fs.rmSync(tmpDir, { recursive: true, force: true });
350
- });
351
-
352
- it("无 sessionRef → outcome-only(turns 空)", async () => {
353
- const engine = new PiEngine({ getService: () => null });
354
- const view = await engine.read(makeHandle({}));
355
- expect(view).toEqual({ engineId: "pi", turns: [], source: "outcome-only" });
356
- });
357
-
358
- it("sessionFile 不存在/损坏 → outcome-only(不 throw)", async () => {
359
- const engine = new PiEngine({ getService: () => null });
360
- const view = await engine.read(makeHandle({ sessionFile: path.join(tmpDir, "missing.jsonl") }));
361
- expect(view.source).toBe("outcome-only");
362
- });
363
-
364
- it("pi JSONL 原生读取(第①级):turns 重建 + usage 聚合 + 内部态剥离", async () => {
365
- const file = path.join(tmpDir, "s.jsonl");
366
- const lines: string[] = [
367
- JSON.stringify({ type: "session", version: 3, id: "sess-uuid", timestamp: "2026-01-01T00:00:00.000Z", cwd: tmpDir }),
368
- JSON.stringify({
369
- type: "custom", id: "id-1", parentId: null, timestamp: "2026-01-01T00:00:00.000Z",
370
- customType: IDENTITY_CUSTOM_TYPE,
371
- data: { id: "bg-1", agent: "worker", mode: "background", task: "t", startedAt: 500 },
372
- }),
373
- JSON.stringify({
374
- type: "message", id: "msg-1", parentId: "id-1", timestamp: new Date(1000).toISOString(),
375
- message: {
376
- role: "assistant",
377
- content: [
378
- { type: "text", text: "hello" },
379
- { type: "toolCall", id: "tc-1", name: "bash", arguments: { cmd: "ls" } },
380
- ],
381
- usage: { input: 10, output: 20, cacheRead: 1, cacheWrite: 2, totalTokens: 33, cost: { total: 0.5 } },
382
- stopReason: "stop",
383
- timestamp: 1000,
384
- },
385
- }),
386
- JSON.stringify({
387
- type: "message", id: "tr-1", parentId: "msg-1", timestamp: new Date(2000).toISOString(),
388
- message: {
389
- role: "toolResult", toolCallId: "tc-1", toolName: "bash",
390
- content: [{ type: "text", text: "ok" }], timestamp: 2000,
391
- },
392
- }),
393
- ];
394
- fs.writeFileSync(file, lines.join("\n") + "\n");
395
-
396
- const engine = new PiEngine({ getService: () => null });
397
- const view = await engine.read(makeHandle({ sessionFile: file }));
398
- expect(view.source).toBe("native");
399
- expect(view.engineId).toBe("pi");
400
- expect(view.sessionId).toBe("bg-1");
401
- expect(view.turns).toHaveLength(1);
402
- expect(view.turns[0].text).toBe("hello");
403
- expect(view.turns[0].closed).toBe(true);
404
- // toolCall 纯净形状(无 _status/startedTs 内部态)
405
- expect(view.turns[0].toolCalls[0]).toMatchObject({ toolName: "bash" });
406
- expect("_status" in view.turns[0].toolCalls[0]).toBe(false);
407
- // usage 聚合(turn usageDelta → AgentUsageTotal)
408
- expect(view.usage).toEqual({ input: 10, output: 20, cacheRead: 1, cacheWrite: 2, cost: 0.5, total: 33 });
409
- });
410
- });
411
-
412
- // ── probe ──
413
-
414
- describe("PiEngine.probe(D7 + C1 形状)", () => {
415
- const originalArgv = process.argv;
416
- const originalExecPath = process.execPath;
417
- const originalPath = process.env.PATH;
418
-
419
- afterEach(() => {
420
- Object.defineProperty(process, "argv", { value: originalArgv, configurable: true });
421
- Object.defineProperty(process, "execPath", { value: originalExecPath, configurable: true });
422
- process.env.PATH = originalPath;
423
- });
424
-
425
- it("探针成功:invocation + version 两级 check,engineVersion 实测", async () => {
426
- const probeVersion = vi.fn(async () => "pi 0.84.1");
427
- const engine = new PiEngine({ getService: () => null, probeVersion });
428
- const report = await engine.probe();
429
- expect(report.ok).toBe(true);
430
- expect(report.engineVersion).toBe("pi 0.84.1");
431
- expect(report.checks.map((c) => c.name)).toEqual(["invocation", "version"]);
432
- expect(report.error).toBeUndefined();
433
- expect(probeVersion).toHaveBeenCalledTimes(1);
434
- });
435
-
436
- it("版本探测失败 → ok=false 且 error.recovery 非空(C1:恢复指引必填)", async () => {
437
- const engine = new PiEngine({ getService: () => null, probeVersion: async () => undefined });
438
- const report = await engine.probe();
439
- expect(report.ok).toBe(false);
440
- expect(report.error?.code).toBe("engine_probe_failed");
441
- expect(report.error?.recovery.length).toBeGreaterThan(0);
442
- });
443
-
444
- it("结果缓存:二次 probe 不重跑;force 强探重跑", async () => {
445
- const probeVersion = vi.fn(async () => "pi 1.0");
446
- const engine = new PiEngine({ getService: () => null, probeVersion });
447
- const first = await engine.probe();
448
- const second = await engine.probe();
449
- expect(second).toBe(first); // 缓存命中(同对象)
450
- expect(probeVersion).toHaveBeenCalledTimes(1);
451
- await engine.probe({ force: true });
452
- expect(probeVersion).toHaveBeenCalledTimes(2);
453
- });
454
-
455
- it("invocation 不可解析(PATH 无 pi)→ 第 1 check 失败,不再尝试版本探测", async () => {
456
- // bun 虚拟脚本 + 通用 runtime → 退化为 PATH 依赖形态(command === "pi")
457
- Object.defineProperty(process, "argv", { value: ["bun", "/$bunfs/root/pi"], configurable: true });
458
- Object.defineProperty(process, "execPath", { value: "/usr/bin/bun", configurable: true });
459
- process.env.PATH = path.join(os.tmpdir(), `no-pi-here-${Date.now()}`);
460
- const probeVersion = vi.fn(async () => "should-not-run");
461
- const engine = new PiEngine({ getService: () => null, probeVersion });
462
- const report = await engine.probe();
463
- expect(report.ok).toBe(false);
464
- expect(report.checks).toHaveLength(1);
465
- expect(report.checks[0].name).toBe("invocation");
466
- expect(report.checks[0].ok).toBe(false);
467
- expect(probeVersion).not.toHaveBeenCalled();
468
- });
469
- });
@@ -1,155 +0,0 @@
1
- // reader.test.ts —— PiEngine reader(P5):readPiSessionView 对 session-reconstructor
2
- // 的投影包装。断言三件事:①合法 JSONL → SessionView(turns/toolCalls strip 内部态/
3
- // usage 聚合/source='native');②reconstructor 降级条件(文件缺失/缺 identity/无
4
- // assistant)→ undefined 不 throw;③不泄漏 InternalToolCall 内部态(_status/startedTs)。
5
-
6
- import * as fs from "node:fs";
7
- import * as os from "node:os";
8
- import * as path from "node:path";
9
-
10
- import { beforeAll, describe, expect, it } from "vitest";
11
-
12
- import { readPiSessionView } from "../reader.ts";
13
-
14
- let tmpDir: string;
15
-
16
- beforeAll(() => {
17
- tmpDir = fs.mkdtempSync(join(os.tmpdir(), "pi-reader-"));
18
- });
19
-
20
- // node:path 的 join 在 ESM 测试里直接用(避免顶部 import 与 beforeAll 顺序问题)
21
- function join(...segs: string[]): string {
22
- return path.join(...segs);
23
- }
24
-
25
- /** 最小合法 subagent JSONL:header + identity + 一轮 assistant(text/thinking/toolCall)+ toolResult。 */
26
- function writeValidSession(file: string): void {
27
- const lines = [
28
- JSON.stringify({ type: "session", id: "pi-sess-1", cwd: "/proj", timestamp: "2026-08-25T10:00:00Z" }),
29
- JSON.stringify({
30
- type: "custom",
31
- customType: "subagent-identity",
32
- data: { id: "bg-1-abc", agent: "reviewer", mode: "background", task: "review code", slug: "rev", startedAt: 1756000000000 },
33
- }),
34
- JSON.stringify({
35
- type: "message",
36
- timestamp: "2026-08-25T10:00:01Z",
37
- message: {
38
- role: "assistant",
39
- timestamp: 1756000001000,
40
- content: [
41
- { type: "thinking", thinking: "let me look" },
42
- { type: "toolCall", id: "tc-1", name: "bash", arguments: { command: "ls" } },
43
- ],
44
- usage: { input: 10, output: 5, cacheRead: 1, cacheWrite: 2, cost: { total: 0.1 } },
45
- stopReason: "toolUse",
46
- },
47
- }),
48
- JSON.stringify({
49
- type: "message",
50
- timestamp: "2026-08-25T10:00:02Z",
51
- message: { role: "toolResult", toolCallId: "tc-1", toolName: "bash", content: [{ type: "text", text: "file-a" }], timestamp: 1756000002000 },
52
- }),
53
- JSON.stringify({
54
- type: "message",
55
- timestamp: "2026-08-25T10:00:03Z",
56
- message: {
57
- role: "assistant",
58
- timestamp: 1756000003000,
59
- content: [{ type: "text", text: "all good" }],
60
- usage: { input: 20, output: 8, cacheRead: 0, cacheWrite: 0, cost: { total: 0.05 } },
61
- stopReason: "stop",
62
- },
63
- }),
64
- ];
65
- fs.writeFileSync(file, `${lines.join("\n")}\n`, "utf8");
66
- }
67
-
68
- describe("readPiSessionView", () => {
69
- it("projects a valid subagent JSONL to a native SessionView", async () => {
70
- const file = join(tmpDir, "valid.jsonl");
71
- writeValidSession(file);
72
-
73
- const view = await readPiSessionView(file);
74
-
75
- expect(view).toBeDefined();
76
- expect(view?.engineId).toBe("pi");
77
- expect(view?.source).toBe("native");
78
- // 两轮 assistant message → 两个 turn(toolResult 不产 turn)
79
- expect(view?.turns).toHaveLength(2);
80
-
81
- const [turn1, turn2] = view?.turns ?? [];
82
- expect(turn1?.text).toBe("");
83
- expect(turn1?.thinking).toBe("let me look");
84
- expect(turn1?.toolCalls).toHaveLength(1);
85
- const tc = turn1?.toolCalls[0];
86
- expect(tc?.toolName).toBe("bash");
87
- expect(tc?.args).toEqual({ command: "ls" });
88
- expect(tc?.result).toEqual({ content: [{ type: "text", text: "file-a" }] });
89
- // InternalToolCall 内部态不泄漏(导出纯净形状)
90
- expect(tc).not.toHaveProperty("_status");
91
- expect(tc).not.toHaveProperty("startedTs");
92
- expect(turn1?.closed).toBe(true);
93
-
94
- expect(turn2?.text).toBe("all good");
95
- expect(turn2?.closed).toBe(true);
96
-
97
- // usage 聚合:两轮 usageDelta 之和(cost 浮点累加有精度噪声,用 toBeCloseTo)
98
- expect(view?.usage?.input).toBe(30)
99
- expect(view?.usage?.output).toBe(13)
100
- expect(view?.usage?.cacheRead).toBe(1)
101
- expect(view?.usage?.cacheWrite).toBe(2)
102
- expect(view?.usage?.cost).toBeCloseTo(0.15, 10)
103
- expect(view?.usage?.total).toBe(46);
104
- });
105
-
106
- it("returns undefined (no throw) when file is missing", async () => {
107
- await expect(readPiSessionView(join(tmpDir, "nope.jsonl"))).resolves.toBeUndefined();
108
- });
109
-
110
- it("returns undefined when identity entry is missing", async () => {
111
- const file = join(tmpDir, "no-identity.jsonl");
112
- fs.writeFileSync(
113
- file,
114
- `${JSON.stringify({ type: "session", id: "s" })}\n${JSON.stringify({
115
- type: "message",
116
- message: { role: "assistant", content: [{ type: "text", text: "hi" }], timestamp: 1 },
117
- })}\n`,
118
- "utf8",
119
- );
120
- await expect(readPiSessionView(file)).resolves.toBeUndefined();
121
- });
122
-
123
- it("returns undefined when no assistant message exists", async () => {
124
- const file = join(tmpDir, "no-assistant.jsonl");
125
- fs.writeFileSync(
126
- file,
127
- `${JSON.stringify({ type: "session", id: "s" })}\n${JSON.stringify({
128
- type: "custom",
129
- customType: "subagent-identity",
130
- data: { id: "bg-2", agent: "w", mode: "background", task: "t", startedAt: 1 },
131
- })}\n`,
132
- "utf8",
133
- );
134
- await expect(readPiSessionView(file)).resolves.toBeUndefined();
135
- });
136
-
137
- it("omits usage when no message carries it", async () => {
138
- const file = join(tmpDir, "no-usage.jsonl");
139
- fs.writeFileSync(
140
- file,
141
- `${JSON.stringify({ type: "session", id: "s" })}\n${JSON.stringify({
142
- type: "custom",
143
- customType: "subagent-identity",
144
- data: { id: "bg-3", agent: "w", mode: "background", task: "t", startedAt: 1 },
145
- })}\n${JSON.stringify({
146
- type: "message",
147
- message: { role: "assistant", content: [{ type: "text", text: "hi" }], stopReason: "stop", timestamp: 1 },
148
- })}\n`,
149
- "utf8",
150
- );
151
- const view = await readPiSessionView(file);
152
- expect(view?.turns).toHaveLength(1);
153
- expect(view?.usage).toBeUndefined();
154
- });
155
- });