@zhushanwen/subagent-core 0.4.0 → 0.5.1

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 (272) hide show
  1. package/dist/{chunk-4KN4TTG7.js → chunk-43ONBFZX.js} +1 -1
  2. package/dist/{chunk-X7SZ5HLQ.js → chunk-V3VHZ2VX.js} +20 -27
  3. package/dist/execution/engine/engines/zcode/constants.cjs +29 -41
  4. package/dist/execution/engine/engines/zcode/constants.d.cts +65 -53
  5. package/dist/execution/engine/engines/zcode/constants.d.ts +65 -53
  6. package/dist/execution/engine/engines/zcode/constants.js +17 -27
  7. package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
  8. package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
  9. package/dist/execution/engine/engines/zcode/reader.js +2 -2
  10. package/dist/index.cjs +16418 -14070
  11. package/dist/index.d.cts +5136 -4016
  12. package/dist/index.d.ts +5136 -4016
  13. package/dist/index.js +16343 -14048
  14. package/dist/{types-DpUO16pj.d.cts → types-Dv4QhSJ_.d.cts} +215 -112
  15. package/dist/{types-DpUO16pj.d.ts → types-Dv4QhSJ_.d.ts} +215 -112
  16. package/package.json +3 -3
  17. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
  18. package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
  19. package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
  20. package/src/__tests__/m2-append-content-probe.test.ts +0 -1
  21. package/src/__tests__/manifest-store.test.ts +10 -9
  22. package/src/__tests__/record-store-cache.test.ts +0 -2
  23. package/src/__tests__/record-store-index.test.ts +1 -2
  24. package/src/__tests__/review-fix-loop-script.test.ts +4 -2
  25. package/src/__tests__/review-fix-loop-utils.test.ts +10 -10
  26. package/src/__tests__/robustness-low-batch1.test.ts +6 -5
  27. package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
  28. package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
  29. package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
  30. package/src/__tests__/session-runner.test.ts +1 -1
  31. package/src/core/__tests__/host-services.test.ts +2 -2
  32. package/src/core/__tests__/logger.test.ts +1 -1
  33. package/src/core/error-message.ts +9 -0
  34. package/src/core/host-services.ts +21 -5
  35. package/src/core/notify-ports.ts +18 -5
  36. package/src/execution/__tests__/agent-profile.test.ts +4 -4
  37. package/src/execution/__tests__/agent-registry.test.ts +370 -0
  38. package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
  39. package/src/execution/__tests__/agents-assembly.test.ts +2 -2
  40. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
  41. package/src/execution/__tests__/chat-engine-routing.test.ts +68 -33
  42. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +4 -4
  43. package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
  44. package/src/execution/__tests__/delivery-methods.test.ts +75 -62
  45. package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
  46. package/src/execution/__tests__/descendant-sweep.test.ts +6 -6
  47. package/src/execution/__tests__/dialog-queue.test.ts +2 -2
  48. package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
  49. package/src/execution/__tests__/epipe-fallback.test.ts +29 -24
  50. package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
  51. package/src/execution/__tests__/execute-nesting.test.ts +34 -188
  52. package/src/execution/__tests__/execution-record.test.ts +217 -60
  53. package/src/execution/__tests__/execution-runtime-face.test.ts +5 -5
  54. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +3 -3
  55. package/src/execution/__tests__/finalize-record.test.ts +173 -17
  56. package/src/execution/__tests__/gc-timer.test.ts +55 -2
  57. package/src/execution/__tests__/get-record-for-action-restart.test.ts +12 -12
  58. package/src/execution/__tests__/get-state-handshake.test.ts +1 -1
  59. package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
  60. package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
  61. package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
  62. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
  63. package/src/execution/__tests__/keep-alive-no-progress.test.ts +50 -148
  64. package/src/execution/__tests__/kill-all-escalation.test.ts +2 -2
  65. package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
  66. package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
  67. package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +1 -1
  68. package/src/execution/__tests__/model-resolver.test.ts +2 -2
  69. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
  70. package/src/execution/__tests__/nested-visibility.test.ts +2 -0
  71. package/src/execution/__tests__/notify-ledger.test.ts +973 -18
  72. package/src/execution/__tests__/output-collector.test.ts +117 -6
  73. package/src/execution/__tests__/pi-invocation.test.ts +1 -1
  74. package/src/execution/__tests__/record-store.test.ts +10 -9
  75. package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
  76. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
  77. package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
  78. package/src/execution/__tests__/rpc-mode.test.ts +2 -2
  79. package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
  80. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +15 -9
  81. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +4 -4
  82. package/src/execution/__tests__/run-spawn-edges.test.ts +17 -15
  83. package/src/execution/__tests__/run-spawn-integration.test.ts +2 -2
  84. package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
  85. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
  86. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +4 -4
  87. package/src/execution/__tests__/service-kill-escalation.test.ts +7 -5
  88. package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
  89. package/src/execution/__tests__/session-file-gc.test.ts +35 -0
  90. package/src/execution/__tests__/session-pending.test.ts +257 -14
  91. package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
  92. package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +1 -1
  93. package/src/execution/__tests__/session-runner-close-prune.test.ts +2 -2
  94. package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
  95. package/src/execution/__tests__/session-runner-epipe.test.ts +3 -3
  96. package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +5 -4
  97. package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
  98. package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
  99. package/src/execution/__tests__/settled-watchdog.test.ts +282 -47
  100. package/src/execution/__tests__/spawn-args.test.ts +11 -10
  101. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
  102. package/src/execution/__tests__/spawn-event-adapter.test.ts +1 -1
  103. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
  104. package/src/execution/__tests__/spawned-children.test.ts +2 -1
  105. package/src/execution/__tests__/start-sync-model-guard.test.ts +4 -4
  106. package/src/execution/__tests__/stdin-writer.test.ts +6 -4
  107. package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
  108. package/src/execution/__tests__/subagent-actions-core.test.ts +42 -22
  109. package/src/execution/__tests__/subagent-service-message-close.test.ts +29 -26
  110. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +8 -8
  111. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +27 -22
  112. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +30 -29
  113. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +45 -20
  114. package/src/execution/__tests__/subagent-service.test.ts +37 -30
  115. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
  116. package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
  117. package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
  118. package/src/execution/__tests__/temp-prompt.test.ts +1 -1
  119. package/src/execution/__tests__/timeout-integration.test.ts +6 -5
  120. package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
  121. package/src/execution/__tests__/turn-limiter.test.ts +1 -1
  122. package/src/execution/__tests__/ui-request-handler-factory.test.ts +12 -6
  123. package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
  124. package/src/execution/__tests__/ui-request-queue.test.ts +142 -2
  125. package/src/execution/__tests__/worktree-manager.test.ts +14 -5
  126. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
  127. package/src/execution/agent-registry.ts +74 -30
  128. package/src/execution/agent-result-mapper.ts +3 -0
  129. package/src/execution/cold-resurrect.ts +199 -0
  130. package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
  131. package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
  132. package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
  133. package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
  134. package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
  135. package/src/execution/engine/__tests__/common/pool-manager.test.ts +211 -51
  136. package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
  137. package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
  138. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +22 -112
  139. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +15 -28
  140. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +12 -12
  141. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +1 -1
  142. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +21 -82
  143. package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +4 -7
  144. package/src/execution/engine/__tests__/engine-discovery.test.ts +15 -3
  145. package/src/execution/engine/__tests__/model-prompt.test.ts +15 -3
  146. package/src/execution/engine/__tests__/registry.test.ts +4 -2
  147. package/src/execution/engine/__tests__/routing.test.ts +115 -6
  148. package/src/execution/engine/common/capability-gate.ts +92 -0
  149. package/src/execution/engine/common/journal-wiring.ts +97 -0
  150. package/src/execution/engine/common/kill-chain.ts +42 -10
  151. package/src/execution/engine/common/nesting-guard.ts +66 -0
  152. package/src/execution/engine/common/persona-router.ts +18 -8
  153. package/src/execution/engine/common/pool-manager.ts +332 -78
  154. package/src/execution/engine/common/session-view-service.ts +506 -0
  155. package/src/execution/engine/common/session-view-types.ts +125 -0
  156. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +174 -28
  157. package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
  158. package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
  159. package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +1 -1
  160. package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
  161. package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
  162. package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
  163. package/src/execution/engine/engines/pi/reader.ts +11 -0
  164. package/src/execution/engine/engines/pi/registration.ts +4 -2
  165. package/src/execution/{session-runner.ts → engine/engines/pi/session-runner.ts} +617 -412
  166. package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
  167. package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
  168. package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
  169. package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
  170. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +54 -27
  171. package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
  172. package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +13 -12
  173. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
  174. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
  175. package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
  176. package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
  177. package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +20 -8
  178. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +77 -110
  179. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +25 -319
  180. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
  181. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
  182. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
  183. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
  184. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +48 -148
  185. package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
  186. package/src/execution/engine/engines/zcode/connection.ts +24 -11
  187. package/src/execution/engine/engines/zcode/constants.ts +75 -71
  188. package/src/execution/engine/engines/zcode/golden-sample.ts +8 -46
  189. package/src/execution/engine/engines/zcode/parser.ts +12 -346
  190. package/src/execution/engine/engines/zcode/preparer.ts +12 -143
  191. package/src/execution/engine/engines/zcode/session-channel.ts +351 -39
  192. package/src/execution/engine/engines/zcode/zcode-engine.ts +665 -760
  193. package/src/execution/engine/host-task-spec.ts +32 -36
  194. package/src/execution/engine/model-validation.ts +177 -0
  195. package/src/execution/engine/port.ts +24 -6
  196. package/src/execution/engine/routing.ts +75 -1
  197. package/src/execution/engine/types.ts +30 -103
  198. package/src/execution/execution-record.ts +222 -144
  199. package/src/execution/finalize-record.ts +131 -93
  200. package/src/execution/idle-gc.ts +28 -0
  201. package/src/execution/lifecycle-predicates.ts +1 -1
  202. package/src/execution/notify-host.ts +212 -0
  203. package/src/execution/record-store.ts +119 -73
  204. package/src/execution/round-settlement.ts +93 -0
  205. package/src/execution/session-file-gc.ts +96 -62
  206. package/src/execution/session-reconstructor.ts +256 -143
  207. package/src/execution/sessions-index.ts +117 -47
  208. package/src/execution/settled-watchdog.ts +264 -52
  209. package/src/execution/subagent-actions-core.ts +22 -22
  210. package/src/execution/subagent-service.ts +815 -963
  211. package/src/execution/subprocess-agent-runner.ts +144 -97
  212. package/src/execution/types.ts +9 -0
  213. package/src/execution/ui-request-handler-factory.ts +102 -74
  214. package/src/execution/ui-request-queue.ts +50 -19
  215. package/src/index.ts +442 -316
  216. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +1 -1
  217. package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
  218. package/src/orchestration/__tests__/args-validator.test.ts +14 -0
  219. package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +1 -1
  220. package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +11 -9
  221. package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
  222. package/src/orchestration/__tests__/file-run-store.test.ts +7 -6
  223. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +2 -2
  224. package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +1 -1
  225. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
  226. package/src/orchestration/__tests__/lifecycle.test.ts +7 -5
  227. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
  228. package/src/orchestration/__tests__/run-snapshot.test.ts +8 -5
  229. package/src/orchestration/__tests__/script-lint.test.ts +17 -0
  230. package/src/orchestration/__tests__/test-mocks.ts +2 -0
  231. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
  232. package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
  233. package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +27 -19
  234. package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
  235. package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
  236. package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
  237. package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +1 -1
  238. package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
  239. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
  240. package/src/orchestration/agent-opts-resolver.ts +1 -1
  241. package/src/orchestration/args-validator.ts +53 -31
  242. package/src/orchestration/execute-agent-call.ts +19 -73
  243. package/src/orchestration/launcher.ts +128 -81
  244. package/src/orchestration/lifecycle.ts +43 -45
  245. package/src/orchestration/models/ports.ts +4 -4
  246. package/src/orchestration/models/run-runtime.ts +2 -2
  247. package/src/orchestration/models/trace.ts +1 -1
  248. package/src/orchestration/models/types.ts +111 -22
  249. package/src/orchestration/models/workflow-run.ts +1 -1
  250. package/src/orchestration/script-lint.ts +91 -58
  251. package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +157 -150
  252. package/src/shared/__tests__/meta-parser.test.ts +151 -0
  253. package/src/shared/__tests__/resource-discovery.test.ts +258 -215
  254. package/src/shared/atomic-write.ts +12 -9
  255. package/src/shared/meta-parser.ts +158 -84
  256. package/src/shared/model-ref.ts +15 -2
  257. package/src/shared/resource-discovery.ts +9 -183
  258. package/src/shared/schema-jsonify.ts +1 -1
  259. package/workflows/review-fix-loop-utils.cjs +151 -89
  260. package/workflows/review-fix-loop-utils.d.cts +287 -0
  261. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  262. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  263. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  264. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  265. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  266. package/src/execution/engine/engines/zcode/__tests__/preparer-appserver.test.ts +0 -387
  267. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -710
  268. package/src/execution/engine/engines/zcode/appserver-home.ts +0 -442
  269. package/src/execution/engine/engines/zcode/appserver-probe.ts +0 -141
  270. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  271. package/src/execution/execute-options-mapper.ts +0 -115
  272. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
@@ -1,4 +1,4 @@
1
- // src/core/spawn-event-adapter.ts
1
+ // src/execution/engine/engines/pi/spawn-event-adapter.ts
2
2
  //
3
3
  // pi 子进程 stdout JSON 事件流的解析器。Core 叶子原语(仅依赖 types.ts)。
4
4
  //
@@ -20,7 +20,8 @@
20
20
  import * as fs from "node:fs";
21
21
  import * as path from "node:path";
22
22
 
23
- import type { SdkEvent } from "./types.ts";
23
+ import type { SdkEvent } from "../../../types.ts";
24
+ import { toErrorMessage } from "../../../../core/error-message.ts";
24
25
 
25
26
  /** pi stdout header 行(session 元信息)。type 固定为 "session"。 */
26
27
  export interface SpawnSessionHeader {
@@ -158,6 +159,56 @@ function isExtensionUiRequest(obj: unknown): obj is ExtensionUiRequestEnvelope {
158
159
  );
159
160
  }
160
161
 
162
+ /** 必填 string 字段提取:类型不符降级空串(字段容错——仍归类已知 method,不丢 method 信息)。 */
163
+ function reqStr(r: Record<string, unknown>, key: string): string {
164
+ const v = r[key];
165
+ return typeof v === "string" ? v : "";
166
+ }
167
+
168
+ /** string[] 字段提取:数组剔除非字符串元素;非数组降级 onMissing(options 传 [],
169
+ * widgetLines 传 undefined——两者对缺失值的载荷语义不同:前者恒挂键,后者键挂值 undefined)。 */
170
+ function strArrayField<T extends string[] | undefined>(
171
+ r: Record<string, unknown>,
172
+ key: string,
173
+ onMissing: T,
174
+ ): string[] | T {
175
+ const v = r[key];
176
+ return Array.isArray(v)
177
+ ? v.filter((x): x is string => typeof x === "string")
178
+ : onMissing;
179
+ }
180
+
181
+ /** timeout 条件展开:非 number 不挂键(timeout?: number 的字段省略语义)。 */
182
+ function optTimeout(r: Record<string, unknown>): { timeout?: number } {
183
+ return typeof r.timeout === "number" ? { timeout: r.timeout } : {};
184
+ }
185
+
186
+ /** placeholder 条件展开:非 string 不挂键。 */
187
+ function optPlaceholder(r: Record<string, unknown>): { placeholder?: string } {
188
+ return typeof r.placeholder === "string" ? { placeholder: r.placeholder } : {};
189
+ }
190
+
191
+ /** prefill 条件展开:非 string 不挂键。 */
192
+ function optPrefill(r: Record<string, unknown>): { prefill?: string } {
193
+ return typeof r.prefill === "string" ? { prefill: r.prefill } : {};
194
+ }
195
+
196
+ /** notifyType 条件展开:仅接受三种已知枚举值,其余不挂键。 */
197
+ function optNotifyType(
198
+ r: Record<string, unknown>
199
+ ): { notifyType?: "info" | "warning" | "error" } {
200
+ const v = r.notifyType;
201
+ return v === "info" || v === "warning" || v === "error" ? { notifyType: v } : {};
202
+ }
203
+
204
+ /** widgetPlacement 条件展开:仅接受两种已知枚举值,其余不挂键。 */
205
+ function optWidgetPlacement(
206
+ r: Record<string, unknown>
207
+ ): { widgetPlacement?: "aboveEditor" | "belowEditor" } {
208
+ const v = r.widgetPlacement;
209
+ return v === "aboveEditor" || v === "belowEditor" ? { widgetPlacement: v } : {};
210
+ }
211
+
161
212
  /**
162
213
  * 从已通过 isExtensionUiRequest 守卫的 envelope 构造 ExtensionUiRequest 变体。
163
214
  *
@@ -166,6 +217,7 @@ function isExtensionUiRequest(obj: unknown): obj is ExtensionUiRequestEnvelope {
166
217
  *
167
218
  * 字段类型容错:协议字段类型不符(如 options 非数组)时,该字段降级为空数组/undefined
168
219
  *(数组类字段做元素类型过滤,剔除非字符串元素),仍归类为已知 method(不丢 method 信息)。
220
+ * 字段级提取/条件展开由上方字段 helper 承担,本函数只做 method 分发。
169
221
  */
170
222
  function buildExtensionUiRequest(env: ExtensionUiRequestEnvelope): ExtensionUiRequest {
171
223
  const r: Record<string, unknown> = env;
@@ -173,69 +225,58 @@ function buildExtensionUiRequest(env: ExtensionUiRequestEnvelope): ExtensionUiRe
173
225
  case "select":
174
226
  return {
175
227
  method: "select",
176
- title: typeof r.title === "string" ? r.title : "",
177
- options: Array.isArray(r.options)
178
- ? r.options.filter((x): x is string => typeof x === "string")
179
- : [],
180
- ...(typeof r.timeout === "number" ? { timeout: r.timeout } : {}),
228
+ title: reqStr(r, "title"),
229
+ options: strArrayField(r, "options", []),
230
+ ...optTimeout(r),
181
231
  };
182
232
  case "confirm":
183
233
  return {
184
234
  method: "confirm",
185
- title: typeof r.title === "string" ? r.title : "",
186
- message: typeof r.message === "string" ? r.message : "",
187
- ...(typeof r.timeout === "number" ? { timeout: r.timeout } : {}),
235
+ title: reqStr(r, "title"),
236
+ message: reqStr(r, "message"),
237
+ ...optTimeout(r),
188
238
  };
189
239
  case "input":
190
240
  return {
191
241
  method: "input",
192
- title: typeof r.title === "string" ? r.title : "",
193
- ...(typeof r.placeholder === "string" ? { placeholder: r.placeholder } : {}),
194
- ...(typeof r.timeout === "number" ? { timeout: r.timeout } : {}),
242
+ title: reqStr(r, "title"),
243
+ ...optPlaceholder(r),
244
+ ...optTimeout(r),
195
245
  };
196
246
  case "editor":
197
247
  return {
198
248
  method: "editor",
199
- title: typeof r.title === "string" ? r.title : "",
200
- ...(typeof r.prefill === "string" ? { prefill: r.prefill } : {}),
249
+ title: reqStr(r, "title"),
250
+ ...optPrefill(r),
201
251
  };
202
252
  case "notify":
203
253
  return {
204
254
  method: "notify",
205
- message: typeof r.message === "string" ? r.message : "",
206
- ...(r.notifyType === "info" || r.notifyType === "warning" || r.notifyType === "error"
207
- ? { notifyType: r.notifyType }
208
- : {}),
255
+ message: reqStr(r, "message"),
256
+ ...optNotifyType(r),
209
257
  };
210
258
  case "setStatus":
211
259
  return {
212
260
  method: "setStatus",
213
- statusKey: typeof r.statusKey === "string" ? r.statusKey : "",
261
+ statusKey: reqStr(r, "statusKey"),
214
262
  statusText: typeof r.statusText === "string" ? r.statusText : undefined,
215
263
  };
216
- case "setWidget": {
217
- const placement = r.widgetPlacement;
218
- const widgetLines = Array.isArray(r.widgetLines)
219
- ? r.widgetLines.filter((x): x is string => typeof x === "string")
220
- : undefined;
264
+ case "setWidget":
221
265
  return {
222
266
  method: "setWidget",
223
- widgetKey: typeof r.widgetKey === "string" ? r.widgetKey : "",
224
- widgetLines,
225
- ...(placement === "aboveEditor" || placement === "belowEditor"
226
- ? { widgetPlacement: placement }
227
- : {}),
267
+ widgetKey: reqStr(r, "widgetKey"),
268
+ widgetLines: strArrayField(r, "widgetLines", undefined),
269
+ ...optWidgetPlacement(r),
228
270
  };
229
- }
230
271
  case "setTitle":
231
272
  return {
232
273
  method: "setTitle",
233
- title: typeof r.title === "string" ? r.title : "",
274
+ title: reqStr(r, "title"),
234
275
  };
235
276
  case "set_editor_text":
236
277
  return {
237
278
  method: "set_editor_text",
238
- text: typeof r.text === "string" ? r.text : "",
279
+ text: reqStr(r, "text"),
239
280
  };
240
281
  default:
241
282
  // 未知 method:保留全部原始字段,避免协议演进时丢信息
@@ -273,7 +314,7 @@ export function parseSpawnLine(line: string): ParsedSpawnLine | null {
273
314
  return {
274
315
  kind: "invalid",
275
316
  raw: trimmed,
276
- error: err instanceof Error ? err.message : String(err),
317
+ error: toErrorMessage(err),
277
318
  };
278
319
  }
279
320
 
@@ -1,4 +1,4 @@
1
- // src/execution/stdin-writer.ts
1
+ // src/execution/engine/engines/pi/stdin-writer.ts
2
2
  //
3
3
  // 向 rpc 子进程 stdin 写入命令的 helper 集合。
4
4
  //
@@ -10,9 +10,10 @@
10
10
  import type { ChildProcess } from "node:child_process";
11
11
  import * as crypto from "node:crypto";
12
12
 
13
- import { getLogger } from "../core/logger.ts";
13
+ import { getLogger } from "../../../../core/logger.ts";
14
14
 
15
- import type { UiResponse } from "./dialog-queue.ts";
15
+ import type { UiResponse } from "../../../dialog-queue.ts";
16
+ import { toErrorMessage } from "../../../../core/error-message.ts";
16
17
 
17
18
  const logger = getLogger("subagents");
18
19
 
@@ -25,7 +26,7 @@ const logger = getLogger("subagents");
25
26
  * 是 stdin 域中立模块,epipe 计数属 stdin 错误域,职责合理。
26
27
  *
27
28
  * 错误处理两半面共用本计数器(合并计数,防 spawn→EPIPE→resume 死循环):
28
- * ① 同步 write 抛错(writeStdinLine throw → deliverMessage catch 递增)
29
+ * ① 同步 write 抛错(writeStdinLine throw → PiEngine.deliverPrompt catch 递增)
29
30
  * ② 异步 stream 'error' event(session-runner.ts child.stdin.on('error') 递增)
30
31
  */
31
32
  const epipeConsecutiveFailures = new Map<string, number>();
@@ -79,7 +80,7 @@ export function respond(child: ChildProcess, id: string, out: UiResponse, signal
79
80
  } catch (err) {
80
81
  // [R2] out.value 含循环引用/BigInt 等不可序列化结构——降级 cancelled,避免父进程崩溃。
81
82
  logger.warn(`[subagents] JSON.stringify failed for ui response ${id}, degrading to cancelled`, {
82
- detail: err instanceof Error ? err.message : String(err),
83
+ detail: toErrorMessage(err),
83
84
  });
84
85
  line = JSON.stringify({ type: "extension_ui_response", id, cancelled: true });
85
86
  }
@@ -158,7 +159,7 @@ export function sendGetStateCommand(child: ChildProcess): string {
158
159
  *
159
160
  * [R1] write 返回 false 时记 warn(不阻塞,内核缓冲会随后排空)。
160
161
  * [R3] write 抛 EPIPE / ERR_STREAM_DESTROYED 时 throw 含 EPIPE 关键词的 Error,
161
- * 让上层(deliverMessage)能捕获并自动转冷路径 resume。
162
+ * 让上层(PiEngine.deliverPrompt)能捕获并自动转冷路径 resume。
162
163
  * stdin 已关闭/销毁时跳过——respond 已检查 signal,sendPromptCommand 已检查 destroyed。
163
164
  *
164
165
  * @param child 子进程
@@ -173,11 +174,11 @@ function writeStdinLine(child: ChildProcess, line: string, warnTag: string): voi
173
174
  if (!ok) logger.warn(`[subagents] stdin backpressure on ${warnTag}`);
174
175
  } catch (err) {
175
176
  // [R3] EPIPE / ERR_STREAM_DESTROYED:stdin 管道已断,子进程已退出或 stdin 被销毁。
176
- // [v4 A-1] 错误处理两半面:① 同步 write 抛错(本 catch)——上层 deliverMessage 捕获后
177
+ // [v4 A-1] 错误处理两半面:① 同步 write 抛错(本 catch)——上层(PiEngine.deliverPrompt)捕获后
177
178
  // 调 recordEpipeFailure 递增计数;② 异步 stream 'error' event(session-runner.ts 的
178
179
  // child.stdin.on('error') listener)。两者共用本模块 export 的 recordEpipeFailure
179
180
  // helper 合并计数(防 spawn→EPIPE→resume 死循环)。
180
- // throw 让上层(deliverMessage)捕获并自动转冷路径 resume + 消息重放。
181
+ // throw 让上层(PiEngine.deliverPrompt)捕获并自动转冷路径 resume + 消息重放。
181
182
  if (
182
183
  err !== null &&
183
184
  typeof err === "object" &&
@@ -192,7 +193,7 @@ function writeStdinLine(child: ChildProcess, line: string, warnTag: string): voi
192
193
  }
193
194
  // 非 EPIPE 错误(不应发生,但兜底降级为 warn 不崩溃)
194
195
  logger.warn(`[subagents] unexpected stdin write error on ${warnTag}`, {
195
- detail: err instanceof Error ? err.message : String(err),
196
+ detail: toErrorMessage(err),
196
197
  });
197
198
  }
198
199
  }
@@ -1,4 +1,4 @@
1
- // src/core/temp-prompt.ts
1
+ // src/execution/engine/engines/pi/temp-prompt.ts
2
2
  //
3
3
  // 将 agent systemPrompt 写入临时文件,供 pi CLI --append-system-prompt 使用。
4
4
  // Core 叶子原语(node 内置 + 同目录 bestEffort 清理 helper)。注意 bestEffort
@@ -14,7 +14,7 @@ import * as fs from "node:fs";
14
14
  import * as os from "node:os";
15
15
  import * as path from "node:path";
16
16
 
17
- import { bestEffort } from "./best-effort.ts";
17
+ import { bestEffort } from "../../../best-effort.ts";
18
18
 
19
19
  /** 临时 prompt 文件创建结果。dir 供调用方清理。 */
20
20
  export interface TempPromptFile {
@@ -1,4 +1,4 @@
1
- // src/core/turn-limiter.ts
1
+ // src/execution/engine/engines/pi/turn-limiter.ts
2
2
  //
3
3
  // soft/hard turn 限制器。maxTurns 到达 → steer 提醒收尾;
4
4
  // graceTurns 后仍不结束 → abort。
@@ -43,13 +43,29 @@
43
43
  * sendPushes?: [frame, ...] send 应答前逐帧推送(推送流 + 终态帧全显式
44
44
  * 逐字回放,不经 withExtra 改写)
45
45
  * sendResult?: object 缺省 {accepted:true}
46
+ * crashAfterSendMs?: number [P0-1 U4] send 应答后 N ms 自杀 exit(1)(连接
47
+ * 崩溃收割注入——onClose → failAllTurns 在途
48
+ * turn 收割;进程死 → 下次 request 惰性重建
49
+ * boot 新代重读 scenario,重试轮/下一任务形态
50
+ * 切换经测试侧 rewriteScenario)
51
+ * rebootSendPushes?: [frame, ...] [P0-1 U4] 非首代进程(本 fake 启动时 state 流水
52
+ * 已有 boot 记录——崩溃/杀链后的重建代)的 send
53
+ * 推送序列,替代 sendPushes:崩溃后惰性重建的
54
+ * 重试轮拿到不同行为(如完整终态流)——首轮挂起
55
+ * + 重试轮成功的静态注入通道(同任务重试轮无法
56
+ * 经测试侧 rewriteScenario 插手,run 整体 await)
46
57
  * readError?: {code,message,data} read 应答 error 帧(read 兜底降级链断言)
47
58
  * readResult?: object 覆盖 read 应答
48
- * stopBehavior?: 'terminal'|'none' session/stop 的行为(R4 abort 链断言面):
59
+ * stopBehavior?: 'terminal'|'none'|'hang'
60
+ * session/stop 的行为(R4 abort 链断言面):
49
61
  * 'terminal'(缺省)= stop 时推送该会话的
50
62
  * turn.terminal 终态帧(stop 优雅生效——不杀
51
63
  * 进程的 abort 路径);'none' = 只应答不推终态
52
- * (grace 窗口耗尽 → killChain 兜底路径)
64
+ * (grace 窗口耗尽 → killChain 兜底路径);
65
+ * 'hang' = 连应答都不给(P0-1 U2 超时入口态③——
66
+ * 控制面假死注入,stop 3s 超时 → 连接级失败判据)
67
+ * stopError?: {code,message,data} stop 应答 error 帧(P0-1 U2 超时入口态②——
68
+ * 协议性 error(如会话已回收)注入,断言不升级杀链)
53
69
  * }
54
70
  *
55
71
  * 多会话支持(R4 引擎接线 / RA3 双会话地基):
@@ -59,15 +75,6 @@
59
75
  * (缺省关:R2/R3 单会话用例的字节级行为不变。)
60
76
  * session/stop 应答 {stopped:true};按 scenario.stopBehavior 决定是否
61
77
  * 推送终态帧(见上)。stopTerminal 推送同样受 STAMP 改写。
62
- *
63
- * 探针连接支持(R5 降级链——D8 冒烟探针 / D2 门控断言面):
64
- * ZCODE_APPSERVER_PROBE_CONN=1 本进程是探针连接(引擎 runAppServerSmokeProbe 叠加
65
- * 的 env 标记):scenario 只读 FAKE_PROBE_SCENARIO(常驻
66
- * 主连接的 FAKE_SESSION_SCENARIO 不作用于探针——故障注入可
67
- * 只命中主连接或只命中探针);env 快照记 probe 标志。
68
- * FAKE_PROBE_SCENARIO=<path> 仅探针进程消费的 JSON:
69
- * { createError?: {code,message,data} } 探针 create 应答 error 帧(探针失败注入)
70
- * { hangCreate?: true } create 永不应答(预算超时注入)
71
78
  */
72
79
  import fs from 'node:fs';
73
80
  import readline from 'node:readline';
@@ -77,25 +84,28 @@ const EXTRA_KEYS = process.env.FAKE_EXTRA_KEYS === '1';
77
84
  const PROTOCOL_AS_PUSH = process.env.FAKE_PROTOCOL_PUSH === '1';
78
85
  // [R4] 多会话推送改写开关(见文件头注释)
79
86
  const STAMP_SESSION = process.env.FAKE_STAMP_SESSION === '1';
80
- // [R5] 探针连接判定(引擎探针在 env 叠 ZCODE_APPSERVER_PROBE_CONN=1——见 appserver-probe.ts)
81
- const IS_PROBE = process.env.ZCODE_APPSERVER_PROBE_CONN === '1';
82
87
 
83
- // 会话场景(R3/R5):启动时读取一次(env 固化语义与其他 FAKE_ 开关一致)。探针进程
84
- // 只读 FAKE_PROBE_SCENARIO(与主连接的故障注入互不串扰)
88
+ // 会话场景(R3):启动时读取一次(env 固化语义与其他 FAKE_ 开关一致)
85
89
  let SCENARIO = null;
86
- if (process.env.FAKE_SESSION_SCENARIO && !IS_PROBE) {
90
+ if (process.env.FAKE_SESSION_SCENARIO) {
87
91
  try {
88
92
  SCENARIO = JSON.parse(fs.readFileSync(process.env.FAKE_SESSION_SCENARIO, 'utf8'));
89
93
  } catch (err) {
90
94
  log('scenario-load-failed', { message: String(err && err.message) });
91
95
  }
92
96
  }
93
- if (process.env.FAKE_PROBE_SCENARIO && IS_PROBE) {
97
+
98
+ // [P0-1 U4] 本进程代数(state 流水已有 boot 记录数 + 1):崩溃/杀链后的惰性重建代
99
+ // ≥2——rebootSendPushes 仅对重建代生效(重试轮拿到与首轮不同的推送序列)
100
+ let BOOT_GEN = 1;
101
+ if (STATE_FILE && SCENARIO && SCENARIO.rebootSendPushes) {
94
102
  try {
95
- SCENARIO = JSON.parse(fs.readFileSync(process.env.FAKE_PROBE_SCENARIO, 'utf8'));
96
- } catch (err) {
97
- log('scenario-load-failed', { message: String(err && err.message) });
98
- }
103
+ const priorBoots = fs
104
+ .readFileSync(STATE_FILE, 'utf8')
105
+ .split('\n')
106
+ .filter((l) => l.includes('"ev":"boot"')).length;
107
+ BOOT_GEN = priorBoots + 1;
108
+ } catch { /* 流水读失败按首代处理 */ }
99
109
  }
100
110
 
101
111
  let seq = 0;
@@ -130,7 +140,6 @@ log('env', {
130
140
  telemetry: process.env.ZCODE_MODEL_TELEMETRY_ENABLED,
131
141
  nested: process.env.ZSW_NESTED,
132
142
  unifiedNested: process.env.XYZ_AGENT_SUBAGENT,
133
- probe: process.env.ZCODE_APPSERVER_PROBE_CONN,
134
143
  });
135
144
  log('boot', { pid: process.pid, argv: process.argv.slice(2) });
136
145
  if (process.env.FAKE_STDERR === '1') {
@@ -212,8 +221,6 @@ async function handleRequest(f) {
212
221
  process.exit(1);
213
222
  return; // 不可达(exit 先行),保持 switch 完整
214
223
  case 'session/create': {
215
- // [R5] 探针预算超时注入:hangCreate 时永不应答(探针 deadline 收割判据)
216
- if (SCENARIO && SCENARIO.hangCreate) return;
217
224
  if (SCENARIO && SCENARIO.createError) {
218
225
  return replyErr(id, SCENARIO.createError.code, SCENARIO.createError.message, SCENARIO.createError.data);
219
226
  }
@@ -228,13 +235,33 @@ async function handleRequest(f) {
228
235
  if (SCENARIO && SCENARIO.sendError) {
229
236
  return replyErr(id, SCENARIO.sendError.code, SCENARIO.sendError.message, SCENARIO.sendError.data);
230
237
  }
231
- // 推送帧逐字回放(STAMP_SESSION 时按目标会话归因改写)
232
- pushFrames(SCENARIO && SCENARIO.sendPushes, String(params.sessionId || ''));
238
+ // 推送帧逐字回放(STAMP_SESSION 时按目标会话归因改写);重建代走 rebootSendPushes
239
+ // (U4:重试轮的不同行为通道)
240
+ const pushes =
241
+ BOOT_GEN > 1 && SCENARIO && SCENARIO.rebootSendPushes
242
+ ? SCENARIO.rebootSendPushes
243
+ : SCENARIO && SCENARIO.sendPushes;
244
+ pushFrames(pushes, String(params.sessionId || ''));
245
+ // [P0-1 U4] 崩溃收割注入:应答后 N ms 自杀(onClose → failAllTurns 在途 turn
246
+ // 收割的确定性触发面;exit(1) 非零码与 test/suicide 同形态)
247
+ const crashAfterSendMs = SCENARIO && SCENARIO.crashAfterSendMs;
248
+ if (typeof crashAfterSendMs === 'number' && crashAfterSendMs >= 0) {
249
+ setTimeout(() => {
250
+ log('crash-injected', { afterMs: crashAfterSendMs });
251
+ process.exit(1);
252
+ }, crashAfterSendMs).unref();
253
+ }
233
254
  return reply(id, (SCENARIO && SCENARIO.sendResult) || { accepted: true });
234
255
  }
235
256
  case 'session/stop': {
236
- // [R4] abort 链断言面:缺省推终态(stop 优雅生效);stopBehavior:'none' 只应答
257
+ // [R4] abort 链断言面:缺省推终态(stop 优雅生效);stopBehavior:'none' 只应答;
258
+ // stopError 注入协议性 error 应答帧(P0-1 U2 态②——不升级杀链判据);
259
+ // stopBehavior:'hang' 永不应答(态③——stop 3s 超时 = 连接级失败判据)
237
260
  const behavior = (SCENARIO && SCENARIO.stopBehavior) || 'terminal';
261
+ if (behavior === 'hang') return;
262
+ if (SCENARIO && SCENARIO.stopError) {
263
+ return replyErr(id, SCENARIO.stopError.code, SCENARIO.stopError.message, SCENARIO.stopError.data);
264
+ }
238
265
  if (behavior === 'terminal') {
239
266
  pushFrames([TURN_TERMINAL_FRAME], String(params.sessionId || ''));
240
267
  }