@sema-agent/server 1.323.0 → 2.0.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 (539) hide show
  1. package/dist/approval-hmac.d.ts +40 -0
  2. package/dist/approval-hmac.js +67 -0
  3. package/dist/approval.d.ts +31 -0
  4. package/dist/approval.js +72 -4
  5. package/dist/audit.d.ts +26 -0
  6. package/dist/audit.js +40 -1
  7. package/dist/auth-bridge.d.ts +10 -0
  8. package/dist/auth-bridge.js +47 -4
  9. package/dist/auth-keys.d.ts +19 -0
  10. package/dist/auth-keys.js +13 -0
  11. package/dist/bake-runner/main.d.ts +5 -0
  12. package/dist/bake-runner/main.js +43 -4
  13. package/dist/bake-runner/protocol.d.ts +57 -0
  14. package/dist/bake-runner/protocol.js +58 -3
  15. package/dist/bake-runner/runner.d.ts +54 -0
  16. package/dist/bake-runner/runner.js +87 -5
  17. package/dist/bench/l8/artifact.d.ts +63 -0
  18. package/dist/bench/l8/artifact.js +61 -2
  19. package/dist/bench/l8/escape.d.ts +36 -0
  20. package/dist/bench/l8/escape.js +25 -0
  21. package/dist/bench/l8/index.d.ts +14 -0
  22. package/dist/bench/l8/index.js +14 -0
  23. package/dist/bench/l8/probes.d.ts +74 -0
  24. package/dist/bench/l8/probes.js +60 -0
  25. package/dist/bench/l8/run-probes.d.ts +43 -0
  26. package/dist/bench/l8/run-probes.js +45 -2
  27. package/dist/bench/s1/arms.d.ts +126 -0
  28. package/dist/bench/s1/arms.js +188 -13
  29. package/dist/bench/s1/live-deps.d.ts +66 -0
  30. package/dist/bench/s1/live-deps.js +249 -11
  31. package/dist/bench/s1/oracle.d.ts +49 -0
  32. package/dist/bench/s1/oracle.js +36 -1
  33. package/dist/bench/s1/repair-oracle-adapter.d.ts +33 -0
  34. package/dist/bench/s1/repair-oracle-adapter.js +30 -0
  35. package/dist/bench/s1/reviewer.d.ts +38 -0
  36. package/dist/bench/s1/reviewer.js +34 -0
  37. package/dist/bench/s1/row.d.ts +77 -0
  38. package/dist/bench/s1/row.js +62 -0
  39. package/dist/bench/s1/run-firm.d.ts +47 -0
  40. package/dist/bench/s1/run-firm.js +70 -4
  41. package/dist/bench/s1/runner-ctx.d.ts +71 -0
  42. package/dist/bench/s1/runner-ctx.js +36 -0
  43. package/dist/bench/s1/tasks.d.ts +108 -0
  44. package/dist/bench/s1/tasks.js +115 -0
  45. package/dist/boot-reclaim.d.ts +19 -0
  46. package/dist/boot-reclaim.js +20 -0
  47. package/dist/brain.d.ts +25 -0
  48. package/dist/brain.js +61 -1
  49. package/dist/budget.d.ts +66 -0
  50. package/dist/budget.js +128 -4
  51. package/dist/capabilities/builtin-tools.d.ts +3 -0
  52. package/dist/capabilities/builtin-tools.js +3 -0
  53. package/dist/capabilities/center-plugins.d.ts +17 -1
  54. package/dist/capabilities/center-plugins.js +45 -4
  55. package/dist/capabilities/center-prompts.d.ts +46 -0
  56. package/dist/capabilities/center-prompts.js +57 -3
  57. package/dist/capabilities/code-review-council.d.ts +28 -0
  58. package/dist/capabilities/code-review-council.js +40 -7
  59. package/dist/capabilities/collab-wire.d.ts +2 -0
  60. package/dist/capabilities/collab-workflows.d.ts +7 -0
  61. package/dist/capabilities/collab-workflows.js +44 -1
  62. package/dist/capabilities/oa-tools.d.ts +6 -0
  63. package/dist/capabilities/oa-tools.js +10 -0
  64. package/dist/capabilities/prompt.d.ts +14 -0
  65. package/dist/capabilities/prompt.js +14 -0
  66. package/dist/capabilities/prompts/code-review.d.ts +14 -0
  67. package/dist/capabilities/prompts/code-review.js +14 -0
  68. package/dist/capabilities/prompts/identity.d.ts +6 -0
  69. package/dist/capabilities/prompts/identity.js +6 -0
  70. package/dist/capabilities/prompts/team.d.ts +4 -0
  71. package/dist/capabilities/prompts/team.js +4 -0
  72. package/dist/capabilities/repo-tools.d.ts +11 -0
  73. package/dist/capabilities/repo-tools.js +8 -0
  74. package/dist/capabilities/sandbox-file-send.d.ts +95 -0
  75. package/dist/capabilities/sandbox-file-send.js +91 -3
  76. package/dist/capabilities/scenarios.d.ts +130 -0
  77. package/dist/capabilities/scenarios.js +180 -7
  78. package/dist/capabilities/select-environment-tool.d.ts +7 -0
  79. package/dist/capabilities/select-environment-tool.js +30 -0
  80. package/dist/capabilities/send-user-file-tool.d.ts +33 -0
  81. package/dist/capabilities/send-user-file-tool.js +65 -1
  82. package/dist/capabilities/skills.d.ts +29 -0
  83. package/dist/capabilities/skills.js +13 -2
  84. package/dist/capabilities/team.d.ts +22 -0
  85. package/dist/capabilities/team.js +22 -2
  86. package/dist/capabilities/tool-defer.d.ts +26 -0
  87. package/dist/capabilities/tool-defer.js +3 -0
  88. package/dist/config-center/apply-effective.d.ts +65 -0
  89. package/dist/config-center/apply-effective.js +204 -12
  90. package/dist/config-center/http-client.d.ts +34 -0
  91. package/dist/config-center/http-client.js +68 -0
  92. package/dist/config-center/restart-signal.d.ts +22 -0
  93. package/dist/config-center/restart-signal.js +39 -0
  94. package/dist/config-center/skills-mcp.d.ts +20 -1
  95. package/dist/config-center/skills-mcp.js +42 -7
  96. package/dist/config-center/types.d.ts +92 -1
  97. package/dist/config-lkg.d.ts +12 -0
  98. package/dist/config-lkg.js +41 -0
  99. package/dist/config-provider.d.ts +78 -0
  100. package/dist/config-provider.js +165 -2
  101. package/dist/config-types.d.ts +546 -0
  102. package/dist/config.d.ts +64 -0
  103. package/dist/config.js +455 -60
  104. package/dist/degenerate-instrument.d.ts +38 -0
  105. package/dist/degenerate-instrument.js +55 -3
  106. package/dist/elicitation.d.ts +39 -0
  107. package/dist/elicitation.js +87 -3
  108. package/dist/env-facts.d.ts +61 -0
  109. package/dist/env-facts.js +73 -7
  110. package/dist/fleet/fleet-bus.d.ts +185 -0
  111. package/dist/fleet/fleet-bus.js +333 -27
  112. package/dist/fleet/subagent-tail-bus.d.ts +11 -0
  113. package/dist/fleet/subagent-tail-bus.js +33 -2
  114. package/dist/fleet-client.d.ts +38 -0
  115. package/dist/fleet-client.js +44 -9
  116. package/dist/fleet-lease.d.ts +46 -0
  117. package/dist/fleet-lease.js +73 -5
  118. package/dist/hooks/branch-transcript.d.ts +8 -0
  119. package/dist/hooks/branch-transcript.js +33 -0
  120. package/dist/hooks/cc-stop-prompt.d.ts +42 -0
  121. package/dist/hooks/cc-stop-prompt.js +43 -1
  122. package/dist/hooks/hook-llm.d.ts +15 -0
  123. package/dist/hooks/hook-llm.js +47 -0
  124. package/dist/hooks/hook-runner.d.ts +89 -0
  125. package/dist/hooks/hook-runner.js +327 -18
  126. package/dist/http/idempotency.d.ts +31 -0
  127. package/dist/http/idempotency.js +34 -0
  128. package/dist/http/principal-gate.d.ts +17 -0
  129. package/dist/http/principal-gate.js +35 -3
  130. package/dist/http/route-ctx.d.ts +36 -0
  131. package/dist/http/routes/approvals-assistant.d.ts +25 -0
  132. package/dist/http/routes/approvals-assistant.js +253 -23
  133. package/dist/http/routes/attachments.js +22 -4
  134. package/dist/http/routes/capabilities.d.ts +7 -0
  135. package/dist/http/routes/capabilities.js +202 -1
  136. package/dist/http/routes/fleet.d.ts +6 -0
  137. package/dist/http/routes/fleet.js +94 -5
  138. package/dist/http/routes/images.d.ts +17 -0
  139. package/dist/http/routes/images.js +222 -14
  140. package/dist/http/routes/leader.d.ts +7 -0
  141. package/dist/http/routes/leader.js +10 -0
  142. package/dist/http/routes/memory-policy.d.ts +6 -0
  143. package/dist/http/routes/memory-policy.js +38 -6
  144. package/dist/http/routes/notify-wake.d.ts +10 -0
  145. package/dist/http/routes/notify-wake.js +19 -3
  146. package/dist/http/routes/observability.d.ts +6 -0
  147. package/dist/http/routes/observability.js +19 -2
  148. package/dist/http/routes/runs.d.ts +15 -0
  149. package/dist/http/routes/runs.js +464 -41
  150. package/dist/http/routes/session-sync.d.ts +15 -0
  151. package/dist/http/routes/session-sync.js +229 -19
  152. package/dist/http/routes/sessions-list.d.ts +6 -0
  153. package/dist/http/routes/sessions-list.js +35 -4
  154. package/dist/http/routes/sessions.d.ts +14 -0
  155. package/dist/http/routes/sessions.js +176 -31
  156. package/dist/http/routes/side-query.d.ts +8 -0
  157. package/dist/http/routes/side-query.js +26 -1
  158. package/dist/http/routes/tasks.d.ts +18 -0
  159. package/dist/http/routes/tasks.js +501 -38
  160. package/dist/http/routes/trace-usage.d.ts +10 -0
  161. package/dist/http/routes/trace-usage.js +66 -14
  162. package/dist/http/routes/workflows.d.ts +12 -0
  163. package/dist/http/routes/workflows.js +180 -19
  164. package/dist/http/run-meta.d.ts +11 -0
  165. package/dist/http/run-meta.js +6 -0
  166. package/dist/http/send.d.ts +19 -0
  167. package/dist/http/send.js +11 -0
  168. package/dist/http/server.d.ts +255 -0
  169. package/dist/http/server.js +921 -75
  170. package/dist/http/sse-log.d.ts +15 -0
  171. package/dist/http/sse-log.js +16 -0
  172. package/dist/http/tar.d.ts +9 -0
  173. package/dist/http/tar.js +21 -5
  174. package/dist/http/wire-gate.d.ts +9 -0
  175. package/dist/http/wire-gate.js +9 -0
  176. package/dist/http/wire-types.d.ts +187 -0
  177. package/dist/http/workspace-content.d.ts +8 -0
  178. package/dist/http/workspace-content.js +10 -0
  179. package/dist/images/bake-validate.d.ts +63 -0
  180. package/dist/images/bake-validate.js +71 -1
  181. package/dist/images/manifest.d.ts +19 -0
  182. package/dist/images/manifest.js +6 -1
  183. package/dist/index.d.ts +1 -5
  184. package/dist/index.js +10 -5
  185. package/dist/key-resolver.d.ts +23 -0
  186. package/dist/key-resolver.js +27 -2
  187. package/dist/leader/diffout.d.ts +23 -0
  188. package/dist/leader/diffout.js +8 -1
  189. package/dist/leader/diffup.d.ts +32 -0
  190. package/dist/leader/diffup.js +43 -0
  191. package/dist/leader/endpoint.d.ts +20 -0
  192. package/dist/leader/endpoint.js +25 -2
  193. package/dist/leader/fanout.d.ts +60 -0
  194. package/dist/leader/fanout.js +29 -3
  195. package/dist/leader/grader-env-factory.d.ts +74 -0
  196. package/dist/leader/grader-env-factory.js +62 -3
  197. package/dist/leader/leader.d.ts +97 -0
  198. package/dist/leader/leader.js +151 -4
  199. package/dist/leader/merge.d.ts +94 -0
  200. package/dist/leader/merge.js +112 -9
  201. package/dist/leader/planner.d.ts +52 -0
  202. package/dist/leader/planner.js +47 -3
  203. package/dist/leader/repair-oracle.d.ts +61 -0
  204. package/dist/leader/repair-oracle.js +59 -1
  205. package/dist/leader/repair-wire.d.ts +78 -0
  206. package/dist/leader/repair-wire.js +79 -2
  207. package/dist/leader/wire.d.ts +79 -0
  208. package/dist/leader/wire.js +255 -8
  209. package/dist/lsp/e2b-bridge.d.ts +16 -0
  210. package/dist/lsp/e2b-bridge.js +32 -4
  211. package/dist/lsp/e2b-manager.d.ts +10 -0
  212. package/dist/lsp/e2b-manager.js +18 -2
  213. package/dist/lsp/lsp-frames.d.ts +12 -0
  214. package/dist/lsp/lsp-frames.js +12 -0
  215. package/dist/lsp/manager.d.ts +12 -0
  216. package/dist/lsp/manager.js +35 -2
  217. package/dist/lsp/types.d.ts +10 -0
  218. package/dist/lsp/ws-transport.d.ts +12 -0
  219. package/dist/lsp/ws-transport.js +53 -5
  220. package/dist/lsp-evict.d.ts +14 -0
  221. package/dist/lsp-evict.js +15 -1
  222. package/dist/main.js +2132 -96
  223. package/dist/memory-export.d.ts +1 -0
  224. package/dist/memory-export.js +4 -0
  225. package/dist/memory-scope.d.ts +49 -0
  226. package/dist/memory-scope.js +87 -4
  227. package/dist/memory-sync-client.d.ts +24 -0
  228. package/dist/memory-sync-client.js +41 -2
  229. package/dist/memory-sync.d.ts +23 -0
  230. package/dist/memory-sync.js +70 -1
  231. package/dist/model-select.d.ts +39 -0
  232. package/dist/model-select.js +42 -1
  233. package/dist/observability/cost-quota.d.ts +20 -0
  234. package/dist/observability/cost-quota.js +4 -0
  235. package/dist/observability/cost-taxonomy.d.ts +45 -0
  236. package/dist/observability/cost-taxonomy.js +34 -0
  237. package/dist/observability/logger.d.ts +1 -0
  238. package/dist/observability/logger.js +6 -0
  239. package/dist/observability/metrics.d.ts +13 -0
  240. package/dist/observability/metrics.js +63 -0
  241. package/dist/observability/otel-exporter.d.ts +9 -0
  242. package/dist/observability/otel-exporter.js +11 -3
  243. package/dist/observability/principal-context.d.ts +9 -0
  244. package/dist/observability/principal-context.js +9 -0
  245. package/dist/observability/prompt-manifest.d.ts +37 -0
  246. package/dist/observability/prompt-manifest.js +35 -1
  247. package/dist/observability/rate-limit.d.ts +10 -0
  248. package/dist/observability/rate-limit.js +1 -0
  249. package/dist/observability/tool-trace.d.ts +24 -0
  250. package/dist/observability/tool-trace.js +41 -1
  251. package/dist/orchestration/hardened-vm-runner.d.ts +107 -0
  252. package/dist/orchestration/hardened-vm-runner.js +119 -4
  253. package/dist/orchestration/hardened-vm-worker-runner.d.ts +14 -0
  254. package/dist/orchestration/hardened-vm-worker-runner.js +26 -1
  255. package/dist/orchestration/hardened-vm-worker.js +27 -0
  256. package/dist/orchestration/subagent-steer.d.ts +44 -0
  257. package/dist/orchestration/subagent-steer.js +45 -1
  258. package/dist/orchestration/workflow-agent-steer.d.ts +54 -0
  259. package/dist/orchestration/workflow-agent-steer.js +80 -1
  260. package/dist/orchestration/workflow-completion-inbox.d.ts +189 -2
  261. package/dist/orchestration/workflow-completion-inbox.js +283 -32
  262. package/dist/orchestration/workflow-notify-journal.d.ts +132 -1
  263. package/dist/orchestration/workflow-notify-journal.js +187 -13
  264. package/dist/parked-decide.d.ts +61 -0
  265. package/dist/parked-decide.js +58 -1
  266. package/dist/per-task-image.d.ts +54 -0
  267. package/dist/per-task-image.js +41 -0
  268. package/dist/plan-cache-probe.d.ts +35 -0
  269. package/dist/plan-cache-probe.js +18 -3
  270. package/dist/plugins/approval-exemption-store.d.ts +7 -0
  271. package/dist/plugins/approval-exemption-store.js +28 -2
  272. package/dist/plugins/approval-store-sql.d.ts +64 -0
  273. package/dist/plugins/approval-store-sql.js +32 -0
  274. package/dist/plugins/background-agent-store-sql.d.ts +55 -0
  275. package/dist/plugins/background-agent-store-sql.js +91 -4
  276. package/dist/plugins/background-shell-support.d.ts +98 -0
  277. package/dist/plugins/background-shell-support.js +117 -13
  278. package/dist/plugins/blob-backend.d.ts +104 -0
  279. package/dist/plugins/blob-backend.js +163 -6
  280. package/dist/plugins/breaker-state-sql.d.ts +65 -1
  281. package/dist/plugins/breaker-state-sql.js +46 -8
  282. package/dist/plugins/caching-session-store.d.ts +42 -0
  283. package/dist/plugins/caching-session-store.js +63 -3
  284. package/dist/plugins/checkpoint-store-sql.d.ts +179 -0
  285. package/dist/plugins/checkpoint-store-sql.js +239 -11
  286. package/dist/plugins/file-outcome-sink.d.ts +4 -0
  287. package/dist/plugins/file-outcome-sink.js +9 -0
  288. package/dist/plugins/file-resume-anchor-store.d.ts +20 -0
  289. package/dist/plugins/file-resume-anchor-store.js +43 -4
  290. package/dist/plugins/file-run-store.d.ts +90 -0
  291. package/dist/plugins/file-run-store.js +145 -13
  292. package/dist/plugins/file-snapshot-store-sql.d.ts +133 -1
  293. package/dist/plugins/file-snapshot-store-sql.js +178 -10
  294. package/dist/plugins/file-workflow-journal-store.d.ts +10 -0
  295. package/dist/plugins/file-workflow-journal-store.js +10 -0
  296. package/dist/plugins/fork-routing-session-store.d.ts +47 -0
  297. package/dist/plugins/fork-routing-session-store.js +51 -3
  298. package/dist/plugins/host-platform.d.ts +69 -0
  299. package/dist/plugins/host-platform.js +81 -2
  300. package/dist/plugins/image-bake-store-sql.d.ts +136 -1
  301. package/dist/plugins/image-bake-store-sql.js +241 -7
  302. package/dist/plugins/image-index-sql.d.ts +46 -0
  303. package/dist/plugins/image-index-sql.js +113 -4
  304. package/dist/plugins/k8s-bg-scripts.d.ts +34 -0
  305. package/dist/plugins/k8s-bg-scripts.js +88 -4
  306. package/dist/plugins/k8s-exec-protocol.d.ts +33 -0
  307. package/dist/plugins/k8s-exec-protocol.js +41 -0
  308. package/dist/plugins/local-checkpoint-store.d.ts +40 -0
  309. package/dist/plugins/local-checkpoint-store.js +86 -7
  310. package/dist/plugins/local-session-store.d.ts +157 -0
  311. package/dist/plugins/local-session-store.js +289 -34
  312. package/dist/plugins/local-task-attachment-store.js +14 -2
  313. package/dist/plugins/mailbox-store-sql.d.ts +38 -0
  314. package/dist/plugins/mailbox-store-sql.js +39 -6
  315. package/dist/plugins/memory-engine-pg.d.ts +30 -0
  316. package/dist/plugins/memory-engine-pg.js +122 -4
  317. package/dist/plugins/memory-engine-tidb.d.ts +26 -0
  318. package/dist/plugins/memory-engine-tidb.js +115 -5
  319. package/dist/plugins/memory-engine-vector-util.d.ts +5 -0
  320. package/dist/plugins/memory-engine-vector-util.js +5 -0
  321. package/dist/plugins/memory-resume-anchor-store.d.ts +8 -0
  322. package/dist/plugins/memory-resume-anchor-store.js +17 -0
  323. package/dist/plugins/memory-run-store.d.ts +63 -0
  324. package/dist/plugins/memory-run-store.js +73 -8
  325. package/dist/plugins/memory-session-policy-store.d.ts +17 -0
  326. package/dist/plugins/memory-session-policy-store.js +17 -0
  327. package/dist/plugins/memory-sync-store-pg.d.ts +42 -0
  328. package/dist/plugins/memory-sync-store-pg.js +45 -2
  329. package/dist/plugins/memory-sync-store-tidb.d.ts +9 -0
  330. package/dist/plugins/memory-sync-store-tidb.js +31 -1
  331. package/dist/plugins/outcome-ledger-sql.d.ts +63 -0
  332. package/dist/plugins/outcome-ledger-sql.js +97 -3
  333. package/dist/plugins/pg-approval-store.d.ts +7 -0
  334. package/dist/plugins/pg-approval-store.js +7 -0
  335. package/dist/plugins/pg-breaker-state.d.ts +6 -0
  336. package/dist/plugins/pg-breaker-state.js +6 -0
  337. package/dist/plugins/pg-checkpoint-store.d.ts +8 -0
  338. package/dist/plugins/pg-checkpoint-store.js +8 -0
  339. package/dist/plugins/pg-cost-quota.d.ts +17 -0
  340. package/dist/plugins/pg-cost-quota.js +6 -0
  341. package/dist/plugins/pg-file-snapshot-store.d.ts +6 -0
  342. package/dist/plugins/pg-file-snapshot-store.js +6 -0
  343. package/dist/plugins/pg-image-bake.d.ts +9 -0
  344. package/dist/plugins/pg-image-bake.js +9 -0
  345. package/dist/plugins/pg-image-index.d.ts +9 -0
  346. package/dist/plugins/pg-image-index.js +9 -0
  347. package/dist/plugins/pg-outcome-ledger.d.ts +9 -0
  348. package/dist/plugins/pg-outcome-ledger.js +9 -0
  349. package/dist/plugins/pg-pool.d.ts +50 -0
  350. package/dist/plugins/pg-pool.js +78 -0
  351. package/dist/plugins/pg-query.d.ts +11 -0
  352. package/dist/plugins/pg-rate-limiter.d.ts +23 -0
  353. package/dist/plugins/pg-rate-limiter.js +12 -2
  354. package/dist/plugins/pg-resume-anchor-store.d.ts +5 -0
  355. package/dist/plugins/pg-resume-anchor-store.js +5 -0
  356. package/dist/plugins/pg-run-store.d.ts +7 -0
  357. package/dist/plugins/pg-run-store.js +7 -0
  358. package/dist/plugins/pg-safe-json.d.ts +13 -0
  359. package/dist/plugins/pg-safe-json.js +40 -4
  360. package/dist/plugins/pg-session-policy-store.d.ts +5 -0
  361. package/dist/plugins/pg-session-policy-store.js +5 -0
  362. package/dist/plugins/pg-session-storage.d.ts +72 -0
  363. package/dist/plugins/pg-session-storage.js +152 -20
  364. package/dist/plugins/pg-session-store.d.ts +10 -0
  365. package/dist/plugins/pg-session-store.js +10 -0
  366. package/dist/plugins/pg-tool-result-store.d.ts +7 -0
  367. package/dist/plugins/pg-tool-result-store.js +7 -0
  368. package/dist/plugins/pg-workflow-journal-store.d.ts +7 -0
  369. package/dist/plugins/pg-workflow-journal-store.js +7 -0
  370. package/dist/plugins/pg-workflow-run-store.d.ts +7 -0
  371. package/dist/plugins/pg-workflow-run-store.js +7 -0
  372. package/dist/plugins/posix-shell-fs.d.ts +3 -0
  373. package/dist/plugins/posix-shell-fs.js +31 -1
  374. package/dist/plugins/remote-env-adb.d.ts +25 -0
  375. package/dist/plugins/remote-env-adb.js +95 -12
  376. package/dist/plugins/remote-env-e2b.d.ts +146 -0
  377. package/dist/plugins/remote-env-e2b.js +371 -40
  378. package/dist/plugins/remote-env-file-error.d.ts +34 -0
  379. package/dist/plugins/remote-env-file-error.js +37 -0
  380. package/dist/plugins/remote-env-host.d.ts +151 -0
  381. package/dist/plugins/remote-env-host.js +468 -70
  382. package/dist/plugins/remote-env-k8s.d.ts +135 -0
  383. package/dist/plugins/remote-env-k8s.js +318 -32
  384. package/dist/plugins/remote-env-local-docker.d.ts +65 -0
  385. package/dist/plugins/remote-env-local-docker.js +149 -24
  386. package/dist/plugins/remote-env-ssh.d.ts +35 -0
  387. package/dist/plugins/remote-env-ssh.js +117 -20
  388. package/dist/plugins/remote-scratchpad.d.ts +38 -0
  389. package/dist/plugins/remote-scratchpad.js +32 -2
  390. package/dist/plugins/remote-shell.d.ts +22 -0
  391. package/dist/plugins/remote-shell.js +27 -1
  392. package/dist/plugins/resume-anchor-store-sql.d.ts +28 -0
  393. package/dist/plugins/resume-anchor-store-sql.js +11 -0
  394. package/dist/plugins/roster-store-sql.d.ts +27 -0
  395. package/dist/plugins/roster-store-sql.js +54 -0
  396. package/dist/plugins/run-store-sql.d.ts +194 -0
  397. package/dist/plugins/run-store-sql.js +210 -9
  398. package/dist/plugins/s3-presign.d.ts +20 -0
  399. package/dist/plugins/s3-presign.js +49 -2
  400. package/dist/plugins/scheduler-support.d.ts +12 -0
  401. package/dist/plugins/scheduler-support.js +75 -3
  402. package/dist/plugins/send-file-ledger.d.ts +15 -0
  403. package/dist/plugins/send-file-ledger.js +53 -4
  404. package/dist/plugins/send-user-file.d.ts +77 -0
  405. package/dist/plugins/send-user-file.js +92 -4
  406. package/dist/plugins/session-policy-store-sql.d.ts +15 -0
  407. package/dist/plugins/session-policy-store-sql.js +75 -3
  408. package/dist/plugins/session-store.d.ts +45 -0
  409. package/dist/plugins/session-store.js +51 -0
  410. package/dist/plugins/sql-driver.d.ts +77 -0
  411. package/dist/plugins/sql-driver.js +4 -0
  412. package/dist/plugins/sql-escape.d.ts +8 -0
  413. package/dist/plugins/sql-escape.js +8 -0
  414. package/dist/plugins/sql-row-helpers.d.ts +25 -0
  415. package/dist/plugins/sql-row-helpers.js +25 -0
  416. package/dist/plugins/store-backend.d.ts +103 -0
  417. package/dist/plugins/store-backend.js +120 -27
  418. package/dist/plugins/store-contracts.d.ts +62 -0
  419. package/dist/plugins/store-contracts.js +3 -0
  420. package/dist/plugins/task-attachment-store.d.ts +60 -0
  421. package/dist/plugins/task-attachment-store.js +49 -3
  422. package/dist/plugins/task-list-store-sql.d.ts +25 -0
  423. package/dist/plugins/task-list-store-sql.js +21 -0
  424. package/dist/plugins/tidb-approval-store.d.ts +6 -0
  425. package/dist/plugins/tidb-approval-store.js +6 -0
  426. package/dist/plugins/tidb-breaker-state.d.ts +5 -0
  427. package/dist/plugins/tidb-breaker-state.js +5 -0
  428. package/dist/plugins/tidb-checkpoint-store.d.ts +7 -0
  429. package/dist/plugins/tidb-checkpoint-store.js +7 -0
  430. package/dist/plugins/tidb-cost-quota.d.ts +6 -0
  431. package/dist/plugins/tidb-cost-quota.js +1 -0
  432. package/dist/plugins/tidb-file-snapshot-store.d.ts +6 -0
  433. package/dist/plugins/tidb-file-snapshot-store.js +6 -0
  434. package/dist/plugins/tidb-image-bake.d.ts +8 -0
  435. package/dist/plugins/tidb-image-bake.js +8 -0
  436. package/dist/plugins/tidb-image-index.d.ts +8 -0
  437. package/dist/plugins/tidb-image-index.js +8 -0
  438. package/dist/plugins/tidb-outcome-ledger.d.ts +10 -0
  439. package/dist/plugins/tidb-outcome-ledger.js +10 -0
  440. package/dist/plugins/tidb-pool.d.ts +56 -0
  441. package/dist/plugins/tidb-pool.js +181 -1
  442. package/dist/plugins/tidb-rate-limiter.d.ts +11 -0
  443. package/dist/plugins/tidb-rate-limiter.js +5 -2
  444. package/dist/plugins/tidb-resume-anchor-store.d.ts +5 -0
  445. package/dist/plugins/tidb-resume-anchor-store.js +5 -0
  446. package/dist/plugins/tidb-run-store.d.ts +7 -0
  447. package/dist/plugins/tidb-run-store.js +7 -0
  448. package/dist/plugins/tidb-session-policy-store.d.ts +5 -0
  449. package/dist/plugins/tidb-session-policy-store.js +5 -0
  450. package/dist/plugins/tidb-session-storage.d.ts +43 -0
  451. package/dist/plugins/tidb-session-storage.js +62 -3
  452. package/dist/plugins/tidb-session-store.d.ts +142 -0
  453. package/dist/plugins/tidb-session-store.js +264 -16
  454. package/dist/plugins/tidb-tool-result-store.d.ts +5 -0
  455. package/dist/plugins/tidb-tool-result-store.js +7 -0
  456. package/dist/plugins/tidb-workflow-journal-store.d.ts +7 -0
  457. package/dist/plugins/tidb-workflow-journal-store.js +7 -0
  458. package/dist/plugins/tidb-workflow-run-store.d.ts +8 -0
  459. package/dist/plugins/tidb-workflow-run-store.js +8 -0
  460. package/dist/plugins/tool-result-store-sql.d.ts +58 -0
  461. package/dist/plugins/tool-result-store-sql.js +38 -2
  462. package/dist/plugins/web-search.d.ts +35 -0
  463. package/dist/plugins/web-search.js +45 -9
  464. package/dist/plugins/workflow-journal-limits.d.ts +10 -0
  465. package/dist/plugins/workflow-journal-limits.js +10 -0
  466. package/dist/plugins/workflow-journal-store-sql.d.ts +78 -0
  467. package/dist/plugins/workflow-journal-store-sql.js +58 -2
  468. package/dist/plugins/workflow-run-store-sql.d.ts +84 -0
  469. package/dist/plugins/workflow-run-store-sql.js +84 -6
  470. package/dist/plugins/worktree-isolation.d.ts +45 -0
  471. package/dist/plugins/worktree-isolation.js +105 -6
  472. package/dist/plugins/write-behind-counter.d.ts +56 -1
  473. package/dist/plugins/write-behind-counter.js +53 -14
  474. package/dist/principal-jwt.d.ts +24 -0
  475. package/dist/principal-jwt.js +60 -5
  476. package/dist/project-memory.d.ts +22 -0
  477. package/dist/project-memory.js +144 -15
  478. package/dist/prompts-domain-validate.d.ts +28 -0
  479. package/dist/prompts-domain-validate.js +42 -1
  480. package/dist/question.d.ts +33 -0
  481. package/dist/question.js +69 -2
  482. package/dist/resource-suspend.d.ts +21 -0
  483. package/dist/resource-suspend.js +16 -0
  484. package/dist/router/route-orchestration.d.ts +78 -0
  485. package/dist/router/route-orchestration.js +77 -0
  486. package/dist/run-local.d.ts +32 -0
  487. package/dist/run-local.js +172 -8
  488. package/dist/runs.d.ts +189 -4
  489. package/dist/runs.js +465 -24
  490. package/dist/runtime-caps-resolver.d.ts +106 -0
  491. package/dist/runtime-caps-resolver.js +89 -4
  492. package/dist/runtime-governance.d.ts +84 -0
  493. package/dist/runtime-governance.js +127 -1
  494. package/dist/sandbox-pkg-source.d.ts +23 -0
  495. package/dist/sandbox-pkg-source.js +37 -0
  496. package/dist/sealed-key.d.ts +54 -0
  497. package/dist/sealed-key.js +68 -3
  498. package/dist/security.d.ts +108 -0
  499. package/dist/security.js +145 -6
  500. package/dist/sema-registry.d.ts +21 -0
  501. package/dist/sema-registry.js +21 -0
  502. package/dist/session-leaf-bus.d.ts +31 -0
  503. package/dist/session-leaf-bus.js +32 -0
  504. package/dist/session-sync-content.d.ts +46 -0
  505. package/dist/session-sync-content.js +47 -1
  506. package/dist/session-sync-kernel.d.ts +89 -0
  507. package/dist/session-sync-kernel.js +48 -3
  508. package/dist/session-sync.d.ts +125 -0
  509. package/dist/session-sync.js +181 -8
  510. package/dist/session-titler.d.ts +26 -0
  511. package/dist/session-titler.js +41 -7
  512. package/dist/session-watch.d.ts +53 -1
  513. package/dist/session-watch.js +73 -9
  514. package/dist/sighup-idle.d.ts +30 -0
  515. package/dist/sighup-idle.js +12 -1
  516. package/dist/spec-fields.d.ts +91 -3
  517. package/dist/spec-fields.js +116 -4
  518. package/dist/task-cwd.d.ts +50 -0
  519. package/dist/task-cwd.js +68 -1
  520. package/dist/task-mcp.d.ts +47 -0
  521. package/dist/task-mcp.js +29 -0
  522. package/dist/task-settings.d.ts +175 -0
  523. package/dist/task-settings.js +226 -11
  524. package/dist/task-workflow.d.ts +67 -0
  525. package/dist/task-workflow.js +75 -8
  526. package/dist/tool-approval.d.ts +91 -0
  527. package/dist/tool-approval.js +215 -0
  528. package/dist/trace/artifacts.d.ts +9 -0
  529. package/dist/trace/artifacts.js +30 -5
  530. package/dist/trace/core-keyset-guard.d.ts +18 -0
  531. package/dist/trace/ledger-sink.d.ts +43 -0
  532. package/dist/trace/ledger-sink.js +64 -5
  533. package/dist/trace/project.d.ts +133 -0
  534. package/dist/trace/project.js +189 -2
  535. package/dist/trace/redact.d.ts +19 -0
  536. package/dist/trace/redact.js +66 -9
  537. package/dist/usage-analytics.d.ts +26 -0
  538. package/dist/usage-analytics.js +26 -3
  539. package/package.json +1 -1
@@ -7,13 +7,35 @@ interface ProjectMemoryCtx {
7
7
  sessionId?: string;
8
8
  phase?: "fresh" | "resume" | "post-compact" | "post-clear";
9
9
  }
10
+ /**
11
+ * Build a `loadProjectMemory` for the host lane. Returns null (skip) unless hands are enabled AND cwd is a local
12
+ * directory. Reads the instruction-file chain (AGENTS.md → CLAUDE.md → .claude/CLAUDE.md, S-1) + (non-subagent)
13
+ * `git log -5` / `git status`, redacts secrets, and caps the total. A subagent gets a trimmed instruction file and
14
+ * no git narrative (cost control, H7). When an instruction file is hit the return is a `ProjectMemoryLoad`
15
+ * declaring it in `instructionSources` (path + sha256 over the raw bounded-read window) so core's
16
+ * instructions-change lane can probe it mid-run.
17
+ *
18
+ * Session snapshot cache (S-2): keyed on ctx.sessionId — a session keeps ONE stable instruction snapshot
19
+ * (mid-run file edits surface via the probe as tail attachments, never a silently re-rendered prefix).
20
+ * `phase: "post-compact"` forces a re-read (core re-renders the prefix there anyway). No entry for
21
+ * sessionless one-shot runs. (post-clear never arrives from core — RB-9 — so it is not a cache key here.)
22
+ */
10
23
  export declare function makeLoadProjectMemory(opts: {
11
24
  logger?: {
12
25
  debug?: (msg: string, data: Record<string, unknown>) => void;
13
26
  };
14
27
  maxBytes?: number;
28
+ /** TEST-ONLY: shrink the snapshot-cache bound so the settle-time trim is observable without 256 sessions. */
15
29
  cacheMax?: number;
16
30
  }): (ctx: ProjectMemoryCtx) => Promise<string | null | ProjectMemoryLoad>;
31
+ /**
32
+ * ② The `RunnerDeps.probeInstructionSources` seam: re-fingerprint the declared instruction files mid-run so
33
+ * core's instructions-change lane can append a tail attachment when one changes. Same read posture as the
34
+ * loader (lstat symlink gate → bounded read of the first `INSTRUCTION_READ_CAP` bytes → sha256) — any drift
35
+ * here would fabricate phantom "changed" signals every turn. Per-source failure → `contentHash: null`
36
+ * (source gone/unreadable); any unexpected top-level failure → `null` (probe abstains; core also races this
37
+ * against a 2s ceiling and treats a throw as null, but we stay honest on our side of the seam).
38
+ */
17
39
  export declare function makeProbeInstructionSources(): NonNullable<import("@sema-agent/core").RunnerDeps["probeInstructionSources"]>;
18
40
  export {};
19
41
  //# sourceMappingURL=project-memory.d.ts.map
@@ -1,46 +1,95 @@
1
+ /**
2
+ * design/113 C4 — `RunnerDeps.loadProjectMemory` (core 1.182): the DEPLOYMENT half that makes sema "open like CC" —
3
+ * inject the project's CLAUDE.md + recent git narrative as a read-only, fenced virtual memory layer at the tail of the
4
+ * env block, so a fresh "你好" lands on "I'm the AI for the acme-widget project…" instead of a blank greeting.
5
+ *
6
+ * core's half (1.182/1.184): it calls this once per prepare, fences+sanitizes the return as UNTRUSTED data (CLAUDE.md
7
+ * is data, not an instruction), caps it at MAX_MEMORY_BYTES, and (1.184) auto-prepends a TRUSTED framing line. We just
8
+ * return the content.
9
+ *
10
+ * 🔴 HOST/FILE LANE ONLY. The ctx hands us only `cwd` (a string) — NO executionEnv instance and NO sessionId. So we can
11
+ * read with the worker's own `fs`/`execFile` ONLY when cwd is a LOCAL path (the host lane). On a remote sandbox lane
12
+ * (e2b/k8s/ssh/adb/local-docker) cwd lives in the container — the worker can't read it, and there's no env handle in
13
+ * the ctx to exec through — so main.ts only wires this on the host lane; here we defensively re-check (stat the dir).
14
+ */
1
15
  import { promises as fs, constants as fsConstants } from "node:fs";
2
16
  import { execFile } from "node:child_process";
3
17
  import { createHmac, randomBytes } from "node:crypto";
4
18
  import { isAbsolute, join, sep } from "node:path";
5
19
  import { scrubSecretEnv } from "@sema-agent/core";
6
20
  import { redactSecrets } from "./trace/redact.js";
21
+ /** The instruction-file name chain (core 1.302 S-1): AGENTS.md wins, CLAUDE.md is the fallback, then the
22
+ * `.claude/` nested form. The FIRST hit is the single declared instruction source. */
7
23
  const INSTRUCTION_FILE_CHAIN = ["AGENTS.md", "CLAUDE.md", ".claude/CLAUDE.md"];
24
+ /** One byte budget shared by the loader AND the probe — the fingerprint is sha256 over the first
25
+ * `INSTRUCTION_READ_CAP` raw bytes, so both sides MUST read the same bounded window or every probe
26
+ * would report a phantom change. (Consequence: an edit past the cap is invisible to the probe —
27
+ * honest limit of the bounded-read design, same reason the injected content is capped.) */
8
28
  const INSTRUCTION_READ_CAP = 24 * 1024;
29
+ /** Cap a string to a byte budget on a UTF-8 character boundary (never split a multi-byte char). */
9
30
  function capUtf8(s, maxBytes) {
10
31
  const buf = Buffer.from(s, "utf8");
11
32
  if (buf.length <= maxBytes)
12
33
  return s;
13
34
  let end = maxBytes;
35
+ // back off to a UTF-8 lead byte (0xxxxxxx or 11xxxxxx) so we don't slice mid-character
14
36
  while (end > 0 && (buf[end] & 0xc0) === 0x80)
15
37
  end -= 1;
16
38
  return buf.subarray(0, end).toString("utf8");
17
39
  }
40
+ /** Bounded raw read of an ABSOLUTE path (lstat symlink gate → first `maxBytes` bytes). The shared primitive
41
+ * under both the loader and `makeProbeInstructionSources` — one read posture, one fingerprint. */
18
42
  async function readRawCapped(target, maxBytes, truncatedFlag = { v: false }) {
19
43
  let fh;
20
44
  try {
45
+ // Symlink containment: a `CLAUDE.md` symlink must NOT read an arbitrary file outside the repo (double-review #3).
46
+ // 🔴 win32 真机(S6, 2026-07-04): `fsConstants.O_NOFOLLOW` is UNDEFINED on Windows Node, so `O_RDONLY | undefined`
47
+ // silently collapses to `O_RDONLY` (0) — the flag is a no-op and the symlink IS followed (verified: read out the
48
+ // outside file). O_NOFOLLOW only exists/atomically-enforces on POSIX. So gate portably with an explicit lstat
49
+ // symlink-reject: authoritative on win32 (where the open-flag can't enforce it), belt-and-suspenders on POSIX.
21
50
  const lst = await fs.lstat(target);
22
51
  if (lst.isSymbolicLink())
23
- return null;
52
+ return null; // a symlinked CLAUDE.md → refuse (no arbitrary-file read), same as O_NOFOLLOW → ELOOP
24
53
  if (lst.size > maxBytes)
25
- truncatedFlag.v = true;
54
+ truncatedFlag.v = true; // S23: cap fired — surfaced as claudeTruncated on the injection event
55
+ // Keep O_NOFOLLOW in the flags too: on POSIX it closes the tiny lstat→open TOCTOU window atomically; on win32 it's
56
+ // a harmless 0. BOUNDED read of the first maxBytes bytes — never buffer the whole file, so a 50MB/hostile CLAUDE.md
57
+ // can't amplify memory (double-review #2: the old fs.readFile loaded the WHOLE file before capping).
26
58
  fh = await fs.open(target, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0));
27
59
  const buf = Buffer.allocUnsafe(maxBytes);
28
60
  const { bytesRead } = await fh.read(buf, 0, maxBytes, 0);
29
61
  return buf.subarray(0, bytesRead);
30
62
  }
31
63
  catch {
32
- return null;
64
+ return null; // ENOENT / EISDIR / ELOOP (a symlink, rejected by O_NOFOLLOW) / EACCES — absent or unreadable → no content
33
65
  }
34
66
  finally {
35
67
  await fh?.close();
36
68
  }
37
69
  }
70
+ /** Keyed fingerprint over the RAW bounded-read window (pre-capUtf8 bytes — the ①"cap 前原始字节" contract).
71
+ * KEYED, not a plain digest (self-review, information-surface lens): core puts the short form of this
72
+ * fingerprint into the MODEL-VISIBLE instructions-change notice and the steering trace — a plain sha256
73
+ * of the raw bytes would let anyone holding a known template dictionary-compare low-entropy controlled
74
+ * fields against the digest. A per-process random key makes the digest correspond to nothing outside
75
+ * this process. Loader and probe share THIS one function (any split would fabricate phantom "changed"
76
+ * signals); sources are re-declared at every prepare in the declaring process, so a restart (new key)
77
+ * never gets compared against old fingerprints. */
38
78
  const INSTRUCTION_HASH_KEY = randomBytes(16);
39
79
  function instructionHash(raw) {
40
80
  return `hmac-sha256:${createHmac("sha256", INSTRUCTION_HASH_KEY).update(raw).digest("hex")}`;
41
81
  }
82
+ /** The "declared absent, watched for appearance" fingerprint for higher-priority chain members —
83
+ * core 1.310 ([1006]①) widened `instructionSources[].contentHash` to `string | null`, so this is a
84
+ * plain typed null (an appearing file renders as `hash absent → <hash>` in the change notice). */
42
85
  const ABSENT_HASH = null;
86
+ /** Recover (root, rel) for a path the LOADER declared — every declared path is `root + one chain member`,
87
+ * so the chain suffix identifies the split unambiguously. The probe needs this to re-run the loader's
88
+ * parent-directory symlink gate each round (self-review: the probe checked only the final component, so
89
+ * swapping `.claude` for a symlink out of the repo MID-RUN made the probe fingerprint an outside file). */
43
90
  function chainCoordinates(absPath) {
91
+ // LONGEST suffix wins: `…/.claude/CLAUDE.md` also ends with the bare `/CLAUDE.md` — matching in chain
92
+ // order would split off `.claude` into the root and skip the parent gate entirely (caught by the test).
44
93
  let best = null;
45
94
  for (const rel of INSTRUCTION_FILE_CHAIN) {
46
95
  const suffix = sep + rel.split("/").join(sep);
@@ -50,6 +99,11 @@ function chainCoordinates(absPath) {
50
99
  }
51
100
  return best && { root: best.root, rel: best.rel };
52
101
  }
102
+ /** Reject a symlink on ANY intermediate directory of `rel` under root (adversarial review F2): the final
103
+ * component's lstat/O_NOFOLLOW can't see a `.claude` DIRECTORY that is itself a symlink out of the repo
104
+ * (e.g. → ~/.claude) — the target file there lstat's as a plain file and would be read and injected.
105
+ * Same TOCTOU honesty as the final-component gate: the lstat→open window on a swapped intermediate dir
106
+ * is accepted (a local attacker with user rights can read the target directly anyway). */
53
107
  async function hasSymlinkedParent(root, rel) {
54
108
  const parts = rel.split("/").slice(0, -1);
55
109
  let cur = root;
@@ -61,30 +115,60 @@ async function hasSymlinkedParent(root, rel) {
61
115
  }
62
116
  return false;
63
117
  }
118
+ /** Run a fixed git subcommand under root with execFile (argv array → NO shell → no injection), timeout + maxBuffer.
119
+ * 🔴 The repo's own `.git/config` can otherwise STEER these read-only calls into code execution — double-review proved
120
+ * `core.fsmonitor=<prog>` runs `<prog>` on `git status` (auto-fires on every prepare in a hostile working dir). We
121
+ * neutralize the exec-config inlets: `-c core.fsmonitor=false -c core.hooksPath=/dev/null` override the repo's values,
122
+ * and GIT_CONFIG_GLOBAL/SYSTEM=/dev/null drop the global/system config so a planted one can't inject either. */
64
123
  function git(root, args, maxBytes) {
65
124
  const safeArgs = ["-c", "core.fsmonitor=false", "-c", "core.hooksPath=/dev/null", ...args];
66
125
  return new Promise((res) => {
67
- execFile("git", safeArgs, { cwd: root, timeout: 5000, maxBuffer: maxBytes, env: { ...scrubSecretEnv(process.env), GIT_CONFIG_GLOBAL: "/dev/null", GIT_CONFIG_SYSTEM: "/dev/null" } }, (err, stdout, stderr) => {
126
+ execFile("git", safeArgs,
127
+ // scrubSecretEnv: a git hook / credential helper must not see the orchestrator's *_KEY/*_TOKEN/*_SECRET env.
128
+ // GIT_CONFIG_GLOBAL/SYSTEM=/dev/null: ignore ~/.gitconfig + /etc/gitconfig so a planted exec-config can't steer us.
129
+ { cwd: root, timeout: 5000, maxBuffer: maxBytes, env: { ...scrubSecretEnv(process.env), GIT_CONFIG_GLOBAL: "/dev/null", GIT_CONFIG_SYSTEM: "/dev/null" } }, (err, stdout, stderr) => {
68
130
  if (!err)
69
131
  return res({ out: stdout.trim() });
132
+ // S23: the git narrative used to vanish with zero fingerprint — classify why (→ gitDropReason).
70
133
  const e = err;
71
134
  const fail = e.killed ? "timeout" : e.code === "ENOENT" ? "git-missing" : /not a git repository/i.test(String(stderr)) ? "non-repo" : /maxBuffer/i.test(String(e.message)) ? "maxbuffer" : "error";
72
135
  res({ out: "", fail });
73
136
  });
74
137
  });
75
138
  }
139
+ /**
140
+ * Build a `loadProjectMemory` for the host lane. Returns null (skip) unless hands are enabled AND cwd is a local
141
+ * directory. Reads the instruction-file chain (AGENTS.md → CLAUDE.md → .claude/CLAUDE.md, S-1) + (non-subagent)
142
+ * `git log -5` / `git status`, redacts secrets, and caps the total. A subagent gets a trimmed instruction file and
143
+ * no git narrative (cost control, H7). When an instruction file is hit the return is a `ProjectMemoryLoad`
144
+ * declaring it in `instructionSources` (path + sha256 over the raw bounded-read window) so core's
145
+ * instructions-change lane can probe it mid-run.
146
+ *
147
+ * Session snapshot cache (S-2): keyed on ctx.sessionId — a session keeps ONE stable instruction snapshot
148
+ * (mid-run file edits surface via the probe as tail attachments, never a silently re-rendered prefix).
149
+ * `phase: "post-compact"` forces a re-read (core re-renders the prefix there anyway). No entry for
150
+ * sessionless one-shot runs. (post-clear never arrives from core — RB-9 — so it is not a cache key here.)
151
+ */
76
152
  export function makeLoadProjectMemory(opts) {
77
- const totalCap = opts.maxBytes ?? 32 * 1024;
153
+ const totalCap = opts.maxBytes ?? 32 * 1024; // service self-cap, tighter than core's 100KiB MAX_MEMORY_BYTES backstop
78
154
  const claudeCap = INSTRUCTION_READ_CAP;
79
155
  const subagentClaudeCap = 4 * 1024;
80
156
  const gitCap = 8 * 1024;
81
157
  const cache = new Map();
82
158
  const CACHE_MAX = opts.cacheMax ?? 256;
83
159
  return async (ctx) => {
160
+ // All gates that decide WHETHER anything loads run BEFORE the cache (F3): a hands-less or bad-cwd call
161
+ // must answer null itself, never serve (or seed) a session slot it wasn't allowed to read.
84
162
  if (!ctx.handsEnabled)
85
- return null;
163
+ return null; // hands-less chat: no real project (H4)
86
164
  if (!isAbsolute(ctx.cwd))
87
165
  return null;
166
+ // Canonicalize through the FILESYSTEM, not lexically (self-review, information-surface lens): a
167
+ // lexical resolve() keeps symlinks and case aliases distinct — a symlinked cwd re-pointed at another
168
+ // project would keep hitting the OLD slot and serve project A's instruction snapshot inside project B,
169
+ // and a case alias would silently split one project across two slots. realpath is both the cache key
170
+ // AND the read root, so key and content can never disagree. Unresolvable cwd (gone/unreadable) → null,
171
+ // the same answer doLoad's stat gate would give.
88
172
  let root;
89
173
  try {
90
174
  root = await fs.realpath(ctx.cwd);
@@ -92,17 +176,26 @@ export function makeLoadProjectMemory(opts) {
92
176
  catch {
93
177
  return null;
94
178
  }
179
+ // Subagents share the parent's project but get a differently-capped view — never let the two shapes
180
+ // poison one cache slot; the subagent leg just stays uncached (cheap, trimmed read).
95
181
  const cacheKey = ctx.sessionId && !ctx.isSubagent ? `${ctx.sessionId}\u0000${root}` : undefined;
96
182
  if (cacheKey) {
97
183
  const hit = cache.get(cacheKey);
98
184
  if (hit && ctx.phase !== "post-compact")
99
185
  return hit.load;
186
+ // Post-compact single-flight (codex lens-1 remainder): two post-compact calls on one slot must share
187
+ // ONE fresh read — each starting its own would leave the surviving snapshot dependent on launch
188
+ // order. An in-flight entry that was ITSELF started post-compact is that generation's read (the
189
+ // settle window is milliseconds; a next compaction landing inside it joins the same read — accepted).
100
190
  if (hit && !hit.settled && hit.phase === "post-compact")
101
191
  return hit.load;
102
192
  }
103
193
  const load = doLoad(ctx, root);
104
194
  if (cacheKey) {
105
195
  if (cache.size >= CACHE_MAX && !cache.has(cacheKey)) {
196
+ // Evict the oldest SETTLED entry only (codex lens-1 remainder): deleting an in-flight promise
197
+ // orphans its read (the key's next call starts a second one). No settled entry → allow a
198
+ // temporary over-cap; loads settle in milliseconds, so the map stays bounded in practice.
106
199
  for (const [k, e] of cache) {
107
200
  if (e.settled) {
108
201
  cache.delete(k);
@@ -112,6 +205,10 @@ export function makeLoadProjectMemory(opts) {
112
205
  }
113
206
  const entry = { load, settled: false, phase: ctx.phase };
114
207
  cache.set(cacheKey, entry);
208
+ // Release-review finding: a burst of >CACHE_MAX concurrent DISTINCT loads sails past the insert-time
209
+ // eviction (nothing settled to evict yet) and, without this, the map would stay at the burst's
210
+ // high-water mark forever (each later insert evicts exactly one settled entry, net zero). Trim back
211
+ // down to the cap as loads settle — oldest settled first, in-flight entries always survive.
115
212
  const trimSettled = () => {
116
213
  if (cache.size <= CACHE_MAX)
117
214
  return;
@@ -128,6 +225,9 @@ export function makeLoadProjectMemory(opts) {
128
225
  trimSettled();
129
226
  }, () => {
130
227
  entry.settled = true;
228
+ // A rejected load must not poison the slot (doLoad catches everything today; belt for future
229
+ // edits). Guard the delete on identity (codex lens-1): an OLD generation's failure must not
230
+ // evict the NEWER entry that a post-compact refresh has already installed in the same slot.
131
231
  if (cache.get(cacheKey) === entry)
132
232
  cache.delete(cacheKey);
133
233
  trimSettled();
@@ -138,7 +238,12 @@ export function makeLoadProjectMemory(opts) {
138
238
  async function doLoad(ctx, root) {
139
239
  const st = await fs.stat(root).catch(() => null);
140
240
  if (!st?.isDirectory())
141
- return null;
241
+ return null; // remote-lane cwd not present locally, or a bad path → skip
242
+ // S-1 file-name chain: first hit wins and is the ONE declared instruction source.
243
+ // Consistent-snapshot selection (codex lens-1 remainder): the chain walk is not atomic — a
244
+ // higher-priority file created between "checked absent" and "picked the fallback" would silently
245
+ // lose to the fallback until a post-compact reload. After a non-top pick, re-verify the members
246
+ // above it; an appearance redoes the walk (bounded — after the retries the last pick stands).
142
247
  const claudeTrunc = { v: false };
143
248
  let claudeRaw = null;
144
249
  let hitFile;
@@ -153,7 +258,7 @@ export function makeLoadProjectMemory(opts) {
153
258
  for (let i = 0; i < INSTRUCTION_FILE_CHAIN.length; i++) {
154
259
  const rel = INSTRUCTION_FILE_CHAIN[i];
155
260
  if (rel.includes("/") && (await hasSymlinkedParent(root, rel)))
156
- continue;
261
+ continue; // F2: a symlinked .claude dir escapes the repo
157
262
  const raw = await readRawCapped(join(root, rel), claudeCap, claudeTrunc);
158
263
  if (raw !== null) {
159
264
  claudeRaw = capUtf8(raw.toString("utf8"), claudeCap);
@@ -164,10 +269,11 @@ export function makeLoadProjectMemory(opts) {
164
269
  }
165
270
  }
166
271
  if (hitIndex <= 0)
167
- break;
272
+ break; // top pick or nothing found: no higher-priority member to re-verify
168
273
  let appeared = false;
169
274
  for (const rel of INSTRUCTION_FILE_CHAIN.slice(0, hitIndex)) {
170
275
  const higher = await fs.lstat(join(root, rel)).catch(() => null);
276
+ // A symlink would be REFUSED by the read gate — its appearance is not a better pick.
171
277
  if (higher && !higher.isSymbolicLink()) {
172
278
  appeared = true;
173
279
  break;
@@ -177,9 +283,9 @@ export function makeLoadProjectMemory(opts) {
177
283
  break;
178
284
  }
179
285
  const claude = ctx.isSubagent && claudeRaw ? capUtf8(claudeRaw, subagentClaudeCap) : claudeRaw;
180
- const claudeTruncated = claudeTrunc.v || Boolean(ctx.isSubagent && claudeRaw && Buffer.byteLength(claudeRaw, "utf8") > subagentClaudeCap);
286
+ const claudeTruncated = claudeTrunc.v || Boolean(ctx.isSubagent && claudeRaw && Buffer.byteLength(claudeRaw, "utf8") > subagentClaudeCap); // S23
181
287
  let gitNarrative = "";
182
- let gitOk = true;
288
+ let gitOk = true; // S23: subagent (git not attempted) stays ok=absent-by-design
183
289
  let gitDropReason;
184
290
  if (!ctx.isSubagent) {
185
291
  const [log, status] = await Promise.all([
@@ -192,22 +298,33 @@ export function makeLoadProjectMemory(opts) {
192
298
  if (log.out)
193
299
  parts.push(`## Recent commits\n${log.out}`);
194
300
  if (status.out)
195
- parts.push(`## Working tree\n${status.out.split("\n").slice(0, 40).join("\n")}`);
301
+ parts.push(`## Working tree\n${status.out.split("\n").slice(0, 40).join("\n")}`); // bound the dirty list
196
302
  gitNarrative = parts.join("\n\n");
197
303
  }
198
304
  const sections = [];
199
305
  if (claude && hitFile)
200
- sections.push(`# ${hitFile}\n${claude}`);
306
+ sections.push(`# ${hitFile}\n${claude}`); // heading = the REAL file name (S-1)
201
307
  if (gitNarrative)
202
308
  sections.push(gitNarrative);
203
309
  if (sections.length === 0)
204
310
  return null;
311
+ // redact secrets BEFORE capping (a key must not survive into the injected context, where a tool could exfil it).
205
312
  const redacted = redactSecrets(sections.join("\n\n"));
206
313
  const capped = capUtf8(redacted, totalCap);
314
+ // S23: gitOk/gitDropReason/claudeTruncated — a silently-emptied narrative now has a fingerprint here.
315
+ // cacheSize: the snapshot cache's population at THIS load (bound observability — the settle-time trim
316
+ // keeps it ≤ the cap once in-flight bursts settle; also what the deterministic trim test asserts).
207
317
  opts.logger?.debug?.("project_memory_loaded", { cwd: root, bytes: Buffer.byteLength(capped, "utf8"), isSubagent: ctx.isSubagent, gitOk, ...(gitDropReason ? { gitDropReason } : {}), claudeTruncated, ...(hitFile ? { instructionFile: hitFile } : {}), ...(ctx.phase ? { phase: ctx.phase } : {}), cacheSize: cache.size });
208
318
  if (!capped)
209
319
  return null;
320
+ // Declare the instruction source (①): absolute path + fingerprint. The hash is over the PRE-redaction,
321
+ // pre-cap raw window — the probe re-reads the file itself, so the fingerprint must be file-derived, not
322
+ // derived from the redacted/assembled injection text.
210
323
  if (hitFile && hitHash) {
324
+ // Watch the chain members ABOVE the pick too (codex lens-1 remainder): core's change lane only
325
+ // probes DECLARED paths, so a higher-priority file appearing mid-run would otherwise never produce
326
+ // a signal until a post-compact reload. Absent members are pre-declared with the runtime's
327
+ // "absent" hash (ABSENT_HASH note) — appearance renders as `hash absent → <hash>` in the notice.
211
328
  return {
212
329
  content: capped,
213
330
  instructionSources: [
@@ -219,15 +336,27 @@ export function makeLoadProjectMemory(opts) {
219
336
  return capped;
220
337
  }
221
338
  }
339
+ /**
340
+ * ② The `RunnerDeps.probeInstructionSources` seam: re-fingerprint the declared instruction files mid-run so
341
+ * core's instructions-change lane can append a tail attachment when one changes. Same read posture as the
342
+ * loader (lstat symlink gate → bounded read of the first `INSTRUCTION_READ_CAP` bytes → sha256) — any drift
343
+ * here would fabricate phantom "changed" signals every turn. Per-source failure → `contentHash: null`
344
+ * (source gone/unreadable); any unexpected top-level failure → `null` (probe abstains; core also races this
345
+ * against a 2s ceiling and treats a throw as null, but we stay honest on our side of the seam).
346
+ */
222
347
  export function makeProbeInstructionSources() {
223
348
  return async (sources) => {
224
349
  try {
225
350
  return await Promise.all(sources.map(async ({ path }) => {
226
351
  if (!isAbsolute(path))
227
- return { path, contentHash: null };
352
+ return { path, contentHash: null }; // we only ever declare absolute paths
353
+ // Re-run the loader's parent-directory symlink gate EVERY round (self-review: the probe checked
354
+ // only the final component, so swapping `.claude` for a symlink out of the repo mid-run made the
355
+ // probe fingerprint an outside file — and its short form reaches the model-visible notice).
356
+ // Declared paths are always root+chain-member, so the coordinates are recoverable from the path.
228
357
  const coords = chainCoordinates(path);
229
358
  if (coords && coords.rel.includes("/") && (await hasSymlinkedParent(coords.root, coords.rel))) {
230
- return { path, contentHash: null };
359
+ return { path, contentHash: null }; // swapped-in symlinked parent → refuse, same as the loader
231
360
  }
232
361
  const raw = await readRawCapped(path, INSTRUCTION_READ_CAP);
233
362
  return { path, contentHash: raw === null ? null : instructionHash(raw) };
@@ -1,10 +1,21 @@
1
1
  import { type PromptTextDeclaration, type PublishedPromptArtifactEnvelope } from "@sema-agent/core";
2
+ /** [1057]⓪ 下发形(remote effective 的 additive key,JSON verbatim 面——不经 registry-core parse,所以
3
+ * cli 补位前 center 发的 `contentHash` 也原样到达)。 */
2
4
  export interface EffectiveCenterPrompts {
5
+ /** `center:<contentDigest 前 12>` — 纯内容寻址(同内容重发布=同 packId,epoch 不误重 pin)。 */
3
6
  packId: string;
7
+ /** canonical JSON 全量 sha256(非盐化,operator 对账位 [1050]②)。 */
4
8
  contentDigest: string;
9
+ /** covering 已在 center 走完的基线终形(层信息不下发,worker 零解析义务)。 */
5
10
  sections: PromptTextDeclaration[];
11
+ /** per-scenario 完整重算终形(整包替换基线,非增量);无键=用基线。 */
6
12
  scenarioOverrides?: Record<string, PromptTextDeclaration[]>;
7
13
  }
14
+ /**
15
+ * 结构判形(防炸底线,非语义复检)。`ok:false` 时调用方拒绝采用该候选的 prompts 面并 warn——绝不让
16
+ * 一个坏 pack 把每个任务的 prepare 炸掉。校验与 core assemble 的 THROW 条件同形(id 规范/长度/core/
17
+ * 保留、slot 闭集)+ 下发信封两键形;`contentHash` 只查形(值的校验归 core 1.315,错值 core 丢弃+warn)。
18
+ */
8
19
  export declare function validateCenterPrompts(raw: unknown): {
9
20
  ok: true;
10
21
  value: EffectiveCenterPrompts;
@@ -12,13 +23,30 @@ export declare function validateCenterPrompts(raw: unknown): {
12
23
  ok: false;
13
24
  error: string;
14
25
  };
26
+ /** core 引擎版本(verifyPromptArtifact 的 compatibleCore range 输入)——经 exports map 解析包根读
27
+ * package.json(`require('@sema-agent/core/package.json')` 被 exports 封死,ERR_PACKAGE_PATH_NOT_EXPORTED
28
+ * 第一手教训)。解析失败回 "0.0.0" = range-gated artifact 被诚实拒(fail-closed 响,绝不静默采用)。 */
15
29
  export declare const CORE_ENGINE_VERSION: string;
30
+ /** validatePromptsDomain 的归一产物:两轴的已判形面 + 变更检测身份(adopt 去重键,跨轴稳定)。 */
16
31
  export interface PromptsDomainFaces {
32
+ /** A 形(declaration 轴)——centerPromptProvider 继续消费(现行链路零改动)。 */
17
33
  declarations?: EffectiveCenterPrompts;
34
+ /** B 形(catalog 轴)——core S1 verify 已过(digest 复算/上限/range 全管线);server 不解释内容,
35
+ * 原样交 core artifact 仓(e/b 班车接线位)。 */
18
36
  catalog?: PublishedPromptArtifactEnvelope;
37
+ /** 采用去重键:两轴 digest 拼接(轴缺席记 "-")。 */
19
38
  identity: string;
39
+ /** 观测面([985]a §3:`center_prompts_adopted` 增 axes,看两轴共存窗)。 */
20
40
  axes: Array<"declarations" | "catalog">;
21
41
  }
42
+ /**
43
+ * prompts 域候选门 v2(validateCenterPrompts 的双轴升级;整拒语义不变=任一在场轴坏形 ⇒ 整个 prompts
44
+ * 面拒绝采用,LKG/内置继续服务)。两形都认:
45
+ * - legacy 平铺(无 schemaVersion 键)= declaration 轴单轴(存量 center 停发平铺前的兼容窗);
46
+ * - `{schemaVersion:1, declarations?, catalog?}`(registry-core `EffectivePromptsWire`)= 至少一轴。
47
+ * catalog 轴的语义权威=core `verifyPromptArtifact`(形/digest 逐位复算/ARTIFACT_LIMITS/compatibleCore
48
+ * range 全在 core 一处——[1242]③ a 解,上限单真源永不漂)。
49
+ */
22
50
  export declare function validatePromptsDomain(raw: unknown): {
23
51
  ok: true;
24
52
  value: PromptsDomainFaces;
@@ -1,9 +1,22 @@
1
+ /**
2
+ * prompts 域候选门(判形)——从 capabilities/center-prompts.ts **下沉**的中立叶子(design/158 S6,
3
+ * lens2 §G:`config-lkg.ts → capabilities/center-prompts.ts` 是全仓唯一一条显式分层反向边,config 层
4
+ * 值 import capabilities 层)。本模块只依赖 node 内置 + `@sema-agent/core`,不依赖 capabilities/
5
+ * config 任何东西,config-lkg(LKG 读侧复判)与 capabilities(候选门)同引即无反向边。
6
+ * center-prompts.ts 原位置 re-export 保兼容,语义/文案零改动——逐字搬运。
7
+ *
8
+ * ─── 以下为原 center-prompts.ts 的判形半场,注释原样保留 ───
9
+ *
10
+ * 本模块仅有的一层「形校验」不是语义复检,是**防炸底线**:core 对坏形声明的守卫是 THROW(assemble 期),
11
+ * 一个坏 pack 会让每个任务 prepare 炸掉——server 在采用前做结构判形,坏形=拒绝采用该候选的 prompts 面
12
+ * (warn 点名,沿用上一个好的/内置),任务面永不因配置坏形而全灭(config 候选门同精神,只作用于本域)。
13
+ */
1
14
  import { createHash } from "node:crypto";
2
15
  import { createRequire } from "node:module";
3
16
  import { readFileSync } from "node:fs";
4
17
  import { dirname, join } from "node:path";
5
18
  import { verifyPromptArtifact } from "@sema-agent/core";
6
- const ID_RE = /^[a-z0-9][a-z0-9/._-]*$/;
19
+ const ID_RE = /^[a-z0-9][a-z0-9/._-]*$/; // core assemble 同形(≤128、非 core/ 前缀在下面单查)
7
20
  const SLOTS = new Set(["identity", "scenario", "behavior"]);
8
21
  const HASH_RE = /^sha256:[0-9a-f]{64}$/;
9
22
  function declarationIssue(d, where) {
@@ -18,6 +31,10 @@ function declarationIssue(d, where) {
18
31
  return `${where}: bad slot`;
19
32
  if (typeof o.text !== "string" || o.text.length === 0)
20
33
  return `${where}: text must be a non-empty string`;
34
+ // 发版复审(1.224 批)F1:contentHash **必备且重算比对**——core 的 epoch 声明轴用 (id,slot,chars,
35
+ // contentHash?),hash 缺席/被 core 丢弃(错值)后**同长度文本编辑不改 artifactDigest=不重 pin**,
36
+ // 恰是撤 restart 臂所依赖的审计不变量被击穿。center 链路恒逐 section 铸([1065]),正常路径零影响;
37
+ // 这里拒的是坏发布/被改载荷(整拒候选,LKG/内置继续服务)。
21
38
  if (typeof o.contentHash !== "string" || !HASH_RE.test(o.contentHash))
22
39
  return `${where}: contentHash is required (sha256:<64hex> — the epoch declaration axis needs it for byte-level change detection)`;
23
40
  const expected = `sha256:${createHash("sha256").update(o.text).digest("hex")}`;
@@ -25,6 +42,11 @@ function declarationIssue(d, where) {
25
42
  return `${where}: contentHash does not match sha256(text) — stale or tampered declaration`;
26
43
  return undefined;
27
44
  }
45
+ /**
46
+ * 结构判形(防炸底线,非语义复检)。`ok:false` 时调用方拒绝采用该候选的 prompts 面并 warn——绝不让
47
+ * 一个坏 pack 把每个任务的 prepare 炸掉。校验与 core assemble 的 THROW 条件同形(id 规范/长度/core/
48
+ * 保留、slot 闭集)+ 下发信封两键形;`contentHash` 只查形(值的校验归 core 1.315,错值 core 丢弃+warn)。
49
+ */
28
50
  export function validateCenterPrompts(raw) {
29
51
  if (raw === null || typeof raw !== "object")
30
52
  return { ok: false, error: "prompts is not an object" };
@@ -33,6 +55,11 @@ export function validateCenterPrompts(raw) {
33
55
  return { ok: false, error: "bad packId form (center:<digest12>)" };
34
56
  if (typeof p.contentDigest !== "string" || !HASH_RE.test(p.contentDigest))
35
57
  return { ok: false, error: "bad contentDigest form" };
58
+ // 发版复审 F2/F4 两条硬化:
59
+ // - 数组内 id 必须唯一(core composer 对 duplicate section id 是 THROW——独立判形查不出对撞,必须
60
+ // 整数组查重;基线与各 override 互不查——override 整包替换,不同数组不共存于一次装配);
61
+ // - 空数组=坏形拒绝(F4:wire 契约是「整包替换终形」,空数组语义未定义——「显式清空场景」不是 v1
62
+ // 用例,静默把空重解释为「回落内置」会跑出与 center 发布物不同的提示词;语义决定权推回 center)。
36
63
  const arrayIssue = (decls, where) => {
37
64
  if (!Array.isArray(decls))
38
65
  return `${where} is not an array`;
@@ -65,6 +92,10 @@ export function validateCenterPrompts(raw) {
65
92
  }
66
93
  return { ok: true, value: raw };
67
94
  }
95
+ // ═══ 双轴门(a 实现班车,[985]a/[1242]/[1248] 过轮定稿;registry-core 0.10.20 同班车)═══
96
+ /** core 引擎版本(verifyPromptArtifact 的 compatibleCore range 输入)——经 exports map 解析包根读
97
+ * package.json(`require('@sema-agent/core/package.json')` 被 exports 封死,ERR_PACKAGE_PATH_NOT_EXPORTED
98
+ * 第一手教训)。解析失败回 "0.0.0" = range-gated artifact 被诚实拒(fail-closed 响,绝不静默采用)。 */
68
99
  export const CORE_ENGINE_VERSION = (() => {
69
100
  try {
70
101
  const entry = createRequire(import.meta.url).resolve("@sema-agent/core");
@@ -74,6 +105,14 @@ export const CORE_ENGINE_VERSION = (() => {
74
105
  return "0.0.0";
75
106
  }
76
107
  })();
108
+ /**
109
+ * prompts 域候选门 v2(validateCenterPrompts 的双轴升级;整拒语义不变=任一在场轴坏形 ⇒ 整个 prompts
110
+ * 面拒绝采用,LKG/内置继续服务)。两形都认:
111
+ * - legacy 平铺(无 schemaVersion 键)= declaration 轴单轴(存量 center 停发平铺前的兼容窗);
112
+ * - `{schemaVersion:1, declarations?, catalog?}`(registry-core `EffectivePromptsWire`)= 至少一轴。
113
+ * catalog 轴的语义权威=core `verifyPromptArtifact`(形/digest 逐位复算/ARTIFACT_LIMITS/compatibleCore
114
+ * range 全在 core 一处——[1242]③ a 解,上限单真源永不漂)。
115
+ */
77
116
  export function validatePromptsDomain(raw) {
78
117
  if (raw === null || typeof raw !== "object")
79
118
  return { ok: false, error: "prompts is not an object" };
@@ -100,6 +139,8 @@ export function validatePromptsDomain(raw) {
100
139
  const c = verifyPromptArtifact(w.catalog, { engineVersion: CORE_ENGINE_VERSION });
101
140
  if (!c.ok)
102
141
  return { ok: false, error: `catalog axis: ${c.code}: ${c.reason}` };
142
+ // verify 返回的是重建后的 typed artifact;wire 上的 envelope 原样保留(sourceRevision 不进 digest,
143
+ // e/b 接线时 core artifact 仓吃 envelope 全形)。
103
144
  value.catalog = w.catalog;
104
145
  value.axes.push("catalog");
105
146
  }
@@ -1,10 +1,19 @@
1
1
  import { type AskQuestionRequest, type QuestionAnswer, type AskQuestion } from "@sema-agent/core";
2
+ /** A live question frame delivered to whoever tails this run's stream. `type` IS the SSE event name (mirrors the
3
+ * named-event convention; the payload also carries `type` so a proxy that strips event names still works). The shell
4
+ * renders `question` as a dialog and dismisses on `question_complete`. */
2
5
  export interface QuestionFrame {
3
6
  type: "question" | "question_complete";
4
7
  questionId: string;
8
+ /** "question" only: the model's structured questions, secret-redacted. UNTRUSTED-for-display (shell renders; never
9
+ * re-feeds a model). Absent on an over-cap payload (the ask then headless-defaults). */
5
10
  questions?: AskQuestion[];
11
+ /** "question_complete" only: whether the human answered (`answered`) or the ask was released unanswered
12
+ * (`unanswered` — ttl/abort → the model got the headless default). Cosmetic dialog-dismiss. */
6
13
  outcome?: "answered" | "unanswered";
7
14
  }
15
+ /** The per-run context `onQuestion` recovers via ALS. `emit` delivers a frame to the run's live stream; `abortSignal`
16
+ * (the run's own cancel signal) releases a question parked awaiting a human when the run aborts. */
8
17
  export interface QuestionRunContext {
9
18
  taskId: string;
10
19
  owner: string | null;
@@ -12,11 +21,17 @@ export interface QuestionRunContext {
12
21
  abortSignal?: AbortSignal;
13
22
  }
14
23
  export interface QuestionThrottle {
24
+ /** Max concurrent in-flight questions per run leg (parallel tool calls can each ask). Breach ⇒ headless default. */
15
25
  maxConcurrentPerRun: number;
26
+ /** Max total questions one run leg surfaces to the human. Breach ⇒ headless default (flood defense). */
16
27
  maxTotalPerRun: number;
28
+ /** An unanswered question auto-releases (headless default) after this (ms) — the human walked away; don't hold core. */
17
29
  ttlMs: number;
18
30
  }
19
31
  export declare const DEFAULT_QUESTION_THROTTLE: QuestionThrottle;
32
+ /** Validate the respond body = core's {@link QuestionAnswer}. `selected`/`note` are OPAQUE passthrough (core fences
33
+ * them: `selected ⊆ options`, `note` untrusted-fenced) — we validate only the outer SHAPE (answers[] of {header,
34
+ * selected:string[], note?}), never the option semantics. */
20
35
  export declare function parseQuestionResponse(body: unknown): {
21
36
  ok: true;
22
37
  value: QuestionAnswer;
@@ -24,19 +39,37 @@ export declare function parseQuestionResponse(body: unknown): {
24
39
  ok: false;
25
40
  error: string;
26
41
  };
42
+ /** @deprecated design/158 N22: renamed to {@link parseQuestionResponse} — unifies the HITL trio's parse-fn
43
+ * vocabulary (`parseQuestionResponse` / `parseElicitationResponse` / `parseToolApprovalResponse`, all "the
44
+ * human's reply body"). Kept as a compat alias. */
27
45
  export declare const parseQuestionAnswer: typeof parseQuestionResponse;
46
+ /**
47
+ * Coordinates AskUserQuestion HITL for the singleton runner. Process-local + same-replica (the pending map is in memory,
48
+ * like ElicitationCoordinator / steerableRuns): a respond that lands on another replica finds nothing → 404. Present
49
+ * (passed into `RunnerDeps.onQuestion` + the respond route) ONLY when `ASK_QUESTION_ENABLED` — absent ⇒ core mounts the
50
+ * AskUserQuestion tool with the headless default (a run never hangs; the model just can't get a live answer).
51
+ */
28
52
  export declare class QuestionCoordinator {
29
53
  private readonly als;
30
54
  private readonly pending;
31
55
  private readonly counters;
32
56
  private readonly throttle;
33
57
  constructor(throttle?: QuestionThrottle);
58
+ /** Run `fn` with the per-run question context ambient. On exit, release any still-pending question for this run (a
59
+ * live-only question cannot outlive its leg → headless default) and drop the run's counters (no leak). */
34
60
  runWithContext<T>(ctx: QuestionRunContext, fn: () => Promise<T>): Promise<T>;
61
+ /** `RunnerDeps.onQuestion`. core calls this when the agent's AskUserQuestion tool fires; the resolved answer is what
62
+ * the model sees. Headless default (`NO_HUMAN`) in every case with no live human, so the run never hangs. Arrow
63
+ * property so it can be passed as `onQuestion: coordinator.question` with `this` bound. */
35
64
  question: (req: AskQuestionRequest, signal?: AbortSignal) => Promise<QuestionAnswer>;
65
+ /** `POST /v1/questions/:id/respond` — resolve a parked question with the shell's answer. Owner-gated with a 404 (no
66
+ * existence oracle): a non-owner AND an unknown id (answered / expired / wrong replica) both get 404. Returns the
67
+ * HTTP {status, body}; the HTTP layer owns auth (gatedPrincipal + REQUIRE_PRINCIPAL) before calling. */
36
68
  respond(id: string, principal: string | undefined, body: unknown): {
37
69
  status: number;
38
70
  body: unknown;
39
71
  };
72
+ /** Test/observability hook: number of currently-parked questions. */
40
73
  pendingCount(): number;
41
74
  private countersFor;
42
75
  }