@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,678 +0,0 @@
1
- // src/core/session-reconstructor.ts
2
- //
3
- // 从 subagent 的 session.jsonl 重建完整的 SubagentRecord 数据。
4
- //
5
- // 背景:subagent 执行时 SDK 把完整对话(assistant text/thinking/toolCall + usage +
6
- // toolResult)实时 flush 进 session.jsonl。终态后内存 record 被立即淘汰(archive),
7
- // collectRecords 读时用本模块从 session.jsonl 重建 turns[],恢复 eventLog/result/error
8
- // 等富数据——session.jsonl 是唯一 source of truth(history.jsonl 已废弃)。
9
- //
10
- // 身份恢复:session.jsonl 的 header 不含 ExecutionRecord.id / agent / mode,故
11
- // session-runner 在创建 session 后立即写一条 custom entry(customType:"subagent-identity")
12
- // 携带 {id, agent, mode, task, startedAt}。本模块读这条 entry 恢复身份。
13
- //
14
- // 纯函数 + 防御性 I/O:任何文件缺失/损坏/格式漂移/缺 identity entry 均返回 undefined
15
- // (不抛),消费方降级跳过该 record 而非崩溃。与 execution-record.ts 同层(Core 纯数据变换)。
16
- //
17
- // 直接读文件 + 逐行 JSON.parse(session.jsonl = newline-delimited JSON),不依赖 SDK
18
- // SessionManager 类——避免 tsconfig paths fallback 把 class 降级为 interface 的坑。
19
-
20
- import * as fs from "node:fs";
21
-
22
- import type {
23
- AgentEventLogEntry,
24
- AgentUsage,
25
- ExecutionMode,
26
- ExecutionStatus,
27
- InternalToolCall,
28
- Turn,
29
- } from "./types.ts";
30
- import { extractLabelFromArgs } from "./execution-record.ts";
31
-
32
- // ============================================================
33
- // 类型(SDK jsonl 结构的最小子集——窄化为重建所需字段)
34
- // ============================================================
35
-
36
- /** assistant message 的 usage(pi-ai Usage 的最小消费字段)。 */
37
- interface JsonlUsage {
38
- input?: number;
39
- output?: number;
40
- cacheRead?: number;
41
- cacheWrite?: number;
42
- cost?: { total?: number };
43
- }
44
-
45
- /** assistant content block 联合(text/thinking/toolCall——重建只消费这三类)。 */
46
- interface TextBlock { type: "text"; text: string; }
47
- interface ThinkingBlock { type: "thinking"; thinking: string; }
48
- interface ToolCallBlock { type: "toolCall"; id: string; name: string; arguments?: unknown; }
49
- type AssistantContentBlock = TextBlock | ThinkingBlock | ToolCallBlock;
50
-
51
- /** assistant message(pi-ai AssistantMessage 的最小消费字段)。 */
52
- interface JsonlAssistantMessage {
53
- role: "assistant";
54
- content: AssistantContentBlock[];
55
- usage?: JsonlUsage;
56
- stopReason?: string;
57
- errorMessage?: string;
58
- timestamp: number;
59
- }
60
-
61
- /** toolResult message(pi-ai ToolResultMessage 的最小消费字段)。 */
62
- interface JsonlToolResultMessage {
63
- role: "toolResult";
64
- toolCallId: string;
65
- toolName: string;
66
- content?: unknown[];
67
- details?: unknown;
68
- isError?: boolean;
69
- timestamp: number;
70
- }
71
-
72
- /** user message(重建 turns[] 时跳过,仅用于类型穷尽)。 */
73
- interface JsonlUserMessage {
74
- role: "user";
75
- content: unknown;
76
- timestamp: number;
77
- }
78
-
79
- type JsonlMessage = JsonlUserMessage | JsonlAssistantMessage | JsonlToolResultMessage;
80
-
81
- /** custom entry 的 data(session-runner 写入的 subagent-identity)。 */
82
- export interface SubagentIdentityData {
83
- id: string;
84
- agent: string;
85
- mode: ExecutionMode;
86
- task: string;
87
- /**
88
- * 短标签(≤20 字符)。旧文件缺失→读取兜底空串(见 reconstructFromFile)。
89
- * 写入时(session-runner)必填;读取时可选以兼容旧文件。
90
- */
91
- slug?: string;
92
- startedAt: number;
93
- /** 根 Pi session ID(session 隔离过滤用)。旧文件可能缺失。 */
94
- rootSessionId?: string;
95
- /** 直接父 subagent record ID。旧文件缺失 → undefined(顶层)。 */
96
- parentRecordId?: string;
97
- /** subagent 递归深度。旧文件缺失 → 0(顶层)。 */
98
- depth?: number;
99
- /** [MF#4] 本 session 的 fork 深度(session-runner 写入 parentForkDepth+1)。旧文件可能缺失。 */
100
- forkDepth?: number;
101
- /**
102
- * 对话模式标志(可持续对话 subagent)。旧文件缺失 → undefined(按一次性模式处理)。
103
- * session-runner 写入;reconstructFromFile 经 ...identity 展开自动透传到 ReconstructedRecord。
104
- */
105
- chatMode?: boolean;
106
- /**
107
- * [review round2] worktree 隔离标志(该 subagent 创建时 worktree:true)。旧文件缺失 →
108
- * undefined。仅供跨重启重建路径判定「worktree 绑定已丢失」——WorktreeHandle 本身不可
109
- * 序列化,跨重启后无法 reattach,续聊须拒绝(防 resume cwd 静默回落主 repo 破坏隔离)。
110
- */
111
- worktree?: boolean;
112
- /** @deprecated 兼容旧文件:旧 identity entry 写的是 parentSessionId,读取时 fallback 到 rootSessionId。 */
113
- parentSessionId?: string;
114
- }
115
-
116
- /** SDK jsonl entry(getEntries() 返回,header 已排除)。 */
117
- interface JsonlEntry {
118
- type: string;
119
- message?: JsonlMessage;
120
- customType?: string;
121
- data?: unknown;
122
- /** model_change entry 的字段。 */
123
- provider?: string;
124
- modelId?: string;
125
- /** thinking_level_change entry 的字段。 */
126
- thinkingLevel?: string;
127
- /** entry 级别的时间戳(ISO 字符串,SDK 逐行写入)。供 endedAt 推导。 */
128
- timestamp?: string;
129
- }
130
-
131
- // ============================================================
132
- // 公开类型
133
- // ============================================================
134
-
135
- /** custom entry 的 customType 标识(session-runner 写 / reconstructor 读,约定常量)。 */
136
- export const IDENTITY_CUSTOM_TYPE = "subagent-identity";
137
-
138
- /** 重建产出的完整 SubagentRecord 数据(身份 + 可变状态 + 派生 eventLog)。 */
139
- export interface ReconstructedRecord {
140
- // ── 身份(来自 custom entry)──
141
- id: string;
142
- agent: string;
143
- mode: ExecutionMode;
144
- task: string;
145
- /** 短标签(≤20 字符)。旧文件缺失→兜底空串。 */
146
- slug: string;
147
- startedAt: number;
148
- /** 根 Pi session ID(session 隔离过滤用)。旧文件可能缺失。 */
149
- rootSessionId: string | undefined;
150
- /** 直接父 subagent record ID。旧文件缺失 → undefined(顶层)。 */
151
- parentRecordId: string | undefined;
152
- /** subagent 递归深度。旧文件缺失 → 0(顶层)。 */
153
- depth: number;
154
- /** [MF#4] 本 session 的 fork 深度(来自 identity custom entry;旧文件为 undefined)。 */
155
- forkDepth: number | undefined;
156
- /** 对话模式标志(来自 identity custom entry;旧文件为 undefined)。 */
157
- chatMode?: boolean;
158
- /** [review round2] worktree 隔离标志(见 SubagentIdentityData.worktree)。 */
159
- worktree?: boolean;
160
- /**
161
- * 对话轮次计数(非 identity entry 字段,reconstructFromFile 不填)。
162
- * V2 idle record 的 round 只在内存维护(doFinalizeRoundToIdle 递增),磁盘重建不恢复。
163
- */
164
- round?: number;
165
- sessionFile: string;
166
- // ── 可变状态(来自 message entries)──
167
- status: ExecutionStatus;
168
- /** L2 关闭原因子枚举(仅 status="closed" 时有意义)。SP-1 新增。
169
- * 从 stopReason 推导:error/aborted → gc;其余 → gc。 */
170
- closedReason?: import("./types.ts").ClosedReason;
171
- turns: Turn[];
172
- turnCount: number;
173
- totalTokens: number;
174
- lastError: string | undefined;
175
- model: string;
176
- thinkingLevel: string | undefined;
177
- /** 最后一条 entry 的时间戳(ms)。供 finalize/crashed 重建填 endedAt,避免耗时无限增长。 */
178
- endedAt: number | undefined;
179
- /** 各 turn text 拼接的完整正文(镜像 getFullText)。 */
180
- result: string | undefined;
181
- /** 来自最后一条 error/aborted assistant message(无则 undefined)。 */
182
- error: string | undefined;
183
- /** 从 turns[] 派生的离散语义事件序列(与活态 record 同形)。 */
184
- eventLog: AgentEventLogEntry[];
185
- }
186
-
187
- // ============================================================
188
- // 内部 helper
189
- // ============================================================
190
-
191
- /** turn_end 摘要截断长度(镜像 execution-record.ts TURN_SUMMARY_MAX)。 */
192
- const TURN_SUMMARY_MAX = 80;
193
-
194
- /** 从 turns[] 派生 eventLog(镜像 execution-record.ts getEventLog,但接受最小结构)。 */
195
- function deriveEventLog(
196
- turns: Turn[],
197
- lastError: string | undefined,
198
- startedAt: number,
199
- ): AgentEventLogEntry[] {
200
- const log: AgentEventLogEntry[] = [];
201
- for (const turn of turns) {
202
- for (const tc of turn.toolCalls) {
203
- const label = extractLabelFromArgs(tc.toolName, tc.args);
204
- const ts = tc.startedTs;
205
- log.push({ type: "tool_start", label, ts, status: "running" });
206
- if (tc._status !== "running") {
207
- log.push({ type: "tool_end", label, ts, status: tc._status });
208
- }
209
- }
210
- if (turn.closed) {
211
- const summary = turn.text.length > 0
212
- ? (turn.text.length > TURN_SUMMARY_MAX ? turn.text.slice(0, TURN_SUMMARY_MAX) : turn.text)
213
- : "turn";
214
- log.push({ type: "turn_end", label: summary, ts: turn.closedTs ?? startedAt });
215
- }
216
- }
217
- if (lastError) {
218
- log.push({ type: "error", label: lastError, ts: Date.now() });
219
- }
220
- return log;
221
- }
222
-
223
- /** 空 turn(镜像 execution-record.ts 的 emptyTurn,但本模块独立——避免循环依赖)。 */
224
- function emptyTurn(): Turn {
225
- return { text: "", thinking: "", toolCalls: [], usageDelta: undefined, closed: false };
226
- }
227
-
228
- /** JsonlUsage → AgentUsage(cost 取 cost.total,与 session-runner 扁平化一致)。 */
229
- function toAgentUsage(u: JsonlUsage): AgentUsage {
230
- return {
231
- input: u.input ?? 0,
232
- output: u.output ?? 0,
233
- cacheRead: u.cacheRead ?? 0,
234
- cacheWrite: u.cacheWrite ?? 0,
235
- cost: u.cost?.total,
236
- };
237
- }
238
-
239
- /** 累加 AgentUsage(field-wise,镜像 execution-record.ts addUsage)。 */
240
- function addUsage(prev: AgentUsage | undefined, next: AgentUsage): AgentUsage {
241
- if (prev === undefined) return { ...next };
242
- return {
243
- input: prev.input + next.input,
244
- output: prev.output + next.output,
245
- cacheRead: prev.cacheRead + next.cacheRead,
246
- cacheWrite: prev.cacheWrite + next.cacheWrite,
247
- cost: (prev.cost ?? 0) + (next.cost ?? 0),
248
- };
249
- }
250
-
251
- /** 校验 custom entry data 是否为合法 SubagentIdentityData。 */
252
- function isIdentityData(data: unknown): data is SubagentIdentityData {
253
- if (typeof data !== "object" || data === null) return false;
254
- const d = data as Record<string, unknown>;
255
- return (
256
- typeof d.id === "string" &&
257
- typeof d.agent === "string" &&
258
- (d.mode === "sync" || d.mode === "background") &&
259
- typeof d.task === "string" &&
260
- typeof d.startedAt === "number"
261
- );
262
- }/**
263
- * 待匹配的 toolCall(assistant 发起,等 toolResult 回填)。
264
- * 记录在 assistant Turn 上,toolResult 到达时按 toolCallId 找到并填充。
265
- */
266
- interface PendingToolCall {
267
- toolCallId: string;
268
- toolName: string;
269
- args: unknown;
270
- /** 所属 Turn(toolResult 回填时推进这个 Turn 的 toolCalls)。 */
271
- turn: Turn;
272
- /** assistant message timestamp(作为 InternalToolCall.startedTs)。 */
273
- startedTs: number;
274
- }
275
-
276
- // ============================================================
277
- // 公开函数
278
- // ============================================================
279
-
280
- /**
281
- * 从 session.jsonl 重建完整 SubagentRecord 数据。
282
- *
283
- * ╔══════════════════════════════════════════════════════════════════╗
284
- * ║ 1. readFileSync(sessionFile) + 逐行 JSON.parse(跳 header) ║
285
- * ║ (损坏行静默跳过;失败 → undefined) ║
286
- * ║ 2. 扫 custom entry(customType:"subagent-identity")→ 身份 ║
287
- * ║ 缺 identity → undefined(无法构造 record) ║
288
- * ║ 3. 顺序遍历 message entries: ║
289
- * ║ - role:"assistant" → 开新 Turn ║
290
- * ║ text/thinking 累积;usage → usageDelta ║
291
- * ║ toolCall block → 待匹配队列;stopReason error → lastError ║
292
- * ║ - role:"toolResult" → 配对 toolCallId ║
293
- * ║ 产 InternalToolCall(done/failed)推进请求 Turn ║
294
- * ║ 4. 闭合所有 turn;算 turnCount/totalTokens/result/eventLog ║
295
- * ╚══════════════════════════════════════════════════════════════════╝
296
- *
297
- * 返回 undefined:文件缺失/空/损坏/缺 identity entry/无 assistant message。
298
- * 不抛——消费方(collectRecords)降级跳过该 record。
299
- *
300
- * status 由最后一条 assistant message 的 stopReason 推导(error/aborted → failed,
301
- * 其余 → done)。cancelled 由 tombstone override(record-store 层),本函数不感知。
302
- *
303
- * [perf] 本函数是重路径(全文读 + 全 entry 解析)。列表扫描用 readIdentityHeader
304
- * (只读头部 identity),详情才走本函数(RecordStore.getFullRecord 懒加载)。
305
- */
306
- export function reconstructFromFile(sessionFile: string): ReconstructedRecord | undefined {
307
- // 读文件 + 逐行 JSON.parse(session.jsonl = newline-delimited JSON)。
308
- // 第 1 行是 session header(跳过);后续每行一个 entry。
309
- // 损坏行静默跳过(与 SDK parseSessionEntries 行为一致)。
310
- let raw: string;
311
- try {
312
- raw = fs.readFileSync(sessionFile, "utf-8");
313
- } catch {
314
- return undefined; // 文件缺失 → 降级。
315
- }
316
-
317
- const entries: JsonlEntry[] = [];
318
- const lines = raw.split("\n");
319
- for (let i = 0; i < lines.length; i++) {
320
- const line = lines[i]?.trim();
321
- if (!line) continue;
322
- if (i === 0) {
323
- // 第 1 行是 session header(type:"session"),跳过。
324
- try {
325
- const head = JSON.parse(line) as JsonlEntry;
326
- if (head.type === "session") continue;
327
- } catch (_e) {
328
- void _e; // 首行损坏 → 跳过,继续解析后续。
329
- continue;
330
- }
331
- }
332
- try {
333
- const parsed = JSON.parse(line) as JsonlEntry;
334
- if (parsed && typeof parsed.type === "string") {
335
- entries.push(parsed);
336
- }
337
- } catch (_e) {
338
- void _e; // 损坏行跳过(不阻断后续行)。
339
- }
340
- }
341
-
342
- if (entries.length === 0) return undefined;
343
-
344
- // ── 扫身份 custom entry(必须存在,否则无法构造 record)──
345
- let identity: SubagentIdentityData | undefined;
346
- let model = "";
347
- let thinkingLevel: string | undefined;
348
- for (const entry of entries) {
349
- if (entry.type === "custom" && entry.customType === IDENTITY_CUSTOM_TYPE) {
350
- if (isIdentityData(entry.data)) identity = entry.data;
351
- } else if (entry.type === "model_change") {
352
- // model_change: {provider, modelId} → "provider/modelId"(与 record.model 同形)。
353
- if (typeof entry.provider === "string" && typeof entry.modelId === "string") {
354
- model = `${entry.provider}/${entry.modelId}`;
355
- }
356
- } else if (entry.type === "thinking_level_change") {
357
- if (typeof entry.thinkingLevel === "string") thinkingLevel = entry.thinkingLevel;
358
- }
359
- }
360
- if (!identity) return undefined; // 缺身份 → 无法构造 record。
361
-
362
- // ── 重建 turns[] ──
363
- const turns: Turn[] = [];
364
- const pending: PendingToolCall[] = [];
365
- let lastError: string | undefined;
366
- let totalTokens = 0;
367
- /** 最后一条 entry 的时间戳(ms),推导 endedAt(避免重建 record 耗时随墙钟无限增长)。 */
368
- let lastEntryTsMs: number | undefined;
369
-
370
- for (const entry of entries) {
371
- // entry 级别 timestamp(ISO)→ ms。优先用 entry 级别(每条都有),message.timestamp 作兼底。
372
- if (typeof entry.timestamp === "string") {
373
- const ms = Date.parse(entry.timestamp);
374
- if (!Number.isNaN(ms)) lastEntryTsMs = ms;
375
- }
376
- if (entry.type !== "message") continue;
377
- const msg = entry.message;
378
- if (!msg) continue;
379
- if (typeof msg.timestamp === "number") {
380
- lastEntryTsMs = msg.timestamp;
381
- }
382
-
383
- if (msg.role === "assistant") {
384
- const turn = emptyTurn();
385
- turns.push(turn);
386
-
387
- if (!Array.isArray(msg.content)) continue;
388
- for (const block of msg.content) {
389
- if (block.type === "text") {
390
- turn.text += block.text;
391
- } else if (block.type === "thinking") {
392
- turn.thinking += block.thinking;
393
- } else if (block.type === "toolCall") {
394
- pending.push({
395
- toolCallId: block.id,
396
- toolName: block.name,
397
- args: block.arguments,
398
- turn,
399
- startedTs: msg.timestamp,
400
- });
401
- }
402
- }
403
-
404
- if (msg.usage) {
405
- const u = toAgentUsage(msg.usage);
406
- turn.usageDelta = addUsage(turn.usageDelta, u);
407
- totalTokens += u.input + u.output + u.cacheRead + u.cacheWrite;
408
- }
409
-
410
- // stopReason 驱动 lastError(与 updateFromEvent 一致):
411
- // error/aborted → 设 lastError;stop(正常结束)→ 清 lastError(镜像 turn_end 的清除语义,
412
- // 即前序 turn 的瞬态 error 在后续成功 turn 后恢复,不误判 success=false)。
413
- // [v4 B-1] status 恒 closed 后 lastStopReason 不再参与推导,死变量已删。
414
- if (msg.stopReason === "error" || msg.stopReason === "aborted") {
415
- lastError = msg.errorMessage ?? msg.stopReason;
416
- } else if (msg.stopReason === "stop") {
417
- lastError = undefined;
418
- }
419
- } else if (msg.role === "toolResult") {
420
- const idx = pending.findIndex((p) => p.toolCallId === msg.toolCallId);
421
- if (idx >= 0) {
422
- const p = pending[idx];
423
- pending.splice(idx, 1);
424
- const tc: InternalToolCall = {
425
- toolName: p.toolName,
426
- args: p.args,
427
- result: { content: msg.content, details: msg.details },
428
- isError: msg.isError ?? false,
429
- _status: msg.isError ? "failed" : "done",
430
- startedTs: p.startedTs,
431
- };
432
- p.turn.toolCalls.push(tc);
433
- }
434
- // 未配对(孤儿 toolResult)→ 丢弃。
435
- }
436
- // role:"user" → 跳过(task 来自 identity custom entry)。
437
- }
438
-
439
- if (turns.length === 0) return undefined; // 无 assistant message → 空壳,降级。
440
-
441
- // 闭合所有 turn(重建的是历史,全是已完成 turn)。
442
- for (const turn of turns) {
443
- turn.closed = true;
444
- }
445
-
446
- const turnCount = turns.length;
447
- const resultText = turns
448
- .map((t) => t.text)
449
- .filter((t) => t.length > 0)
450
- .join("\n\n");
451
-
452
- // eventLog 从 turns[] 派生(与活态 record 的 getEventLog 同形,消费方无感知差异)。
453
- const eventLog = deriveEventLog(turns, lastError, identity.startedAt);
454
-
455
- // 终态 status:最后一条 assistant message 的 stopReason 推导(与 finalizeRecord 的判定一致)。
456
- // SP-1:done/failed 合并为 closed,cancelled 由 tombstone override(record-store 层),本函数不感知。
457
- const status: ExecutionStatus = "closed";
458
- // closedReason 统 gc(通用完成/失败)。error/aborted 的区分由 error 字段保留。
459
- const closedReason: import("./types.ts").ClosedReason = "gc";
460
-
461
- // rootSessionId 归一化:新文件读 rootSessionId,旧文件 fallback parentSessionId。
462
- const rootSessionId = identity.rootSessionId ?? identity.parentSessionId;
463
- // slug 兜底:旧 identity entry 无 slug 字段 → 空串(与 SubagentRecord.slug: string 契约一致)。
464
- const slug = identity.slug ?? "";
465
- return {
466
- ...identity,
467
- slug,
468
- rootSessionId,
469
- parentRecordId: identity.parentRecordId,
470
- depth: identity.depth ?? 0,
471
- forkDepth: identity.forkDepth,
472
- sessionFile,
473
- status,
474
- closedReason,
475
- turns,
476
- turnCount,
477
- totalTokens,
478
- lastError,
479
- model,
480
- thinkingLevel,
481
- endedAt: lastEntryTsMs,
482
- result: resultText.length > 0 ? resultText : undefined,
483
- error: lastError,
484
- eventLog,
485
- };
486
- }
487
-
488
- // ============================================================
489
- // 轻量头部读取(列表扫描用)
490
- // ============================================================
491
-
492
- /** 头部读取字节数。首轮会话 identity 在第 2-3 行;但续聊(resume)场景 session_start
493
- * 再次触发,identity append 到文件尾部附近(实测真实目录 1186/1744 文件的 identity
494
- * 不在头 64KB)。头部 miss 时由 RecordStore.scanFile 调 readIdentityAnywhere 全文 fallback。 */
495
- export const IDENTITY_HEAD_BYTES = 65536;
496
-
497
- /** 轻量重建产出:仅身份字段 + 头部可见的 model/thinkingLevel(详情字段一律缺省)。 */
498
- export interface IdentityHeaderRecon {
499
- id: string;
500
- agent: string;
501
- mode: ExecutionMode;
502
- task: string;
503
- slug: string;
504
- startedAt: number;
505
- rootSessionId: string | undefined;
506
- parentRecordId: string | undefined;
507
- depth: number;
508
- forkDepth: number | undefined;
509
- chatMode?: boolean;
510
- /** [review round2] worktree 隔离标志(见 SubagentIdentityData.worktree)。 */
511
- worktree?: boolean;
512
- model: string;
513
- thinkingLevel: string | undefined;
514
- sessionFile: string;
515
- }
516
-
517
- /**
518
- * 只读文件头部,解析 identity custom entry(+途经的 model/thinking_level change)。
519
- *
520
- * 列表扫描专用:单次 readSync 读头部 IDENTITY_HEAD_BYTES 字节,逐行解析到 identity
521
- * 即停。不解析 message entries(turns/eventLog/result 等重数据由
522
- * RecordStore.getFullRecord 懒加载 reconstructFromFile 补齐)。
523
- *
524
- * 与 reconstructFromFile 的行为差异(有意):本函数只要头部有 identity 就返回,
525
- * 不要求存在 assistant message——pi 延迟写入策略下无 assistant 的文件几乎不存在,
526
- * 若存在(崩溃前 flush)也按分支 4 running 呈现(v4 B-1 可续聊语义),
527
- * 而非静默不可见。
528
- *
529
- * 返回 undefined:文件缺失/读失败/头部无 identity。不抛。
530
- * 头部无 identity ≠ 文件无 identity(续聊场景 identity 在尾部附近)——需要覆盖全文件
531
- * 时用 readIdentityAnywhere。
532
- */
533
- export function readIdentityHeader(sessionFile: string): IdentityHeaderRecon | undefined {
534
- let text: string;
535
- try {
536
- const fd = fs.openSync(sessionFile, "r");
537
- try {
538
- const buf = Buffer.alloc(IDENTITY_HEAD_BYTES);
539
- let total = 0;
540
- while (total < buf.length) {
541
- const n = fs.readSync(fd, buf, total, buf.length - total, total);
542
- if (n <= 0) break;
543
- total += n;
544
- }
545
- text = buf.toString("utf-8", 0, total);
546
- } finally {
547
- fs.closeSync(fd);
548
- }
549
- } catch {
550
- return undefined; // 文件缺失/不可读 → 降级跳过
551
- }
552
- return parseIdentityFromText(text, sessionFile);
553
- }
554
-
555
- /**
556
- * 全文件找 identity:头部/尾部都 miss 后的最后 fallback(真实数据仅 ~0.2% 走到)。
557
- *
558
- * 全量 readFileSync + indexOf 预筛(只有含特征串的行才 JSON.parse),从后往前找
559
- * (续聊轮次的 identity 靠尾部,最后一次的 identity 最新鲜)。读全文是成本主体
560
- * (预筛/parse 可忽略)——调用方(RecordStore)应缓存结果避免重复读。
561
- */
562
- export function readIdentityAnywhere(sessionFile: string): IdentityHeaderRecon | undefined {
563
- let text: string;
564
- try {
565
- text = fs.readFileSync(sessionFile, "utf-8");
566
- } catch {
567
- return undefined;
568
- }
569
- const lines = text.split("\n");
570
- for (let i = lines.length - 1; i >= 0; i--) {
571
- const s = lines[i];
572
- if (!s.includes(IDENTITY_CUSTOM_TYPE)) continue; // 预筛:identity 行必含特征串
573
- const recon = parseIdentityFromText(s, sessionFile);
574
- if (recon) return recon;
575
- }
576
- return undefined;
577
- }
578
-
579
- /**
580
- * 只读文件尾部找 identity(续聊场景主力命中点:最后一轮 session_start 追加的
581
- * identity 离文件尾近,实测真实目录 65% 文件 identity 在尾 64KB)。
582
- *
583
- * 尾部块首行可能残缺(从行中间开始)——JSON.parse 失败自然跳过,不影响后续行。
584
- * model/thinking_level 在尾部块中拿不到 identity 之前的途经 entry,返回空/undefined
585
- * (best-effort,详情场景由全量重建补齐)。
586
- */
587
- export function readIdentityTail(sessionFile: string): IdentityHeaderRecon | undefined {
588
- let text: string;
589
- try {
590
- const { size } = fs.statSync(sessionFile);
591
- const start = Math.max(0, size - IDENTITY_HEAD_BYTES);
592
- const fd = fs.openSync(sessionFile, "r");
593
- try {
594
- const buf = Buffer.alloc(size - start);
595
- let total = 0;
596
- while (total < buf.length) {
597
- const n = fs.readSync(fd, buf, total, buf.length - total, start + total);
598
- if (n <= 0) break;
599
- total += n;
600
- }
601
- text = buf.toString("utf-8", 0, total);
602
- } finally {
603
- fs.closeSync(fd);
604
- }
605
- } catch {
606
- return undefined;
607
- }
608
- const lines = text.split("\n");
609
- for (let i = lines.length - 1; i >= 0; i--) {
610
- const s = lines[i];
611
- if (!s.includes(IDENTITY_CUSTOM_TYPE)) continue;
612
- const recon = parseIdentityFromText(s, sessionFile);
613
- if (recon) return recon;
614
- }
615
- return undefined;
616
- }
617
-
618
- /** 从文本片段解析 identity(头部/全文两入口共享)。解析到 identity 即停(返回);
619
- * 找不到返回 undefined。model/thinking_level 仅在 identity 之前的途经 entry 中
620
- * best-effort 提取,详情场景由全量重建补齐。 */
621
- function parseIdentityFromText(text: string, sessionFile: string): IdentityHeaderRecon | undefined {
622
- let identity: SubagentIdentityData | undefined;
623
- let model = "";
624
- let thinkingLevel: string | undefined;
625
- for (const line of text.split("\n")) {
626
- const s = line.trim();
627
- if (!s) continue;
628
- // 预筛([S-4] 同款值匹配):只有含三种目标 entry 值串的行才值得 JSON.parse——
629
- // head 64KB 内大 toolResult 行(数十 KB/行)占多数,全量 parse 是冷扫描 CPU 大头。
630
- // 值字符串在任意序列化格式下连续出现,不耦合 pi 的空格习惯。
631
- if (
632
- !s.includes(IDENTITY_CUSTOM_TYPE) &&
633
- !s.includes('"model_change"') &&
634
- !s.includes('"thinking_level_change"')
635
- ) {
636
- continue;
637
- }
638
- let entry: JsonlEntry;
639
- try {
640
- entry = JSON.parse(s) as JsonlEntry;
641
- } catch {
642
- continue; // 损坏行/截断行(头部读取边界)跳过
643
- }
644
- if (entry.type === "custom" && entry.customType === IDENTITY_CUSTOM_TYPE) {
645
- if (isIdentityData(entry.data)) {
646
- identity = entry.data;
647
- break; // 找到即停(后续行不再解析)
648
- }
649
- } else if (entry.type === "model_change") {
650
- if (typeof entry.provider === "string" && typeof entry.modelId === "string") {
651
- model = `${entry.provider}/${entry.modelId}`;
652
- }
653
- } else if (entry.type === "thinking_level_change") {
654
- if (typeof entry.thinkingLevel === "string") thinkingLevel = entry.thinkingLevel;
655
- }
656
- }
657
- if (!identity) return undefined;
658
-
659
- // 归一化与全量 recon 同源:rootSessionId fallback 旧字段、slug 兜底空串。
660
- const rootSessionId = identity.rootSessionId ?? identity.parentSessionId;
661
- return {
662
- id: identity.id,
663
- agent: identity.agent,
664
- mode: identity.mode,
665
- task: identity.task,
666
- slug: identity.slug ?? "",
667
- startedAt: identity.startedAt,
668
- rootSessionId,
669
- parentRecordId: identity.parentRecordId,
670
- depth: identity.depth ?? 0,
671
- forkDepth: identity.forkDepth,
672
- chatMode: identity.chatMode,
673
- worktree: identity.worktree,
674
- model,
675
- thinkingLevel,
676
- sessionFile,
677
- };
678
- }