@sema-agent/server 1.322.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 +59 -3
  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
package/dist/security.js CHANGED
@@ -1,16 +1,47 @@
1
1
  import { uuidv7 } from "@sema-agent/core";
2
2
  import { PROJECT_ID_REGEX } from "@sema-agent/registry-core";
3
+ // design/158 A4: the env→key-set decoders (parseApprovalHmacKeys / parsePrincipalJwks + their row types) moved to
4
+ // the leaf ./auth-keys.js so config.ts's env-load no longer value-imports this whole auth module (lens2 §F). The
5
+ // verifiers that consume the parsed key-sets now live in ./approval-hmac.js / ./principal-jwt.js (design/158 A13);
6
+ // the four names are RE-EXPORTED for compat.
3
7
  export { parseApprovalHmacKeys, parsePrincipalJwks } from "./auth-keys.js";
4
- import { memoryScopeFor } from "./memory-scope.js";
8
+ import { memoryScopeFor } from "./memory-scope.js"; // design/158 N17: see re-export block below (moved to ./memory-scope.js)
9
+ // design/158 A13: the approval-envelope HMAC (integrity) group and the principal-JWT/direct-door (identity)
10
+ // group moved VERBATIM to ./approval-hmac.js and ./principal-jwt.js respectively — this file's own
11
+ // `verifiedPrincipal` still calls verifyPrincipalJwt for the direct-door branch (value import below); every
12
+ // symbol from both groups is re-exported near the bottom of this file so existing importers keep working.
5
13
  import { verifyPrincipalJwt } from "./principal-jwt.js";
14
+ /** The shape core's `uuidv7()` mints: canonical 8-4-4-4-12 lowercase hex with version nibble `7` and the RFC-4122
15
+ * variant (`8`/`9`/`a`/`b`). Used to shape-validate a caller-supplied session id on the §0.5 fork/delete routes so
16
+ * a crafted id (LIKE metacharacters, over-long, non-canonical) is rejected up front — a SECOND layer behind the
17
+ * tool-result LIKE-escape, not the only one. NB: deliberately NOT enforced on the task-submission `body.sessionId`
18
+ * path (the authorizer) — historical callers/tests pass arbitrary short ids there, and the LIKE-escape +
19
+ * VARCHAR(64) column already neutralize the metacharacter risk; tightening that path is a separate, breaking change.
20
+ * ASYMMETRY (GAP #15, INTENTIONAL): a client MAY create a session via submit with an arbitrary id (e.g. run-local
21
+ * `--session foo`, dev anonymous-share ids) yet then CANNOT fork/delete it (those routes 400 a non-uuidv7 id). This
22
+ * is by design — the wire contract types sessionId as an opaque string, so submit stays permissive; fork/delete add
23
+ * the uuidv7 gate only as defense-in-depth for store ops on a caller-supplied `:id`. Do NOT add a uuidv7 check to
24
+ * submit (breaks the contract + run-local + single-tenant dev). The ONE submit-side guard that IS safe and present
25
+ * is a LENGTH cap (≤64, the column width) in prepareSpec — see server.ts `body.sessionId` check — which prevents a
26
+ * 500/truncation at the INSERT without constraining the id shape. */
6
27
  const UUIDV7_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
28
+ /** True iff `s` matches the canonical uuidv7 shape core mints (see {@link UUIDV7_RE}). */
7
29
  export function isUuidV7(s) {
8
30
  return UUIDV7_RE.test(s);
9
31
  }
32
+ /** Canonical uuid of ANY version (v4 legacy shell sessions included) — the SYNC
33
+ * face's shape gate. Sync stays stricter than submit (arbitrary ≤64 ids) because it is a bulk write
34
+ * face: the shape still shuts out crafted ids (LIKE metacharacters, over-long), but no longer strands a
35
+ * v4-keyed legacy session as unsyncable (it was CREATABLE via the lenient submit yet REJECTED by the v7-only
36
+ * sync gate — a real contradiction). fork/purge/policy keep the v7-only gate (ids we mint ourselves). */
10
37
  const UUID_ANY_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
11
38
  export function isUuidShape(s) {
12
39
  return UUID_ANY_RE.test(s);
13
40
  }
41
+ /** An HTTP error the server maps to a status code (instead of a generic 500). `code` (optional) is a stable
42
+ * machine-readable identifier the HTTP layer echoes as `{code}` beside the human `{error}` message — the
43
+ * "typed rejection" posture (structured code on the wire, prose stays with the shell/web).
44
+ * `extra` (optional) is folded into the error body verbatim (e.g. the scenario allowlist on a reject). */
14
45
  export class HttpError extends Error {
15
46
  status;
16
47
  code;
@@ -25,12 +56,37 @@ export class HttpError extends Error {
25
56
  this.extra = opts.extra;
26
57
  }
27
58
  }
59
+ /**
60
+ * S6 — close the "sessionId / scope are bearer capabilities" hole.
61
+ *
62
+ * The principal is read from a trusted header set by the authenticated caller (e.g. the OA backend
63
+ * that already holds the service token). It is NOT taken from the request body, so a caller cannot
64
+ * forge identity by passing `scope`/`sessionId` for another tenant.
65
+ *
66
+ * Then:
67
+ * - a supplied `sessionId` is ownership-checked against `session_meta.owner` (403 on mismatch);
68
+ * an unknown id is claimed for this principal; a missing id mints a fresh owned session;
69
+ * - the memory scope is derived from the principal.
70
+ *
71
+ * Returns a function shaped for `ServiceDeps.authorize`. When `sessionStore` is not the TiDB store
72
+ * (e.g. in-memory dev backend) ownership can't be enforced, so it only derives principal + sessionId.
73
+ */
28
74
  export function createAuthorizer(config, sessionStore) {
29
75
  return async ({ req, body }) => {
76
+ // F-fix (direct-door principal spoofing, core-steered): the authoritative identity for governance + cost +
77
+ // ownership + memory + checkpoint scope is the VERIFIED principal, never the spoofable header. This swap covers
78
+ // every consumer that flows THROUGH the authorizer (spec.principal + cost/owner/memory/checkpoint scope); the
79
+ // non-authorizer owner/cost sites (runOwnerOk / quotaExceeded / leader / idemKey / the run-route + worker-global
80
+ // presence gates) call `gatedPrincipal` directly, same invariant. BFF/gated = unchanged (no-op there).
30
81
  const principal = verifiedPrincipal(req, config);
31
82
  if (config.requirePrincipal && !principal) {
32
83
  throw new HttpError(401, `missing principal header '${config.principalHeader}'`);
33
84
  }
85
+ // 142-S4 projectId 线程化(design/142 §2 行为面):body.projectId 是「哪个项目」的选择器,不是身份 —
86
+ // scope 的 tenant 段永远来自 verified principal(上面),所以它过 SHAPE 门即可(PROJECT_ID_REGEX,
87
+ // registry-core 0.10.0 与 center 登记簿同一词法;generic lowercase UUID)。不合形状 = 422 typed
88
+ // fail-loud(注入串/大小写/任意路径段绝不进 scope 键或 config.projects 查表)。RESUME 腿不过此门
89
+ // (checkpoint 重建 auth 不跑 authorizer)— 持久化 body 在原始提交时已验过,形状不变。
34
90
  let projectId;
35
91
  if (body.projectId !== undefined) {
36
92
  if (typeof body.projectId !== "string" || !PROJECT_ID_REGEX.test(body.projectId)) {
@@ -38,6 +94,16 @@ export function createAuthorizer(config, sessionStore) {
38
94
  }
39
95
  projectId = body.projectId;
40
96
  }
97
+ // design/114 Phase3 (reuse-path warm-resume): the caller requires the session to ALREADY exist. The authorizer
98
+ // must NOT claim-create a missing id — that would materialize an empty session_meta row and DEFEAT core's
99
+ // acquire({requireExisting}) fail-loud, silently turning a resume of a PURGED/EXPIRED session into a fresh empty
100
+ // run (the exact "looks warm, actually fresh" bug the flag prevents). So with it set: a missing requested id
101
+ // FAILS LOUD with a clean 404 HERE (eager — before any SSE headers, so BOTH the sync and stream legs get a real
102
+ // status, not an SSE-buried error) and is NEVER claim-created; a request with NO sessionId is a caller error (the
103
+ // authorizer would otherwise mint a fresh id — there is no existing session to resume). This is the SERVICE-side
104
+ // complement to core's store-level fail-loud (which still covers run-local / no-ownerOf backends / direct core):
105
+ // without it the store never SEES a missing session (the authorizer pre-registers it), so store honoring alone is
106
+ // inert on the HTTP path.
41
107
  const requireExisting = body.requireExistingSession === true;
42
108
  const ownerOf = sessionStore.ownerOf?.bind(sessionStore);
43
109
  const register = sessionStore.register?.bind(sessionStore);
@@ -48,11 +114,26 @@ export function createAuthorizer(config, sessionStore) {
48
114
  let owner = await ownerOf(requested);
49
115
  if (owner === undefined) {
50
116
  if (requireExisting) {
117
+ // design/114 Phase3: the session is genuinely missing (no owner row) AND the caller requires it to
118
+ // EXIST → FAIL LOUD with a clean HTTP 404 on BOTH the sync AND the streaming leg. The authorizer runs
119
+ // (in prepareSpec) BEFORE any SSE headers are committed, so the stream leg gets a real status code — not
120
+ // a `resume.session_not_found` buried in an SSE `done` payload, which a 200-committed stream cannot
121
+ // upgrade. We must NOT claim-create it either (that would defeat the fail-loud). The durable stores ALSO
122
+ // honor `{requireExisting}` (run-local / a no-ownerOf memory backend / direct core), so the fail-loud
123
+ // still holds on the paths that never reach this authorizer.
51
124
  throw new HttpError(404, "requireExistingSession: session does not exist (resume.session_not_found)");
52
125
  }
53
- await register(requested, principal ?? null);
126
+ await register(requested, principal ?? null); // unknown id → claim for this principal
127
+ // Re-read the authoritative stored owner: register is an idempotent upsert that keeps the
128
+ // FIRST owner, so a concurrent first-claim of the same id by another principal could have won
129
+ // the race. Without this re-check the loser would silently attach to the winner's session.
54
130
  owner = await ownerOf(requested);
55
131
  }
132
+ // Enforce ownership whenever the session HAS an owner — including against callers that present
133
+ // no principal (audit B, security.ts:77): with the old `principal &&` guard, a caller that
134
+ // omitted the header under requirePrincipal=false could attach to ANY owned session by id.
135
+ // Anonymous callers may still attach to anonymous (owner=null) sessions, so single-tenant dev
136
+ // (no principals anywhere) is unaffected; flipping the requirePrincipal default is NOT needed.
56
137
  if (owner != null && owner !== principal) {
57
138
  throw principal
58
139
  ? new HttpError(403, "session does not belong to this principal")
@@ -62,6 +143,8 @@ export function createAuthorizer(config, sessionStore) {
62
143
  sessionId = requested;
63
144
  }
64
145
  else {
146
+ // design/114 Phase3 (M2 parity): requireExistingSession with NO sessionId is a caller error — the authorizer
147
+ // mints a fresh id otherwise, so core's own no-sessionId M2 check can never fire on the service path.
65
148
  if (requireExisting) {
66
149
  throw new HttpError(422, "requireExistingSession requires a sessionId — there is no existing session to resume (resume.session_not_found)");
67
150
  }
@@ -72,27 +155,66 @@ export function createAuthorizer(config, sessionStore) {
72
155
  return { principal, sessionId, memoryScope: memoryScopeFor(config, principal, projectId), resolvedProjectId: projectId };
73
156
  };
74
157
  }
158
+ /** F1/F3 (codex scope-ledger audit 2026-07-14) — the auth-boundary principal SHAPE gate, applied to every
159
+ * verified identity source (trusted header, SSO-bridge sub, direct-door JWT sub) so no downstream consumer
160
+ * ever sees an ambiguous or over-wide principal:
161
+ * - RESERVED internal identifiers are REJECTED (修1, 三路复审 A 组 HIGH — see {@link RESERVED_PRINCIPALS} /
162
+ * {@link RESERVED_PRINCIPAL_PREFIXES} below): a REAL tenant whose principal string-equals an internal scope
163
+ * sentinel would pass the plain string-compare owner/scope gates downstream and merge with internal rows —
164
+ * e.g. `"_"` merges with the anonymous scope family (the checkpoint scope column `auth?.principal ?? "_"`
165
+ * at suspend, and the decide owner-gate treats `cp.scope === "_"` as anonymous-OPEN, server.ts ~L3710; the
166
+ * SendUserFile ledger scope + the /v1/sendfile-links fleet-wide default; the resource-suspend isolation
167
+ * key), `"_leader"` merges with the leader durable-approval owner scope (a tenant so named could list/
168
+ * decide internal leader approvals), `"_leader-…"` with the leader resource-suspend scope family, and
169
+ * `"__none__"` with the missing-principal placeholder scope on the decide/pending gates.
170
+ * - length > 190 is REJECTED: every scope/owner column the principal lands in VERBATIM is VARCHAR(190)
171
+ * (sendfile_link.scope, approval.owner/scope, memory-engine scope, rate-limit keys, …) — an over-long
172
+ * principal would truncate/500 at the INSERT and split one identity into two.
173
+ * Throws a typed 400 `HttpError` (the HTTP layer maps it); the message names the rule (a reserved identifier /
174
+ * the length cap), never a secret and never the internal scope's semantics. */
75
175
  export const PRINCIPAL_MAX_LENGTH = 190;
176
+ /** 修1 — the SINGLE registry of internal sentinel/scope identifiers a tenant principal must never equal.
177
+ * 🔴 新增内部 sentinel scope 必须在此登记(精确值加 RESERVED_PRINCIPALS,前缀族加
178
+ * RESERVED_PRINCIPAL_PREFIXES),否则 assertPrincipalShape 会放行同名租户 = 与内部 scope 行合流的越权面。
179
+ * Current entries (where each is minted): `"_"` = single-user/anonymous sentinel (checkpoint/sendfile/
180
+ * resource-suspend scope family); `"__none__"` = missing-principal placeholder on the decide/pending gates
181
+ * (http/server.ts `principal ?? "__none__"`); `"_leader"` = leader durable-approval scope
182
+ * (src/leader/wire.ts); prefix `"_leader-"` = the leader resource-suspend scope family
183
+ * (`_leader-resource-<workerId>`, src/leader/wire.ts). NB the prefix REQUIRES the hyphen — a tenant named
184
+ * `_leaderX` collides with nothing internal and stays valid (boundary pinned by test). */
76
185
  export const RESERVED_PRINCIPALS = ["_", "__none__", "_leader"];
77
186
  export const RESERVED_PRINCIPAL_PREFIXES = ["_leader-"];
78
187
  export function assertPrincipalShape(principal) {
79
188
  if (RESERVED_PRINCIPALS.includes(principal) || RESERVED_PRINCIPAL_PREFIXES.some((p) => principal.startsWith(p))) {
189
+ // Wording deliberately names the RULE (reserved internal scope sentinel), not what the sentinel does.
80
190
  throw new HttpError(400, `principal ${JSON.stringify(principal)} is reserved (an internal scope sentinel) — authenticate with a real tenant identifier`, { code: "principal_reserved" });
81
191
  }
82
192
  if (principal.length > PRINCIPAL_MAX_LENGTH) {
83
193
  throw new HttpError(400, `principal exceeds ${PRINCIPAL_MAX_LENGTH} characters (the scope-column width every store pins, e.g. sendfile_link.scope VARCHAR(190)); got ${principal.length}`, { code: "principal_too_long" });
84
194
  }
85
195
  }
196
+ /** Read the authenticated principal from the trusted header. Never from the body. */
86
197
  export function principalFrom(req, config) {
87
198
  if (!config.principalHeader)
88
- return undefined;
199
+ return undefined; // no header configured → no principal (defensive; real config always sets it)
89
200
  const raw = req.headers[config.principalHeader.toLowerCase()];
90
201
  const principal = (Array.isArray(raw) ? raw[0] : raw)?.trim() || undefined;
91
202
  if (principal !== undefined)
92
- assertPrincipalShape(principal);
203
+ assertPrincipalShape(principal); // F1/F3: reserved-sentinel + length gate at the boundary
93
204
  return principal;
94
205
  }
206
+ /** Header carrying the crypto-verified principal JWT on a direct-door worker (the issuer signs it; the worker only
207
+ * verifies). The trusted twin of `config.principalHeader` (the latter is client-spoofable on a direct door). */
95
208
  export const PRINCIPAL_TOKEN_HEADER = "x-approval-principal-token";
209
+ /** The DIRECT-DOOR-SAFE principal — the VERIFIED identity for governance + cost + isolation. On a BFF/gated deployment
210
+ * the header is already verified upstream (return it); on a direct-door worker the `principalHeader` is client-
211
+ * spoofable, so identity comes from the crypto-verified `x-approval-principal-token` JWT (the issuer's private key
212
+ * never lives on a worker). `spec.principal` MUST be this, NEVER `principalFrom` — keying a gate or a bill on a
213
+ * spoofable header is a multi-tenant governance/cost bypass (core's TaskSpec.principal contract). Single source for
214
+ * `createAuthorizer` AND every `gatedPrincipal` call site (F-fix: direct-door principal spoofing, core-steered). */
215
+ /** 鉴权桥:请求入口 async 预认证把验过的 registry-JWT principal 挂在这个 symbol 上——它是
216
+ * request-local 真源(来自签名,非自报头),优先于任何头读取。setSsoPrincipal 在 server.ts 的入口块设,
217
+ * verifiedPrincipal 在此读。 */
96
218
  const SSO_PRINCIPAL = Symbol.for("sema.ssoVerifiedPrincipal");
97
219
  export function setSsoPrincipal(req, principal) {
98
220
  req[SSO_PRINCIPAL] = principal;
@@ -101,6 +223,9 @@ export function ssoVerifiedPrincipal(req) {
101
223
  const v = req[SSO_PRINCIPAL];
102
224
  return typeof v === "string" && v.length > 0 ? v : undefined;
103
225
  }
226
+ /** 鉴权桥 scope 透传:registry-JWT 的 `scope` claim(多租户活动租户,registry-core 0.3.0+
227
+ * `VerifiedIdentity.scope`)也挂 request-local——与 principal 同真源(来自签名,非自报头)。用途=可观测/审计
228
+ * 归因,以及未来 scope 级 quota/过滤的读取地基(单一真源)。ABSENT = pre-scope/默认 token,语义"global"。 */
104
229
  const SSO_SCOPE = Symbol.for("sema.ssoVerifiedScope");
105
230
  export function setSsoScope(req, scope) {
106
231
  req[SSO_SCOPE] = scope;
@@ -110,13 +235,15 @@ export function ssoVerifiedScope(req) {
110
235
  return typeof v === "string" && v.length > 0 ? v : undefined;
111
236
  }
112
237
  export function verifiedPrincipal(req, config) {
238
+ // 鉴权桥优先:registry-JWT 验过的 principal 来自签名,在 directDoor 与 BFF/gated 两种部署都胜出
239
+ // (directDoor 下原走 x-approval-principal-token,SSO principal 在其之前返回,成为下游的可信身份)。
113
240
  const sso = ssoVerifiedPrincipal(req);
114
241
  if (sso) {
115
- assertPrincipalShape(sso);
242
+ assertPrincipalShape(sso); // F1/F3: the SSO-bridge sub is a verified identity source too — same boundary gate
116
243
  return sso;
117
244
  }
118
245
  if (!config.directDoorActive)
119
- return principalFrom(req, config);
246
+ return principalFrom(req, config); // BFF/gated: the header is already verified upstream
120
247
  const h = req.headers[PRINCIPAL_TOKEN_HEADER];
121
248
  const token = (Array.isArray(h) ? h[0] : h) ?? "";
122
249
  const sub = verifyPrincipalJwt(token, config.principalJwtPubkeys, {
@@ -124,11 +251,23 @@ export function verifiedPrincipal(req, config) {
124
251
  aud: config.principalJwtAud ?? "\0",
125
252
  maxTtlSec: config.principalJwtMaxTtlSec,
126
253
  })?.sub;
254
+ // F1/F3: gate the direct-door JWT sub as well — a typed 400 naming the rule beats a silent-null 401 (the
255
+ // minter must not be able to issue a "_"-sub token that merges with the anonymous scope family downstream).
127
256
  if (sub !== undefined)
128
257
  assertPrincipalShape(sub);
129
258
  return sub;
130
259
  }
260
+ // design/158 N17: memoryScopeFor / memoryEngineRemoteLanePosture / memoryEngineBackendFor / memorySpecForRequest
261
+ // moved VERBATIM to the leaf ./memory-scope.js (security.ts's name says auth; these four resolve memory-plane
262
+ // config, unrelated). Re-exported here so existing importers (main.ts, config.ts, http/server.ts, run-local.ts,
263
+ // index.ts, tests) keep working untouched — this file's own createAuthorizer below still calls memoryScopeFor.
131
264
  export { memoryScopeFor, memoryEngineRemoteLanePosture, memoryEngineBackendFor, memorySpecForRequest } from "./memory-scope.js";
265
+ // design/158 A13: approval-envelope HMAC (integrity, {@link verifyApprovalHmac}/{@link approvalHmacMessage}/
266
+ // MAX_APPROVAL_REASON_CHARS) and principal-JWT/direct-door proof (identity, {@link verifyPrincipalJwt}/
267
+ // approvalBnd/verifyDirectDoorProof) moved VERBATIM to ./approval-hmac.js and ./principal-jwt.js — this file
268
+ // keeps only the authenticator/principal-shape/SSO-mount group (createAuthorizer, verifiedPrincipal,
269
+ // assertPrincipalShape, principalFrom, setSsoPrincipal/setSsoScope) plus this re-export so existing
270
+ // importers of the moved names keep working unchanged.
132
271
  export { approvalHmacMessage, MAX_APPROVAL_REASON_CHARS, verifyApprovalHmac } from "./approval-hmac.js";
133
272
  export { verifyPrincipalJwt, approvalBnd, verifyDirectDoorProof } from "./principal-jwt.js";
134
273
  //# sourceMappingURL=security.js.map
@@ -1,3 +1,24 @@
1
+ /**
2
+ * Sema-registry adapter — pull the effective config from sema-registry and apply it OVER the
3
+ * env-derived defaults (env = fallback, center = override). Follows the "universal internal
4
+ * schema → translate at the boundary" pattern, with our security boundary kept:
5
+ *
6
+ * - the CENTER owns the LOGICAL config: the model roster (names/capabilities/tier), the role map,
7
+ * and team templates;
8
+ * - the SERVICE env still owns the SECRETS: API keys stay in env (the center never stores a secret);
9
+ * keys are per-model via `apiKeyEnv` → `config.modelApiKeyEnv` → the spec's `getApiKeyAndHeaders`
10
+ * (core 1.45), so each model/cascade-rung authenticates with its own upstream key.
11
+ *
12
+ * Per-model `baseUrl` IS transported (a catalog model may live on a different gateway;
13
+ * core brain honors model.baseUrl, absent = "" = boot-env endpoint). TODO remaining: hot-reload
14
+ * of models/roles needs Runner support — today teams hot-reload via the registry, while a models/roles
15
+ * change is logged as "restart to apply".
16
+ *
17
+ * (design/158 A13, internal-lossless) This module is now a FACADE: the implementation lives in
18
+ * `src/config-center/` split by responsibility group (HTTP client / EffectiveConfig application /
19
+ * restart-signal detection / skills+MCP consumption). Every symbol below is re-exported UNCHANGED —
20
+ * existing `from "./sema-registry.js"` / `from "../sema-registry.js"` imports need zero changes.
21
+ */
1
22
  export { fetchEffective, fetchPrincipalCaps, ConfigCenterHttpError, fetchSkillContent, fetchPromptArtifact, fetchPromptBlob, } from "./config-center/http-client.js";
2
23
  export { mutateInPlace, applyEffective, applyRuntimeGates, applyRuntimeHot, resolveDefaultModelName, logEffectiveDiff, runtimeHasActiveGate, } from "./config-center/apply-effective.js";
3
24
  export { restartReasons, planeHasActiveTiers, modelPlaneChanged, type RestartSlice, type RestartSignal, } from "./config-center/restart-signal.js";
@@ -1,3 +1,24 @@
1
+ /**
2
+ * Sema-registry adapter — pull the effective config from sema-registry and apply it OVER the
3
+ * env-derived defaults (env = fallback, center = override). Follows the "universal internal
4
+ * schema → translate at the boundary" pattern, with our security boundary kept:
5
+ *
6
+ * - the CENTER owns the LOGICAL config: the model roster (names/capabilities/tier), the role map,
7
+ * and team templates;
8
+ * - the SERVICE env still owns the SECRETS: API keys stay in env (the center never stores a secret);
9
+ * keys are per-model via `apiKeyEnv` → `config.modelApiKeyEnv` → the spec's `getApiKeyAndHeaders`
10
+ * (core 1.45), so each model/cascade-rung authenticates with its own upstream key.
11
+ *
12
+ * Per-model `baseUrl` IS transported (a catalog model may live on a different gateway;
13
+ * core brain honors model.baseUrl, absent = "" = boot-env endpoint). TODO remaining: hot-reload
14
+ * of models/roles needs Runner support — today teams hot-reload via the registry, while a models/roles
15
+ * change is logged as "restart to apply".
16
+ *
17
+ * (design/158 A13, internal-lossless) This module is now a FACADE: the implementation lives in
18
+ * `src/config-center/` split by responsibility group (HTTP client / EffectiveConfig application /
19
+ * restart-signal detection / skills+MCP consumption). Every symbol below is re-exported UNCHANGED —
20
+ * existing `from "./sema-registry.js"` / `from "../sema-registry.js"` imports need zero changes.
21
+ */
1
22
  export { fetchEffective, fetchPrincipalCaps, ConfigCenterHttpError, fetchSkillContent, fetchPromptArtifact, fetchPromptBlob, } from "./config-center/http-client.js";
2
23
  export { mutateInPlace, applyEffective, applyRuntimeGates, applyRuntimeHot, resolveDefaultModelName, logEffectiveDiff, runtimeHasActiveGate, } from "./config-center/apply-effective.js";
3
24
  export { restartReasons, planeHasActiveTiers, modelPlaneChanged, } from "./config-center/restart-signal.js";
@@ -1,5 +1,36 @@
1
+ /**
2
+ * Session leaf-advance bus — the S2 fast path of the session-level SSE subscription
3
+ * ([1196]/[1208]③: an append that lands on THIS replica fans out to watchers synchronously,
4
+ * zero latency on single-replica deployments; cross-replica watchers still ride the probe lane).
5
+ *
6
+ * Deliberately a REPLICA-LOCAL singleton (module state), not a constructor-threaded dependency:
7
+ * the leaf write sits at the bottom of the per-session storage stack (TiDB/Pg `persist()` — a
8
+ * static-factory + N-arg constructor chain away from main.ts), while the one consumer
9
+ * (SessionWatchRegistry.notifyLocal) is replica-local by design. A bus keeps the wiring one line
10
+ * per write site and one line in main; anything smarter re-plumbs four layers for the same effect.
11
+ *
12
+ * Contract:
13
+ * - `emitLeafAdvance` MUST be fire-and-forget from the writer's perspective: it never throws
14
+ * (listener errors are swallowed) and does no async work — a broken watcher must not fail or
15
+ * slow a session write.
16
+ * - Emit AFTER the storage commit succeeds (a rolled-back CAS must not fan out a leaf that never
17
+ * became durable).
18
+ * - Owner IS carried and MUST be the COMMIT-TIME row owner (codex two rounds: without owner the
19
+ * generation fence is skipped; a wake-time snapshot is worse — stale-A over a reclaimed row false-
20
+ * matches an old A entry and leaks the new tenant's leaf into the old stream). Zero-cost source:
21
+ * the persist transaction's own leaf_seq SELECT carries the owner column — the emitted owner is the
22
+ * row's tenant at the moment the write committed.
23
+ * - `leafSeq`(the row's committed leaf_seq)rides every emit: DB commits serialize, but the
24
+ * post-commit continuations don't — without an ordering token a delayed leaf-N delivery after
25
+ * leaf-N+1 would walk the registry BACKWARD (and a stale notification could false-drop a newer
26
+ * generation on owner mismatch). The registry keeps the highest accepted seq and ignores lower.
27
+ * - The local (file/in-mem) lane does not emit: those sessions persist inside core's storage
28
+ * backend with no server-side write hook; the probe lane covers them at its normal cadence.
29
+ */
1
30
  type LeafListener = (sessionId: string, leafId: string | null, owner: string | null | undefined, leafSeq: number) => void;
31
+ /** main.ts wires this once at boot (→ SessionWatchRegistry.notifyLocal). Last write wins; tests reset with undefined. */
2
32
  export declare function setLeafAdvanceListener(fn: LeafListener | undefined): void;
33
+ /** Called by the SQL session-storage write sites post-commit. Never throws, never awaits. */
3
34
  export declare function emitLeafAdvance(sessionId: string, leafId: string | null, owner: string | null | undefined, leafSeq: number): void;
4
35
  export {};
5
36
  //# sourceMappingURL=session-leaf-bus.d.ts.map
@@ -1,12 +1,44 @@
1
+ /**
2
+ * Session leaf-advance bus — the S2 fast path of the session-level SSE subscription
3
+ * ([1196]/[1208]③: an append that lands on THIS replica fans out to watchers synchronously,
4
+ * zero latency on single-replica deployments; cross-replica watchers still ride the probe lane).
5
+ *
6
+ * Deliberately a REPLICA-LOCAL singleton (module state), not a constructor-threaded dependency:
7
+ * the leaf write sits at the bottom of the per-session storage stack (TiDB/Pg `persist()` — a
8
+ * static-factory + N-arg constructor chain away from main.ts), while the one consumer
9
+ * (SessionWatchRegistry.notifyLocal) is replica-local by design. A bus keeps the wiring one line
10
+ * per write site and one line in main; anything smarter re-plumbs four layers for the same effect.
11
+ *
12
+ * Contract:
13
+ * - `emitLeafAdvance` MUST be fire-and-forget from the writer's perspective: it never throws
14
+ * (listener errors are swallowed) and does no async work — a broken watcher must not fail or
15
+ * slow a session write.
16
+ * - Emit AFTER the storage commit succeeds (a rolled-back CAS must not fan out a leaf that never
17
+ * became durable).
18
+ * - Owner IS carried and MUST be the COMMIT-TIME row owner (codex two rounds: without owner the
19
+ * generation fence is skipped; a wake-time snapshot is worse — stale-A over a reclaimed row false-
20
+ * matches an old A entry and leaks the new tenant's leaf into the old stream). Zero-cost source:
21
+ * the persist transaction's own leaf_seq SELECT carries the owner column — the emitted owner is the
22
+ * row's tenant at the moment the write committed.
23
+ * - `leafSeq`(the row's committed leaf_seq)rides every emit: DB commits serialize, but the
24
+ * post-commit continuations don't — without an ordering token a delayed leaf-N delivery after
25
+ * leaf-N+1 would walk the registry BACKWARD (and a stale notification could false-drop a newer
26
+ * generation on owner mismatch). The registry keeps the highest accepted seq and ignores lower.
27
+ * - The local (file/in-mem) lane does not emit: those sessions persist inside core's storage
28
+ * backend with no server-side write hook; the probe lane covers them at its normal cadence.
29
+ */
1
30
  let listener;
31
+ /** main.ts wires this once at boot (→ SessionWatchRegistry.notifyLocal). Last write wins; tests reset with undefined. */
2
32
  export function setLeafAdvanceListener(fn) {
3
33
  listener = fn;
4
34
  }
35
+ /** Called by the SQL session-storage write sites post-commit. Never throws, never awaits. */
5
36
  export function emitLeafAdvance(sessionId, leafId, owner, leafSeq) {
6
37
  try {
7
38
  listener?.(sessionId, leafId, owner, leafSeq);
8
39
  }
9
40
  catch {
41
+ /* a broken watcher must never fail a session write */
10
42
  }
11
43
  }
12
44
  //# sourceMappingURL=session-leaf-bus.js.map
@@ -1,3 +1,49 @@
1
+ /**
2
+ * session-sync 的**内容判据**——回答一个 id-集合分类器回答不了的问题:
3
+ * 「两条 entry id 集合相等的日志,**内容**是否也相同?」
4
+ *
5
+ * ── 为什么需要它(深挖第一轮 + 2026-07-26 顺着往下查出的第二半)────────────────────────────────────
6
+ * §7 的 `classifySyncRelationshipByIds` 只比 **id 集合**,而 entry id 是 uuidv7、**不是内容寻址** ⇒
7
+ * 「同 id、异载荷」结构上完全可能(wire 本身就收调用方给的 entries)。第一半的后果已知:Phase A 判 `identical`
8
+ * ⇒ 整段跳过、调用方拿 200 而目的端仍是自己那份内容(真 HTTP 复现过)。
9
+ *
10
+ * 🔴 **第二半是我一开始判错的地方**:我在黑板 [1701] 说「server 单方面修不了」。那句只对 **Phase A** 成立
11
+ * (那时 server 手上没有源端内容,必须靠调用方送摘要)。但 **commit 时 server 同时握着两份日志**
12
+ * (staged + dst),所以内容比较**根本不需要调用方配合** —— 而 4 处 commit/import 路径当时都写着
13
+ * 「`relation === "identical"` ⇒ 跳过 entries 写入」,把「id 集合相等」当成了「内容相同」。
14
+ * 后果:一个**已经把整条日志上传完**的调用方(没送摘要、或送了但不可比),在 commit 处仍然拿到 no-op。
15
+ * ⇒ 两半都要修:Phase A 需要调用方的 `logDigest`(省掉无谓上传),commit 这一半是 server 自己的活。
16
+ *
17
+ * ── 判据来源:core 1.414 导出的 `sessionLogDigest` ──────────────────────────────────────────────────
18
+ * 覆盖每条 entry 的**全部字段**(id / parentId / type / timestamp / 载荷)且**顺序显著**,逐条带长度前缀
19
+ * (所以两份日志不可能被重新切分成同样的字节)。core 明确它可以两端各算 —— 与 `boundInputHash` 不同,
20
+ * 因为这里**分叉的代价是多同步一趟,不是错答案、也不是拒绝**(审批路径上分叉会拒掉一个合法的人类决定,
21
+ * 方向相反)。
22
+ *
23
+ * ── ⚠️ v1 摘要下本判据的**退化行为**(core 黑板 [1709];1.415.0 已修,现行下限已远高于此 ——
24
+ * 承重下限与理由见 `test/core-dependency-floor.test.ts`,别在这里记版本号)────────────────
25
+ * v1 的摘要区分 `{a: undefined}` 与 `{}`,而 core 自己成规模产 own-key=undefined 的 entry ⇒ 同一份日志的
26
+ * 内存形与 JSON 往返形摘要必然不同。本函数在 commit 处比的是 **staged**(刚从 wire 解析,JSON 形)与 **dst**
27
+ * (从存储读回,也是 JSON 形)—— 两侧同形,所以**这一处**不受那条影响;但若某个后端把 staged 留在内存形,
28
+ * 判据会退化成「恒不相等 ⇒ 恒改写」。
29
+ * 🔴 那个退化方向是**安全**的(多写一遍,不会丢数据),这是刻意选的:判据不确定时**宁可改写**,
30
+ * 因为反方向的错(误判"内容相同"而跳过写入)正是本函数要修的那个缺陷。
31
+ * ⇒ 所以这里**不加 scheme 门**。(Phase A 那条路曾加过 scheme **名字门**,后被 tsc 判恒真并撤掉,
32
+ * 换成「依赖下限 + 行为门」—— 名字门只认识旧名字,守不住这条性质;见 server.ts Phase A 段注释与
33
+ * `test/sync-content-digest.test.ts`。)
34
+ *
35
+ * ⚠️ 抽成共享函数而不是在 4 处各写一遍:core [1689] RB-74 的教训(宣布"同族类修完成"而三个实现只落了一个),
36
+ * 本仓今天也刚在 33 处 exec→FileError 包装上吃过同款。判据收成一处,才谈得上机器看守。
37
+ */
1
38
  import { type SessionTreeEntry } from "@sema-agent/core";
39
+ /**
40
+ * id 集合已判 `identical` 的两条日志,**内容是否真的相同**。
41
+ *
42
+ * `true` ⇒ 内容也相同,跳过 entries 写入是**对的**(只需 owner 重戳)。
43
+ * `false` ⇒ **同 id 异内容**:必须真正改写目的端,否则调用方拿到的是一句"已同步"的谎。
44
+ *
45
+ * 🔴 这里**不抛错、不拒绝**:core 定的消费口径是「digest 不符永远不得变成 error / 409 / 拒绝同步」——
46
+ * 不符只意味着"多干一趟活",而不是"这次同步非法"。
47
+ */
2
48
  export declare function identicalIdsAlsoIdenticalContent(staged: readonly SessionTreeEntry[], dst: readonly SessionTreeEntry[] | null): boolean;
3
49
  //# sourceMappingURL=session-sync-content.d.ts.map
@@ -1,7 +1,53 @@
1
+ /**
2
+ * session-sync 的**内容判据**——回答一个 id-集合分类器回答不了的问题:
3
+ * 「两条 entry id 集合相等的日志,**内容**是否也相同?」
4
+ *
5
+ * ── 为什么需要它(深挖第一轮 + 2026-07-26 顺着往下查出的第二半)────────────────────────────────────
6
+ * §7 的 `classifySyncRelationshipByIds` 只比 **id 集合**,而 entry id 是 uuidv7、**不是内容寻址** ⇒
7
+ * 「同 id、异载荷」结构上完全可能(wire 本身就收调用方给的 entries)。第一半的后果已知:Phase A 判 `identical`
8
+ * ⇒ 整段跳过、调用方拿 200 而目的端仍是自己那份内容(真 HTTP 复现过)。
9
+ *
10
+ * 🔴 **第二半是我一开始判错的地方**:我在黑板 [1701] 说「server 单方面修不了」。那句只对 **Phase A** 成立
11
+ * (那时 server 手上没有源端内容,必须靠调用方送摘要)。但 **commit 时 server 同时握着两份日志**
12
+ * (staged + dst),所以内容比较**根本不需要调用方配合** —— 而 4 处 commit/import 路径当时都写着
13
+ * 「`relation === "identical"` ⇒ 跳过 entries 写入」,把「id 集合相等」当成了「内容相同」。
14
+ * 后果:一个**已经把整条日志上传完**的调用方(没送摘要、或送了但不可比),在 commit 处仍然拿到 no-op。
15
+ * ⇒ 两半都要修:Phase A 需要调用方的 `logDigest`(省掉无谓上传),commit 这一半是 server 自己的活。
16
+ *
17
+ * ── 判据来源:core 1.414 导出的 `sessionLogDigest` ──────────────────────────────────────────────────
18
+ * 覆盖每条 entry 的**全部字段**(id / parentId / type / timestamp / 载荷)且**顺序显著**,逐条带长度前缀
19
+ * (所以两份日志不可能被重新切分成同样的字节)。core 明确它可以两端各算 —— 与 `boundInputHash` 不同,
20
+ * 因为这里**分叉的代价是多同步一趟,不是错答案、也不是拒绝**(审批路径上分叉会拒掉一个合法的人类决定,
21
+ * 方向相反)。
22
+ *
23
+ * ── ⚠️ v1 摘要下本判据的**退化行为**(core 黑板 [1709];1.415.0 已修,现行下限已远高于此 ——
24
+ * 承重下限与理由见 `test/core-dependency-floor.test.ts`,别在这里记版本号)────────────────
25
+ * v1 的摘要区分 `{a: undefined}` 与 `{}`,而 core 自己成规模产 own-key=undefined 的 entry ⇒ 同一份日志的
26
+ * 内存形与 JSON 往返形摘要必然不同。本函数在 commit 处比的是 **staged**(刚从 wire 解析,JSON 形)与 **dst**
27
+ * (从存储读回,也是 JSON 形)—— 两侧同形,所以**这一处**不受那条影响;但若某个后端把 staged 留在内存形,
28
+ * 判据会退化成「恒不相等 ⇒ 恒改写」。
29
+ * 🔴 那个退化方向是**安全**的(多写一遍,不会丢数据),这是刻意选的:判据不确定时**宁可改写**,
30
+ * 因为反方向的错(误判"内容相同"而跳过写入)正是本函数要修的那个缺陷。
31
+ * ⇒ 所以这里**不加 scheme 门**。(Phase A 那条路曾加过 scheme **名字门**,后被 tsc 判恒真并撤掉,
32
+ * 换成「依赖下限 + 行为门」—— 名字门只认识旧名字,守不住这条性质;见 server.ts Phase A 段注释与
33
+ * `test/sync-content-digest.test.ts`。)
34
+ *
35
+ * ⚠️ 抽成共享函数而不是在 4 处各写一遍:core [1689] RB-74 的教训(宣布"同族类修完成"而三个实现只落了一个),
36
+ * 本仓今天也刚在 33 处 exec→FileError 包装上吃过同款。判据收成一处,才谈得上机器看守。
37
+ */
1
38
  import { sessionLogDigest } from "@sema-agent/core";
39
+ /**
40
+ * id 集合已判 `identical` 的两条日志,**内容是否真的相同**。
41
+ *
42
+ * `true` ⇒ 内容也相同,跳过 entries 写入是**对的**(只需 owner 重戳)。
43
+ * `false` ⇒ **同 id 异内容**:必须真正改写目的端,否则调用方拿到的是一句"已同步"的谎。
44
+ *
45
+ * 🔴 这里**不抛错、不拒绝**:core 定的消费口径是「digest 不符永远不得变成 error / 409 / 拒绝同步」——
46
+ * 不符只意味着"多干一趟活",而不是"这次同步非法"。
47
+ */
2
48
  export function identicalIdsAlsoIdenticalContent(staged, dst) {
3
49
  if (dst === null)
4
- return false;
50
+ return false; // 目的端没有日志 ⇒ 谈不上"内容相同",按需改写
5
51
  return sessionLogDigest(staged) === sessionLogDigest(dst);
6
52
  }
7
53
  //# sourceMappingURL=session-sync-content.js.map
@@ -1,22 +1,81 @@
1
+ /**
2
+ * 2c session-sync KERNEL (design/158 A2) — the PURE half of session-sync: the §7 relation classifier, the staging-id
3
+ * scheme, the {@link StagingHandle}/{@link ImportStagingStore} contracts and the {@link SyncConflictError} type.
4
+ * Moved VERBATIM out of session-sync.ts (which keeps the StoreBackend-coupled ORCHESTRATION: exportSession/
5
+ * importSession/planSync) so the three DB session adapters (local/pg/tidb) and security.ts can depend on these
6
+ * symbols WITHOUT touching the orchestration module — session-sync.ts value-imports StoreBackend and type-imports
7
+ * security's OwnerAwareSessionStore, so importing it from security.ts formed the repo's only true type cycle
8
+ * (security ↔ session-sync; lens2 §B/§E). This file imports NOTHING from the repo (core types only) — a leaf,
9
+ * same shape as session-sync-content.ts. session-sync.ts re-exports everything here, so existing import sites
10
+ * keep working unchanged.
11
+ */
1
12
  import type { SessionTreeEntry } from "@sema-agent/core";
13
+ /**
14
+ * P1d-β (PUSH streaming, docs/DESIGN-session-sync.md §15 + the persistence synthesis) — a TWO-PHASE STAGED import
15
+ * handle. The whole-bundle `importSession` (session-sync.ts) buffers every entry in one JSON body (server memory ∝ session size);
16
+ * β instead STREAMS the entry log (NDJSON) into a SHADOW session id, validating it ONLINE per line through core's
17
+ * StreamingImportValidator (the single invariant gate — core 1.143.0), then ATOMICALLY swaps
18
+ * the shadow rows into the real session id in ONE txn — so server memory is bounded by the in-flight BATCH, not the
19
+ * whole log. A handle is minted by {@link ImportStagingStore.beginImportStaging} (Phase A) and driven by the NDJSON
20
+ * route (Phase B): `appendBatch` per batch, then `commit` (the swap) or `abort` (drop the staging rows).
21
+ *
22
+ * Invariants the implementations uphold:
23
+ * - The staging rows live under `stagingId = ${realSessionId}#stg-${token}` (the `#` is illegal in a real uuidv7, so
24
+ * it can NEVER collide with a real session id) and have NO `session_meta` row → they are INVISIBLE to wake / ownerOf
25
+ * / listSessions (the existing orphan invariant) until `commit` writes the real session_meta LAST as the sole
26
+ * commit point. A crash before commit leaves only collectable orphan staging rows, never a half-session.
27
+ * - `appendBatch` is IDEMPOTENT (INSERT … ON DUPLICATE KEY / ON CONFLICT DO NOTHING on the `(session_id, entry_id)`
28
+ * uk), so a re-streamed batch (a resumed Phase B) is a no-op.
29
+ * - `commit` re-classifies the relation IN-TXN against the dst's CURRENT entry ids (closing the Phase-A plan→commit
30
+ * TOCTOU): a flip to fork/stale without the caller's overwrite consent rolls back and throws {@link SyncConflictError}.
31
+ */
2
32
  export interface StagingHandle {
33
+ /** The shadow session id the staged rows live under (`${realSessionId}#stg-${token}`) — opaque to the route. */
3
34
  readonly stagingId: string;
35
+ /** The real (destination) session id the staged rows are committed INTO. */
4
36
  readonly realSessionId: string;
37
+ /** Append a bounded batch of entries to the staging id, re-seq'd dense from a running counter held in the handle.
38
+ * Idempotent (ON DUPLICATE KEY / ON CONFLICT DO NOTHING) — a re-streamed batch is a no-op. One txn per batch. */
5
39
  appendBatch(entries: SessionTreeEntry[]): Promise<void>;
40
+ /** ATOMICALLY swap the staged rows into the real session id (ONE txn): in-txn re-classify (TOCTOU close) → purge dst
41
+ * → row-key rename staging→real → session_meta LAST (the commit point). `owner` is re-stamped (§9). Throws
42
+ * {@link SyncConflictError} on an unconsented fork/stale flip. Returns the committed relation. */
6
43
  commit(owner: string | null, opts?: {
7
44
  resolution?: "overwrite-dst";
8
45
  }): Promise<{
9
46
  relation: SyncRelation["relation"];
10
47
  }>;
48
+ /** Drop the staging rows (Phase B aborted before commit) — DELETE the staging-id session_event rows. Idempotent. */
11
49
  abort(): Promise<void>;
12
50
  }
51
+ /** A session store that can stage a streamed import (P1d-β). The 3 backends implement it; the in-memory dev store
52
+ * does not → the method is optional (the route 501s when absent, parity with the other §0.5 optional seams). */
13
53
  export type ImportStagingStore = {
54
+ /** Begin a staged import into `realSessionId` under a shadow id `${realSessionId}#stg-${token}` (the ROUTE mints the
55
+ * uuidv7 `token` and passes it — the store NEVER calls Date.now/uuidv7 itself, so the staging id is deterministic
56
+ * and the route owns the lease key). Returns a {@link StagingHandle} the route streams batches into then commits. */
14
57
  beginImportStaging(realSessionId: string, token: string): StagingHandle;
58
+ /** Reaper — drop staging-id session_event rows with NO session_meta whose oldest row is older than the grace window
59
+ * (an in-flight stream's rows stay fresh → never reaped). Mirrors `sweepOrphanBlobs`' grace discipline. */
15
60
  sweepStagingSessions?(): Promise<number>;
16
61
  };
62
+ /** The staging-id format: a real session id with a `#stg-${token}` suffix. The `#` is illegal in a uuidv7, so a
63
+ * staging id can never collide with a real session id (the orphan invariant) and is recognizable for the reaper. */
17
64
  export declare function stagingIdFor(realSessionId: string, token: string): string;
65
+ /** The substring marker every staging id carries (the reaper's `LIKE '%#stg-%'` selector). */
18
66
  export declare const STAGING_ID_MARKER = "#stg-";
67
+ /** Recover the real session id from a staging id (everything before the `#stg-` marker), or null if not a staging id. */
19
68
  export declare function realIdOfStaging(stagingId: string): string | null;
69
+ /**
70
+ * §7 — the relationship between a SOURCE bundle's entry log and the DESTINATION's CURRENT entry log, the gate that
71
+ * decides whether an import is a safe sync or a data-losing overwrite. Five exhaustive cases:
72
+ * - `fresh` — the dst has no such session (nothing to lose) → import is unconditional.
73
+ * - `identical` — src and dst hold the SAME entry-id set → the conversation log is already present & equal (no-op).
74
+ * - `fast_forward` — dst's entries are a STRICT subset of src (src is strictly ahead = clean append) → safe to apply.
75
+ * - `stale` — src's entries are a STRICT subset of dst (src is strictly behind) → applying would LOSE the dst
76
+ * entries the src never saw → a conflict (refused unless the user explicitly overwrites).
77
+ * - `fork` — each side has ≥1 entry the other lacks (true divergence after a common ancestor) → a conflict.
78
+ */
20
79
  export type SyncRelation = {
21
80
  relation: "fresh";
22
81
  } | {
@@ -33,8 +92,38 @@ export type SyncRelation = {
33
92
  srcExclusive: string[];
34
93
  dstExclusive: string[];
35
94
  };
95
+ /**
96
+ * §7 — classify how importing `srcEntries` into a destination holding `dstEntries` would relate the two logs. PURE
97
+ * (no I/O); the §7 fork detector. The comparison is over the ENTRY-ID SETS, not leaf_id:
98
+ *
99
+ * Entry ids are copied VERBATIM across backends (fork/import re-seq only `seq`; id/parentId/payload are byte-identical
100
+ * — see tidb-session-store fork/importEntries), so a set comparison of ids is the SOUND divergence test §7 demands. It
101
+ * fixes v1's leaf_id-only check, which was unsound BOTH ways:
102
+ * - FALSE NEGATIVE (the dangerous one): a cross-end rewind moves `LeafEntry.targetId` back onto a shared OLD entry id,
103
+ * so two genuinely-forked logs report the SAME leaf_id → v1 would silently overwrite = data loss (exactly the 2c
104
+ * use case). Set comparison sees each side's exclusive ids and reports `fork`.
105
+ * - FALSE POSITIVE: a clean fast-forward ends on a NEW leaf id ≠ the dst's leaf → v1 flags a (non-)conflict. Set
106
+ * comparison sees dst ⊊ src and reports `fast_forward` (safe).
107
+ *
108
+ * `commonAncestor` for a fork = the entry id present in BOTH logs that appears LAST in `srcEntries` oldest-first order
109
+ * (the deepest shared appended entry = the divergence point), or `null` if the logs share no entry at all.
110
+ */
36
111
  export declare function classifySyncRelationship(srcEntries: SessionTreeEntry[], dstEntries: SessionTreeEntry[] | null): SyncRelation;
112
+ /**
113
+ * §7 — the SAME relation classifier as {@link classifySyncRelationship}, over entry-id LISTS (oldest-first) instead of
114
+ * full entries. This is the canonical implementation the entries-typed wrapper delegates to. It exists in its own right
115
+ * for the P1d HTTP `/sync/plan` route: the two peers are different PROCESSES (the local shell + the cloud), so the
116
+ * planning peer holds only the OTHER end's entry-id list (not its `SessionTreeEntry[]`) — the relation is decidable from
117
+ * the ids alone (ids are copied VERBATIM across backends, so a set comparison of ids is the sound divergence test §7
118
+ * demands; see the wrapper's doc-comment for why leaf_id was unsound). `srcIds`/`dstIds` are OLDEST-FIRST so the
119
+ * fork `commonAncestor` (the deepest shared id) and the ordered exclusive/new lists are derived correctly.
120
+ */
37
121
  export declare function classifySyncRelationshipByIds(srcIds: string[], dstIds: string[] | null): SyncRelation;
122
+ /**
123
+ * §7 — a typed conflict the route maps to HTTP 409: an import that WOULD lose destination history (a `fork` or a
124
+ * `stale` source) and the caller did NOT pass an explicit `{ resolution: "overwrite-dst" }`. Carries the classified
125
+ * relation so the route/shell can surface the exclusive entry sets to the user for a keep-local / keep-cloud decision.
126
+ */
38
127
  export declare class SyncConflictError extends Error {
39
128
  readonly sessionId: string;
40
129
  readonly relation: Extract<SyncRelation, {