@sema-agent/server 7.146.0 → 7.147.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 (398) hide show
  1. package/MIGRATION.md +384 -0
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/USAGE.md +170 -66
  5. package/deploy/facts/lanes.json +7 -0
  6. package/deploy/sema-up/README.md +2 -2
  7. package/deploy/sema-up/chart/templates/_helpers.tpl +22 -0
  8. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -4
  9. package/deploy/sema-up/chart/templates/server.yaml +5 -4
  10. package/deploy/sema-up/chart/values.yaml +1 -1
  11. package/deploy/sema-up/cluster-up.sh +2 -1
  12. package/deploy/sema-up/lib/flagshape.sh +4 -0
  13. package/deploy/sema-up/lib/lanes.json +2 -5
  14. package/deploy/sema-up/sema-up.sh +12 -9
  15. package/deploy/sema-up/stack/compose.yaml +5 -4
  16. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -3
  17. package/dist/approval-card.d.ts +4 -4
  18. package/dist/approval.d.ts +3 -3
  19. package/dist/audit.js +2 -2
  20. package/dist/bench/s1/live-deps.js +3 -1
  21. package/dist/boot/crash-last.js +2 -1
  22. package/dist/boot/device-lane.js +5 -5
  23. package/dist/boot/engine-lease.d.ts +12 -11
  24. package/dist/boot/execution-env.d.ts +2 -1
  25. package/dist/boot/execution-env.js +45 -33
  26. package/dist/boot/execution-lane.d.ts +37 -9
  27. package/dist/boot/execution-lane.js +74 -20
  28. package/dist/boot/exit-boundary.d.ts +1 -1
  29. package/dist/boot/exit-last.js +2 -1
  30. package/dist/boot/governance-seams.d.ts +2 -2
  31. package/dist/boot/leader.js +1 -1
  32. package/dist/boot/memory-boundary.d.ts +11 -11
  33. package/dist/boot/memory-boundary.js +3 -3
  34. package/dist/boot/memory-consolidation.d.ts +13 -24
  35. package/dist/boot/memory-consolidation.js +0 -13
  36. package/dist/boot/org-memory.js +3 -2
  37. package/dist/boot/parked-revive-gate.d.ts +1 -1
  38. package/dist/boot/parked-revive-gate.js +1 -1
  39. package/dist/boot/reapers.js +1 -1
  40. package/dist/boot/resolve-spec.js +91 -111
  41. package/dist/boot/retention-lane.d.ts +4 -42
  42. package/dist/boot/session-faces.d.ts +1 -0
  43. package/dist/boot/session-faces.js +8 -2
  44. package/dist/boot/stage-01-config.d.ts +1 -1
  45. package/dist/boot/stage-01-config.js +6 -2
  46. package/dist/boot/stage-02-web-admin-pull.d.ts +1 -1
  47. package/dist/boot/stage-02-web-admin-pull.js +10 -8
  48. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  49. package/dist/boot/stage-04-stores.d.ts +1 -1
  50. package/dist/boot/stage-05-execution-env.d.ts +2 -2
  51. package/dist/boot/stage-05-execution-env.js +3 -3
  52. package/dist/boot/stage-06-runners.d.ts +3 -3
  53. package/dist/boot/stage-06-runners.js +1 -3
  54. package/dist/boot/stage-07-capability-layer.d.ts +3 -3
  55. package/dist/boot/stage-07-capability-layer.js +4 -9
  56. package/dist/boot/stage-08-reapers.d.ts +3 -3
  57. package/dist/boot/stage-09-leader.d.ts +4 -3
  58. package/dist/boot/stage-10-http-server.d.ts +4 -3
  59. package/dist/boot/stage-10-http-server.js +2 -1
  60. package/dist/boot/stores.d.ts +9 -0
  61. package/dist/boot/stores.js +18 -7
  62. package/dist/boot/web-admin.js +3 -3
  63. package/dist/capabilities/center-plugins.d.ts +2 -0
  64. package/dist/capabilities/center-plugins.js +6 -2
  65. package/dist/capabilities/composite-members.d.ts +1 -0
  66. package/dist/capabilities/composite-members.js +1 -0
  67. package/dist/capabilities/execution-lane.d.ts +7 -7
  68. package/dist/capabilities/execution-lane.js +2 -2
  69. package/dist/capabilities/hands-lane.d.ts +1 -1
  70. package/dist/capabilities/scenarios.d.ts +32 -18
  71. package/dist/capabilities/scenarios.js +13 -9
  72. package/dist/capabilities/settings-contract.d.ts +29 -0
  73. package/dist/capabilities/settings-contract.js +14 -0
  74. package/dist/capabilities/skills.d.ts +5 -5
  75. package/dist/capability-facts.d.ts +38 -0
  76. package/dist/capability-facts.js +34 -1
  77. package/dist/center-credential-renewer.js +3 -2
  78. package/dist/config-catalog.js +6 -5
  79. package/dist/config-invariants.d.ts +18 -3
  80. package/dist/config-invariants.js +36 -19
  81. package/dist/config-lkg.d.ts +1 -1
  82. package/dist/config-lkg.js +5 -6
  83. package/dist/config-provider.js +2 -0
  84. package/dist/config-types.d.ts +190 -186
  85. package/dist/config.d.ts +68 -5
  86. package/dist/config.js +80 -54
  87. package/dist/degenerate-instrument.js +1 -1
  88. package/dist/deploy-facts.js +3 -2
  89. package/dist/deployment-shape.d.ts +21 -12
  90. package/dist/deployment-shape.js +24 -6
  91. package/dist/env-facts.d.ts +7 -5
  92. package/dist/env-facts.js +10 -6
  93. package/dist/execution-config-root.d.ts +5 -5
  94. package/dist/execution-config-root.js +5 -5
  95. package/dist/execution-env-purpose.d.ts +14 -0
  96. package/dist/execution-env-purpose.js +29 -0
  97. package/dist/execution-lane-caps.d.ts +49 -86
  98. package/dist/execution-lane-caps.js +52 -62
  99. package/dist/execution-placement.d.ts +18 -2
  100. package/dist/execution-placement.js +19 -0
  101. package/dist/file-history-disclosure.d.ts +2 -2
  102. package/dist/fleet/drain-entry.d.ts +17 -10
  103. package/dist/fleet/drain-entry.js +1 -1
  104. package/dist/fleet/serving-lease.js +3 -4
  105. package/dist/history-anchor.d.ts +22 -0
  106. package/dist/history-anchor.js +14 -0
  107. package/dist/hooks/command-spawn.d.ts +1 -4
  108. package/dist/hooks/command-spawn.js +0 -11
  109. package/dist/hooks/hook-runner.d.ts +52 -8
  110. package/dist/hooks/hook-runner.js +160 -36
  111. package/dist/http/approval-sweeps.d.ts +2 -5
  112. package/dist/http/approval-sweeps.js +3 -2
  113. package/dist/http/checkpoint-ctx.d.ts +17 -0
  114. package/dist/http/checkpoint-ctx.js +6 -0
  115. package/dist/http/claim-latency.d.ts +10 -0
  116. package/dist/http/claim-latency.js +12 -0
  117. package/dist/http/dispatch.js +1 -1
  118. package/dist/http/durable-run-leg.js +2 -1
  119. package/dist/http/execution-context.d.ts +3 -1
  120. package/dist/http/execution-context.js +4 -0
  121. package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
  122. package/dist/http/memory-compliance-failure-reply.js +3 -0
  123. package/dist/http/memory-store-refusal-reply.d.ts +3 -3
  124. package/dist/http/memory-store-refusal-reply.js +3 -0
  125. package/dist/http/owner-access.d.ts +11 -0
  126. package/dist/http/owner-access.js +7 -4
  127. package/dist/http/principal-gate.d.ts +3 -14
  128. package/dist/http/principal-gate.js +0 -13
  129. package/dist/http/request-guards.d.ts +1 -1
  130. package/dist/http/resume-legs.d.ts +7 -10
  131. package/dist/http/resume-legs.js +79 -50
  132. package/dist/http/rewind-files-reply.d.ts +34 -0
  133. package/dist/http/rewind-files-reply.js +36 -0
  134. package/dist/http/route-ctx.d.ts +32 -16
  135. package/dist/http/route-table.js +2 -0
  136. package/dist/http/routes/approvals-assistant.js +5 -25
  137. package/dist/http/routes/capabilities.js +8 -2
  138. package/dist/http/routes/devices.js +1 -1
  139. package/dist/http/routes/memory-origin.d.ts +1 -1
  140. package/dist/http/routes/notify-wake.js +2 -1
  141. package/dist/http/routes/projects.d.ts +70 -0
  142. package/dist/http/routes/projects.js +86 -0
  143. package/dist/http/routes/rules.js +30 -2
  144. package/dist/http/routes/runs.js +8 -8
  145. package/dist/http/routes/session-sync.js +27 -10
  146. package/dist/http/routes/sessions.d.ts +7 -1
  147. package/dist/http/routes/sessions.js +104 -2
  148. package/dist/http/routes/tasks.js +9 -3
  149. package/dist/http/server.d.ts +24 -10
  150. package/dist/http/server.js +17 -6
  151. package/dist/http/stored-body-replay.d.ts +5 -3
  152. package/dist/http/stored-body-replay.js +10 -1
  153. package/dist/http/wire-types.d.ts +19 -10
  154. package/dist/index.d.ts +2 -2
  155. package/dist/index.js +1 -1
  156. package/dist/instruction-source-notice.d.ts +1 -1
  157. package/dist/memory-embedder-reembed.d.ts +38 -0
  158. package/dist/memory-embedder-reembed.js +20 -0
  159. package/dist/memory-incident-sink.d.ts +0 -28
  160. package/dist/memory-incident-sink.js +5 -0
  161. package/dist/memory-scope.d.ts +2 -2
  162. package/dist/memory-scope.js +1 -1
  163. package/dist/memory-store-refusal.d.ts +17 -4
  164. package/dist/memory-store-refusal.js +1 -1
  165. package/dist/memory-sync-client.d.ts +2 -0
  166. package/dist/memory-sync-client.js +13 -11
  167. package/dist/memory-sync.js +1 -1
  168. package/dist/model-compat.d.ts +35 -21
  169. package/dist/model-compat.js +49 -21
  170. package/dist/model-entry-refusal.d.ts +11 -1
  171. package/dist/model-entry-refusal.js +7 -0
  172. package/dist/namespaced-rule-name.d.ts +18 -1
  173. package/dist/namespaced-rule-name.js +12 -0
  174. package/dist/observability/fail-open.d.ts +17 -9
  175. package/dist/observability/fail-open.js +17 -9
  176. package/dist/observability/metrics.d.ts +2 -0
  177. package/dist/observability/metrics.js +2 -0
  178. package/dist/observability/secret-env-scrub.d.ts +30 -4
  179. package/dist/observability/secret-env-scrub.js +15 -3
  180. package/dist/orchestration/workflow-agent-session-index.d.ts +7 -12
  181. package/dist/orchestration/workflow-agent-session-index.js +1 -6
  182. package/dist/orchestration/workflow-completion-inbox.d.ts +26 -6
  183. package/dist/orchestration/workflow-completion-inbox.js +63 -45
  184. package/dist/org-memory-admission.d.ts +5 -2
  185. package/dist/org-memory-admission.js +25 -10
  186. package/dist/parked-decide.d.ts +33 -26
  187. package/dist/parked-decide.js +36 -44
  188. package/dist/plugins/approval-ask-store-file.d.ts +10 -2
  189. package/dist/plugins/approval-ask-store-file.js +37 -4
  190. package/dist/plugins/approval-ask-store-memory.d.ts +5 -3
  191. package/dist/plugins/approval-ask-store-memory.js +11 -2
  192. package/dist/plugins/approval-ask-store-sql.d.ts +3 -0
  193. package/dist/plugins/approval-ask-store-sql.js +3 -1
  194. package/dist/plugins/blob-backend.d.ts +38 -195
  195. package/dist/plugins/blob-backend.js +33 -229
  196. package/dist/plugins/caching-session-store.d.ts +9 -4
  197. package/dist/plugins/checkpoint-index-columns.d.ts +1 -1
  198. package/dist/plugins/checkpoint-index-columns.js +3 -2
  199. package/dist/plugins/checkpoint-store-face.d.ts +1 -1
  200. package/dist/plugins/device-store-sql.d.ts +2 -2
  201. package/dist/plugins/device-store-sql.js +5 -10
  202. package/dist/plugins/execution-lane-rename-m40.d.ts +20 -0
  203. package/dist/plugins/execution-lane-rename-m40.js +10 -0
  204. package/dist/plugins/execution-placement-sql.d.ts +63 -88
  205. package/dist/plugins/execution-placement-sql.js +94 -54
  206. package/dist/plugins/file-run-store.d.ts +26 -12
  207. package/dist/plugins/file-run-store.js +63 -63
  208. package/dist/plugins/imported-layer-root-retirement.d.ts +17 -8
  209. package/dist/plugins/imported-layer-root-retirement.js +4 -8
  210. package/dist/plugins/inbox-payload-column.d.ts +14 -0
  211. package/dist/plugins/inbox-payload-column.js +13 -0
  212. package/dist/plugins/local-checkpoint-store.d.ts +5 -0
  213. package/dist/plugins/local-checkpoint-store.js +11 -7
  214. package/dist/plugins/local-data-dir-modes-m39.d.ts +48 -0
  215. package/dist/plugins/local-data-dir-modes-m39.js +182 -0
  216. package/dist/plugins/local-engine-high-water.d.ts +11 -0
  217. package/dist/plugins/local-engine-high-water.js +59 -0
  218. package/dist/plugins/local-session-store.d.ts +91 -25
  219. package/dist/plugins/local-session-store.js +124 -45
  220. package/dist/plugins/local-task-attachment-store.d.ts +2 -0
  221. package/dist/plugins/local-task-attachment-store.js +10 -11
  222. package/dist/plugins/memory-embedder-fingerprint.d.ts +33 -10
  223. package/dist/plugins/memory-embedder-fingerprint.js +52 -12
  224. package/dist/plugins/memory-embedder.d.ts +1 -1
  225. package/dist/plugins/memory-embedder.js +2 -2
  226. package/dist/plugins/memory-engine-pg.d.ts +4 -3
  227. package/dist/plugins/memory-engine-pg.js +4 -4
  228. package/dist/plugins/memory-engine-sql-apply.d.ts +13 -4
  229. package/dist/plugins/memory-engine-sql-apply.js +1 -1
  230. package/dist/plugins/memory-engine-tidb.d.ts +8 -5
  231. package/dist/plugins/memory-engine-tidb.js +7 -8
  232. package/dist/plugins/one-time-migrations.d.ts +145 -35
  233. package/dist/plugins/one-time-migrations.js +272 -120
  234. package/dist/plugins/owner-only-file-mode.d.ts +29 -0
  235. package/dist/plugins/owner-only-file-mode.js +141 -0
  236. package/dist/plugins/permission-rule-store-file.d.ts +8 -8
  237. package/dist/plugins/permission-rule-store-file.js +14 -2
  238. package/dist/plugins/pg-pool.d.ts +2 -1
  239. package/dist/plugins/pg-pool.js +11 -4
  240. package/dist/plugins/release-version.d.ts +20 -0
  241. package/dist/plugins/release-version.js +28 -0
  242. package/dist/plugins/remote-env-adb.d.ts +20 -4
  243. package/dist/plugins/remote-env-adb.js +39 -11
  244. package/dist/plugins/remote-env-e2b.d.ts +12 -3
  245. package/dist/plugins/remote-env-e2b.js +6 -4
  246. package/dist/plugins/remote-env-host.d.ts +9 -1
  247. package/dist/plugins/remote-env-host.js +6 -5
  248. package/dist/plugins/remote-env-k8s.d.ts +5 -2
  249. package/dist/plugins/remote-env-k8s.js +15 -4
  250. package/dist/plugins/remote-env-local-docker.d.ts +4 -1
  251. package/dist/plugins/remote-env-local-docker.js +3 -3
  252. package/dist/plugins/remote-env-ssh.d.ts +8 -2
  253. package/dist/plugins/remote-env-ssh.js +26 -24
  254. package/dist/plugins/remote-shell.d.ts +59 -30
  255. package/dist/plugins/remote-shell.js +175 -62
  256. package/dist/plugins/retention-declaration.d.ts +37 -0
  257. package/dist/plugins/retention-declaration.js +9 -0
  258. package/dist/plugins/retention-deployment.d.ts +126 -0
  259. package/dist/plugins/retention-deployment.js +88 -0
  260. package/dist/plugins/retention-lane-store-sql.d.ts +74 -4
  261. package/dist/plugins/retention-lane-store-sql.js +103 -1
  262. package/dist/plugins/retention-sql.d.ts +29 -0
  263. package/dist/plugins/retention-sql.js +8 -0
  264. package/dist/plugins/schema-consistency.d.ts +0 -6
  265. package/dist/plugins/schema-consistency.js +1 -2
  266. package/dist/plugins/schema-ensure-legs.d.ts +1 -1
  267. package/dist/plugins/schema-ensure-legs.js +11 -1
  268. package/dist/plugins/session-ext-table.d.ts +74 -0
  269. package/dist/plugins/session-ext-table.js +121 -0
  270. package/dist/plugins/session-fork.d.ts +1 -1
  271. package/dist/plugins/session-row-sql.d.ts +8 -7
  272. package/dist/plugins/session-row-sql.js +15 -7
  273. package/dist/plugins/session-store-sql.d.ts +131 -0
  274. package/dist/plugins/session-store-sql.js +298 -0
  275. package/dist/plugins/session-workspace-cell.d.ts +2 -2
  276. package/dist/plugins/session-workspace-cell.js +2 -2
  277. package/dist/plugins/shared-memory-store-sql.d.ts +10 -0
  278. package/dist/plugins/shared-memory-store-sql.js +13 -13
  279. package/dist/plugins/snapshot-bucket-presence.js +1 -1
  280. package/dist/plugins/sql-driver.d.ts +23 -7
  281. package/dist/plugins/sql-driver.js +41 -8
  282. package/dist/plugins/sql-errors.d.ts +5 -2
  283. package/dist/plugins/sql-errors.js +4 -0
  284. package/dist/plugins/store-backend.d.ts +35 -8
  285. package/dist/plugins/store-backend.js +184 -62
  286. package/dist/plugins/store-contracts.d.ts +9 -2
  287. package/dist/plugins/store-contracts.js +1 -0
  288. package/dist/plugins/task-attachment-store.d.ts +6 -8
  289. package/dist/plugins/task-attachment-store.js +15 -10
  290. package/dist/plugins/task-list-store-sql.d.ts +1 -1
  291. package/dist/plugins/text-column-capacity.d.ts +21 -0
  292. package/dist/plugins/text-column-capacity.js +5 -0
  293. package/dist/plugins/tidb-pool.d.ts +3 -2
  294. package/dist/plugins/tidb-pool.js +19 -31
  295. package/dist/plugins/user-input-ledger-sql.d.ts +1 -1
  296. package/dist/read-face-posture.d.ts +6 -6
  297. package/dist/read-face-posture.js +2 -2
  298. package/dist/request-value-closure.d.ts +5 -5
  299. package/dist/request-value-closure.js +1 -1
  300. package/dist/rules-consent.d.ts +41 -13
  301. package/dist/rules-consent.js +101 -53
  302. package/dist/run-local.js +17 -13
  303. package/dist/runs.d.ts +48 -30
  304. package/dist/runs.js +26 -16
  305. package/dist/runtime-caps-resolver.d.ts +15 -8
  306. package/dist/runtime-caps-resolver.js +14 -10
  307. package/dist/sealed-key-layout.d.ts +2 -3
  308. package/dist/sealed-key-layout.js +0 -1
  309. package/dist/sealed-key.js +7 -5
  310. package/dist/security.d.ts +5 -3
  311. package/dist/sema-config-dir.js +2 -2
  312. package/dist/server-secret-env.d.ts +2 -0
  313. package/dist/service-version.d.ts +2 -1
  314. package/dist/service-version.js +2 -2
  315. package/dist/session-error-wire.d.ts +1 -1
  316. package/dist/session-incarnation.d.ts +8 -5
  317. package/dist/session-resident-background.d.ts +85 -32
  318. package/dist/session-resident-background.js +75 -7
  319. package/dist/session-row.d.ts +1 -1
  320. package/dist/session-sync-kernel.d.ts +1 -1
  321. package/dist/session-workspace.d.ts +11 -2
  322. package/dist/session-workspace.js +5 -0
  323. package/dist/sighup-idle.d.ts +1 -1
  324. package/dist/store-posture.d.ts +2 -1
  325. package/dist/stored-request-hooks-m20.d.ts +3 -2
  326. package/dist/stored-request-hooks-m20.js +19 -14
  327. package/dist/stores-sql/blob-index-sql.d.ts +148 -0
  328. package/dist/stores-sql/blob-index-sql.js +154 -0
  329. package/dist/stores-sql/checkpoint-store-sql.d.ts +1 -1
  330. package/dist/stores-sql/checkpoint-store-sql.js +11 -27
  331. package/dist/{plugins → stores-sql}/file-history-store-sql.d.ts +23 -11
  332. package/dist/{plugins → stores-sql}/file-history-store-sql.js +23 -18
  333. package/dist/{plugins → stores-sql}/pg-session-storage.d.ts +23 -76
  334. package/dist/{plugins → stores-sql}/pg-session-storage.js +80 -209
  335. package/dist/{plugins → stores-sql}/retention-store-sql.d.ts +123 -217
  336. package/dist/{plugins → stores-sql}/retention-store-sql.js +66 -190
  337. package/dist/{plugins → stores-sql}/session-event-payload.d.ts +1 -1
  338. package/dist/{plugins → stores-sql}/session-event-payload.js +1 -1
  339. package/dist/stores-sql/session-policy-store-sql.d.ts +1 -1
  340. package/dist/stores-sql/session-write-hooks.d.ts +59 -0
  341. package/dist/stores-sql/session-write-hooks.js +2 -0
  342. package/dist/{plugins → stores-sql}/tidb-session-storage.d.ts +10 -11
  343. package/dist/{plugins → stores-sql}/tidb-session-storage.js +10 -21
  344. package/dist/{plugins → stores-sql}/tidb-session-store.d.ts +32 -122
  345. package/dist/{plugins → stores-sql}/tidb-session-store.js +71 -171
  346. package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
  347. package/dist/stores-sql/tool-result-store-sql.js +1 -1
  348. package/dist/stores-sql/windowed-session-storage.d.ts +56 -0
  349. package/dist/stores-sql/windowed-session-storage.js +61 -0
  350. package/dist/task-a2a.d.ts +7 -1
  351. package/dist/task-a2a.js +15 -14
  352. package/dist/task-cwd.d.ts +11 -3
  353. package/dist/task-cwd.js +17 -1
  354. package/dist/task-mcp.d.ts +10 -2
  355. package/dist/task-mcp.js +13 -16
  356. package/dist/task-settings.d.ts +9 -4
  357. package/dist/task-settings.js +17 -6
  358. package/dist/tool-approval.d.ts +21 -8
  359. package/dist/tool-approval.js +10 -6
  360. package/dist/trace/core-keyset-guard.d.ts +9 -3
  361. package/dist/trace/engine-notice-wire.d.ts +1 -1
  362. package/dist/trace/engine-notice-wire.js +2 -0
  363. package/dist/trace/exit-seat.d.ts +23 -1
  364. package/dist/trace/exit-seat.js +3 -0
  365. package/dist/trace/project.d.ts +33 -16
  366. package/dist/trace/project.js +12 -9
  367. package/dist/trace/redact.d.ts +1 -1
  368. package/dist/trace/redact.js +61 -73
  369. package/dist/trace/self-minted-wire.d.ts +263 -10
  370. package/dist/trace/self-minted-wire.js +90 -2
  371. package/dist/trace/sema-provenance.d.ts +45 -41
  372. package/dist/trace/sema-provenance.js +81 -10
  373. package/dist/trace/task-notification-facets.d.ts +70 -2
  374. package/dist/trace/task-notification-facets.js +71 -1
  375. package/dist/trace/wire-projection-faces.d.ts +38 -2
  376. package/dist/trace/wire-projection-faces.js +26 -1
  377. package/dist/unread-request-members.d.ts +66 -0
  378. package/dist/unread-request-members.js +41 -0
  379. package/dist/user-input-ledger.d.ts +2 -2
  380. package/dist/web-admin-client/apply-effective.js +22 -26
  381. package/dist/web-admin-client/candidate-gate.d.ts +35 -3
  382. package/dist/web-admin-client/candidate-gate.js +53 -5
  383. package/dist/web-admin-client/center-request.d.ts +4 -1
  384. package/dist/web-admin-client/center-request.js +2 -1
  385. package/dist/web-admin-client/effective-keys.js +0 -1
  386. package/dist/web-admin-client/facade.d.ts +1 -1
  387. package/dist/web-admin-client/http-client.d.ts +1 -0
  388. package/dist/web-admin-client/http-client.js +17 -9
  389. package/dist/web-admin-client/restart-signal.js +5 -2
  390. package/dist/web-admin-client/skills-mcp.d.ts +20 -6
  391. package/dist/web-admin-client/skills-mcp.js +26 -21
  392. package/dist/web-admin-client/types.d.ts +34 -49
  393. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +2 -2
  394. package/package.json +13 -12
  395. package/scripts/drain-check-local.mjs +2 -28
  396. package/scripts/drain-check.mysql.sql +2 -18
  397. package/scripts/drain-check.pg.sql +2 -18
  398. package/wire-changes/server@7.147.0.json +813 -0
@@ -66,6 +66,11 @@
66
66
  * 人的授予、搭上一个人的在飞请求、带上一个人的 etag 去换 304。在飞期间换了人,答复由传输层丢弃
67
67
  * (`http-client.ts` `requestPrincipalView`),按这一次取数失败走下面的 fail-closed 臂(降级项落在发起那一箱)。
68
68
  *
69
+ * 🔐 场景面同一条故障律、另一种拒法:同一次硬失败把场景那一面记成 `"unavailable"`(读数第三态,见 `capabilities/scenarios.ts`
70
+ * `ScenarioRulingRead`),场景门据它拒这条 run(503 `state.scenario_assignment_unavailable`)—— 场景面没有「拒掉放大位、照跑」的中间形:
71
+ * 受限主体的指派与白名单此刻不可知,落部署缺省或照放点名都可能比他的指派更宽。治理两键形不对同记 `"unavailable"`(经 `onError` 一行)。
72
+ * 缺席(无 principal / 中心不发两键)仍是 `undefined`;没接中心的部署根本没有本客户端。
73
+ *
69
74
  * The resolver maps center's `EntitlementRuntimeCaps` → the SUBSET core enforces ({@link RuntimeCaps}): center
70
75
  * also carries `allowUltracode` (a shell/UX reasoning-tier cap the engine has no primitive for), which we DROP —
71
76
  * this seam feeds the ENGINE, and `allowUltracode` is enforced at the service settings-resolution layer, not here.
@@ -77,7 +82,7 @@ import type { RuntimeCaps } from "@sema-agent/core";
77
82
  import type { EntitlementRuntimeCaps } from "@sema-agent/settings-schema";
78
83
  import { fetchPrincipalCaps, type ExecutionRuling } from "./web-admin-client/facade.js";
79
84
  import type { CenterEndpoint } from "./web-admin-client/center-request.js";
80
- import type { ScenarioRuling } from "./capabilities/scenarios.js";
85
+ import type { ScenarioRulingRead } from "./capabilities/scenarios.js";
81
86
  import type { ServiceConfig } from "./config-types.js";
82
87
  import { type Logger } from "./observability/logger.js";
83
88
  /** test-only: reset the once-per-process trace so each test observes a fresh "first hit". */
@@ -181,17 +186,18 @@ export interface PrincipalEntitlementsClient {
181
186
  * 都重抓,denyTtl 的界对提交腿失效)。让它升格的是一次真提交自己吃到的硬失败,不是那次读。
182
187
  */
183
188
  peekRuntimeCaps: (principal: string | undefined) => Promise<RuntimeCaps | undefined>;
184
- /** The resolved per-principal scenario ruling for resolveSpec's gateScenarioRequest —
185
- * FAIL-OPEN on error / older center without scenario keys / no principal (undefined = no governance, legacy passthrough).
186
- * Scenario switching is not a privilege-amplifying face; a center blip must not pin users to `default`. */
187
- scenarioRuling: (principal: string | undefined) => Promise<ScenarioRuling | undefined>;
189
+ /** The resolved per-principal scenario ruling for resolveSpec's gateScenarioRequest — a three-state read
190
+ * ({@link ScenarioRulingRead}): the ruling; `undefined` = absent (no principal ⇒ no center call; older center without
191
+ * the scenario keys) = no governance; `"unavailable"` = the center could not answer (hard fetch failure — same error entry
192
+ * as the caps face's fail-closed deny — or malformed ruling keys) ⇒ the gate refuses the run. */
193
+ scenarioRuling: (principal: string | undefined) => Promise<ScenarioRulingRead>;
188
194
  /**
189
195
  * {@link PrincipalEntitlementsClient.scenarioRuling} 的**只读**孪生(同 {@link PrincipalEntitlementsClient.peekRuntimeCaps} 的界):同一只缓存 / 同一条抓取 /
190
- * 同一份 fail-open 判决(`undefined` = 无治理),唯一的差别是 center 硬失败时本腿铸的 fail-closed 降级项**只对读面自己算数**,提交腿不认、照常重抓。
196
+ * 同一份三态读数(故障 ⇒ `"unavailable"`,读面与提交腿同拒),唯一的差别是 center 硬失败时本腿铸的降级项**只对读面自己算数**,提交腿不认、照常重抓。
191
197
  * 读面(`GET /v1/capabilities/mcp?scenario=` 的场景门)问中心裁定时必须走这一只 —— 经 `scenarioRuling` 问,center 抖动的那一拍会替这个主体的**真提交**
192
198
  * 留下 `{allowWorkflows:false, allowFork:false, autoMode:false}` 的短窗 deny(读面成了别人被拒的原因,与 `peekRuntimeCaps` 的病灶同一类)。
193
199
  */
194
- peekScenarioRuling: (principal: string | undefined) => Promise<ScenarioRuling | undefined>;
200
+ peekScenarioRuling: (principal: string | undefined) => Promise<ScenarioRulingRead>;
195
201
  /** (stage7 P5) The resolved per-principal execution-lane ruling for resolveSpec's
196
202
  * gateExecutionLane. FAIL-OPEN + audit on error (this phase is "honest-but-bypassable";
197
203
  * tightening to fail-closed is a future, separate decision) / older center without the execution key / no principal. */
@@ -215,7 +221,8 @@ export declare function gateExecutionLane(ruling: ExecutionRuling | undefined, o
215
221
  * `(principal) => Promise<RuntimeCaps | undefined>`; `scenarioRuling` rides the SAME fetch/cache/in-flight
216
222
  * (zero extra center RTT — center attaches the ruling to the caps body). Wire ONLY when a center is
217
223
  * configured (and not in dry-run) — absent ⇒ core sees `undefined` ⇒ NO per-principal restriction, and the
218
- * scenario gate sees `undefined` ⇒ legacy body-or-default chain.
224
+ * scenario gate sees `undefined` (absent) ⇒ request-name-or-deployment-default chain. Present ⇒ a center that cannot answer
225
+ * reads `"unavailable"` on the scenario face (the gate refuses), never `undefined`.
219
226
  */
220
227
  export declare function createPrincipalEntitlementsClient(opts: EntitlementsResolverOpts): PrincipalEntitlementsClient;
221
228
  /** Back-compat face for core's seam-only consumers: the caps half of {@link createPrincipalEntitlementsClient}. */
@@ -91,6 +91,13 @@ export function createPrincipalEntitlementsClient(opts) {
91
91
  const fetchCaps = opts.fetchCaps ?? fetchPrincipalCaps;
92
92
  const now = opts.now ?? (() => Date.now());
93
93
  const onError = opts.onError ?? ((err, principal) => defaultLogger.warn("runtime_caps_resolve_failed", { principal, err: String(err) }));
94
+ const audit = (err, principal) => {
95
+ try {
96
+ onError(err, principal);
97
+ }
98
+ catch {
99
+ }
100
+ };
94
101
  const binNow = createIdentityBins(opts.center.credential, (credential) => ({
95
102
  center: { baseUrl: opts.center.baseUrl, credential },
96
103
  cache: new Map(),
@@ -136,14 +143,14 @@ export function createPrincipalEntitlementsClient(opts) {
136
143
  return entry;
137
144
  }
138
145
  if (r.executionDrift) {
139
- try {
140
- onError(new Error(`execution ruling wire drift: ${r.executionDrift}`), principal);
141
- }
142
- catch { }
146
+ audit(new Error(`execution ruling wire drift: ${r.executionDrift}`), principal);
147
+ }
148
+ if (r.scenarioDrift) {
149
+ audit(new Error(`scenario ruling wire drift: ${r.scenarioDrift}`), principal);
143
150
  }
144
151
  const entry = {
145
152
  caps: toCoreRuntimeCaps(r.runtimeCaps),
146
- ...(r.scenario ? { scenario: r.scenario } : {}),
153
+ ...(r.scenarioDrift ? { scenario: "unavailable" } : r.scenario ? { scenario: r.scenario } : {}),
147
154
  ...(r.execution ? { execution: r.execution } : {}),
148
155
  ...(r.etag ? { etag: r.etag } : {}),
149
156
  expiresAt: now() + ttlMs,
@@ -159,14 +166,11 @@ export function createPrincipalEntitlementsClient(opts) {
159
166
  catch {
160
167
  e = new Error("center fetch failed with an unstringifiable rejection reason");
161
168
  }
162
- const entry = { caps: { allowWorkflows: false, allowFork: false, autoMode: false, autoModeDenySource: "org", bypassPermissions: false }, expiresAt: now() + denyTtlMs };
169
+ const entry = { caps: { allowWorkflows: false, allowFork: false, autoMode: false, autoModeDenySource: "org", bypassPermissions: false }, scenario: "unavailable", expiresAt: now() + denyTtlMs };
163
170
  if (!recordDeny)
164
171
  readMintedDeny.add(entry);
165
172
  putCache(bin.cache, principal, entry);
166
- try {
167
- onError(e, principal);
168
- }
169
- catch { }
173
+ audit(e, principal);
170
174
  return entry;
171
175
  }
172
176
  finally {
@@ -1,13 +1,12 @@
1
1
  /**
2
- * 钥匙保管目录的布局常量 —— 引擎建目录、写钥匙文件、建停驻行封签子目录时用的**唯一**值(`src/sealed-key.ts` 读它们)。
2
+ * 钥匙保管目录的布局常量 —— 引擎建目录、建停驻行封签子目录时用的**唯一**值(`src/sealed-key.ts` 读它们)。
3
+ * 钥匙文件的权限位不在这里:它就是本服务文件的那一个值 `plugins/owner-only-file-mode.ts` 的 `OWNER_ONLY_FILE_MODE`(部署事实同读它)。
3
4
  *
4
5
  * 单独成一只零依赖的叶子模块:随包部署事实 `deploy/facts/sealed-key.json`(`src/deploy-facts.ts` 投影、`scripts/gen-deploy-lanes.ts` 生成)
5
6
  * 读的是同一份值,生成器不必为了三个常量把整只保管模块(libsodium / 中心上报)装载进来。
6
7
  */
7
8
  /** 保管目录的权限位:每次建店都 `mkdir` + `chmod` 成它(目录预先存在时 `mkdir` 的 mode 不生效,所以另 `chmod` 一次)。 */
8
9
  export declare const SEALED_KEY_DIR_MODE = 448;
9
- /** 钥匙文件 `<publicKeyId>.json` 的权限位(`writeFile` 的 mode 受 umask 掩,所以另 `chmod` 一次)。 */
10
- export declare const SEALED_KEY_FILE_MODE = 384;
11
10
  /**
12
11
  * 停驻行凭据封签那一域的保管子目录名(在模型钥匙保管目录之下:`<保管目录>/checkpoint-ctx-keys/`)。**一个域一对钥匙**:模型钥匙(`ModelEntry.sealedApiKey`,
13
12
  * 浏览器对着 caps 公钥裸封)与停驻行封签各用自己目录里的钥匙对 —— 一边的开箱口在另一边的密文上恒「不持有那把钥匙」,不是靠哪一侧多判一句信封。
@@ -1,4 +1,3 @@
1
1
  export const SEALED_KEY_DIR_MODE = 0o700;
2
- export const SEALED_KEY_FILE_MODE = 0o600;
3
2
  export const CHECKPOINT_CTX_KEY_SUBDIR = "checkpoint-ctx-keys";
4
3
  //# sourceMappingURL=sealed-key-layout.js.map
@@ -1,8 +1,10 @@
1
1
  import { createHash } from "node:crypto";
2
- import { chmod, mkdir, readdir, readFile, writeFile } from "node:fs/promises";
2
+ import { chmod, readdir, readFile, writeFile } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
+ import { ensureDir } from "@sema-agent/core";
4
5
  import _sodium from "libsodium-wrappers";
5
- import { CHECKPOINT_CTX_KEY_SUBDIR, SEALED_KEY_DIR_MODE, SEALED_KEY_FILE_MODE } from "./sealed-key-layout.js";
6
+ import { CHECKPOINT_CTX_KEY_SUBDIR, SEALED_KEY_DIR_MODE } from "./sealed-key-layout.js";
7
+ import { OWNER_ONLY_FILE_MODE } from "./plugins/owner-only-file-mode.js";
6
8
  import { buildDisplaySafeUrl } from "./trace/redact.js";
7
9
  import { createCenterCredentialSource } from "./center-credential.js";
8
10
  import { centerFetch } from "./web-admin-client/center-request.js";
@@ -62,7 +64,7 @@ export function judgeSealedKeyPublicKey(publicKeyB64) {
62
64
  export async function ensureSealedKeyStore(dir, logger) {
63
65
  await _sodium.ready;
64
66
  const sodium = _sodium;
65
- await mkdir(dir, { recursive: true, mode: SEALED_KEY_DIR_MODE });
67
+ ensureDir(dir);
66
68
  await chmod(dir, SEALED_KEY_DIR_MODE);
67
69
  const keys = new Map();
68
70
  for (const name of (await readdir(dir)).filter((n) => n.endsWith(".json")).sort()) {
@@ -100,8 +102,8 @@ export async function ensureSealedKeyStore(dir, logger) {
100
102
  createdAt: new Date().toISOString(),
101
103
  };
102
104
  const path = join(dir, `${record.publicKeyId}.json`);
103
- await writeFile(path, JSON.stringify(record, null, 2) + "\n", { mode: SEALED_KEY_FILE_MODE });
104
- await chmod(path, SEALED_KEY_FILE_MODE);
105
+ await writeFile(path, JSON.stringify(record, null, 2) + "\n", { mode: OWNER_ONLY_FILE_MODE });
106
+ await chmod(path, OWNER_ONLY_FILE_MODE);
105
107
  keys.set(record.publicKeyId, { publicKey: kp.publicKey, privateKey: kp.privateKey, publicKeyB64, createdAt: record.createdAt });
106
108
  logger?.info("sealed_key_generated", { publicKeyId: record.publicKeyId, publicKey: publicKeyB64, dir, note: "new X25519 sealed-box keypair in this directory — the private key exists only here: keep the directory across restarts and identical on every replica that has to open what it sealed, and back it up as a private key" });
107
109
  }
@@ -25,7 +25,7 @@ export interface SessionListItem {
25
25
  * ⇒ 在跑 latest 键诚实缺席)。
26
26
  * 读法一致:缺席 = 「此行无已知 engine runId」,禁读成其它含义。⚠️ 与 `lastRunId`(= latest run 的 **task_id**)
27
27
  * 是两条身份轴,命名对齐 core `SessionStoreSummary.lastTaskRunId`。wire:additive 键零投影透传
28
- * (sessions-list.ts);sema-sdk spec `SessionSummary` 闭集候 SDK 半场开键([ref]/.82 班车)。 */
28
+ * (sessions-list.ts);sema-sdk spec `SessionSummary` 已声明此键(对账门 `test/sdk-live-parity.test.ts`)。 */
29
29
  lastTaskRunId?: string;
30
30
  /** The session's title — the user's (`PATCH /v1/sessions/:id`) or, until the user sets one, the auto-titler's
31
31
  * (null = untitled / lister face has no session_meta). One column, two writers, one order: `session-row.ts`. */
@@ -193,7 +193,8 @@ export declare function sameSessionOwner(deployment: DeploymentShapeInput<"princ
193
193
  /**
194
194
  * 本仓会话店的面 = core `SessionStore` + 本仓的行面(登记 / 列表 / 换装 / 同步……)。
195
195
  * 🔴 **按 id 读一行只有一只**:core 的 `headOf(id)`(`{ owner, incarnation, leafId }`,同一行一次读;core 7.55.0 [ref] S2)。
196
- * 属主 = `headOf(id)?.owner`、住客 = 头的 `incarnation`(比较用 core `compareOccupants`,拿令牌去写用 `sessionFaceOfHead`)、叶子 = 头的 `leafId`
196
+ * 属主 = `headOf(id)?.owner`、住客 = 头的 `incarnation`(两头比较用 core `compareOccupants`:没有行 ⇒ `unknown`,两侧都有令牌且相等或都无令牌 ⇒ `same`,
197
+ * 一侧有一侧无 ⇒ `different`;拿令牌去写用 `sessionFaceOfHead`,它对无令牌的头响亮拒)、叶子 = 头的 `leafId`
197
198
  * —— 此前本面另有五只按 id 读(`ownerOf` / `incarnationOf` / `sessionFaceOf` / `getHead` / `getLeafId`),全部退役;规则在 `src/session-incarnation.ts` 头注,
198
199
  * 「店有没有这只读」只判 `headReadOf` 一处。
199
200
  */
@@ -288,7 +289,8 @@ export type OwnerAwareSessionStore = SessionStore & {
288
289
  importEntries?: (sessionId: string, owner: string | null, entries: SessionTreeEntry[]) => Promise<void>;
289
290
  /** 2c session-sync (§7/§8) — IDEMPOTENT replace: atomically purge any existing conversation log for `sessionId`
290
291
  * then import `entries` verbatim under `owner`. Unlike importEntries (plain INSERT, fresh-only) this is safe to
291
- * re-run / apply over an existing session (fast-forward, retry). owner-guarded delete (defense-in-depth). */
292
+ * re-run / apply over an existing session (fast-forward, retry). Owner-guarded (defense-in-depth): the importer's own row is
293
+ * rewritten in place — its incarnation and the deployment cells kept on it (title, pin, instruction baseline, workspace, placement) stay. */
292
294
  replaceEntries?: (sessionId: string, owner: string | null, entries: SessionTreeEntry[]) => Promise<void>;
293
295
  /** 2c session-sync P1d-β (PUSH streaming) — begin a STAGED import into `realSessionId` under a shadow id
294
296
  * `${realSessionId}#stg-${token}` (the route mints the uuidv7 `token`). Returns a {@link StagingHandle} the NDJSON
@@ -1,6 +1,6 @@
1
- import { mkdirSync } from "node:fs";
2
1
  import { homedir } from "node:os";
3
2
  import { join, resolve } from "node:path";
3
+ import { ensureDir } from "@sema-agent/core";
4
4
  export function declaredSemaConfigDir(env = process.env) {
5
5
  const raw = env.SEMA_CONFIG_DIR;
6
6
  if (raw === undefined)
@@ -20,7 +20,7 @@ export function provisionSemaConfigDir(config, logger) {
20
20
  if (dir === undefined)
21
21
  return;
22
22
  try {
23
- mkdirSync(dir, { recursive: true, mode: 0o700 });
23
+ ensureDir(dir);
24
24
  }
25
25
  catch (e) {
26
26
  logger.warn("sema_config_dir_unprovisioned", {
@@ -119,6 +119,8 @@ export interface HostSubprocessEnvRequest {
119
119
  * 九条宿主腿都只经它(直接或经 {@link gitSubprocessEnv}):host shell(三个继承词原样交给 `policy`)、project-memory / center-plugins / leader 三条 git 腿、
120
120
  * 本地语言服务器、bake-runner 的每一只子进程组、local-docker 与 adb 两条 CLI 腿(`"all"`)、settings hooks 的命令腿(十二名严格名单 + 有效环境层作授予)。`allow` 只在**有部署级出路**的现场非空(今天 = `LSP_ENV_ALLOW` / `BAKE_ENV_ALLOW`,
121
121
  * 它们的现场在 `SECRET_ENV_SCRUB_SITES` 里登记了 `remedy`,披露行因此是 warn + 放行名单 + 出路句);其余现场传 `[]`。
122
+ * 「扣了哪些名字」一腿一个读者:host shell 腿由引擎读 `withheldEnv` 说(`inherit_env.names_withheld`,现场登记 `told:"engine-notice"` ⇒ 本函数对它只计数、不写披露行);
123
+ * 其余各条腿(含 host 适配器类里不交给引擎的 git worktree 基环境,`HostEnvConfig.gitBase`)引擎没有读者,披露行是唯一的读法(`told:"log"`)。
122
124
  * 返回 `NodeJS.ProcessEnv` 形(值可能是 `undefined` 的键本来就不会进子进程);调用方显式要交的键(`LC_ALL`、`cfg.env` …)叠在它之上。
123
125
  * 调用时机 = 每次要交 env 时现算一次(`process.env` 在本仓是 boot 期输入,各次同值;计数因此是「每组合一次」)。
124
126
  * 引擎对坏策略 / 点到自有凭据名的白名单在这里**抛**(spawn 时的拒是不变量;构造时的拒由各构造点自己先问 `inheritEnvPolicyProblem`)。
@@ -1,5 +1,6 @@
1
1
  /** Service version for GET /v1/capabilities — read from the package.json shipped next to src/ in the
2
- * image (Dockerfile COPYs it), once per process. Best-effort: an unreadable file reports "unknown", never crashes boot. */
2
+ * image (Dockerfile COPYs it), once per process. Best-effort: an unreadable file — or a `version` that is not a string — reports "unknown", never crashes boot.
3
+ * (Whether "unknown" may serve is each reader's own judgment: the local data root's engine high-water refuses a build whose version is not a release version.) */
3
4
  declare function serviceVersion(): string;
4
5
  export { serviceVersion };
5
6
  //# sourceMappingURL=service-version.d.ts.map
@@ -6,8 +6,8 @@ function serviceVersion() {
6
6
  }
7
7
  function readServiceVersion() {
8
8
  try {
9
- const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
10
- return pkg.version ?? "unknown";
9
+ const version = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"))?.version;
10
+ return typeof version === "string" ? version : "unknown";
11
11
  }
12
12
  catch {
13
13
  return "unknown";
@@ -21,7 +21,7 @@
21
21
  * (悬空父而回放没丢记录 / 自指 / 成环 / 叶子缺席 / 分叉走链 —— 7.137.0–7.143.0 那一形是 `invalid_session`,见下一词)。不是 4xx:调用方没做错
22
22
  * 任何事;不是 503:重试改不了判(修复在运维手里)—— 与会话规则店的 `corrupt` 同一档同一理由。码不另铸(core 的词
23
23
  * 原样上 wire,契约既有立场:不为上游码铸孪生码)。三种会话后端同词:文件店由 core 铸,两只 SQL 店由
24
- * `plugins/session-event-payload.ts` 铸(坏的 `session_event.payload` 行)。
24
+ * `stores-sql/session-event-payload.ts` 铸(坏的 `session_event.payload` 行)。
25
25
  * · `invalid_session` —— `import` 面 **422 `invalid_entries`**(修前 session-sync 的那一行,码位 / 状态逐字不变);`open` 面**留白**:core 7.62.0
26
26
  * ([ref] / [ref])起它只是导入门的词,打开已存日志从不抛它 —— 走不成一棵树的已存日志是 `corrupt_session`(上一词);回放丢了记录的悬空父不再失败,
27
27
  * run 从断点续上并在流上说 `session.lineage_rerooted`。7.137.0–7.143.0 本表在 open 面给过它一格 500 `invalid_session`(那时 core 用它说已存日志的结构坏),
@@ -28,11 +28,14 @@
28
28
  * 内容读不出时,头照答行上的属主与住客,叶子那一格带着读它时撞上的那只故障({@link UnreadableLeaf}),**谁读叶子谁收到它**。
29
29
  * 于是只判归属的读者(授权门、各路由的属主门、删除的围栏、住客读)对坏内容与好内容同答,内容的故障只让门放行之后读内容的那一位看见;
30
30
  * 行本身读不出(local:边档里还没有这只会话的那一格、要从存档推出它在不在,而存档读不出)⇒ 头读整只拒(读故障,不是答案)。
31
- * · **两头是不是同一位住客:core 的 `compareOccupants`**(三答 `same` / `different` / `unknown`;任一侧没有行或没有令牌 ⇒ `unknown`,
32
- * `unknown` 永不当 `same`)。本仓自写的比较(`sameSessionOccupant`)退役:同一个问题只有引擎那一只判官。
31
+ * · **两头是不是同一位住客:core 的 `compareOccupants`**(三答 `same` / `different` / `unknown`;core 7.65.0 起:任一侧没有行 ⇒ `unknown`;
32
+ * 两侧都有行时按引擎的一种读法比两格 —— 都有令牌且相等,或都没有令牌(缺席 / `""` / 非串)⇒ `same`,一侧有一侧没有 ⇒ `different`;
33
+ * `unknown` 永不当 `same`,没有令牌也永不当通配)。本仓自写的比较(`sameSessionOccupant`)退役:同一个问题只有引擎那一只判官。
34
+ * 「这只头有没有令牌」不从 `compareOccupants` 推,读头本身(`head.incarnation`)。
33
35
  * · **一位活住客必须有令牌 —— 读到空化身 ⇒ 响亮拒**({@link SessionIncarnationMissingError}):本仓比 core 多的那一条律,只住在一处 ——
34
36
  * 把头投成 {@link SessionFace}(属主 + 一只令牌)的 {@link sessionFaceOfHead}(批量来源读与换装回读用同一只 {@link sessionFaceFromRow})。
35
- * 要拿令牌去**写**(带化身条件的 UPDATE、认领、空间分区键)或要响亮区分「行坏了」的读者经它;只**比较**两头的读者用 `compareOccupants`。
37
+ * 要拿令牌去**写**(带化身条件的 UPDATE、认领、空间分区键)或要响亮区分「行坏了」的读者经它;只**比较**两头的读者用 `compareOccupants`
38
+ * (它对两只无令牌的头答 `same` —— 拒无令牌行从来不是它的答案,是这一只的)。
36
39
  * 空值只可能来自没铸化身的写腿、人为改库,或跳过了 7.104.0–7.135.x(那几版的起服迁移给存量行铸令牌,窗关后已删码)直接升上来的库 ——
37
40
  * 把它当「通配」就是让任何人都能和这一行比成同一位住客。
38
41
  * · **不上 wire、不进模型上下文、不进日志正文**:日志里要点名时只打 {@link incarnationLogPrefix}(前 8 位)。值本身不出进程;唯一出进程的形是
@@ -131,10 +134,10 @@ export interface CarriedRowCells {
131
134
  readonly forkKey: string | null;
132
135
  }
133
136
  /**
134
- * session-sync **换装**(整段换装 / 暂存提交)时行格的去留 —— 三只店共用的一句判据:换装只换内容,换的是**同一行**
137
+ * session-sync **换装**(整段换装 / 暂存提交)时行格的去留 —— local 店的判据(SQL 两店的换装就地改写同一行,化身与旁表行原地不动,同一结局、无需沿用判):换装只换内容,换的是**同一行**
135
138
  * ⇒ 行在且那一格里有一只令牌(唯一解码 {@link incarnationFromCell} 的 `absent` 读法)⇒ 化身与 fork 键(`fork_key` / local `forkKey`:建这一行的那次 fork
136
139
  * 请求的键,只由 fork 创建点写、此后每个写携带)**一起沿用**(属主重戳与否不改这一判:同一行 = 同一位住客);行不在(这是一次新建)或还是空的存量形 ⇒
137
- * 铸一只新化身、没有 fork 键。属主不在这里判:每只店在自己的属主门上判过被换的那一行(SQL 孪生的 replace 只交「属主门删得到的那一行」),读不中的换装一个字节不写。
140
+ * 铸一只新化身、没有 fork 键。属主不在这里判:店在自己的属主门上判过被换的那一行,读不中的换装一个字节不写。
138
141
  */
139
142
  export declare function carriedRowCells(sessionId: string, prior: {
140
143
  incarnation?: unknown;
@@ -1,57 +1,110 @@
1
1
  /**
2
- * `/health.inflight` 计法表第四类 —— **会话驻留的后台 shell / monitor**。
2
+ * `/health.inflight` 计法表里**会话驻留的后台行**两类 —— 后台子代理(`backgroundAgents`,进阻断集)与后台 shell / monitor(`sessionResident`,只进总数)。
3
3
  *
4
4
  * ## 病
5
- * 引擎在飞数原先只数 HTTP 腿与 leader 腿。模型在会话里起的后台 shell / monitor(`run_in_background`)活过起它的那一条腿 —— 腿一收,它在这份数里是 0:
6
- * 读 `/health` 判「这台引擎是否空闲」的外部判官看不见它们,只好另拼一条谓词 —— 同一个事实两个读法。
7
- *
8
- * ## 两个事实(本文件只产总数里的第三项 `sessionResident`)
9
- * `/health.inflight`(总数,{@link inflightTotal})= 引擎此刻托管着多少活 = `http + leader + sessionResident`,可观测事实;
10
- * `drainState.blockingInflight`(阻断集,{@link blockingInflightOf})= 还有没有必须等完的活 = `http + leader`,排空 / 孤儿窗 / 附着租约自退 / SIGHUP 空闲窗判停读它。
11
- * 本文件产出的 `sessionResident` **只进总数、不进阻断集**:驻留 shell 不是一条腿,等它没有意义;一只不退出的 shell(`while true`)若阻断,崩溃孤儿引擎就永生。
12
- * 窗到 / 排空完成,退出边界的后台收割收掉它们,retain 行按 retain 既有语义活过受控退。
13
- *
14
- * ## 读法(本文件是唯一属主)
15
- * 行集 = core `TaskRegistry.liveTasks(access)` 的投影:`type ∈ {background_bash, monitor}` ∧ `status === "running"` ∧ `sessionScoped` ∧ 非 retain
16
- * ({@link isSessionResidentShellRow})。
5
+ * 引擎在飞数原先只数 HTTP 腿与 leader 腿。模型在会话里起的后台活 —— `run_in_background` 的 shell / monitor、core `backgroundScope:"session"` 下的
6
+ * 后台子代理(Agent / Fork)—— 活过起它的那一条腿:腿一收,三张登记簿里都没有它,而引擎还托管着它。读 `/health` 判「这台引擎是否空闲」的外部判官看不见它们,
7
+ * 只好另拼一条谓词(同一个事实两个读法);附着租约 / 排空 / SIGHUP 空闲窗对还在烧模型的后台子代理同样看不见,把它随引擎的受控退中断。
8
+ *
9
+ * ## 两个事实(本文件产分项里的两项;两个和只在 `fleet/drain-entry.ts` 各写一次)
10
+ * `/health.inflight`(总数,{@link inflightTotal})= 引擎此刻托管着多少活 = `http + leader + backgroundAgents + sessionResident`,可观测事实;
11
+ * `drainState.blockingInflight`(阻断集,{@link blockingInflightOf})= 还有没有必须等完的活 = `http + leader + backgroundAgents`,排空 / 孤儿窗 / 附着租约自退 / SIGHUP 空闲窗判停读它。
12
+ * 两个和读**同一只**分项函数(`http/server.ts` 的 `inflightBreakdown`),本文件的读数在一次走查里同时交出两项 —— 判停与 `/health` 不是两份算法。
13
+ * · `backgroundAgents` **进阻断集**:后台子代理是一条在干活的模型腿,干完自己收尾(在审批 / 问答卡上等人时行仍是 `running`、照计;窗满转成耐久停驻后不再计);
14
+ * 不等它 = 受控退把一条还在干活的子代理中断(账本行落终态,模型工作丢)。与驻留 shell 的分界不是「有没有墙钟上限」—— core [ref] 已退役会话级子代理的
15
+ * 30 min 缺省墙钟,两类都没有 —— 而是「会不会自己结束」:模型腿干完即止,`while true` 的 shell 永不。
16
+ * 上界 = 停滞收割窗 `BG_AGENT_STALL_MS`(下面「停滞收割」一节):任务表行一直是 `running`、却不再有工具活动的子代理 —— 挂死的,或已收尾、但 core 在把行转终态之前
17
+ * await 的那一次委派行写 / 工作树收尾挂住了的(core `agents/subagent.js` 子代收尾链:`await rowSettled` 先于 `settleBackgroundAgent`)—— 静默满窗即被收,不再无界地撑着判停窗。
18
+ * · `sessionResident` **只进总数**:驻留 shell 不是一条腿,等它没有意义;一只不退出的 shell(`while true`)若阻断,崩溃孤儿引擎就永生、排空每次等满窗。
19
+ * 窗到 / 排空完成,退出边界的后台收割收掉它们,retain 行按 retain 既有语义活过受控退。
20
+ *
21
+ * ## 读法(本文件是唯一属主;行判一处写:{@link sessionResidentTermOf})
22
+ * 行集 = core `TaskRegistry.liveTasks(access)` 的投影,按行类型与状态分到两项之一或不计:
23
+ *
24
+ * | 行(`sessionScoped` 为真) | 状态 `pending` / `running` | `parked` | 终态 |
25
+ * |---------------------------------------------------|----------------------------|-------------------|------|
26
+ * | `background_agent`(后台子代理) | `backgroundAgents` | 不计(耐久停驻) | 不计 |
27
+ * | `background_bash` / `monitor`,非 retain | `sessionResident` | 不计 | 不计 |
28
+ * | `background_bash` / `monitor`,retain | 不计(交付的活服务,活过受控退) |||
29
+ * | `workflow` | 不计(见下) |||
30
+ *
31
+ * · **`sessionScoped` 为假的行不计**:挂在 run 腿上的后台行随腿登记在 `http` 项里,数它是第二次(腿一收,core 的拆腿收割把它们一起结掉)。
32
+ * · **`parked` 不计**:与停驻的 run 同一条律 —— 停驻是耐久的(引擎退了不丢,下次起来仍可赎回),不占执行座;算它,一张没人答的审批就让引擎永远退不掉。
33
+ * · **`workflow` 行不计**(计法表成文的一行,不是遗漏):任务表对一条 workflow 只投 `running`,一条腿停在审批门上等人时也还是 `running` ——
34
+ * 这只读法分不出「在干活」与「在等人」。进阻断集 ⇒ 一张没人答的审批让崩溃孤儿引擎永生(与驻留 shell 同一病);只进总数 ⇒ 多一类只报不阻断的项、
35
+ * 判据与停驻律对不上。停驻位(core `runParkedOf`)要由任务表投出来才能按停驻律分(请托 core);到货前 workflow 照旧不进在飞,与 7.146.x 同。
36
+ * · **状态是闭集**(`SemaTaskStatus` 穷举):core 加一个词 ⇒ 这里编译红,不会被静默读成「不计」。
37
+ * · **一行只数一次**:各会话的可见集可以相交(core `canAccess` 对后台子代理还认 `rootSessionId` —— 子会话与根会话都在围栏表时,两次读都看得见同一行)⇒ 整趟走查按 `task_id` 去重。
17
38
  * · **选座 `liveTasks`,不读 `list()`**:`list()` 是显示投影,硬帽 500 行(core 注:resolution must NEVER ride the display-capped list());
18
- * 进程级的在飞总数是外部判官判「引擎是否空闲」的依据,不能骑显示帽 —— 超过 500 行时 `list()` 会静默少数,方向恰是「以为空闲」。`liveTasks` 无显示帽。
19
- * · **retain 行不计**:显式 retain 的行是「交付的活服务」,按 core 契约活过引擎的受控退(退出边界对它 `retained_skipped`),
20
- * 不是「引擎托管着、会随它收掉」的活 —— 报它,判官会把一个本就该活过引擎的服务读成引擎的负载。
21
- * · **只数 shell 与 monitor**:后台 agent / workflow 行属计法表的别的类,不在这一类里。
22
- * · **非会话驻留行不数**:挂在 run 腿上的后台行(`sessionScoped` 为假)随腿登记在 HTTP 腿项里,数它是第二次。
39
+ * 超过 500 行时 `list()` 会静默少数,方向恰是「以为空闲」。`liveTasks` 无显示帽。
23
40
  *
24
41
  * ## 枚举源
25
- * core 的 `canAccess` 要求访问元组带 `scope`(缺 scope 一律拒),`list` / `liveTasks` 因此只读「调用方可达行」,没有进程总数的读口(core 不立新 getter)。
26
- * 进程级的数要由本仓自己枚举「本进程有哪些会话」:枚举源 = **围栏表**(`boot/execution-env.ts` 的 `SessionScopedRegistries.sessionOwners`):
42
+ * core 的 `canAccess` 要求访问元组带 `scope`(缺 scope 一律拒),`list` / `liveTasks` 因此只读「调用方可达行」,没有进程总数的读口。
43
+ * 进程级的数由本仓自己枚举「本进程有哪些会话」:枚举源 = **围栏表**(`boot/execution-env.ts` 的 `SessionScopedRegistries.sessionOwners`):
27
44
  * 每次提交经 resolve-spec 写一笔(会话 id → 属主),删会话的 E21 级联清一笔,LRU 有界。scope 轴 = {@link sessionChildrenScope}(会话属主 `?? "default"`,
28
- * 删除门 / 换绑门 / 结清口 / 会话后台读面同一个取法,不另取)。
45
+ * 删除门 / 换绑门 / 结清口 / 会话后台读面同一个取法,不另取)。会话驻留的后台子代理 `owner` = 会话 id([ref] 纪律),同一只访问元组够得着。
46
+ * 〔待 core:一只进程级、不按访问元组收窄的计数读口(`countRunningBackgroundShells` 的子代理孪生)到货后,子代理一项改读它 —— 下面三条边界随之消失。〕
29
47
  *
30
48
  * ## 读到的边界(成文,不静默)
31
- * · 围栏表是 LRU(上界 4096 会话):被挤出表的会话,它的驻留行在这里不可见 —— 回到改前的读数(不是新的错),不会多数;
49
+ * · 围栏表是 LRU(上界 4096 会话):被挤出表的会话,它的会话驻留行在这里不可见 —— 回到 7.146.x 前的读数(不是新的错),不会多数;
32
50
  * · 不经 resolve-spec 的内部车道(服务为自己起的 run)不写围栏表,它们起的会话驻留行同样不可见;
33
51
  * · 删会话的级联在 `dropSessionScoped` 之后、后台收割之前失败(会话行因此没删)时,围栏表已先清:该会话还在跑的驻留行在下一次提交重新围栏之前不可见
34
- * (同样回到改前的读数;修法是把 `dropSession` 的「清秘密」与「忘身份」拆开,属围栏表的属主,不在本读法里);
52
+ * (修法是把 `dropSession` 的「清秘密」与「忘身份」拆开,属围栏表的属主,不在本读法里);
35
53
  * · 每次读是 O(围栏表会话数 × 注册表行数)(`liveTasks` 逐会话走一遍注册表);表的上界 4096、注册表行数小,量级是毫秒。
54
+ * 这一读在判停路径上(排空 1 s 拍 / 租约拍 / SIGHUP 拍)每拍付一次 —— 后台子代理进阻断集的代价,与 `/health` 同一份。
55
+ *
56
+ * ## 停滞收割:先收尸,再数活(本文件是收割的唯一调用点)
57
+ * 引擎把会话驻留后台子代理的反僵尸义务交给调用方:`TaskRegistry.reapStaleSessionBackgroundAgents(staleMs)` 把**最后一次工具活动**距今超过 `staleMs` 的
58
+ * `running` 行收成 `killed`(归因 `system`,措辞与耐久 stale-running 清扫同一句)并中止它的 run;停驻行、随腿的行、终态行它不碰。
59
+ * {@link countSessionResidentBackground} 每读一次先调它一次、再走任务表 —— 所以计法表里「在跑的后台子代理」= 引擎任务表此刻说 `running` 的行,
60
+ * 而任务表在被数之前已经按停滞窗结清过一遍。本服务不另判「这一行其实不活」(行说 running、本服务说不活 = 一个事实两种读法):不活的行由引擎收成终态,本文件只数。
61
+ * · **拍**:不另起计时器。读口的读者就是拍 —— 排空 1 s 拍、附着租约拍、SIGHUP 空闲窗 1 s 拍、`/health`、崩溃遗言;每一处判停读数之前都先收过一次。
62
+ * 没有任何读者的进程里没有判据要读这一项,僵尸行只停在任务表的显示面上。
63
+ * · **窗**:`BG_AGENT_STALL_MS`,缺省 = 下限 = 派生值(`config.ts` 的 `backgroundAgentStallFloorMs`:等人的四个窗取大 + 引擎单命令上限)。
64
+ * 子代在审批卡 / 问答卡上等人时行是 `running`、没有工具活动 —— 窗不盖住等人的窗,就会把一只等你回来批的子代当僵尸收掉。
65
+ * · **收割失败**(引擎抛)⇒ 读口照数任务表(没收掉的行照算在跑:宁可等,与收割接线之前同读)并经 `stall.report` 报出;读口不抛。
36
66
  *
37
67
  * ## 读不出 ⇒ 非空闲(响亮,不替成 0)
38
- * 本函数在 `/health` 应答和崩溃遗言(uncaught 处理器里读总数)里被调,**不许抛**(崩溃遗言里一次抛会吞掉遗言本身)。判停路径(排空 / 租约 / SIGHUP)读阻断集,
39
- * 不求值本函数。某个会话的 `liveTasks` 读失败 ⇒ 该会话按 **1 只在跑**计(读不出 ⇒ 非空闲:判官宁可当有活)并经 `onUnreadable` 报出 ——
40
- * 调用方必须给报口(装配层一会话一行 `session_resident_background_unreadable`),不存在静默的 0。
68
+ * 本函数在判停路径(排空首读在期限计时器装上之前)、`/health` 应答与崩溃遗言里被调,**不许抛**(判停首读一抛 ⇒ 期限计时器装不上 ⇒ 永不硬停;
69
+ * 崩溃遗言里一抛会吞掉遗言本身)。某个会话的读失败(含行判遇到闭集外的值)⇒ 该会话按 **1 只在跑的后台子代理**计 —— 落在阻断项里,判停也看得见
70
+ * (读不出 ⇒ 非空闲:宁可当有活)—— 并经 `onUnreadable` 报出;调用方必须给报口(装配层一会话一行 `session_resident_background_unreadable`),不存在静默的 0。
41
71
  */
42
72
  import { type TaskListRow, type TaskRegistry } from "@sema-agent/core";
73
+ import type { InflightBreakdown } from "./fleet/drain-entry.js";
43
74
  /** 枚举源的形:会话 id → 会话属主(`null` = 匿名)。`Map` 满足它。 */
44
75
  export type SessionOwners = Iterable<readonly [sessionId: string, owner: string | null]>;
45
- /** 这一类里的行判:唯一写处(计数与单测同读)。 */
46
- export declare function isSessionResidentShellRow(row: TaskListRow): boolean;
76
+ /** 本文件交出的两项(键名属主 = {@link InflightBreakdown})。 */
77
+ export type SessionResidentCounts = Pick<InflightBreakdown, "backgroundAgents" | "sessionResident">;
78
+ /** 一行落在哪一项。 */
79
+ export type SessionResidentTerm = keyof SessionResidentCounts;
80
+ /**
81
+ * 行判:唯一写处(计数与单测同读)。`undefined` = 这一行不进在飞(理由见文件头的表)。闭集外的行类型 / 状态 ⇒ **抛**(由 {@link countSessionResidentBackground}
82
+ * 按「读不出」收:该会话计 1、报出)—— 不静默读成「不计」。
83
+ */
84
+ export declare function sessionResidentTermOf(row: TaskListRow): SessionResidentTerm | undefined;
47
85
  /** 一个会话的驻留行读失败的报口(由调用方给出:装配层记运维行)。 */
48
86
  export type UnreadableSessionReport = (sessionId: string, err: unknown) => void;
87
+ /** 一次停滞收割的结局:收掉了 `count` 行(> 0 才报)/ 收割本身抛了。闭集,装配层按 `kind` 穷举。 */
88
+ export type StallReapOutcome = {
89
+ readonly kind: "reaped";
90
+ readonly count: number;
91
+ } | {
92
+ readonly kind: "failed";
93
+ readonly err: unknown;
94
+ };
95
+ /** 停滞收割的策略:窗(ms,`BG_AGENT_STALL_MS`)与报口。读口必给 —— 没有「不收割」的读法。 */
96
+ export interface StallReapPolicy {
97
+ readonly stallMs: number;
98
+ readonly report: (outcome: StallReapOutcome) => void;
99
+ }
49
100
  /**
50
- * 本进程里会话驻留的、仍在跑的后台 shell / monitor 行数。`registry` 缺省 = 进程级单例;参数只供测试换桩(只用到 `liveTasks`)。
51
- * `onUnreadable` 必给:读失败的会话按 1 计并经它报出(文件头「读不出 ⇒ 非空闲」)。读法与边界见文件头。
101
+ * 本进程里会话驻留的、仍在跑的后台行,按项计数(一次走查交出两项)。**先收尸再数活**:走查之前按 `stall` 收一次停滞的后台子代理(文件头「停滞收割」)。
102
+ * `registry` 缺省 = 进程级单例;参数只供测试换桩(只用到 `reapStaleSessionBackgroundAgents` 与 `liveTasks`)。
103
+ * `onUnreadable` 必给:读失败的会话按 1 只在跑的后台子代理计并经它报出(文件头「读不出 ⇒ 非空闲」)。读法与边界见文件头。
52
104
  */
53
105
  export declare function countSessionResidentBackground(sessions: SessionOwners, opts: {
54
- readonly registry?: Pick<TaskRegistry, "liveTasks">;
106
+ readonly registry?: Pick<TaskRegistry, "reapStaleSessionBackgroundAgents" | "liveTasks">;
55
107
  readonly onUnreadable: UnreadableSessionReport;
56
- }): number;
108
+ readonly stall: StallReapPolicy;
109
+ }): SessionResidentCounts;
57
110
  //# sourceMappingURL=session-resident-background.d.ts.map
@@ -1,20 +1,88 @@
1
1
  import { defaultTaskRegistry } from "@sema-agent/core";
2
2
  import { sessionChildrenScope } from "./session-children-retire.js";
3
- export function isSessionResidentShellRow(row) {
4
- return (row.type === "background_bash" || row.type === "monitor") && row.status === "running" && row.sessionScoped && row.retained !== true;
3
+ function liveStatus(status) {
4
+ switch (status) {
5
+ case "pending":
6
+ case "running":
7
+ return true;
8
+ case "parked":
9
+ case "completed":
10
+ case "failed":
11
+ case "killed":
12
+ case "cancelled":
13
+ return false;
14
+ default: {
15
+ const unhandled = status;
16
+ throw new Error(`session-resident background: unknown task status ${String(unhandled)}`);
17
+ }
18
+ }
19
+ }
20
+ export function sessionResidentTermOf(row) {
21
+ if (!row.sessionScoped)
22
+ return undefined;
23
+ switch (row.type) {
24
+ case "background_agent":
25
+ return liveStatus(row.status) ? "backgroundAgents" : undefined;
26
+ case "background_bash":
27
+ case "monitor":
28
+ return liveStatus(row.status) && row.retained !== true ? "sessionResident" : undefined;
29
+ case "workflow":
30
+ return undefined;
31
+ default: {
32
+ const unhandled = row.type;
33
+ throw new Error(`session-resident background: unknown task type ${String(unhandled)}`);
34
+ }
35
+ }
5
36
  }
6
37
  export function countSessionResidentBackground(sessions, opts) {
7
38
  const registry = opts.registry ?? defaultTaskRegistry;
8
- let n = 0;
39
+ reapStalled(registry, opts.stall);
40
+ let backgroundAgents = 0;
41
+ let sessionResident = 0;
42
+ const counted = new Set();
9
43
  for (const [sessionId, owner] of sessions) {
10
44
  try {
11
- n += registry.liveTasks({ owner: sessionId, sessionId, scope: sessionChildrenScope(owner) }).filter(isSessionResidentShellRow).length;
45
+ const fresh = [];
46
+ for (const row of registry.liveTasks({ owner: sessionId, sessionId, scope: sessionChildrenScope(owner) })) {
47
+ const term = sessionResidentTermOf(row);
48
+ if (term !== undefined && !counted.has(row.task_id))
49
+ fresh.push([row.task_id, term]);
50
+ }
51
+ for (const [taskId, term] of fresh) {
52
+ if (counted.has(taskId))
53
+ continue;
54
+ counted.add(taskId);
55
+ if (term === "backgroundAgents")
56
+ backgroundAgents += 1;
57
+ else
58
+ sessionResident += 1;
59
+ }
12
60
  }
13
61
  catch (err) {
14
- n += 1;
15
- opts.onUnreadable(sessionId, err);
62
+ backgroundAgents += 1;
63
+ reportSafely(["session_resident_background_unreadable_report_threw", sessionId], () => opts.onUnreadable(sessionId, err));
16
64
  }
17
65
  }
18
- return n;
66
+ return { backgroundAgents, sessionResident };
67
+ }
68
+ function reapStalled(registry, stall) {
69
+ let count;
70
+ try {
71
+ count = registry.reapStaleSessionBackgroundAgents(stall.stallMs);
72
+ }
73
+ catch (err) {
74
+ reportSafely(["background_agent_stall_report_threw"], () => stall.report({ kind: "failed", err }));
75
+ return;
76
+ }
77
+ if (count > 0)
78
+ reportSafely(["background_agent_stall_report_threw"], () => stall.report({ kind: "reaped", count }));
79
+ }
80
+ function reportSafely(fallbackLine, report) {
81
+ try {
82
+ report();
83
+ }
84
+ catch (reportErr) {
85
+ console.error(...fallbackLine, reportErr);
86
+ }
19
87
  }
20
88
  //# sourceMappingURL=session-resident-background.js.map
@@ -30,7 +30,7 @@ export interface SessionRowTagInput {
30
30
  */
31
31
  export declare function sessionRowTagOf(row: SessionRowTagInput): string;
32
32
  /**
33
- * 列表行上的 `rowTag` 键(present-iff 这一行可被条件写 = 店有行写口 ∧ 行上有化身):三只店的列表行映射都经它,化身那一格由调用方经
33
+ * 列表行上的 `rowTag` 键(present-iff 这一行可被条件写 = 店有行写口 ∧ 行上有化身):local 店与 SQL 合成店(两方言一只)的列表行映射都经它,化身那一格由调用方经
34
34
  * `incarnationFromCell(…, "absent")` 解码好交进来(`undefined` = 行上没有令牌 ⇒ 键缺席,不铸)。
35
35
  */
36
36
  export declare function sessionRowTagKey(row: {
@@ -115,7 +115,7 @@ export declare const STAGED_LOG_BATCH = 500;
115
115
  /**
116
116
  * The ROW contract a staged entry must meet before it is batched — what the stores need to persist it, not a session-tree invariant
117
117
  * (those are core's): the SQL stores' `session_event` columns `entry_id` / `parent_id` are `VARCHAR(64)` and `type` is `VARCHAR(32) NOT NULL`
118
- * (`plugins/tidb-pool.ts` and `plugins/pg-session-storage.ts`, the DDL both staged appends write into; both dialects count characters, not
118
+ * (`plugins/tidb-pool.ts` and `stores-sql/pg-session-storage.ts`, the DDL both staged appends write into; both dialects count characters, not
119
119
  * UTF-16 units). An entry outside it used to reach the staging write and fail there as a store fault (5xx) — a client's bad data read as an
120
120
  * infrastructure failure. The local store holds the same contract (one gate for all stores: a log that cannot sync to SQL is refused at the door).
121
121
  */
@@ -6,7 +6,7 @@
6
6
  * · **判官只有引擎一只**:每条腿起点一帧 `workspace_changed`(`cwd` / `root` / `entered?` / `project?` / `remote`),之后每变一帧;
7
7
  * 这条腿属于哪个项目由引擎对检出的 `.sema/project` 记号判一次(带了 `TaskSpec.projectId` 就必须等于记号,
8
8
  * 否则整腿拒 `config.project_identity_mismatch`;没有记号时声明就是身份)。本仓**不判**项目、不读记号。
9
- * · **会话行只存一格**:`workspace` = 该会话上一条腿**自己的**最后一帧(SQL `session_meta.workspace`;local 店
9
+ * · **会话行只存一格**:`workspace` = 该会话上一条腿**自己的**最后一帧(SQL `session_ext.workspace`;local 店
10
10
  * `session-workspaces.json` 那一格)。成员由 {@link SESSION_WORKSPACE_DISPOSITIONS} 一张表定(引擎给帧加成员 ⇒ 表 tsc 红,
11
11
  * 门在 `trace/core-keyset-guard.ts` ⑰ 读同一张表)。**唯一写者** = 腿的记录座 {@link createSessionWorkspaceRecorder}
12
12
  * (持流的四条腿逐帧喂同一只;委派子代转上来的帧 —— 带 `parentToolCallId` / `sourceTaskId` / `bgAgentId` —— 不是这条腿的位置,不认)。
@@ -27,7 +27,8 @@
27
27
  * `TaskSpec.memory.projectKey`,按 git 仓库(origin 远端 / 本机路径)键控,与 `.sema/project` 记号无关;引擎 7.58.0 自己也写明
28
28
  * 「只声明的身份不改记忆的键」。两者是否该合成一个身份,是另一张设计票。
29
29
  * · 多租户记忆分区(`proj:<租户>/<projectId>`)与登记簿种子读的是**这次提交**的 `projectId`(按提交挑盘,修前即如此),不读行。
30
- * · 行上的 `root` / `cwd` / `entered` / `remote` 今天只存不读(会话面读它们归 wire 半场那一车);fork 出的新会话从「没有记录」起。
30
+ * · 行上的项目还有一位读者:会话视图 `GET /v1/sessions/:id` 体顶层的 `projectId`(唯一读口 {@link readSessionProjectId},与视图的 `agent` 同一次视图读)。
31
+ * `root` / `cwd` / `entered` / `remote` 今天只存不读;fork 出的新会话从「没有记录」起(项目声明按引擎契约每腿都带,fork 的首腿由调用方带上)。
31
32
  * · **只回结果的腿(verify / cascade,含续跑的 verify 臂)不记行**:引擎在组合入口里自己排空内层腿的流,宿主手里没有流,而引擎给组合入口开的
32
33
  * 帧座(`onStatusEvent` / `onWiringManifest`)没有这一帧 ⇒ 这条腿的位置与项目到不了行,行停在更早一条腿的那一帧(没有记号的检出里,
33
34
  * 下一条不带 `projectId` 的提交续声明的是那一帧声明过的项目)。本仓不替引擎铸「这条腿站在哪里」;要引擎为组合入口开这一帧的座。
@@ -111,6 +112,14 @@ export interface SessionWorkspaceRecorder {
111
112
  * 这条腿的关键路径上,池饿死时这条腿本来就停;上界归部署(`DB_QUERY_TIMEOUT_MS`、MySQL 池的排队上界)。local 后端的写不经池。
112
113
  */
113
114
  export declare function createSessionWorkspaceRecorder(store: SessionWorkspaceStore | undefined, witness: DelegationRootWitness | undefined): SessionWorkspaceRecorder;
115
+ /**
116
+ * 会话视图的 `projectId` —— **唯一读口**:行上最后一帧的 `project.id`(引擎对这只会话最后一条自己的腿的项目判决,记号判的与声明的同读;
117
+ * 「哪一种」不上 wire)。店没有这一面 / 没有记录 / 那一帧没有项目 ⇒ `undefined`(调用方不铸键)。两种读不出分两臂,与续声明那一读(`legProjectIdOf`)同读:
118
+ * · 店读抛(库连接 / 超时)⇒ 原样上抛 —— 视图读响亮失败(与 `agent` 同律:缺键读作「这台 server 没有说」,不把一次故障说成这句话);
119
+ * · 存下的那一格读不懂(被带外改坏)⇒ 店的同一只解码读作没有记录并计一次(F 类 `server.session-workspace.record-degraded`,`op=read`)⇒ 键缺席;
120
+ * 这只会话的下一条记帧的腿整格重写。
121
+ */
122
+ export declare function readSessionProjectId(store: SessionWorkspaceStore | undefined, sessionId: string): Promise<string | undefined>;
114
123
  /**
115
124
  * **这条腿交给引擎的 `TaskSpec.projectId`**(唯一铸点;见文件头第三句)。`submitted` = 这次提交自己带的、已过形状门且折成小写的值
116
125
  * (新提交:鉴权口的 `resolvedProjectId`;续跑:持久化体的同一个键)。它在场就不读行。行读失败(库抖)原样上抛 —— 读不到「这只会话的项目」