@sema-agent/server 7.132.0 → 7.133.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 (402) hide show
  1. package/MIGRATION.md +266 -0
  2. package/README.md +8 -9
  3. package/README.zh-CN.md +7 -6
  4. package/USAGE.md +174 -55
  5. package/deploy/sema-up/README.md +19 -1
  6. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -2
  7. package/deploy/sema-up/chart/templates/server.yaml +5 -2
  8. package/deploy/sema-up/stack/compose.yaml +3 -0
  9. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
  10. package/dist/adoption/plan.d.ts +3 -2
  11. package/dist/adoption/plan.js +7 -5
  12. package/dist/adoption/runner.js +3 -10
  13. package/dist/adoption/sql.d.ts +3 -2
  14. package/dist/adoption/sql.js +3 -5
  15. package/dist/adoption/wire.d.ts +4 -1
  16. package/dist/adoption/wire.js +1 -0
  17. package/dist/approval-ask-audit-store.d.ts +31 -13
  18. package/dist/approval-ask-audit-store.js +272 -74
  19. package/dist/approval-ask-machine.d.ts +15 -0
  20. package/dist/approval-ask-machine.js +6 -0
  21. package/dist/approval-ask-retention.d.ts +136 -0
  22. package/dist/approval-ask-retention.js +102 -0
  23. package/dist/approval-card.d.ts +79 -19
  24. package/dist/approval-card.js +44 -13
  25. package/dist/approval-deny-reasons.d.ts +1 -1
  26. package/dist/approval.d.ts +9 -0
  27. package/dist/approval.js +24 -3
  28. package/dist/audit.d.ts +27 -10
  29. package/dist/audit.js +12 -16
  30. package/dist/bake-runner/main.js +3 -2
  31. package/dist/boot/deferred-sandbox-path-env.js +1 -1
  32. package/dist/boot/execution-env.js +9 -7
  33. package/dist/boot/execution-lane.js +11 -0
  34. package/dist/boot/leader.js +2 -0
  35. package/dist/boot/memory-boundary.js +2 -2
  36. package/dist/boot/memory-consolidation.d.ts +5 -4
  37. package/dist/boot/memory-consolidation.js +7 -6
  38. package/dist/boot/org-delivery.d.ts +28 -0
  39. package/dist/boot/org-delivery.js +20 -0
  40. package/dist/boot/reapers.d.ts +3 -0
  41. package/dist/boot/reapers.js +21 -1
  42. package/dist/boot/resolve-spec.d.ts +3 -0
  43. package/dist/boot/resolve-spec.js +60 -81
  44. package/dist/boot/runner-deps.js +1 -0
  45. package/dist/boot/session-faces.d.ts +1 -0
  46. package/dist/boot/session-faces.js +4 -2
  47. package/dist/boot/stage-02-web-admin-pull.js +4 -1
  48. package/dist/boot/stage-06-runners.d.ts +2 -0
  49. package/dist/boot/stage-06-runners.js +6 -3
  50. package/dist/boot/stage-07-capability-layer.d.ts +2 -0
  51. package/dist/boot/stage-07-capability-layer.js +24 -3
  52. package/dist/boot/stage-08-reapers.d.ts +2 -0
  53. package/dist/boot/stage-08-reapers.js +2 -2
  54. package/dist/boot/stage-09-leader.d.ts +3 -0
  55. package/dist/boot/stage-10-http-server.d.ts +3 -0
  56. package/dist/boot/stage-10-http-server.js +5 -6
  57. package/dist/boot/stores.js +2 -2
  58. package/dist/boot/web-admin.d.ts +4 -0
  59. package/dist/boot/web-admin.js +151 -63
  60. package/dist/boot/workflow-orchestration.d.ts +2 -0
  61. package/dist/boot/workflow-orchestration.js +2 -1
  62. package/dist/brain.js +8 -3
  63. package/dist/breaker-key.d.ts +6 -0
  64. package/dist/breaker-key.js +29 -0
  65. package/dist/caller-text-echo.d.ts +9 -6
  66. package/dist/caller-text-echo.js +8 -11
  67. package/dist/capabilities/center-plugins.d.ts +7 -0
  68. package/dist/capabilities/center-plugins.js +1 -1
  69. package/dist/capabilities/composite-members.d.ts +1 -1
  70. package/dist/capabilities/composite-members.js +1 -1
  71. package/dist/capabilities/execution-lane.js +2 -2
  72. package/dist/capabilities/hands-lane.d.ts +21 -0
  73. package/dist/capabilities/hands-lane.js +10 -0
  74. package/dist/capabilities/mcp-probe.d.ts +36 -4
  75. package/dist/capabilities/mcp-probe.js +27 -4
  76. package/dist/capabilities/scenarios.d.ts +63 -7
  77. package/dist/capabilities/scenarios.js +39 -7
  78. package/dist/capability-facts.d.ts +34 -4
  79. package/dist/capability-facts.js +28 -2
  80. package/dist/center-config-tier.d.ts +69 -0
  81. package/dist/center-config-tier.js +42 -0
  82. package/dist/checkpoint-identity.d.ts +16 -0
  83. package/dist/checkpoint-identity.js +19 -0
  84. package/dist/config-catalog.d.ts +17 -10
  85. package/dist/config-catalog.js +43 -28
  86. package/dist/config-d-migration.d.ts +3 -1
  87. package/dist/config-d-migration.js +2 -2
  88. package/dist/config-dir-trust.d.ts +114 -0
  89. package/dist/config-dir-trust.js +388 -0
  90. package/dist/config-invariants.d.ts +18 -5
  91. package/dist/config-invariants.js +35 -3
  92. package/dist/config-provider.d.ts +6 -1
  93. package/dist/config-provider.js +6 -2
  94. package/dist/config-types.d.ts +71 -14
  95. package/dist/config-types.js +8 -0
  96. package/dist/config.d.ts +13 -0
  97. package/dist/config.js +121 -59
  98. package/dist/delegated-session-owner.d.ts +185 -0
  99. package/dist/delegated-session-owner.js +119 -0
  100. package/dist/device-protocol.d.ts +5 -3
  101. package/dist/device-protocol.js +1 -1
  102. package/dist/device-ws-hub.js +21 -2
  103. package/dist/device-ws-protocol.d.ts +70 -6
  104. package/dist/device-ws-protocol.js +50 -23
  105. package/dist/elicitation.js +3 -2
  106. package/dist/entry-problems.d.ts +34 -0
  107. package/dist/entry-problems.js +14 -0
  108. package/dist/execution-lane-caps.d.ts +49 -10
  109. package/dist/execution-lane-caps.js +43 -4
  110. package/dist/field-conflict.d.ts +43 -0
  111. package/dist/field-conflict.js +20 -0
  112. package/dist/fleet/fleet-bus.d.ts +80 -6
  113. package/dist/fleet/fleet-bus.js +41 -9
  114. package/dist/hooks/classic-stations.d.ts +10 -5
  115. package/dist/hooks/classic-stations.js +4 -4
  116. package/dist/hooks/command-spawn.d.ts +57 -0
  117. package/dist/hooks/command-spawn.js +139 -0
  118. package/dist/hooks/hook-llm.js +2 -2
  119. package/dist/hooks/hook-runner.d.ts +127 -25
  120. package/dist/hooks/hook-runner.js +668 -287
  121. package/dist/hooks/hook-source.d.ts +44 -0
  122. package/dist/hooks/hook-source.js +40 -0
  123. package/dist/http/active-run-conflict.d.ts +5 -13
  124. package/dist/http/active-run-conflict.js +17 -27
  125. package/dist/http/admission.js +103 -60
  126. package/dist/http/approval-sweeps.js +55 -18
  127. package/dist/http/caller-trust.d.ts +77 -0
  128. package/dist/http/caller-trust.js +143 -0
  129. package/dist/http/checkpoint-ctx.d.ts +16 -16
  130. package/dist/http/checkpoint-ctx.js +13 -10
  131. package/dist/http/claimed-run.d.ts +4 -3
  132. package/dist/http/device-placement.d.ts +2 -4
  133. package/dist/http/device-placement.js +2 -1
  134. package/dist/http/dispatch.js +10 -4
  135. package/dist/http/durable-run-leg.d.ts +4 -32
  136. package/dist/http/durable-run-leg.js +34 -10
  137. package/dist/http/owner-access.d.ts +56 -0
  138. package/dist/http/owner-access.js +42 -0
  139. package/dist/http/principal-gate.d.ts +48 -23
  140. package/dist/http/principal-gate.js +39 -12
  141. package/dist/http/readiness.d.ts +11 -5
  142. package/dist/http/readiness.js +10 -3
  143. package/dist/http/request-guards.d.ts +16 -23
  144. package/dist/http/request-guards.js +30 -15
  145. package/dist/http/resume-ctx-read.d.ts +2 -5
  146. package/dist/http/resume-ctx-read.js +7 -4
  147. package/dist/http/resume-legs.d.ts +3 -4
  148. package/dist/http/resume-legs.js +126 -69
  149. package/dist/http/retired-service-deps.d.ts +43 -0
  150. package/dist/http/retired-service-deps.js +18 -0
  151. package/dist/http/route-ctx.d.ts +44 -28
  152. package/dist/http/route-ctx.js +4 -0
  153. package/dist/http/route-table.js +2 -0
  154. package/dist/http/routes/a2a-serve.js +3 -4
  155. package/dist/http/routes/admin-config-refresh.js +1 -1
  156. package/dist/http/routes/admin-drain.js +1 -1
  157. package/dist/http/routes/admin-memory-optout.js +5 -1
  158. package/dist/http/routes/adoption.js +2 -9
  159. package/dist/http/routes/approvals-assistant.js +49 -48
  160. package/dist/http/routes/background.js +3 -2
  161. package/dist/http/routes/capabilities.js +20 -4
  162. package/dist/http/routes/config-catalog.d.ts +3 -3
  163. package/dist/http/routes/config-catalog.js +1 -1
  164. package/dist/http/routes/devices.js +3 -17
  165. package/dist/http/routes/diagnostics.js +5 -1
  166. package/dist/http/routes/images.js +6 -7
  167. package/dist/http/routes/leader.js +1 -8
  168. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  169. package/dist/http/routes/mcp-reconnect.js +3 -2
  170. package/dist/http/routes/memory-bundle.js +1 -1
  171. package/dist/http/routes/memory-compliance.js +1 -1
  172. package/dist/http/routes/memory-consolidation.js +1 -1
  173. package/dist/http/routes/memory-origin.js +1 -1
  174. package/dist/http/routes/memory-policy.d.ts +1 -1
  175. package/dist/http/routes/memory-policy.js +3 -2
  176. package/dist/http/routes/notify-wake.js +8 -21
  177. package/dist/http/routes/observability.js +2 -2
  178. package/dist/http/routes/principal-inbox.d.ts +39 -0
  179. package/dist/http/routes/principal-inbox.js +76 -0
  180. package/dist/http/routes/retention-ops.js +2 -9
  181. package/dist/http/routes/rules.js +5 -18
  182. package/dist/http/routes/runs.d.ts +5 -0
  183. package/dist/http/routes/runs.js +33 -106
  184. package/dist/http/routes/session-sync.js +15 -28
  185. package/dist/http/routes/sessions.js +30 -40
  186. package/dist/http/routes/side-query.js +6 -4
  187. package/dist/http/routes/tasks.js +50 -14
  188. package/dist/http/routes/workflows.d.ts +351 -0
  189. package/dist/http/routes/workflows.js +153 -119
  190. package/dist/http/send.d.ts +24 -3
  191. package/dist/http/send.js +14 -2
  192. package/dist/http/server.d.ts +17 -18
  193. package/dist/http/server.js +15 -13
  194. package/dist/http/stored-body-replay.js +17 -4
  195. package/dist/http/submit-ctx.js +4 -3
  196. package/dist/http/submit-replay.d.ts +4 -3
  197. package/dist/http/submit-replay.js +5 -4
  198. package/dist/http/wire-types.d.ts +10 -7
  199. package/dist/index.d.ts +1 -1
  200. package/dist/index.js +0 -1
  201. package/dist/lane-home-probe.d.ts +78 -9
  202. package/dist/lane-home-probe.js +78 -12
  203. package/dist/leader/endpoint.d.ts +4 -1
  204. package/dist/leader/endpoint.js +11 -10
  205. package/dist/limit-refusal.d.ts +17 -5
  206. package/dist/limit-refusal.js +4 -1
  207. package/dist/mcp-assertion-header.d.ts +31 -10
  208. package/dist/mcp-assertion-header.js +10 -3
  209. package/dist/mcp-tool-faces.js +1 -3
  210. package/dist/memory-project-layer.d.ts +37 -0
  211. package/dist/memory-project-layer.js +46 -0
  212. package/dist/memory-scope.d.ts +23 -16
  213. package/dist/memory-scope.js +24 -8
  214. package/dist/memory-sync-client.d.ts +27 -13
  215. package/dist/memory-sync-client.js +107 -18
  216. package/dist/model-entry-refusal.d.ts +9 -1
  217. package/dist/model-entry-refusal.js +6 -1
  218. package/dist/model-plane-face.d.ts +51 -0
  219. package/dist/model-plane-face.js +24 -0
  220. package/dist/model-provider.d.ts +5 -0
  221. package/dist/model-provider.js +4 -2
  222. package/dist/model-route-endpoint.d.ts +8 -11
  223. package/dist/model-route-endpoint.js +4 -7
  224. package/dist/model-route-env.d.ts +22 -0
  225. package/dist/model-route-env.js +2 -0
  226. package/dist/model-route-gap.d.ts +60 -30
  227. package/dist/model-route-gap.js +21 -15
  228. package/dist/observability/corrupt-read-seat.d.ts +7 -0
  229. package/dist/observability/corrupt-read-seat.js +9 -0
  230. package/dist/observability/err-text.d.ts +6 -0
  231. package/dist/observability/err-text.js +18 -4
  232. package/dist/observability/fail-open.d.ts +35 -9
  233. package/dist/observability/fail-open.js +35 -9
  234. package/dist/observability/metrics.js +1 -0
  235. package/dist/observability/prompt-manifest.d.ts +3 -17
  236. package/dist/observability/prompt-manifest.js +45 -42
  237. package/dist/observability/tool-trace.js +9 -9
  238. package/dist/operator-ask.d.ts +10 -0
  239. package/dist/operator-ask.js +3 -0
  240. package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
  241. package/dist/orchestration/workflow-agent-session-index.js +9 -13
  242. package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
  243. package/dist/orchestration/workflow-completion-inbox.js +13 -0
  244. package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
  245. package/dist/orchestration/workflow-notify-journal.js +27 -34
  246. package/dist/orchestration/workflow-park-decision.d.ts +89 -0
  247. package/dist/orchestration/workflow-park-decision.js +118 -0
  248. package/dist/org-delivery-gate.d.ts +81 -0
  249. package/dist/org-delivery-gate.js +59 -0
  250. package/dist/panel-tool-names.d.ts +23 -0
  251. package/dist/panel-tool-names.js +8 -0
  252. package/dist/parked-decide.d.ts +39 -6
  253. package/dist/parked-decide.js +98 -51
  254. package/dist/parked-revive-surface.d.ts +9 -2
  255. package/dist/parked-revive-surface.js +11 -8
  256. package/dist/permission-rule-list.d.ts +1 -1
  257. package/dist/permission-rule-list.js +2 -2
  258. package/dist/plugins/approval-ask-store-file.d.ts +16 -1
  259. package/dist/plugins/approval-ask-store-file.js +21 -0
  260. package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
  261. package/dist/plugins/approval-ask-store-memory.js +34 -2
  262. package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
  263. package/dist/plugins/approval-ask-store-sql.js +37 -1
  264. package/dist/plugins/blob-backend.d.ts +38 -25
  265. package/dist/plugins/blob-backend.js +29 -19
  266. package/dist/plugins/breaker-state-sql.d.ts +2 -2
  267. package/dist/plugins/breaker-state-sql.js +4 -4
  268. package/dist/plugins/caching-session-store.d.ts +3 -0
  269. package/dist/plugins/caching-session-store.js +3 -0
  270. package/dist/plugins/checkpoint-store-sql.d.ts +14 -0
  271. package/dist/plugins/checkpoint-store-sql.js +20 -2
  272. package/dist/plugins/file-history-store-sql.d.ts +5 -2
  273. package/dist/plugins/file-history-store-sql.js +3 -1
  274. package/dist/plugins/file-run-store.d.ts +5 -13
  275. package/dist/plugins/file-run-store.js +9 -0
  276. package/dist/plugins/fork-routing-session-store.d.ts +9 -1
  277. package/dist/plugins/fork-routing-session-store.js +12 -1
  278. package/dist/plugins/host-platform.d.ts +2 -0
  279. package/dist/plugins/host-platform.js +2 -1
  280. package/dist/plugins/local-checkpoint-store.d.ts +2 -0
  281. package/dist/plugins/local-checkpoint-store.js +6 -1
  282. package/dist/plugins/local-session-store.d.ts +1 -1
  283. package/dist/plugins/local-session-window.d.ts +39 -0
  284. package/dist/plugins/local-session-window.js +54 -0
  285. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
  286. package/dist/plugins/mailbox-store-sql.d.ts +30 -48
  287. package/dist/plugins/mailbox-store-sql.js +77 -52
  288. package/dist/plugins/memory-embedder-fingerprint.js +2 -1
  289. package/dist/plugins/memory-run-store.d.ts +5 -13
  290. package/dist/plugins/memory-run-store.js +8 -0
  291. package/dist/plugins/one-time-migrations.d.ts +110 -5
  292. package/dist/plugins/one-time-migrations.js +320 -8
  293. package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
  294. package/dist/plugins/org-delivery-quota-store.js +228 -0
  295. package/dist/plugins/pg-pool.js +39 -7
  296. package/dist/plugins/pg-session-storage.d.ts +17 -4
  297. package/dist/plugins/pg-session-storage.js +29 -6
  298. package/dist/plugins/remote-env-adb.d.ts +6 -12
  299. package/dist/plugins/remote-env-adb.js +12 -2
  300. package/dist/plugins/remote-env-k8s.d.ts +8 -12
  301. package/dist/plugins/remote-env-k8s.js +23 -5
  302. package/dist/plugins/remote-env-local-docker.d.ts +10 -15
  303. package/dist/plugins/remote-env-local-docker.js +12 -9
  304. package/dist/plugins/remote-env-ssh.d.ts +10 -16
  305. package/dist/plugins/remote-env-ssh.js +17 -11
  306. package/dist/plugins/run-store-sql.d.ts +16 -14
  307. package/dist/plugins/run-store-sql.js +22 -2
  308. package/dist/plugins/schema-indexes.js +2 -0
  309. package/dist/plugins/send-user-file.js +2 -2
  310. package/dist/plugins/session-epoch-anchor.d.ts +32 -6
  311. package/dist/plugins/session-epoch-anchor.js +2 -3
  312. package/dist/plugins/session-store.d.ts +18 -8
  313. package/dist/plugins/session-store.js +15 -4
  314. package/dist/plugins/sql-driver.d.ts +74 -11
  315. package/dist/plugins/sql-driver.js +210 -12
  316. package/dist/plugins/sql-errors.d.ts +23 -0
  317. package/dist/plugins/sql-errors.js +21 -0
  318. package/dist/plugins/store-backend.d.ts +36 -1
  319. package/dist/plugins/store-backend.js +40 -14
  320. package/dist/plugins/store-contracts.d.ts +42 -0
  321. package/dist/plugins/store-contracts.js +1 -0
  322. package/dist/plugins/tidb-pool.d.ts +6 -1
  323. package/dist/plugins/tidb-pool.js +44 -10
  324. package/dist/plugins/tidb-session-storage.d.ts +3 -2
  325. package/dist/plugins/tidb-session-storage.js +2 -2
  326. package/dist/plugins/tidb-session-store.d.ts +24 -4
  327. package/dist/plugins/tidb-session-store.js +28 -4
  328. package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
  329. package/dist/plugins/workflow-journal-store-sql.js +19 -6
  330. package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
  331. package/dist/plugins/workflow-run-store-sql.js +50 -9
  332. package/dist/posture-source.d.ts +18 -10
  333. package/dist/posture-source.js +4 -1
  334. package/dist/project-identity.d.ts +45 -6
  335. package/dist/project-identity.js +162 -8
  336. package/dist/project-layer-key.d.ts +28 -0
  337. package/dist/project-layer-key.js +29 -0
  338. package/dist/question.js +3 -2
  339. package/dist/read-deny-entry.d.ts +25 -0
  340. package/dist/read-deny-entry.js +12 -0
  341. package/dist/read-face-posture.d.ts +37 -11
  342. package/dist/read-face-posture.js +32 -3
  343. package/dist/request-key-closure.d.ts +7 -0
  344. package/dist/request-key-closure.js +9 -1
  345. package/dist/request-value-closure.d.ts +5 -0
  346. package/dist/request-value-closure.js +11 -3
  347. package/dist/rule-entry-list.d.ts +26 -2
  348. package/dist/rule-entry-list.js +72 -12
  349. package/dist/rules-consent.js +3 -4
  350. package/dist/run-acceptance.d.ts +19 -3
  351. package/dist/run-acceptance.js +13 -1
  352. package/dist/run-local.js +36 -6
  353. package/dist/runs.d.ts +10 -9
  354. package/dist/runs.js +21 -3
  355. package/dist/runtime-caps-resolver.d.ts +16 -6
  356. package/dist/runtime-caps-resolver.js +18 -5
  357. package/dist/sandbox-pkg-source.d.ts +19 -1
  358. package/dist/sandbox-pkg-source.js +29 -7
  359. package/dist/security.d.ts +87 -9
  360. package/dist/security.js +52 -9
  361. package/dist/session-error-wire.d.ts +19 -2
  362. package/dist/session-error-wire.js +5 -1
  363. package/dist/session-titled-frame.d.ts +33 -0
  364. package/dist/session-titled-frame.js +4 -0
  365. package/dist/session-titler.d.ts +9 -1
  366. package/dist/session-titler.js +15 -4
  367. package/dist/spec-fields.js +21 -2
  368. package/dist/sql-engine-posture.d.ts +3 -1
  369. package/dist/task-cwd.d.ts +1 -1
  370. package/dist/task-mcp.d.ts +3 -3
  371. package/dist/task-mcp.js +7 -66
  372. package/dist/task-settings.d.ts +89 -88
  373. package/dist/task-settings.js +71 -63
  374. package/dist/text-bidi.d.ts +0 -4
  375. package/dist/text-bidi.js +1 -3
  376. package/dist/tighten-only-seats.d.ts +150 -0
  377. package/dist/tighten-only-seats.js +196 -0
  378. package/dist/tool-approval.d.ts +303 -87
  379. package/dist/tool-approval.js +623 -239
  380. package/dist/trace/core-keyset-guard.d.ts +104 -22
  381. package/dist/trace/exit-seat.d.ts +28 -0
  382. package/dist/trace/exit-seat.js +76 -0
  383. package/dist/trace/ledger-events.d.ts +3 -2
  384. package/dist/trace/project.d.ts +80 -12
  385. package/dist/trace/project.js +41 -28
  386. package/dist/trace/projection-table.d.ts +100 -0
  387. package/dist/trace/projection-table.js +130 -0
  388. package/dist/trace/redact.d.ts +54 -0
  389. package/dist/trace/redact.js +778 -152
  390. package/dist/trace/self-minted-wire.d.ts +345 -1
  391. package/dist/trace/self-minted-wire.js +117 -1
  392. package/dist/trace/wire-projection-faces.d.ts +298 -2
  393. package/dist/trace/wire-projection-faces.js +154 -13
  394. package/dist/url-refusal.js +2 -0
  395. package/dist/web-admin-client/apply-effective.d.ts +12 -0
  396. package/dist/web-admin-client/apply-effective.js +56 -5
  397. package/dist/web-admin-client/facade.d.ts +1 -1
  398. package/dist/web-admin-client/facade.js +1 -1
  399. package/dist/web-admin-client/read-face.js +5 -9
  400. package/dist/web-admin-client/skills-mcp.js +4 -5
  401. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
  402. package/package.json +7 -3
@@ -1,6 +1,8 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { readFileSync, realpathSync, statSync } from "node:fs";
3
3
  import { basename, dirname, join, resolve } from "node:path";
4
+ import { encodeScopeSegment } from "@sema-agent/core";
5
+ import { mintProjectLayerKey, PROJECT_LAYER_KEY_PREFIX, projectLayerOwnerOf } from "./project-layer-key.js";
4
6
  const UNREADABLE = { absent: "unreadable" };
5
7
  const BARE = { absent: "bare" };
6
8
  function isMissing(err) {
@@ -53,7 +55,7 @@ function identityOfGitFile(dir) {
53
55
  const gitDir = gitDirFact.ok;
54
56
  const commonText = readTextFact(join(gitDir, "commondir"));
55
57
  if (commonText === "missing")
56
- return { root: dir };
58
+ return { root: dir, gitConfig: join(gitDir, "config") };
57
59
  if (commonText === "unreadable")
58
60
  return UNREADABLE;
59
61
  const commonFact = realpathFact(resolve(gitDir, commonText.ok));
@@ -68,7 +70,7 @@ function identityOfGitFile(dir) {
68
70
  const backFact = realpathFact(resolve(gitDir, back.ok));
69
71
  if (typeof backFact !== "object" || backFact.ok !== join(dir, ".git"))
70
72
  return UNREADABLE;
71
- return { root: basename(common) !== ".git" ? common : dirname(common) };
73
+ return { root: basename(common) !== ".git" ? common : dirname(common), gitConfig: join(common, "config") };
72
74
  }
73
75
  function canonicalTaskRoot(taskRoot) {
74
76
  const rest = [];
@@ -86,6 +88,10 @@ function canonicalTaskRoot(taskRoot) {
86
88
  }
87
89
  }
88
90
  export function resolveProjectIdentity(taskRoot) {
91
+ const located = locateProject(taskRoot);
92
+ return "root" in located ? { root: located.root } : located;
93
+ }
94
+ function locateProject(taskRoot) {
89
95
  const root = canonicalTaskRoot(taskRoot);
90
96
  if (root === "unreadable")
91
97
  return UNREADABLE;
@@ -96,7 +102,7 @@ export function resolveProjectIdentity(taskRoot) {
96
102
  return UNREADABLE;
97
103
  if (typeof dotGit === "object") {
98
104
  if (dotGit.ok === "dir")
99
- return { root: dir };
105
+ return { root: dir, gitConfig: join(dir, ".git", "config") };
100
106
  if (dotGit.ok === "file")
101
107
  return identityOfGitFile(dir);
102
108
  }
@@ -108,13 +114,161 @@ export function resolveProjectIdentity(taskRoot) {
108
114
  dir = parent;
109
115
  }
110
116
  }
117
+ function digest24(text) {
118
+ return createHash("sha256").update(text, "utf8").digest("hex").slice(0, 24);
119
+ }
120
+ const RETIRED_PROJECT_KEY_PREFIX = "repo:";
111
121
  export function mintRepoScopeKey(projectRoot) {
112
- return `repo:${createHash("sha256").update(projectRoot, "utf8").digest("hex").slice(0, 24)}`;
122
+ return `${RETIRED_PROJECT_KEY_PREFIX}${digest24(projectRoot)}`;
123
+ }
124
+ export function isServerMintedProjectKey(key) {
125
+ return key.startsWith(PROJECT_LAYER_KEY_PREFIX) || key.startsWith(RETIRED_PROJECT_KEY_PREFIX);
126
+ }
127
+ export function assertProjectLayerOwnable(scope, envName) {
128
+ if (isServerMintedProjectKey(scope)) {
129
+ throw new Error(`${envName}=${JSON.stringify(scope)} names a server-minted project-layer key (the "${PROJECT_LAYER_KEY_PREFIX}" family, or the retired "${RETIRED_PROJECT_KEY_PREFIX}" family) — ` +
130
+ "project layers are derived per task from the project identity and cannot be named as a deployment scope. Use a user key (user:<principal>) or a plain name.");
131
+ }
132
+ const owner = ownerSegmentFact(scope);
133
+ if (!owner.ok) {
134
+ throw new Error(`${envName}=${JSON.stringify(scope)} cannot own per-project memory layers: ${owner.why} — ` +
135
+ "the layer owner (the principal of a user: key, otherwise the name itself) must encode to at most 64 scope-segment characters.");
136
+ }
137
+ }
138
+ function ownerSegmentFact(scope) {
139
+ try {
140
+ encodeScopeSegment(projectLayerOwnerOf(scope));
141
+ return { ok: true };
142
+ }
143
+ catch (err) {
144
+ return { ok: false, why: err instanceof Error ? err.message : String(err) };
145
+ }
146
+ }
147
+ const GIT_CONFIG_MAX_BYTES = 256 * 1024;
148
+ function readOriginRemoteUrl(configPath) {
149
+ const st = statFact(configPath);
150
+ if (st === "missing")
151
+ return "missing";
152
+ if (st === "unreadable" || st.ok !== "file")
153
+ return "unreadable";
154
+ let size;
155
+ try {
156
+ size = statSync(configPath).size;
157
+ }
158
+ catch (err) {
159
+ return isMissing(err) ? "missing" : "unreadable";
160
+ }
161
+ if (size > GIT_CONFIG_MAX_BYTES)
162
+ return "unreadable";
163
+ const text = readTextFact(configPath);
164
+ if (typeof text !== "object")
165
+ return text;
166
+ let inOrigin = false;
167
+ for (const raw of gitConfigLogicalLines(text.ok)) {
168
+ const line = raw.trim();
169
+ if (line.startsWith("[")) {
170
+ const header = /^\[\s*([A-Za-z0-9.-]+)(?:\s+"((?:[^"\\]|\\.)*)")?\s*\]/.exec(line);
171
+ inOrigin = header !== null && header[1].toLowerCase() === "remote" && header[2] !== undefined && header[2].replace(/\\(.)/g, "$1") === "origin";
172
+ continue;
173
+ }
174
+ if (!inOrigin)
175
+ continue;
176
+ const kv = /^([A-Za-z][A-Za-z0-9-]*)\s*=\s*(.*)$/.exec(line);
177
+ if (kv === null || kv[1].toLowerCase() !== "url")
178
+ continue;
179
+ const value = gitConfigValue(kv[2]);
180
+ if (value !== "")
181
+ return { ok: value };
182
+ }
183
+ return { ok: undefined };
184
+ }
185
+ function gitConfigLogicalLines(text) {
186
+ const out = [];
187
+ let pending = "";
188
+ for (const physical of text.split(/\r?\n/)) {
189
+ const trailing = /\\*$/.exec(physical)[0].length;
190
+ if (trailing % 2 === 1) {
191
+ pending += physical.slice(0, -1);
192
+ continue;
193
+ }
194
+ out.push(pending + physical);
195
+ pending = "";
196
+ }
197
+ if (pending !== "")
198
+ out.push(pending);
199
+ return out;
200
+ }
201
+ function gitConfigValue(raw) {
202
+ let out = "";
203
+ let quoted = false;
204
+ for (let i = 0; i < raw.length; i++) {
205
+ const c = raw[i];
206
+ if (c === "\\" && i + 1 < raw.length) {
207
+ out += raw[++i];
208
+ continue;
209
+ }
210
+ if (c === '"') {
211
+ quoted = !quoted;
212
+ continue;
213
+ }
214
+ if (!quoted && (c === "#" || c === ";"))
215
+ break;
216
+ out += c;
217
+ }
218
+ return out.trim();
219
+ }
220
+ const DEFAULT_REMOTE_PORTS = { ssh: "22", "git+ssh": "22", "ssh+git": "22", https: "443", http: "80", git: "9418" };
221
+ export function normalizeGitRemoteUrl(url) {
222
+ const u = url.trim();
223
+ const scheme = /^([A-Za-z][A-Za-z0-9+.-]*):\/\/(.*)$/.exec(u);
224
+ if (scheme !== null) {
225
+ const name = scheme[1].toLowerCase();
226
+ if (name === "file")
227
+ return undefined;
228
+ const rest = scheme[2];
229
+ const slash = rest.indexOf("/");
230
+ const authority = slash < 0 ? rest : rest.slice(0, slash);
231
+ const hostPort = authority.slice(authority.lastIndexOf("@") + 1);
232
+ const port = /:(\d*)$/.exec(hostPort);
233
+ const host = (port === null ? hostPort : hostPort.slice(0, port.index)).toLowerCase();
234
+ if (host === "")
235
+ return undefined;
236
+ const keptPort = port !== null && port[1] !== "" && port[1] !== DEFAULT_REMOTE_PORTS[name] ? `:${port[1]}` : "";
237
+ return `${host}${keptPort}/${cleanRemotePath(slash < 0 ? "" : rest.slice(slash))}`;
238
+ }
239
+ const scp = /^(?:[^@/]+@)?([^:/]{2,}):(.*)$/.exec(u);
240
+ if (scp !== null)
241
+ return `${scp[1].toLowerCase()}/${cleanRemotePath(scp[2])}`;
242
+ return undefined;
113
243
  }
114
- export function projectKeyForTaskRoot(taskRoot) {
244
+ function cleanRemotePath(p) {
245
+ return p.replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "").replace(/\.git$/, "");
246
+ }
247
+ export function projectLayerIdentityOf(taskRoot) {
248
+ const located = locateProject(taskRoot);
249
+ if (!("root" in located))
250
+ return located;
251
+ const path = { tier: "p", digest: digest24(located.root) };
252
+ const origin = located.gitConfig !== undefined ? readOriginRemoteUrl(located.gitConfig) : "missing";
253
+ if (origin === "unreadable")
254
+ return UNREADABLE;
255
+ const remote = origin === "missing" || origin.ok === undefined ? undefined : normalizeGitRemoteUrl(origin.ok);
256
+ if (remote === undefined)
257
+ return { root: located.root, identity: path, lowerTiers: [] };
258
+ return { root: located.root, identity: { tier: "r", digest: digest24(remote) }, lowerTiers: [path] };
259
+ }
260
+ export function projectLayerForTaskRoot(taskRoot, owner) {
115
261
  if (taskRoot === undefined)
116
- return { absent: "unreadable" };
117
- const id = resolveProjectIdentity(taskRoot);
118
- return "root" in id ? { scope: mintRepoScopeKey(id.root) } : { absent: id.absent };
262
+ return { key: UNREADABLE, foldFrom: [] };
263
+ const id = projectLayerIdentityOf(taskRoot);
264
+ if (!("identity" in id))
265
+ return { key: { absent: id.absent }, foldFrom: [] };
266
+ return {
267
+ key: { scope: mintProjectLayerKey(owner, id.identity) },
268
+ foldFrom: [mintRepoScopeKey(id.root), ...id.lowerTiers.map((tier) => mintProjectLayerKey(owner, tier))],
269
+ };
270
+ }
271
+ export function projectKeyForTaskRoot(taskRoot, owner) {
272
+ return projectLayerForTaskRoot(taskRoot, owner).key;
119
273
  }
120
274
  //# sourceMappingURL=project-identity.js.map
@@ -0,0 +1,28 @@
1
+ /** 项目层键的前缀(改名链的前缀词表也读它)。 */
2
+ export declare const PROJECT_LAYER_KEY_PREFIX = "userrepo:";
3
+ /** 身份档:`r` = 仓库身份(origin 远端,跨设备),`p` = 项目根路径(本机)。 */
4
+ export type ProjectIdentityTier = "r" | "p";
5
+ /** 一个项目的身份段(档 + 24 位小写十六进制摘要)。 */
6
+ export interface ProjectLayerIdentity {
7
+ readonly tier: ProjectIdentityTier;
8
+ readonly digest: string;
9
+ }
10
+ /** 解出的项目层键。 */
11
+ export interface ParsedProjectLayerKey {
12
+ /** 解码后的属主(主体名,或不透明全局层名本身)。 */
13
+ readonly owner: string;
14
+ readonly identity: ProjectLayerIdentity;
15
+ }
16
+ /**
17
+ * 全局层 → 它的属主(见文件头文法)。`user:` 形用 core 的解析(段解码、规范形校验);坏的 `user:` 形照 core 原样抛
18
+ * (`config.memory_scope_key`)—— 起服经 `project-identity.ts` `assertProjectLayerOwnable` 在第一刻接住,不留到任务期。
19
+ */
20
+ export declare function projectLayerOwnerOf(globalScope: string): string;
21
+ /** 铸项目层键。属主编码超长 / 空 ⇒ core 段编码原样抛(起服已由 `assertProjectLayerOwnable` 拦住)。 */
22
+ export declare function mintProjectLayerKey(owner: string, identity: ProjectLayerIdentity): string;
23
+ /**
24
+ * 解项目层键。**严格**:前缀 + 恰好一个 `/` + 规范形属主段(`%41` 这类第二种拼法不认 —— 一个属主不许有两把键)+ 档文法。
25
+ * 不合任何一条 ⇒ `undefined`(调用方读作「不是项目层」;属主门据此答与其余拒绝同体的 404)。
26
+ */
27
+ export declare function parseProjectLayerKey(key: string): ParsedProjectLayerKey | undefined;
28
+ //# sourceMappingURL=project-layer-key.d.ts.map
@@ -0,0 +1,29 @@
1
+ import { decodeScopeSegment, encodeScopeSegment, parseScopeKey } from "@sema-agent/core";
2
+ export const PROJECT_LAYER_KEY_PREFIX = "userrepo:";
3
+ const DIGEST = /^[0-9a-f]{24}$/;
4
+ const KEY = /^userrepo:((?:[A-Za-z0-9._-]|%[0-9A-F]{2})+)\/([rp])\.([0-9a-f]{24})$/;
5
+ export function projectLayerOwnerOf(globalScope) {
6
+ const parsed = parseScopeKey(globalScope);
7
+ return parsed.kind === "user" ? parsed.principal : globalScope;
8
+ }
9
+ export function mintProjectLayerKey(owner, identity) {
10
+ if (!DIGEST.test(identity.digest))
11
+ throw new Error(`project layer identity digest must be 24 lowercase hex characters, got ${JSON.stringify(identity.digest)}`);
12
+ return `${PROJECT_LAYER_KEY_PREFIX}${encodeScopeSegment(owner)}/${identity.tier}.${identity.digest}`;
13
+ }
14
+ export function parseProjectLayerKey(key) {
15
+ const m = KEY.exec(key);
16
+ if (m === null)
17
+ return undefined;
18
+ const owner = decodeOwnerSegment(m[1]);
19
+ return owner.ok ? { owner: owner.owner, identity: { tier: m[2], digest: m[3] } } : undefined;
20
+ }
21
+ function decodeOwnerSegment(segment) {
22
+ try {
23
+ return { ok: true, owner: decodeScopeSegment(segment) };
24
+ }
25
+ catch (err) {
26
+ return { ok: false, why: err instanceof Error ? err.message : String(err) };
27
+ }
28
+ }
29
+ //# sourceMappingURL=project-layer-key.js.map
package/dist/question.js CHANGED
@@ -2,6 +2,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
2
2
  import { uuidv7 } from "@sema-agent/core";
3
3
  import { redactDeep } from "./trace/redact.js";
4
4
  import { recordFailOpen } from "./observability/fail-open.js";
5
+ import { refusalBody } from "./http/refusal-body.js";
5
6
  const MAX_QUESTIONS_BYTES = 16384;
6
7
  function isFaceReachable(ctx) {
7
8
  if (ctx.deliverable === undefined)
@@ -150,10 +151,10 @@ export class QuestionCoordinator {
150
151
  respond(id, principal, body) {
151
152
  const parsed = parseQuestionResponse(body);
152
153
  if (!parsed.ok)
153
- return { status: 400, body: { error: parsed.error, errorCode: "request.body_shape" } };
154
+ return { status: 400, body: refusalBody({ errorCode: "request.body_shape", message: parsed.error }) };
154
155
  const entry = this.pending.get(id);
155
156
  if (!entry || (entry.owner !== null && entry.owner !== principal)) {
156
- return { status: 404, body: { error: "no pending question for this id (answered, expired, or not on this replica)", errorCode: "question.not_pending" } };
157
+ return { status: 404, body: refusalBody({ errorCode: "question.not_pending", message: "no pending question for this id (answered, expired, or not on this replica)" }) };
157
158
  }
158
159
  entry.settle(parsed.value, "answered");
159
160
  return { status: 200, body: { questionId: id, delivery: "applied" } };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * **读拒模式条目的归一**(全仓唯一一只读法)—— `READ_DENY_PATTERNS` 的 env 腿(`config.ts`)、中心下发 `readFace.denyPatterns` 的腿(`web-admin-client/read-face.ts`)、
3
+ * 请求 `settings.readDenyPatterns` 的腿(`tighten-only-seats.ts`)三处读同一份元素文法:`"pattern"` 裸串简写 ≡ `{ pattern, caseSensitive: false }`,
4
+ * 对象形 `{ pattern: string, caseSensitive?: boolean }`(与 core `ReadDenyEntry = string | {…}` 同宽)。三份手抄的元素读法就是三个会各自漂的真源,所以收成这一只。
5
+ *
6
+ * 只管**元素形**(串 / 带串 `pattern` 的对象 / 布尔 `caseSensitive`);模式编不编得过由调用方交给 core 的 `compileReadDeny`(引擎同一套规则,宿主不自造第二份校验语义)。
7
+ * 返回的是**接在坐标后面的原因尾巴**(` must be a string or an object with a string 'pattern'` / `.caseSensitive must be boolean when present`),不带坐标 —— 调用方自己前缀坐标
8
+ * (`READ_DENY_PATTERNS[2]` / `readFace.denyPatterns[2]` / `settings.readDenyPatterns[2]`),各腿既有的拒句字节不变。叶模块,零 import。
9
+ */
10
+ /** 归一后的一行(core `compileReadDeny` 收的对象形)。 */
11
+ export interface NormalizedReadDenyEntry {
12
+ readonly pattern: string;
13
+ readonly caseSensitive: boolean;
14
+ }
15
+ /** 一个元素的读数:归一后的行,或接在调用方坐标后面成句的原因尾巴(`after` 自带连接符:空格或点)。 */
16
+ export type ReadDenyEntryReading = {
17
+ readonly ok: true;
18
+ readonly entry: NormalizedReadDenyEntry;
19
+ } | {
20
+ readonly ok: false;
21
+ readonly after: string;
22
+ };
23
+ /** 读一个元素。裸串 ⇒ 大小写默认不敏感(与对象形缺席 `caseSensitive` 一致);坏形 ⇒ 原因子句,不抛、不丢。 */
24
+ export declare function readReadDenyEntry(it: unknown): ReadDenyEntryReading;
25
+ //# sourceMappingURL=read-deny-entry.d.ts.map
@@ -0,0 +1,12 @@
1
+ export function readReadDenyEntry(it) {
2
+ if (typeof it === "string")
3
+ return { ok: true, entry: { pattern: it, caseSensitive: false } };
4
+ if (typeof it !== "object" || it === null || typeof it.pattern !== "string") {
5
+ return { ok: false, after: " must be a string or an object with a string 'pattern'" };
6
+ }
7
+ const cs = it.caseSensitive;
8
+ if (cs !== undefined && typeof cs !== "boolean")
9
+ return { ok: false, after: ".caseSensitive must be boolean when present" };
10
+ return { ok: true, entry: { pattern: it.pattern, caseSensitive: cs === true } };
11
+ }
12
+ //# sourceMappingURL=read-deny-entry.js.map
@@ -17,9 +17,14 @@
17
17
  * ② 运维面:`GET /v1/diagnostics/wiring` 报 `{face, source, note}`,「为什么这台机器是 open」有答案
18
18
  * (裁定的补偿项:升级即放开,得让运维看得见并知道怎么钉回)。
19
19
  *
20
- * ## 优先序(三态,与 `config.ts` 的 `postureOn` 同形)
21
- * `env 显式` > `center 发布` > `posture 派生` > `引擎默认`。env 恒赢的论证逐字见 `web-admin-client/read-face.ts`
20
+ * ## 优先序(与 `config.ts` 的 `postureOn` 同形)
21
+ * `env 显式` > `center 发布` > `lane 声明` > `posture 派生` > `引擎默认`。env 恒赢的论证逐字见 `web-admin-client/read-face.ts`
22
22
  * 头注①(READ 容纳面描述的是**这台机器的磁盘上有什么**,组织的下发面不知道)。
23
+ * 🔴 **`lane` 一臂(S-1492,clay 裁 [ref])**:隔离型执行车道(`e2b` / `k8s` / `local-docker`)的契约行**显式声明**读面缺省 `open`
24
+ * (`execution-lane-caps.ts` 的 `laneReadFaceDefault`;沙箱内部就是模型的整个世界)。运维没写 `READ_FACE` 时,车道声明比整机 posture 更具体 ⇒ 排在它前面;
25
+ * 声明 `roots` 的车道(`host` / `ssh` / `adb` / `device` / 未设车道)不替运维声明缺省,回到既有的 posture 派生,**一个字节不变**。
26
+ * 缺席这一态的派生**只有一只函数**({@link readFaceDefaultFor}),且读的是**最终生效的车道**(`loadConfig` 装配完 `remoteExec` 之后一次;
27
+ * local 形 `config.d/remote-exec.json` 覆写之后由车道合成步再派一次 —— 同一只 {@link settleDerivedReadFace})。
23
28
  *
24
29
  * ## 定界
25
30
  * 本模块**只**管 `face` 一档。内建读拒表(`readDenyPatterns` / `readDenyBuiltinTiers` /
@@ -31,13 +36,14 @@
31
36
  * 本模块的定界不变:并列的那一侧开着哪几档,是那张表自己的缺省说了算。core 的 `config.read_face_deployment_clamped`
32
37
  * (只读挂载钳制)同样不受本件影响。
33
38
  */
39
+ import { type LaneReadFaceDefault, type RemoteExecProvider } from "./execution-lane-caps.js";
34
40
  import { type PostureSource } from "./posture-source.js";
35
41
  /**
36
42
  * 档位来源的闭集词表 —— **S-178 起转 `posture-source.ts` 的共享件**(本模块只是给这一档取个本地名字,
37
43
  * 不再持第二份词表:同一张四词表抄两遍的那天,两份会在加词时分家)。
38
44
  */
39
- export declare const READ_FACE_SOURCE_WORDS: readonly ["env", "center", "posture", "engine-default"];
40
- /** 档位的来源(闭集四词)。加词 ⇒ {@link postureSourceNote} 的穷举 switch 编译红。 */
45
+ export declare const READ_FACE_SOURCE_WORDS: readonly ["env", "center", "lane", "posture", "engine-default"];
46
+ /** 档位的来源(闭集五词)。加词 ⇒ {@link postureSourceNote} 的穷举 switch 编译红。 */
41
47
  export type ReadFaceSource = PostureSource;
42
48
  /** 一台 worker 的 READ 面档位事实(值 + 来源)。`ServiceConfigFlat` 结构上满足本形。 */
43
49
  export interface ReadFacePostureFacts {
@@ -45,10 +51,29 @@ export interface ReadFacePostureFacts {
45
51
  readonly readFaceSource: ReadFaceSource;
46
52
  }
47
53
  /**
48
- * 缺席 `READ_FACE` 时的 posture 派生(`config.ts` 的铸点调用;显式值不经此口)。
49
- * 单用户 turnkey ⇒ `open`;多租户 ⇒ 不铸(引擎默认 `roots`,server 不复制上游默认)。
54
+ * 缺席 `READ_FACE` 时读面缺省的**唯一派生函数**(显式 env 值不经此口):
55
+ * · 车道声明 `open`(隔离型车道)⇒ `open`,来源 `lane`(不论单用户还是多租户 —— 更具体的出处胜 posture);
56
+ * · 车道声明 `roots` ⇒ 既有 posture 派生,逐字不变。
50
57
  */
51
- export declare function readFaceForPosture(singleUserTurnkey: boolean): ReadFacePostureFacts;
58
+ export declare function readFaceDefaultFor(input: {
59
+ readonly laneDefault: LaneReadFaceDefault;
60
+ readonly singleUserTurnkey: boolean;
61
+ }): ReadFacePostureFacts;
62
+ /** {@link settleDerivedReadFace} 动的那几格(`ServiceConfig` 结构上满足本形)。 */
63
+ export interface ReadFaceDeploymentSeat {
64
+ readFace?: "open" | "roots" | undefined;
65
+ readFaceSource: ReadFaceSource;
66
+ remoteExec?: {
67
+ readonly provider: RemoteExecProvider;
68
+ } | undefined;
69
+ }
70
+ /**
71
+ * 把**派生的**读面缺省按这台部署**最终生效的车道**落到配置上(显式 env / center 发布的值与来源原样不动)。返回值 = 这一次有没有改动。
72
+ * 两个调用点,同一只函数:`loadConfig` 装配完 `remoteExec` 之后(env 三元链定的车道);车道合成步在 local 形文件覆写之后
73
+ * (`config.d/remote-exec.json` 能把车道换成 `host` / `local-docker`,读面缺省随最终车道重派 —— 否则它停在已作废的车道上)。
74
+ * 幂等:同一份配置再调一次不改。值与来源**同一处写**(`readFace` 缺席 ⟺ 来源 `engine-default`)。
75
+ */
76
+ export declare function settleDerivedReadFace(seat: ReadFaceDeploymentSeat, singleUserTurnkey: boolean): boolean;
52
77
  /** 本档的运维指路句 —— 骨架由共享件 {@link postureSourceNote} 给(四词穷举在那里,加词即编译红);
53
78
  * 本函数提供两条**键专属**臂(`center` / `posture`)的事实句。
54
79
  *
@@ -67,13 +92,14 @@ export declare function buildReadFaceWiring(facts: ReadFacePostureFacts): {
67
92
  note: string;
68
93
  };
69
94
  /**
70
- * S-176 —— posture 派生的档位在 **boot 期推送面**的那一行(`config.ts` 经既有 `CONFIG_NOTICES` 以 info 级排空)。
95
+ * S-176 —— 派生的档位(`posture` 单机 ⇒ open,或 S-1492 的 `lane` 隔离车道 ⇒ open)在 **boot 期推送面**的那一行(`config.ts` 经既有 `CONFIG_NOTICES` 以 info 级排空)。
71
96
  *
72
97
  * 为什么要有:S-167 的补偿项是「升级即放开,得让运维看得见并知道怎么钉回」,可此前唯一看得见的是**拉取**面
73
- * (`GET /v1/diagnostics/wiring`)—— 只对会去拉的人成立。单机 boot 日志里零字。
74
- * 为什么只在 `posture` 一词上说:另外三词都不是「没人表态、服务替它选了一个更宽的档」——`env` 是运维自己写的,
98
+ * (`GET /v1/diagnostics/wiring`)—— 只对会去拉的人成立。单机 boot 日志里零字。S-1492 的 `lane` 臂同一个补偿:多租户沙箱部署升级后读面从 `roots` 变 `open`,
99
+ * 指路句带挂载告诫与钉回出路。
100
+ * 为什么只在 `posture` / `lane` 两词上说:另外三词都不是「没人表态、服务替它选了一个更宽的档」——`env` 是运维自己写的,
75
101
  * `engine-default` 是本服务没铸(引擎默认接管),`center` 在 boot 这一拍还没到货(它有自己的换席通告)。
76
- * 为什么是 info 不是 warn:每一台照常配置的单机每次启动都成立,是常态事实不是异常(与执行车道落点同级)。
102
+ * 为什么是 info 不是 warn:每一台照常配置的部署每次启动都成立,是常态事实不是异常(与执行车道落点同级)。
77
103
  *
78
104
  * 字段与极性表的 posture 行同名(`knob` / `value` / `source`),另带指路句;三格由 {@link buildReadFaceWiring} 投影出 ——
79
105
  * 拉取面与推送面**同一只函数**,不各算一次。`value` 是字符串:只有 `face` 在场的那一形才会走到这里。
@@ -1,13 +1,42 @@
1
+ import { LANE_OPEN_READ_FACE_CAUTION, executionLaneOf, laneReadFaceDefault } from "./execution-lane-caps.js";
1
2
  import { POSTURE_SOURCE_WORDS, postureSourceNote } from "./posture-source.js";
2
3
  export const READ_FACE_SOURCE_WORDS = POSTURE_SOURCE_WORDS;
3
- export function readFaceForPosture(singleUserTurnkey) {
4
+ function readFaceForPosture(singleUserTurnkey) {
4
5
  return singleUserTurnkey ? { readFace: "open", readFaceSource: "posture" } : { readFaceSource: "engine-default" };
5
6
  }
7
+ export function readFaceDefaultFor(input) {
8
+ return input.laneDefault === "open" ? { readFace: "open", readFaceSource: "lane" } : readFaceForPosture(input.singleUserTurnkey);
9
+ }
10
+ function isDerivedSource(source) {
11
+ switch (source) {
12
+ case "env":
13
+ case "center":
14
+ return false;
15
+ case "lane":
16
+ case "posture":
17
+ case "engine-default":
18
+ return true;
19
+ }
20
+ }
21
+ export function settleDerivedReadFace(seat, singleUserTurnkey) {
22
+ if (!isDerivedSource(seat.readFaceSource))
23
+ return false;
24
+ const next = readFaceDefaultFor({ laneDefault: laneReadFaceDefault(executionLaneOf(seat.remoteExec?.provider)), singleUserTurnkey });
25
+ if (next.readFace === seat.readFace && next.readFaceSource === seat.readFaceSource)
26
+ return false;
27
+ if (next.readFace === undefined)
28
+ delete seat.readFace;
29
+ else
30
+ seat.readFace = next.readFace;
31
+ seat.readFaceSource = next.readFaceSource;
32
+ return true;
33
+ }
6
34
  export function readFaceSourceNote(source) {
7
35
  return postureSourceNote({
8
36
  knob: "READ_FACE",
9
37
  source,
10
38
  centerMeaning: "published by the web-admin and applied HOT — the containment FACE is a swappable engine seat (core 7.10.0), so the next refresh (or POST /v1/admin/config/refresh) swaps it into every Runner with NO restart; set READ_FACE on this machine to take the key back",
39
+ laneMeaning: `declared by the isolated execution lane this deployment runs on (REMOTE_EXEC=e2b|k8s|local-docker): the sandbox is the model's whole world, so reads are not fenced to the workspace roots by default; ${LANE_OPEN_READ_FACE_CAUTION}`,
11
40
  postureMeaning: "derived from the single-user turnkey posture (REQUIRE_PRINCIPAL is not set): reads outside the workspace roots are allowed by default — set READ_FACE=roots to pin the containing posture back",
12
41
  });
13
42
  }
@@ -15,11 +44,11 @@ export function buildReadFaceWiring(facts) {
15
44
  return { face: facts.readFace ?? null, source: facts.readFaceSource, note: readFaceSourceNote(facts.readFaceSource) };
16
45
  }
17
46
  export function buildReadFacePostureNotice(facts) {
18
- if (facts.readFaceSource !== "posture")
47
+ if (facts.readFaceSource !== "posture" && facts.readFaceSource !== "lane")
19
48
  return undefined;
20
49
  const wiring = buildReadFaceWiring(facts);
21
50
  if (wiring.face === null) {
22
- throw new Error("read-face posture notice: source is `posture` but no face was minted — readFaceForPosture's invariant broke");
51
+ throw new Error(`read-face derived notice: source is \`${facts.readFaceSource}\` but no face was minted — readFaceDefaultFor's invariant broke`);
23
52
  }
24
53
  return { event: "config_knob_posture_derived", fields: { knob: "READ_FACE", value: wiring.face, source: wiring.source, note: wiring.note } };
25
54
  }
@@ -58,5 +58,12 @@ export type InterruptSteerBody = {
58
58
  export type SteerBodyForm = "run" | "content" | "interrupt";
59
59
  /** 送话口的顶层键裁决(各形同一只;`form` 选受理集)。 */
60
60
  export declare function steerBodyKeyIssue(raw: unknown, form: SteerBodyForm): KeyClosureIssue | null;
61
+ declare const PRINCIPAL_INBOX_BODY_KEYS: readonly ["to", "content", "urgent"];
62
+ /** 受理口的体形(键 = 受理集,值形由路由逐键判)。 */
63
+ export type PrincipalInboxBody = {
64
+ readonly [K in (typeof PRINCIPAL_INBOX_BODY_KEYS)[number]]?: unknown;
65
+ };
66
+ /** 受理口的顶层键裁决(与提交口 / 送话口同一只组句器)。 */
67
+ export declare function principalInboxBodyKeyIssue(raw: unknown): KeyClosureIssue | null;
61
68
  export {};
62
69
  //# sourceMappingURL=request-key-closure.d.ts.map
@@ -1,4 +1,5 @@
1
1
  import { echoCallerText } from "./caller-text-echo.js";
2
+ import { tightenOnlySeatField } from "./tighten-only-seats.js";
2
3
  export const MAX_KEY_ECHO = 20;
3
4
  export function echoKeyName(prefix, key) {
4
5
  return `${prefix}${echoCallerText(key)}`;
@@ -31,6 +32,7 @@ const TASK_BODY_DECLARED_KEYS = [
31
32
  const TASK_BODY_SCENARIO_KEYS = ["repo"];
32
33
  const ACCEPTED_BODY = new Set([...TASK_BODY_DECLARED_KEYS, ...TASK_BODY_SCENARIO_KEYS]);
33
34
  const UNSUPPORTED_BODY_KEYS = ["handsReadOnly", "readDenyPatterns", "readFace", "shellGate", "writeFace"];
35
+ const BODY_KEY_SETTINGS_SEAT = { readDenyPatterns: tightenOnlySeatField("readDenyPatterns") };
34
36
  const UNSUPPORTED_BODY = {
35
37
  keys: new Set(UNSUPPORTED_BODY_KEYS),
36
38
  label: "unsupported (an engine seat this door does not read from the request body — set by the deployment)",
@@ -49,9 +51,10 @@ function closedBodyKeyIssue(raw, accepted, unsupported, door) {
49
51
  ...(buckets.unknown.length > 0 ? [keyClosureClause(buckets.unknown, `unknown (not ${door} key — check the spelling)`)] : []),
50
52
  ...(buckets.unsupported.length > 0 ? [keyClosureClause(buckets.unsupported, unsupported.label)] : []),
51
53
  ];
54
+ const seatHints = buckets.unsupported.flatMap((key) => (Object.hasOwn(BODY_KEY_SETTINGS_SEAT, key) ? [` \`${key}\` rides ${BODY_KEY_SETTINGS_SEAT[key]} instead.`] : []));
52
55
  return {
53
56
  message: `body: unrecognized top-level key(s) — refused rather than dropped, because a dropped key reads as "in effect" to the caller. ` +
54
- `${parts.join("; ")}. ` +
57
+ `${parts.join("; ")}.${seatHints.join("")} ` +
55
58
  `Accepted: ${[...accepted].sort().join(",")}`,
56
59
  unknownKeys: buckets.unknown.slice(0, MAX_KEY_ECHO),
57
60
  unsupportedKeys: buckets.unsupported.slice(0, MAX_KEY_ECHO),
@@ -75,4 +78,9 @@ const STEER_UNSUPPORTED = {
75
78
  export function steerBodyKeyIssue(raw, form) {
76
79
  return closedBodyKeyIssue(raw, STEER_DOORS[form].accepted, STEER_UNSUPPORTED, STEER_DOORS[form].door);
77
80
  }
81
+ const PRINCIPAL_INBOX_BODY_KEYS = ["to", "content", "urgent"];
82
+ const PRINCIPAL_INBOX_UNSUPPORTED = { keys: new Set(), label: "unsupported" };
83
+ export function principalInboxBodyKeyIssue(raw) {
84
+ return closedBodyKeyIssue(raw, new Set(PRINCIPAL_INBOX_BODY_KEYS), PRINCIPAL_INBOX_UNSUPPORTED, "a principal-inbox message");
85
+ }
78
86
  //# sourceMappingURL=request-key-closure.js.map
@@ -71,6 +71,11 @@ export declare const FILE_HISTORY_DISABLED_NO_RESTORE = "fileHistory: 'disabled'
71
71
  * 正是这个词关掉的记录 —— 两义都与关断词矛盾)。调用前值形已由上面的单成员表与既有布尔门判过。
72
72
  */
73
73
  export declare function fileHistoryRestoreConflict(body: Pick<TaskRequestBody, "fileHistory" | "restoreFiles" | "rewindFiles" | "rewindFilesTo">): boolean;
74
+ /**
75
+ * 还原键里请求**真带了的**那几个(顺序固定:`restoreFiles` · `rewindFilesTo` · 退役的 `rewindFiles`)。{@link fileHistoryRestoreConflict} 的「还原」一半就是它非空 ——
76
+ * 判据只有这一份,拒体的 `detail.fields` 点名的也是它(判与点名不会各读各的)。
77
+ */
78
+ export declare function fileHistoryRestoreKeysInBody(body: Pick<TaskRequestBody, "restoreFiles" | "rewindFiles" | "rewindFilesTo">): Array<"restoreFiles" | "rewindFilesTo" | "rewindFiles">;
74
79
  /**
75
80
  * **单成员闭集键表** —— 每键合法值只有它自己那一个关断词(`word`),缺席=照常,没有「开」的拼法。
76
81
  *
@@ -3,9 +3,17 @@ export const MEMORY_OFF_SPELLING_MESSAGE = "memory must be the string 'off' when
3
3
  export const FILE_HISTORY_OFF_SPELLING_MESSAGE = "fileHistory must be the string 'disabled' when present (the request-level declaration that this run records no file history — no backup of an edited file, and no file restore in the same request; absent = the deployment's setting — there is no 'enabled' spelling)";
4
4
  export const FILE_HISTORY_DISABLED_NO_RESTORE = "fileHistory: 'disabled' cannot ride with a file restore (restoreFiles, rewindFilesTo, or the retired rewindFiles) — the request turns this run's file history off and asks to restore files from it in the same breath; the engine would refuse it (rewind.capture_disabled) only after the session had already been branched at resumeAt, which it does not undo, so it is refused here, before any side effect. Drop fileHistory to restore, or drop the restore to run without file history";
5
5
  export function fileHistoryRestoreConflict(body) {
6
- if (body.fileHistory !== "disabled")
7
- return false;
8
- return body.restoreFiles === true || body.rewindFiles === true || (typeof body.rewindFilesTo === "string" && body.rewindFilesTo.length > 0);
6
+ return body.fileHistory === "disabled" && fileHistoryRestoreKeysInBody(body).length > 0;
7
+ }
8
+ export function fileHistoryRestoreKeysInBody(body) {
9
+ const out = [];
10
+ if (body.restoreFiles === true)
11
+ out.push("restoreFiles");
12
+ if (typeof body.rewindFilesTo === "string" && body.rewindFilesTo.length > 0)
13
+ out.push("rewindFilesTo");
14
+ if (body.rewindFiles === true)
15
+ out.push("rewindFiles");
16
+ return out;
9
17
  }
10
18
  const SINGLE_MEMBER_OFF_FIELDS = [
11
19
  { field: "memoryCapture", word: "off", message: MEMORY_CAPTURE_SPELLING_MESSAGE },
@@ -27,9 +27,13 @@
27
27
  * **真未知名**(拼写合法、没有近似也没有退役对应 —— 懒挂载的合法形,例如一台之后才连上的 MCP 服务器的工具)不是读成空:原样保留、运维行告知一次,不拒。
28
28
  * 选择器读一条条目 = 引擎 `judgeToolNameList` 的读法({@link selectorEntryName}):先取工具名那一段再只判名字(限制侧 `Tool(content)` ⇒ 整只工具,内容里写什么都不读;放行侧内容形引擎告「什么也不授」,受理口不拒);
29
29
  * `*` 在放行侧是「本层不设名单」、在限制侧读成空;限制侧 `mcp__*` / `a2a__*`(整个协议的拒)合法。
30
+ * ⑤ **机读位**:拒体的码与句子是第一处命中的清单的(句子冻结),体另带这一遍判下来的**全部**读成空的条目(`entry-problems.ts` 的 `detail.problems`,{@link inertToolListEntryOf} 铸);
31
+ * 放行侧选择器清单里受理口没拒、却什么也不放的条目随受理应答的 `warnings` 交回({@link allowSelectorWarningsOf})—— 两处读同一次条目读法({@link selectorReadings}),不另判。
30
32
  */
33
+ import type { TightenOnlySeatField } from "./tighten-only-seats.js";
31
34
  import { compileAllowList } from "@sema-agent/core";
32
35
  import { type LimitRefusal } from "./limit-refusal.js";
36
+ import { type EntryProblem } from "./entry-problems.js";
33
37
  /** ① 形:字符串数组(空串也是字符串 —— 引擎把它读成 `grammar` 并通告 / 拒,见 ③)。 */
34
38
  export declare const ruleEntryListShapeOk: (v: unknown) => v is readonly string[];
35
39
  /**
@@ -127,9 +131,9 @@ export type ToolListLayer = keyof typeof TOOL_LIST_FACES;
127
131
  /**
128
132
  * 请求体 `settings.permissions.deny` / `ask`(规则编译器读的收紧表)所在的层 —— **不在** {@link toolListsOf} 的扫描里:它们的判与句子的唯一铸点在 `config.ts` 的
129
133
  * `unmatchableToolNamesRefusal`(经 `task-settings.ts` 的 `rulePolicyBucketsRefusal`,单表桶序;拒点是 `applyTaskSettings`,422),存体预判(`http/stored-body-replay.ts`)调同一只函数(home 同源于部署配置),把命中装成本型。
130
- * 层名进这个联合只为让命中能带坐标进 409 体与运维日志。
134
+ * 层名进这个联合只为让命中能带坐标进 409 体与运维日志。S-1351 起「只收紧」座位族的四座(`tighten-only-seats.ts`,坐标由座位表派生)同走这条路:座位门命中(形 / 超帽 / 条目)与 `permissions.neverAuto` 的名字层。
131
135
  */
132
- export type RulePolicyLayer = "settings.permissions.deny" | "settings.permissions.ask";
136
+ export type RulePolicyLayer = "settings.permissions.deny" | "settings.permissions.ask" | TightenOnlySeatField;
133
137
  /** 一份提交体里第一处「工具名清单里有引擎读成空的条目」:在哪一层、哪个方向、拒码、拒句(超帽时另带机读字段,同 `settings.permissions.*` 桶超帽的形)。 */
134
138
  export interface InertToolListEntry {
135
139
  readonly layer: ToolListLayer | RulePolicyLayer;
@@ -183,5 +187,25 @@ export declare function skillDenyInertEntryOf(body: unknown): SkillDenyInertEntr
183
187
  * `checkpoint-ctx.ts` `resumeBlockedByPolicyAnswer`),拒在认领之前,行 / 卡 / ctx 不动。
184
188
  */
185
189
  export declare function inertToolListEntryOf(body: unknown, sides?: readonly ToolListSide[]): InertToolListEntry | undefined;
190
+ /**
191
+ * 一个调用方工具的名字面(结构型,`ToolSpec` 满足它):主名、别名、委派工具声明的子代工具池里的行(主名与别名)—— 引擎认这些名字是「这条 run 挂着的工具」。
192
+ */
193
+ export interface CallerToolNames {
194
+ readonly name: string;
195
+ readonly aliases?: readonly string[] | undefined;
196
+ readonly agentToolPool?: ReadonlyArray<{
197
+ readonly name: string;
198
+ readonly aliases?: readonly string[] | undefined;
199
+ }> | undefined;
200
+ }
201
+ /**
202
+ * **放行侧选择器清单的受理告知**(根 `allowTools`、子代定义的 `allowTools`)—— 这两张清单没有面向用户的通告通道(规则表与技能的放行清单读成空,引擎有受众 = 用户的通告
203
+ * `permission.allowed_tool_not_granted`;选择器清单上引擎只告运维一行),壳转投的 `.claude/agents` 文件里的 `tools:` 恰落在这两张表上。受理口**不拒**(引擎是这一面的判官,#1736 起
204
+ * 没有任何工具答应的名字保留、只告),把「这几条什么也不放」作为 `warnings` 随受理应答交回:每条 `{ code, field, entry, reason }`(形的属主 `entry-problems.ts`),`code` = 这张清单被拒时的码。
205
+ * 限制侧不告(`denyTools` / `excludeTools` 的近似名 / 退役名 / 文法读不出已是 400)。
206
+ *
207
+ * 在 `resolveSpec` **之后**问(近似名那一类已先 400):`tools` 是这一请求装配出的调用方工具(`spec.tools`,名字面见 {@link CallerToolNames})。超帽 / 形不对的清单不读(受理门先拒)。
208
+ */
209
+ export declare function allowSelectorWarningsOf(body: unknown, tools: readonly CallerToolNames[]): readonly EntryProblem[];
186
210
  export {};
187
211
  //# sourceMappingURL=rule-entry-list.d.ts.map