@sema-agent/server 7.148.0 → 7.150.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 (360) hide show
  1. package/MIGRATION.md +551 -9
  2. package/README.md +17 -2
  3. package/README.zh-CN.md +5 -1
  4. package/USAGE.md +126 -68
  5. package/dist/adoption/wire.d.ts +3 -3
  6. package/dist/approval-card.d.ts +33 -33
  7. package/dist/approval-gate-currency.d.ts +1 -1
  8. package/dist/approval-leg-origin.d.ts +33 -0
  9. package/dist/approval-leg-origin.js +4 -0
  10. package/dist/audit.d.ts +1 -1
  11. package/dist/audit.js +2 -2
  12. package/dist/auth-bridge.d.ts +9 -1
  13. package/dist/auth-bridge.js +4 -4
  14. package/dist/auth-keys.d.ts +10 -1
  15. package/dist/auth-keys.js +8 -0
  16. package/dist/background-session-reap.d.ts +1 -1
  17. package/dist/boot/deferred-sandbox-path-env.d.ts +5 -3
  18. package/dist/boot/deferred-sandbox-path-env.js +1 -2
  19. package/dist/boot/execution-env.js +10 -11
  20. package/dist/boot/execution-lane.d.ts +6 -4
  21. package/dist/boot/execution-lane.js +3 -1
  22. package/dist/boot/org-delivery.d.ts +3 -2
  23. package/dist/boot/parked-revive-gate.d.ts +5 -5
  24. package/dist/boot/parked-revive-gate.js +2 -3
  25. package/dist/boot/resolve-spec.d.ts +4 -5
  26. package/dist/boot/resolve-spec.js +66 -28
  27. package/dist/boot/retention-lane.d.ts +1 -1
  28. package/dist/boot/runner-deps.js +3 -1
  29. package/dist/boot/session-faces.js +21 -21
  30. package/dist/boot/stage-01-config.d.ts +1 -0
  31. package/dist/boot/stage-01-config.js +4 -3
  32. package/dist/boot/stage-02-web-admin-pull.d.ts +1 -0
  33. package/dist/boot/stage-02-web-admin-pull.js +10 -2
  34. package/dist/boot/stage-03-store-backend.d.ts +1 -0
  35. package/dist/boot/stage-03-store-backend.js +4 -4
  36. package/dist/boot/stage-04-stores.d.ts +1 -0
  37. package/dist/boot/stage-05-execution-env.d.ts +1 -0
  38. package/dist/boot/stage-06-runners.d.ts +2 -1
  39. package/dist/boot/stage-06-runners.js +1 -2
  40. package/dist/boot/stage-07-capability-layer.d.ts +2 -1
  41. package/dist/boot/stage-07-capability-layer.js +1 -1
  42. package/dist/boot/stage-08-reapers.d.ts +2 -1
  43. package/dist/boot/stage-09-leader.d.ts +2 -1
  44. package/dist/boot/stage-10-http-server.d.ts +35 -2
  45. package/dist/boot/stage-10-http-server.js +9 -4
  46. package/dist/boot/stores.d.ts +3 -0
  47. package/dist/boot/stores.js +22 -19
  48. package/dist/boot/web-admin.d.ts +1 -1
  49. package/dist/capabilities/tool-defer.d.ts +1 -1
  50. package/dist/capability-facts.d.ts +70 -60
  51. package/dist/capability-facts.js +45 -49
  52. package/dist/card-settle-stored-scope.d.ts +56 -0
  53. package/dist/card-settle-stored-scope.js +27 -0
  54. package/dist/card-void.d.ts +7 -12
  55. package/dist/card-void.js +2 -7
  56. package/dist/config-catalog.d.ts +12 -0
  57. package/dist/config-catalog.js +37 -33
  58. package/dist/config-invariants.d.ts +5 -4
  59. package/dist/config-invariants.js +4 -4
  60. package/dist/config-types.d.ts +49 -16
  61. package/dist/config.d.ts +6 -5
  62. package/dist/config.js +35 -24
  63. package/dist/context-window-notice.d.ts +31 -0
  64. package/dist/context-window-notice.js +28 -0
  65. package/dist/deployment-governance.d.ts +7 -28
  66. package/dist/deployment-governance.js +1 -14
  67. package/dist/deployment-shape.d.ts +20 -11
  68. package/dist/deployment-shape.js +1 -0
  69. package/dist/device-ws-hub.d.ts +1 -0
  70. package/dist/device-ws-hub.js +64 -28
  71. package/dist/device-ws-protocol.d.ts +20 -6
  72. package/dist/device-ws-protocol.js +9 -2
  73. package/dist/engine-identity.d.ts +7 -1
  74. package/dist/engine-identity.js +5 -0
  75. package/dist/env-name-allowlist-knobs.d.ts +6 -5
  76. package/dist/env-name-allowlist-knobs.js +5 -0
  77. package/dist/execution-lane-caps.d.ts +20 -5
  78. package/dist/execution-lane-caps.js +18 -4
  79. package/dist/field-conflict.d.ts +2 -2
  80. package/dist/fleet/engine-signal.d.ts +14 -1
  81. package/dist/fleet/engine-signal.js +5 -1
  82. package/dist/fleet/fleet-reconciler.d.ts +1 -1
  83. package/dist/fleet/serving-lease.d.ts +18 -3
  84. package/dist/fleet/serving-lease.js +81 -35
  85. package/dist/fleet-client.d.ts +13 -11
  86. package/dist/fleet-client.js +53 -33
  87. package/dist/history-anchor.js +1 -1
  88. package/dist/hitl-delivery.d.ts +1 -3
  89. package/dist/hitl-delivery.js +1 -1
  90. package/dist/hooks/command-spawn.d.ts +7 -2
  91. package/dist/hooks/command-spawn.js +13 -6
  92. package/dist/hooks/hook-runner.d.ts +5 -0
  93. package/dist/hooks/hook-runner.js +11 -7
  94. package/dist/http/active-run-conflict.d.ts +3 -7
  95. package/dist/http/active-run-conflict.js +2 -2
  96. package/dist/http/admission.js +5 -5
  97. package/dist/http/approval-sweeps.js +5 -3
  98. package/dist/http/caller-trust.d.ts +2 -2
  99. package/dist/http/caller-trust.js +3 -3
  100. package/dist/http/checkpoint-ctx.d.ts +18 -63
  101. package/dist/http/checkpoint-ctx.js +1 -24
  102. package/dist/http/claim-heartbeat.d.ts +6 -6
  103. package/dist/http/claim-heartbeat.js +6 -6
  104. package/dist/http/claimed-run.d.ts +16 -9
  105. package/dist/http/claimed-run.js +8 -0
  106. package/dist/http/dispatch.js +7 -5
  107. package/dist/http/durable-run-leg.d.ts +8 -1
  108. package/dist/http/durable-run-leg.js +34 -15
  109. package/dist/http/execution-context.d.ts +115 -14
  110. package/dist/http/execution-context.js +130 -40
  111. package/dist/http/owner-access.d.ts +246 -21
  112. package/dist/http/owner-access.js +186 -8
  113. package/dist/http/principal-gate.d.ts +18 -11
  114. package/dist/http/principal-gate.js +3 -1
  115. package/dist/http/readiness.d.ts +4 -2
  116. package/dist/http/resume-ctx-read.d.ts +14 -3
  117. package/dist/http/resume-ctx-read.js +24 -3
  118. package/dist/http/resume-legs.d.ts +35 -3
  119. package/dist/http/resume-legs.js +262 -106
  120. package/dist/http/route-ctx.d.ts +29 -11
  121. package/dist/http/routes/a2a-serve.js +17 -14
  122. package/dist/http/routes/approvals-assistant.d.ts +3 -2
  123. package/dist/http/routes/approvals-assistant.js +11 -11
  124. package/dist/http/routes/capabilities.js +5 -4
  125. package/dist/http/routes/config-catalog.d.ts +1 -1
  126. package/dist/http/routes/diagnostics.d.ts +3 -1
  127. package/dist/http/routes/diagnostics.js +30 -5
  128. package/dist/http/routes/mcp-reconnect.js +2 -2
  129. package/dist/http/routes/memory-origin.d.ts +1 -1
  130. package/dist/http/routes/notify-wake.js +2 -3
  131. package/dist/http/routes/principal-inbox.d.ts +3 -1
  132. package/dist/http/routes/principal-inbox.js +3 -2
  133. package/dist/http/routes/projects.d.ts +1 -0
  134. package/dist/http/routes/projects.js +5 -3
  135. package/dist/http/routes/retention-ops.d.ts +1 -1
  136. package/dist/http/routes/run-permission-mode.d.ts +1 -1
  137. package/dist/http/routes/run-permission-mode.js +2 -2
  138. package/dist/http/routes/runs.d.ts +1 -1
  139. package/dist/http/routes/runs.js +33 -37
  140. package/dist/http/routes/session-memory-sync.js +4 -5
  141. package/dist/http/routes/session-sync.d.ts +24 -5
  142. package/dist/http/routes/session-sync.js +45 -37
  143. package/dist/http/routes/sessions-list.d.ts +1 -1
  144. package/dist/http/routes/sessions.d.ts +1 -1
  145. package/dist/http/routes/sessions.js +18 -44
  146. package/dist/http/routes/tasks.js +136 -101
  147. package/dist/http/routes/trace-usage.js +14 -14
  148. package/dist/http/routes/workflows.d.ts +1 -0
  149. package/dist/http/routes/workflows.js +20 -38
  150. package/dist/http/server.d.ts +12 -9
  151. package/dist/http/server.js +35 -6
  152. package/dist/http/stored-body-replay.d.ts +3 -24
  153. package/dist/http/stored-body-replay.js +2 -12
  154. package/dist/http/submit-ctx.d.ts +2 -2
  155. package/dist/http/submit-ctx.js +5 -5
  156. package/dist/http/submit-replay.d.ts +15 -2
  157. package/dist/http/submit-replay.js +10 -4
  158. package/dist/http/wire-types.d.ts +6 -3
  159. package/dist/index.d.ts +3 -1
  160. package/dist/index.js +1 -0
  161. package/dist/leader/endpoint.js +9 -8
  162. package/dist/leg-facts.d.ts +13 -2
  163. package/dist/leg-facts.js +2 -0
  164. package/dist/local-store-declaration.d.ts +54 -0
  165. package/dist/local-store-declaration.js +59 -0
  166. package/dist/mcp-assertion-header.d.ts +1 -1
  167. package/dist/mcp-assertion-header.js +1 -1
  168. package/dist/mcp-authorization-face.d.ts +18 -14
  169. package/dist/mcp-authorization-face.js +3 -2
  170. package/dist/memory-project-layer.js +1 -1
  171. package/dist/memory-scope.d.ts +4 -4
  172. package/dist/memory-scope.js +4 -4
  173. package/dist/memory-store-refusal.d.ts +1 -1
  174. package/dist/memory-sync-client.js +2 -2
  175. package/dist/model-context-window.d.ts +50 -11
  176. package/dist/model-context-window.js +20 -1
  177. package/dist/model-entry-refusal.d.ts +5 -4
  178. package/dist/model-entry-refusal.js +17 -3
  179. package/dist/model-reach-scope.d.ts +2 -1
  180. package/dist/observability/corrupt-read-seat.d.ts +1 -1
  181. package/dist/observability/fail-open.d.ts +19 -7
  182. package/dist/observability/fail-open.js +19 -7
  183. package/dist/observability/logger.d.ts +7 -0
  184. package/dist/observability/logger.js +3 -1
  185. package/dist/observability/metrics.js +1 -1
  186. package/dist/observability/run-terminal.d.ts +1 -1
  187. package/dist/observability/run-terminal.js +1 -0
  188. package/dist/observability/secret-env-scrub.d.ts +1 -1
  189. package/dist/observability/secret-env-scrub.js +1 -1
  190. package/dist/org-delivery-gate.d.ts +31 -6
  191. package/dist/org-delivery-gate.js +7 -4
  192. package/dist/owner-faces.d.ts +30 -5
  193. package/dist/owner-faces.js +2 -0
  194. package/dist/park-row-commit.d.ts +67 -0
  195. package/dist/park-row-commit.js +76 -0
  196. package/dist/parked-decide.d.ts +9 -7
  197. package/dist/parked-decide.js +25 -6
  198. package/dist/peer-directory.d.ts +1 -1
  199. package/dist/peer-seat.d.ts +1 -1
  200. package/dist/peer-seat.js +52 -59
  201. package/dist/plugins/adoption-log-sql.d.ts +3 -3
  202. package/dist/plugins/adoption-log-sql.js +19 -19
  203. package/dist/plugins/approval-ask-store-sql.d.ts +1 -1
  204. package/dist/plugins/approval-ask-store-sql.js +3 -5
  205. package/dist/plugins/approval-exemption-skill-cutoff.d.ts +64 -0
  206. package/dist/plugins/approval-exemption-skill-cutoff.js +122 -0
  207. package/dist/plugins/approval-exemption-skill-m46.d.ts +0 -6
  208. package/dist/plugins/approval-exemption-skill-m46.js +6 -10
  209. package/dist/plugins/approval-exemption-store.d.ts +26 -1
  210. package/dist/plugins/approval-exemption-store.js +28 -19
  211. package/dist/plugins/ensure-schema-lock-policy.d.ts +36 -3
  212. package/dist/plugins/ensure-schema-lock-policy.js +75 -9
  213. package/dist/plugins/exec-path-law.d.ts +34 -0
  214. package/dist/plugins/exec-path-law.js +13 -0
  215. package/dist/plugins/file-run-store.d.ts +22 -9
  216. package/dist/plugins/file-run-store.js +51 -23
  217. package/dist/plugins/local-checkpoint-store.d.ts +8 -1
  218. package/dist/plugins/local-checkpoint-store.js +5 -1
  219. package/dist/plugins/local-data-root-admission.d.ts +52 -0
  220. package/dist/plugins/local-data-root-admission.js +100 -0
  221. package/dist/plugins/local-engine-high-water.d.ts +28 -7
  222. package/dist/plugins/local-engine-high-water.js +27 -22
  223. package/dist/plugins/local-session-store.d.ts +134 -49
  224. package/dist/plugins/local-session-store.js +149 -108
  225. package/dist/plugins/memory-run-store.d.ts +14 -9
  226. package/dist/plugins/memory-run-store.js +48 -22
  227. package/dist/plugins/one-time-migration-marker.d.ts +19 -3
  228. package/dist/plugins/one-time-migration-marker.js +7 -1
  229. package/dist/plugins/one-time-migrations.d.ts +110 -59
  230. package/dist/plugins/one-time-migrations.js +224 -136
  231. package/dist/plugins/org-delivery-quota-store.d.ts +34 -11
  232. package/dist/plugins/org-delivery-quota-store.js +29 -14
  233. package/dist/plugins/permission-rule-store-sql.d.ts +1 -1
  234. package/dist/plugins/permission-rule-store-sql.js +5 -9
  235. package/dist/plugins/pg-pool.d.ts +1 -1
  236. package/dist/plugins/pg-pool.js +14 -12
  237. package/dist/plugins/posix-shell-fs.js +4 -2
  238. package/dist/plugins/remote-env-adb.js +3 -2
  239. package/dist/plugins/remote-env-device.d.ts +3 -2
  240. package/dist/plugins/remote-env-device.js +8 -6
  241. package/dist/plugins/remote-env-e2b.d.ts +4 -8
  242. package/dist/plugins/remote-env-e2b.js +21 -15
  243. package/dist/plugins/remote-env-host.d.ts +51 -10
  244. package/dist/plugins/remote-env-host.js +97 -31
  245. package/dist/plugins/remote-env-k8s.js +7 -4
  246. package/dist/plugins/remote-env-local-docker.d.ts +6 -3
  247. package/dist/plugins/remote-env-local-docker.js +11 -25
  248. package/dist/plugins/remote-env-ssh.js +4 -3
  249. package/dist/plugins/remote-shell.d.ts +3 -1
  250. package/dist/plugins/remote-shell.js +3 -3
  251. package/dist/plugins/replica-registration.d.ts +35 -0
  252. package/dist/plugins/replica-registration.js +48 -0
  253. package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
  254. package/dist/plugins/run-store-sql.d.ts +27 -8
  255. package/dist/plugins/run-store-sql.js +46 -18
  256. package/dist/plugins/scenario-prefix-switch-m42.d.ts +8 -12
  257. package/dist/plugins/scenario-prefix-switch-m42.js +9 -6
  258. package/dist/plugins/schema-consistency.d.ts +91 -5
  259. package/dist/plugins/schema-consistency.js +189 -7
  260. package/dist/plugins/schema-drift-sentence.d.ts +6 -5
  261. package/dist/plugins/schema-drift-sentence.js +13 -5
  262. package/dist/plugins/serving-requirement.d.ts +49 -0
  263. package/dist/plugins/serving-requirement.js +53 -0
  264. package/dist/plugins/session-placement.d.ts +5 -4
  265. package/dist/plugins/shell-sentinel-owner-m48.d.ts +22 -0
  266. package/dist/plugins/shell-sentinel-owner-m48.js +6 -0
  267. package/dist/plugins/stop-then-start-sentence.d.ts +55 -0
  268. package/dist/plugins/stop-then-start-sentence.js +51 -0
  269. package/dist/plugins/store-backend.d.ts +23 -9
  270. package/dist/plugins/store-backend.js +58 -24
  271. package/dist/plugins/store-contracts.d.ts +45 -5
  272. package/dist/plugins/store-contracts.js +19 -0
  273. package/dist/plugins/tidb-pool.d.ts +11 -6
  274. package/dist/plugins/tidb-pool.js +22 -12
  275. package/dist/plugins/workspace-custody.d.ts +44 -0
  276. package/dist/plugins/workspace-custody.js +47 -0
  277. package/dist/process-instance.d.ts +3 -0
  278. package/dist/process-instance.js +7 -0
  279. package/dist/project-context.d.ts +66 -0
  280. package/dist/project-context.js +70 -0
  281. package/dist/project-identity.d.ts +8 -7
  282. package/dist/project-identity.js +40 -17
  283. package/dist/project-layer-key.d.ts +13 -2
  284. package/dist/project-layer-key.js +9 -1
  285. package/dist/question.d.ts +9 -21
  286. package/dist/question.js +28 -19
  287. package/dist/read-deny-floor-notice.d.ts +36 -0
  288. package/dist/read-deny-floor-notice.js +40 -0
  289. package/dist/{plain-string-record.d.ts → request-declaration-disposition.d.ts} +9 -23
  290. package/dist/request-declaration-disposition.js +39 -0
  291. package/dist/run-cancel-card.d.ts +28 -0
  292. package/dist/run-cancel-card.js +20 -0
  293. package/dist/run-cancel-context.d.ts +10 -0
  294. package/dist/run-cancel-context.js +1 -0
  295. package/dist/run-local.js +28 -13
  296. package/dist/runs.d.ts +31 -7
  297. package/dist/runs.js +34 -16
  298. package/dist/security.d.ts +3 -3
  299. package/dist/server-secret-env.d.ts +34 -20
  300. package/dist/server-secret-env.js +61 -18
  301. package/dist/session-agent.d.ts +4 -12
  302. package/dist/session-agent.js +0 -6
  303. package/dist/session-children-retire.d.ts +6 -3
  304. package/dist/session-children-retire.js +2 -5
  305. package/dist/session-incarnation.d.ts +18 -4
  306. package/dist/session-incarnation.js +4 -1
  307. package/dist/session-notify-door.d.ts +4 -4
  308. package/dist/session-notify-door.js +5 -6
  309. package/dist/session-rules-seat.d.ts +4 -3
  310. package/dist/session-rules-seat.js +3 -11
  311. package/dist/session-sync.js +3 -3
  312. package/dist/session-workspace.d.ts +3 -3
  313. package/dist/store-admission.d.ts +33 -0
  314. package/dist/store-admission.js +49 -0
  315. package/dist/store-posture.d.ts +5 -0
  316. package/dist/store-posture.js +18 -1
  317. package/dist/stores-sql/checkpoint-store-sql.d.ts +22 -3
  318. package/dist/stores-sql/checkpoint-store-sql.js +109 -23
  319. package/dist/stores-sql/file-history-store-sql.d.ts +1 -1
  320. package/dist/stores-sql/file-history-store-sql.js +3 -5
  321. package/dist/stores-sql/retention-store-sql.d.ts +1 -1
  322. package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
  323. package/dist/stores-sql/tool-result-store-sql.js +4 -6
  324. package/dist/task-a2a.d.ts +3 -8
  325. package/dist/task-a2a.js +25 -27
  326. package/dist/task-cwd.d.ts +27 -10
  327. package/dist/task-cwd.js +3 -0
  328. package/dist/task-mcp.d.ts +3 -3
  329. package/dist/task-mcp.js +1 -1
  330. package/dist/task-settings.d.ts +13 -0
  331. package/dist/task-settings.js +14 -7
  332. package/dist/terminal.d.ts +2 -0
  333. package/dist/terminal.js +21 -6
  334. package/dist/tool-approval.d.ts +50 -41
  335. package/dist/tool-approval.js +96 -73
  336. package/dist/trace/engine-notice-wire.d.ts +38 -21
  337. package/dist/trace/engine-notice-wire.js +25 -4
  338. package/dist/trace/ledger-sink.d.ts +3 -1
  339. package/dist/trace/project.d.ts +8 -5
  340. package/dist/trace/project.js +11 -9
  341. package/dist/trace/projection-table.d.ts +33 -2
  342. package/dist/trace/redact.d.ts +12 -0
  343. package/dist/trace/redact.js +5 -1
  344. package/dist/trace/self-minted-wire.d.ts +268 -56
  345. package/dist/trace/self-minted-wire.js +110 -40
  346. package/dist/trace/tool-card.d.ts +3 -0
  347. package/dist/trace/tool-card.js +24 -0
  348. package/dist/trace/tool-output-media.d.ts +2 -1
  349. package/dist/unattended-permission-mode.d.ts +1 -1
  350. package/dist/web-admin-client/apply-effective.d.ts +1 -1
  351. package/dist/web-admin-client/apply-effective.js +22 -9
  352. package/dist/web-admin-client/effective-keys.d.ts +1 -1
  353. package/dist/web-admin-client/skills-mcp.d.ts +1 -1
  354. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -29
  355. package/docs/error-text-lexicon.json +317 -0
  356. package/package.json +4 -2
  357. package/scripts/embed-minimal.mjs +183 -0
  358. package/wire-changes/server@7.149.0.json +372 -0
  359. package/wire-changes/server@7.150.0.json +335 -0
  360. package/dist/plain-string-record.js +0 -70
@@ -5,7 +5,7 @@ import { WebSocketServer } from "ws";
5
5
  import { DEVICE_DRAINING_CODE, DEVICE_ERROR_CODES, DEVICE_ERROR_STATUS, assertDeviceIdShape, } from "./device-store.js";
6
6
  import { MAX_TIMER_DELAY_MS } from "./config-types.js";
7
7
  import { canonicalAddress, createTrustedProxySet } from "./net-address.js";
8
- import { DEVICE_HELLO_ACK_BOUNDS, DEVICE_MIN_PROTOCOL_VERSION, DEVICE_WS_LIMITS, DEVICE_WS_PATH, DEVICE_PROTOCOL_VERSION, asInstructionKind, buildHelloSignaturePayload, deviceHelloAckNumberFlaw, formatGeneration, mintChallengeNonce, mintInstructionId, parseDeviceFrameText, verifyHelloSignature, } from "./device-ws-protocol.js";
8
+ import { DEVICE_HELLO_ACK_BOUNDS, DEVICE_MIN_PROTOCOL_VERSION, DEVICE_WS_LIMITS, DEVICE_WS_PATH, DEVICE_PROTOCOL_VERSION, asInstructionKind, buildHelloSignaturePayload, deviceHelloAckNumberFlaw, deviceProtocolRevisionRefusal, formatGeneration, mintChallengeNonce, mintInstructionId, parseDeviceFrameText, verifyHelloSignature, } from "./device-ws-protocol.js";
9
9
  const OUTCOME_UNKNOWN_SENTENCE = "outcome unknown — the command may have already executed on the device; verify its effect before re-running";
10
10
  const SETTLED_MEMO_MAX = 512;
11
11
  const DRAIN_RETRY_AFTER_SEC = 15;
@@ -27,6 +27,25 @@ function outcomeUnknown(why) {
27
27
  return { ok: false, errorCode: "outcome_unknown", message: `${why} — ${OUTCOME_UNKNOWN_SENTENCE}` };
28
28
  }
29
29
  const WRITE_PAYLOAD_KINDS = new Set(["writeFile", "writeFileExclusive", "writeFileGuarded", "appendFile"]);
30
+ const PAYLOAD_CHUNK_ENVELOPE_BYTES = Buffer.byteLength(JSON.stringify({ t: "payload", gen: String(Number.MAX_SAFE_INTEGER), instructionId: mintInstructionId(), part: "chunk", offset: Number.MAX_SAFE_INTEGER, dataB64: "" }), "utf8");
31
+ export const DEVICE_MAX_PAYLOAD_PART_BYTES = Math.floor((DEVICE_WS_LIMITS.maxFrameBytes - PAYLOAD_CHUNK_ENVELOPE_BYTES) / 4) * 3;
32
+ const FRAME_TOO_LARGE = "frame_too_large";
33
+ function encodeServerFrame(frame) {
34
+ const text = JSON.stringify(frame);
35
+ const bytes = Buffer.byteLength(text, "utf8");
36
+ return bytes <= DEVICE_WS_LIMITS.maxFrameBytes ? { ok: true, text } : { ok: false, bytes };
37
+ }
38
+ function frameTooLargeResult(kind, bytes) {
39
+ return {
40
+ kind: "never_started",
41
+ outcome: {
42
+ ok: false,
43
+ errorCode: "not_supported",
44
+ message: `[${FRAME_TOO_LARGE}] the ${kind} instruction frame would be ${bytes} bytes, over the device protocol's ${DEVICE_WS_LIMITS.maxFrameBytes}-byte frame cap — ` +
45
+ "it was never sent (the device transport drops a connection that carries a frame that size); keep a command and its arguments under the cap, and move large content into a file write (it travels in slices)",
46
+ },
47
+ };
48
+ }
30
49
  const ALLOWED_SUCCESS_OUTCOME_KINDS = {
31
50
  exec: ["exec"],
32
51
  execStream: ["exec"],
@@ -145,14 +164,22 @@ export function createDeviceWsHub(options) {
145
164
  .catch((err) => logger?.error("device_audit_write_failed", { event, err: err instanceof Error ? err.message : String(err) }));
146
165
  }
147
166
  function sendServerFrame(conn, frame) {
167
+ const encoded = encodeServerFrame(frame);
168
+ if (!encoded.ok) {
169
+ logger?.error("device_ws_frame_over_cap", { deviceId: conn.deviceId, t: frame.t, bytes: encoded.bytes, cap: DEVICE_WS_LIMITS.maxFrameBytes });
170
+ return false;
171
+ }
172
+ return writeServerText(conn, frame.t, encoded.text);
173
+ }
174
+ function writeServerText(conn, t, text) {
148
175
  if (conn.ws.readyState !== conn.ws.OPEN)
149
176
  return false;
150
177
  try {
151
- conn.ws.send(JSON.stringify(frame));
178
+ conn.ws.send(text);
152
179
  return true;
153
180
  }
154
181
  catch (err) {
155
- logger?.warn("device_ws_send_failed", { deviceId: conn.deviceId, t: frame.t, err: err instanceof Error ? err.message : String(err) });
182
+ logger?.warn("device_ws_send_failed", { deviceId: conn.deviceId, t, err: err instanceof Error ? err.message : String(err) });
156
183
  return false;
157
184
  }
158
185
  }
@@ -301,11 +328,11 @@ export function createDeviceWsHub(options) {
301
328
  }, reconnectGraceMs);
302
329
  reconnectTimers.set(deviceId, timer);
303
330
  }
304
- function rejectHello(conn, code, minProtocolVersion) {
331
+ function rejectHello(conn, code, version) {
305
332
  if (conn.handshakeTimer)
306
333
  clearTimeout(conn.handshakeTimer);
307
334
  conn.handshakeTimer = null;
308
- sendServerFrame(conn, { t: "helloReject", code, ...(minProtocolVersion === undefined ? {} : { minProtocolVersion }) });
335
+ sendServerFrame(conn, { t: "helloReject", code, ...version });
309
336
  closeConn(conn, { releaseLease: false });
310
337
  }
311
338
  async function fenceConnection(conn) {
@@ -367,7 +394,10 @@ export function createDeviceWsHub(options) {
367
394
  if (draining || closed)
368
395
  return rejectHello(conn, "draining");
369
396
  if (frame.protocolVersion < DEVICE_MIN_PROTOCOL_VERSION || frame.protocolVersion > DEVICE_PROTOCOL_VERSION) {
370
- return rejectHello(conn, "protocol_version_unsupported", DEVICE_MIN_PROTOCOL_VERSION);
397
+ const message = deviceProtocolRevisionRefusal(frame.protocolVersion);
398
+ logger?.warn("device_hello_version_rejected", { declared: frame.protocolVersion, minProtocolVersion: DEVICE_MIN_PROTOCOL_VERSION, protocolVersion: DEVICE_PROTOCOL_VERSION, message });
399
+ metrics?.inc("device_hello_rejected_total", { code: "protocol_version_unsupported" });
400
+ return rejectHello(conn, "protocol_version_unsupported", { minProtocolVersion: DEVICE_MIN_PROTOCOL_VERSION, message });
371
401
  }
372
402
  let idShapeOk = true;
373
403
  try {
@@ -860,8 +890,8 @@ export function createDeviceWsHub(options) {
860
890
  async function dispatch(input) {
861
891
  if (input.payloadPartBytes !== undefined) {
862
892
  const n = input.payloadPartBytes;
863
- if (!Number.isSafeInteger(n) || n <= 0 || n > DEVICE_WS_LIMITS.maxFrameBytes) {
864
- throw new Error(`device-ws: payloadPartBytes must be a positive safe integer ≤ ${DEVICE_WS_LIMITS.maxFrameBytes} (got ${String(n)})`);
893
+ if (!Number.isSafeInteger(n) || n <= 0 || n > DEVICE_MAX_PAYLOAD_PART_BYTES) {
894
+ throw new Error(`device-ws: payloadPartBytes must be a positive safe integer ≤ ${DEVICE_MAX_PAYLOAD_PART_BYTES} (the ${DEVICE_WS_LIMITS.maxFrameBytes}-byte frame cap after base64 and the chunk envelope; got ${String(n)})`);
865
895
  }
866
896
  }
867
897
  if (!Number.isSafeInteger(input.timeoutMs) || input.timeoutMs <= 0) {
@@ -963,7 +993,32 @@ export function createDeviceWsHub(options) {
963
993
  releaseSlot(deviceId);
964
994
  return abortedBeforeCommit();
965
995
  }
996
+ let args = input.args;
997
+ let body = null;
998
+ let sha = "";
999
+ if (input.payload !== undefined && WRITE_PAYLOAD_KINDS.has(input.kind)) {
1000
+ body = Buffer.from(input.payload);
1001
+ sha = createHash("sha256").update(body).digest("hex");
1002
+ args = { ...input.args, contentLen: body.length, sha256: sha };
1003
+ }
966
1004
  const instructionId = mintInstructionId();
1005
+ const instructionFrame = encodeServerFrame({
1006
+ t: "instruction",
1007
+ gen: conn.genStr,
1008
+ instructionId,
1009
+ rootSessionId: input.rootSessionId,
1010
+ issuedSeq: conn.issuedSeq + 1,
1011
+ kind: input.kind,
1012
+ args,
1013
+ ...(input.cwd === undefined ? {} : { cwd: input.cwd }),
1014
+ ...(input.shellEnv === undefined ? {} : { shellEnv: input.shellEnv }),
1015
+ timeoutMs: input.timeoutMs,
1016
+ });
1017
+ if (!instructionFrame.ok) {
1018
+ releaseSlot(deviceId);
1019
+ logger?.warn("device_instruction_frame_over_cap", { deviceId, kind: input.kind, bytes: instructionFrame.bytes, cap: DEVICE_WS_LIMITS.maxFrameBytes });
1020
+ return frameTooLargeResult(input.kind, instructionFrame.bytes);
1021
+ }
967
1022
  conn.issuedSeq += 1;
968
1023
  let resolve;
969
1024
  const settled = new Promise((r) => {
@@ -996,26 +1051,7 @@ export function createDeviceWsHub(options) {
996
1051
  resolve,
997
1052
  };
998
1053
  pending.set(instructionId, p);
999
- let args = input.args;
1000
- let body = null;
1001
- let sha = "";
1002
- if (input.payload !== undefined && WRITE_PAYLOAD_KINDS.has(input.kind)) {
1003
- body = Buffer.from(input.payload);
1004
- sha = createHash("sha256").update(body).digest("hex");
1005
- args = { ...input.args, contentLen: body.length, sha256: sha };
1006
- }
1007
- const wrote = sendServerFrame(conn, {
1008
- t: "instruction",
1009
- gen: conn.genStr,
1010
- instructionId,
1011
- rootSessionId: input.rootSessionId,
1012
- issuedSeq: conn.issuedSeq,
1013
- kind: input.kind,
1014
- args,
1015
- ...(input.cwd === undefined ? {} : { cwd: input.cwd }),
1016
- ...(input.shellEnv === undefined ? {} : { shellEnv: input.shellEnv }),
1017
- timeoutMs: input.timeoutMs,
1018
- });
1054
+ const wrote = writeServerText(conn, "instruction", instructionFrame.text);
1019
1055
  if (body !== null)
1020
1056
  sendPayloadSequence(conn, instructionId, body, input.payloadPartBytes ?? DEVICE_WS_LIMITS.defaultPayloadPartBytes, sha);
1021
1057
  metrics?.inc("device_instruction_dispatched_total", { kind: input.kind });
@@ -4,14 +4,25 @@ export declare const DEVICE_WS_PATH = "/v1/device/ws";
4
4
  /**
5
5
  * 本 server 铸/认的协议**修订号**(wire 上的 `protocolVersion`)。
6
6
  *
7
- * 规则(§5.6):加帧 / 加字段 = additive 不升号;改语义 = 升号;**executor → server 方向的闭集加词也升号** —— 修订号是 executor 在发 hello 之前
8
- * 唯一能读到的「这台 server 受理什么」的事实(challenge 帧带它),所以 server 受理的词集必须是修订号的函数
9
- * ({@link DEVICE_OUTCOME_ERROR_CODES_BY_REVISION},协议文档同名表),不另发第二份列表。闭集变了而修订号没变 = 同一个修订号两种受理集
10
- * (7.132.0 给结局码加 `liveness_no_output` 时没抬号,本版补到 2)。类型锁:抬了号而表没有这一行 ⇒ 编译红。
7
+ * 规则(真源 = 协议文档 `docs/DEVICE-EXECUTOR-PROTOCOL.md` §2.1「Protocol revisions」段,此处只转述):加帧 / 加字段 = additive 不升号;
8
+ * 其余变更一律升号并在增量表加一行,已发布的行不改 —— **server 受理的闭集(executor → server 方向,今天 = 结局 `errorCode` 词集)加词 = 升号**,
9
+ * **语义变更(server 下发的帧意思变了)= 升号**。修订号是 executor 在发 hello 之前唯一能读到的「这台 server 受理什么、发来的帧是什么意思」的事实
10
+ * (challenge 帧带它),所以 server 受理的词集必须是修订号的函数({@link DEVICE_OUTCOME_ERROR_CODES_BY_REVISION},协议文档同名表),不另发第二份列表;
11
+ * 闭集变了而修订号没变 = 同一个修订号两种受理集(7.132.0 给结局码加 `liveness_no_output` 时没抬号,7.136.0 补到 2)。类型锁:抬了号而表没有这一行 ⇒ 编译红。
11
12
  */
12
13
  export declare const DEVICE_PROTOCOL_VERSION: DeviceProtocolRevision;
13
- /** 低于此版本 ⇒ `helloReject: protocol_version_unsupported`(响亮拒,不静默降级,[ref])。兼容窗 = [MIN, 当前]。 */
14
- export declare const DEVICE_MIN_PROTOCOL_VERSION = 1;
14
+ /**
15
+ * 受理下沿:低于它 ⇒ `helloReject: protocol_version_unsupported`(带 `minProtocolVersion` 与一句 {@link deviceProtocolRevisionRefusal},响亮拒,不静默降级,[ref])。
16
+ * 兼容窗 = [MIN, 当前]。律(协议文档 §2.1 规则句):升号的变更旧修订的 executor 守不住 ⇒ 同一版把下沿抬到那一修订号 —— 旧 executor 在 hello 被拒一次,
17
+ * 而不是逐调用失败。今天 = 5:修订号 5 起路径只锚不折(下沿理由见 {@link DEVICE_FLOOR_CHANGE}),写给修订号 ≤ 4 的 executor 认的是折过的路径。
18
+ * 这是**本 server** 的受理下沿,不是 executor 协商时的下界(executor 一侧修订号是累积的:实现了 5 的照样能按 4 服务老 server)。
19
+ */
20
+ export declare const DEVICE_MIN_PROTOCOL_VERSION: DeviceProtocolRevision;
21
+ /**
22
+ * `protocol_version_unsupported` 的那一句 `message`(帧上与服务端 warn 行同一句;executor 可原样示人)。声明值在窗外只有两种:低于下沿 / 高于上沿。
23
+ * 握手之前的帧,任何能开 socket 的对端都读得到 ⇒ 句里只有修订号与下沿引入的版本,不带本进程的服务版本号。
24
+ */
25
+ export declare function deviceProtocolRevisionRefusal(declared: number): string;
15
26
  /** 签名的 domain tag —— 换域即换 tag,防止别处的 Ed25519 签名被拿来当握手用。 */
16
27
  export declare const DEVICE_HELLO_DOMAIN_TAG = "sema.device.hello.v1";
17
28
  /**
@@ -76,6 +87,7 @@ export declare const DEVICE_OUTCOME_ERROR_CODES_BY_REVISION: {
76
87
  readonly 2: readonly ["liveness_no_output"];
77
88
  readonly 3: readonly ["name_too_long"];
78
89
  readonly 4: readonly ["symlink_loop"];
90
+ readonly 5: readonly [];
79
91
  };
80
92
  /** 本包认得的协议修订号(= 增量表的行键)。 */
81
93
  export type DeviceProtocolRevision = keyof typeof DEVICE_OUTCOME_ERROR_CODES_BY_REVISION;
@@ -275,10 +287,12 @@ export type DeviceHelloAckFrame = {
275
287
  chunkGapTimeoutMs?: number;
276
288
  executionCeilingGraceMs?: number;
277
289
  };
290
+ /** `minProtocolVersion` 与 `message` 只出现在 `protocol_version_unsupported` 上(加字段 = additive,不升号;协议文档 §1.4 / §2.3)。 */
278
291
  export type DeviceHelloRejectFrame = {
279
292
  t: "helloReject";
280
293
  code: DeviceHelloRejectCode;
281
294
  minProtocolVersion?: number;
295
+ message?: string;
282
296
  };
283
297
  /**
284
298
  * helloAck 六个数值位的**合法域**(闭区间、整数)—— 一处成文:汇聚端创建时按它校验(越界 ⇒ 响亮拒启,不夹取、不换成缺省),
@@ -1,8 +1,14 @@
1
1
  import { createPublicKey, randomBytes, randomInt, verify as edVerify } from "node:crypto";
2
2
  import { MAX_TIMER_DELAY_MS, inWholeNumberBounds, wholeNumberBoundsRule } from "./config-types.js";
3
3
  export const DEVICE_WS_PATH = "/v1/device/ws";
4
- export const DEVICE_PROTOCOL_VERSION = 4;
5
- export const DEVICE_MIN_PROTOCOL_VERSION = 1;
4
+ export const DEVICE_PROTOCOL_VERSION = 5;
5
+ export const DEVICE_MIN_PROTOCOL_VERSION = 5;
6
+ const DEVICE_FLOOR_CHANGE = 'since server 7.150.0 every path an instruction carries (args.path, args.paths, cwd) arrives unfolded, with "." / ".." / empty segments kept for the device\'s filesystem to resolve';
7
+ export function deviceProtocolRevisionRefusal(declared) {
8
+ return declared < DEVICE_MIN_PROTOCOL_VERSION
9
+ ? `device protocol revision ${declared} is below the lowest revision this server accepts (${DEVICE_MIN_PROTOCOL_VERSION}): ${DEVICE_FLOOR_CHANGE}; upgrade the executor to one that declares revision ${DEVICE_MIN_PROTOCOL_VERSION} or above`
10
+ : `device protocol revision ${declared} is above the highest revision this server speaks (${DEVICE_PROTOCOL_VERSION}): declare the highest revision you implement that is not above challenge.protocolVersion`;
11
+ }
6
12
  export const DEVICE_HELLO_DOMAIN_TAG = "sema.device.hello.v1";
7
13
  export const DEVICE_WS_LIMITS = {
8
14
  maxFrameBytes: 1024 * 1024,
@@ -68,6 +74,7 @@ export const DEVICE_OUTCOME_ERROR_CODES_BY_REVISION = {
68
74
  2: ["liveness_no_output"],
69
75
  3: ["name_too_long"],
70
76
  4: ["symlink_loop"],
77
+ 5: [],
71
78
  };
72
79
  export function deviceOutcomeErrorCodesAt(revision) {
73
80
  if (!Number.isInteger(revision) || revision < 1 || revision > DEVICE_PROTOCOL_VERSION) {
@@ -9,7 +9,7 @@
9
9
  * 落点之前引擎自己按 `spec.principal` 分的那几面按人分(同一个人的各场景在那几面互见)—— 本仓镜像这几面的读口(工作流读面、后台登记簿的停止标记、
10
10
  * leader 子任务的 spec)同读 {@link taskSpecIdentityOf},读到的就是引擎写下的那一个值,不各写一份。
11
11
  */
12
- import type { Person, Subject, SubjectParts } from "./owner-brands.js";
12
+ import { type Person, type Subject, type SubjectParts } from "./owner-brands.js";
13
13
  /** 引擎交界的身份(本仓的类型;二元)。 */
14
14
  export interface EngineIdentity {
15
15
  readonly principal: Person | undefined;
@@ -25,4 +25,10 @@ export declare function specIdentityOf(parts: SubjectParts | undefined): EngineI
25
25
  export declare function taskSpecIdentityOf(parts: SubjectParts | undefined): {
26
26
  readonly principal?: string;
27
27
  };
28
+ /**
29
+ * 引擎按身份分的那几面落下的 **scope**(core 写侧 `spec.principal ?? "default"` 的同一条读法;工作流行的 `scope` 列就是它):一只主体 ⇒ 落点 {@link taskSpecIdentityOf}
30
+ * 写下的人;匿名 ⇒ 单机形的租户键 `"default"`(`owner-faces.ts` 的 `LEGACY_UNOWNED_AMNESTY_TENANT`)。读者只在属主存取器(`http/owner-access.ts`):工作流按 id 的门
31
+ * (调用方一侧按它换成引擎身份再与行的 scope 比)与工作流列表的属主过滤同读这一只;承认之后 journal / 流按承认的那一行的 scope 读。
32
+ */
33
+ export declare function engineScopeOf(subject: Subject | undefined): string;
28
34
  //# sourceMappingURL=engine-identity.d.ts.map
@@ -1,3 +1,5 @@
1
+ import { partsOf } from "./owner-brands.js";
2
+ import { LEGACY_UNOWNED_AMNESTY_TENANT } from "./owner-faces.js";
1
3
  export function specIdentityOf(parts) {
2
4
  if (parts === undefined)
3
5
  return { principal: undefined };
@@ -7,4 +9,7 @@ export function taskSpecIdentityOf(parts) {
7
9
  const { principal } = specIdentityOf(parts);
8
10
  return principal === undefined ? {} : { principal };
9
11
  }
12
+ export function engineScopeOf(subject) {
13
+ return taskSpecIdentityOf(subject === undefined ? undefined : partsOf(subject)).principal ?? LEGACY_UNOWNED_AMNESTY_TENANT;
14
+ }
10
15
  //# sourceMappingURL=engine-identity.js.map
@@ -6,14 +6,15 @@
6
6
  * · `example` 进拒句;
7
7
  * · `multiTenant` = `REQUIRE_PRINCIPAL=true` 下名单作不作数 —— **只有服务进程读的旋钮有这一列**(姿态是服务进程的概念):
8
8
  * - `LSP_ENV_ALLOW` ⇒ ignored:host 腿语言服务器在多租户姿态下本来就不起,名单无处作数,设了要说出来([ref])。
9
+ * - `HOOK_ENV_ALLOW` ⇒ ignored:请求的 `settings.hooks` 在多租户姿态下整只不跑(`task-settings.ts` `taskHooksHonored`,同一只部署形谓词),名单无处作数。
9
10
  * - 三只沙箱名单(e2b / local-docker / k8s 各一只) ⇒ honored:[ref] 照录修前语义(任何姿态下都转发),[ref] 主会话裁定维持 —— 沙箱 env 是部署方为隔离沙箱显式配的
10
11
  * 带外凭据(e2b / docker / k8s 车道本来就是多租户 fleet 的主形),与 LSP 那条「本机子进程」的形不同;多租户下起服说一句。
11
12
  * · `BAKE_ENV_ALLOW`([ref] 残余,7.103.0)由 **bake-runner 进程**读(构建宿主守护进程:没有主体、没有租户 ⇒ 没有姿态列,
12
- * 不进 {@link describeAllowlistPostures} 的姿态句)。它与服务侧四只旋钮同一只解析器、同一只「点名放行」谓词、同一条「原文按凭据类」律。
13
- * · `channel` = 这张名单**交给谁、在谁的减法之上**(闭集两词)。它只定拒句里「交到哪里」那半句与出路的主语,**不定拒不拒**:「不许点哪些名」对五只一律
13
+ * 不进 {@link describeAllowlistPostures} 的姿态句)。它与服务侧五只旋钮同一只解析器、同一只「点名放行」谓词、同一条「原文按凭据类」律。
14
+ * · `channel` = 这张名单**交给谁、在谁的减法之上**(闭集两词)。它只定拒句里「交到哪里」那半句与出路的主语,**不定拒不拒**:「不许点哪些名」对六只一律
14
15
  * = 名单型旋钮名 ∪ 本服务自有凭据名(引擎此刻的声明:起服解析时判一次,声明增长时由换代声明对活配置里每只服务侧名单此刻交出去的名重判一次;判官 = 引擎
15
16
  * `inheritEnvPolicyProblem`,与引擎拒嵌入方白名单同句),规则全文在解析器头注 ②。
16
- * - `host-put-back`(`LSP_ENV_ALLOW` / `BAKE_ENV_ALLOW`)—— 剥后放回形:宿主子进程的 env 先经唯一组合(引擎扣掉本服务自有凭据 + 形状剥),
17
+ * - `host-put-back`(`LSP_ENV_ALLOW` / `HOOK_ENV_ALLOW` / `BAKE_ENV_ALLOW`)—— 剥后放回形:宿主子进程的 env 先经唯一组合(引擎扣掉本服务自有凭据 + 形状剥 / 严格名单),
17
18
  * 名单点到的键再从本进程环境**原样**取回叠上去;点到本服务自有凭据名 = 把引擎刚扣下的那枚交回那只子进程。
18
19
  * - `sandbox-grant`(三只沙箱名单)—— 沙箱 env 的唯一来源(沙箱不从本进程继承任何东西),部署方显式交出的带外凭据([ref] 照转发);
19
20
  * 点到本服务自有凭据名 = 把它装进模型读得到的沙箱 env。沙箱要凭据 ⇒ 部署方给沙箱另铸一把(名与值都不同于本服务的任何凭据)。
@@ -25,7 +26,7 @@
25
26
  * 当场撒谎。为什么是纯叶:`config-catalog.ts` 被 `config.ts` 值引,表留在 `config.ts` 会成装载环。
26
27
  */
27
28
  /** 服务进程(`config.ts` `loadConfig`)读的名单型旋钮 —— 有多租户姿态。 */
28
- export type ServerEnvNameAllowlistKnob = "LSP_ENV_ALLOW" | "E2B_SANDBOX_ENV" | "DOCKER_SANDBOX_ENV" | "K8S_SANDBOX_ENV";
29
+ export type ServerEnvNameAllowlistKnob = "LSP_ENV_ALLOW" | "HOOK_ENV_ALLOW" | "E2B_SANDBOX_ENV" | "DOCKER_SANDBOX_ENV" | "K8S_SANDBOX_ENV";
29
30
  /** bake-runner 进程(`bake-runner/main.ts` `loadEnv`)读的名单型旋钮 —— 构建宿主守护进程没有主体 / 租户,没有姿态。 */
30
31
  export type RunnerEnvNameAllowlistKnob = "BAKE_ENV_ALLOW";
31
32
  export type EnvNameAllowlistKnob = ServerEnvNameAllowlistKnob | RunnerEnvNameAllowlistKnob;
@@ -52,7 +53,7 @@ export type EnvNameAllowlistKnobTable = {
52
53
  readonly [K in EnvNameAllowlistKnob]: K extends ServerEnvNameAllowlistKnob ? ServerEnvNameAllowlistKnobRow : RunnerEnvNameAllowlistKnobRow;
53
54
  };
54
55
  export declare const ENV_NAME_ALLOWLIST_KNOBS: EnvNameAllowlistKnobTable;
55
- /** 名单型旋钮的全部名字(五只;表键派生)—— 两处用:解析器的「点名名单型旋钮 = 形错」、剥除的「名单原文按凭据类」臂。 */
56
+ /** 名单型旋钮的全部名字(六只;表键派生)—— 两处用:解析器的「点名名单型旋钮 = 形错」、剥除的「名单原文按凭据类」臂。 */
56
57
  export declare const ENV_NAME_ALLOWLIST_KNOB_NAMES: ReadonlySet<string>;
57
58
  /**
58
59
  * 多租户姿态句 —— **由表派生**,不许在别处手写。形:`under REQUIRE_PRINCIPAL=true: <旋钮> is ignored; <旋钮> / <旋钮> are forwarded as configured`
@@ -4,6 +4,11 @@ export const ENV_NAME_ALLOWLIST_KNOBS = {
4
4
  channel: "host-put-back",
5
5
  multiTenant: { kind: "ignored", why: "the host-lane language server is not started in this posture, and the language-server env keeps the full secret strip" },
6
6
  },
7
+ HOOK_ENV_ALLOW: {
8
+ example: "HOOK_ENV_ALLOW=HOOK_TOKEN,WEBHOOK_SIGNING_KEY",
9
+ channel: "host-put-back",
10
+ multiTenant: { kind: "ignored", why: "request settings hooks are not run in this posture, so no hook environment reads the list" },
11
+ },
7
12
  E2B_SANDBOX_ENV: { example: "E2B_SANDBOX_ENV=GIT_TOKEN,NPM_TOKEN", channel: "sandbox-grant", multiTenant: { kind: "honored" } },
8
13
  DOCKER_SANDBOX_ENV: { example: "DOCKER_SANDBOX_ENV=GIT_TOKEN,NPM_TOKEN", channel: "sandbox-grant", multiTenant: { kind: "honored" } },
9
14
  K8S_SANDBOX_ENV: { example: "K8S_SANDBOX_ENV=GIT_TOKEN,NPM_TOKEN", channel: "sandbox-grant", multiTenant: { kind: "honored" } },
@@ -16,9 +16,8 @@ export type ExecutionLane = DeclarableLane;
16
16
  export interface ExecutionLaneCaps {
17
17
  /** 调用方送来的 `cwd` 是否被尊重。读者:部署形表行 `callerCwd`(本位即判据;改前对账 `task-cwd.ts` 的 `cwdHonored || deviceCwdHonored`)。 */
18
18
  readonly callerCwd: LaneCapability;
19
- /** core 的后台 shell 面(`run_in_background`/`BashOutput`/`KillShell`)。判别式:各 adapter 的
20
- * `backgroundCapabilities.supported`(`plugins/remote-env-{host,e2b,k8s}.ts`);host 腿的闸在
21
- * `boot/execution-env.ts` 的 `hostCfg.backgroundShell`。 */
19
+ /** core 的后台 shell 面(`run_in_background`/`BashOutput`/`KillShell`),含把运行中的前台命令领养成后台任务(`supportsDetach`)。读者:部署形表行 `backgroundShell`(本位即判据);
20
+ * 三只适配器的 `backgroundCapabilities`(`supported` 与 `supportsDetach` 同一个答案)、host 适配器的装配点与事实 `autoBackgroundOnTimeout` 同读这一行,没有第二份判别式。 */
22
21
  readonly backgroundShell: LaneCapability;
23
22
  /** 自唤醒 scheduler(`CronCreate`/…)。判别式:`boot/execution-env.ts` host 臂的 `hostScheduler`
24
23
  * 与 `http/routes/capabilities.ts` 的 `scheduler` 位(两处同判据)。 */
@@ -330,11 +329,27 @@ export declare function buildLaneHomeBootNote(deployment: LaneHomeDeployment): {
330
329
  readonly event: string;
331
330
  readonly note: string;
332
331
  } | undefined;
332
+ /**
333
+ * 读拒表的字节地板不守时一条 run 的**两种结局**(闭集):`ran` = 部署没要求地板,run 照跑(引擎每 run 一条 `config.read_deny_floor_unkept` 通告);
334
+ * `refused` = 部署要求地板(`READ_DENY_FLOOR_REQUIRED=true`),run 在准备期拒(同码失败终局,同步提交 409)。判官只有引擎一只(`judgeReadFloorKept`),
335
+ * 结局由旋钮分开 —— 本仓只说话。
336
+ */
337
+ export type ReadDenyFloorOutcome = "ran" | "refused";
338
+ /**
339
+ * **读拒字节地板不守的那一句** —— 本仓说这件事的**唯一**组句器(纯字符串 ⇒ `build*`):点名执行环境(`REMOTE_EXEC=<车道>`,运维写的那一格)、
340
+ * 「不守读拒字节地板」与出路 `READ_DENY_FLOOR_REQUIRED`。读它的面(一个事实一句话,不另写第二句):
341
+ * · `ran` —— run 事件流的 `engine_notice` 帧、运维 `engine_notice` 日志行与终局结果的 `readDenyFloor.message`(`read-deny-floor-notice.ts` 的呈现器);
342
+ * · `refused` —— 失败终局的句子(同步提交 409 的 `error`、run 行 `error`、`done` 帧 `terminal.message`,`terminal.ts` 的两只出口属主)与起服那一行
343
+ * `read_deny_floor_required_unkept` 的 `note`({@link buildReadDenyFloorUnkeptNote})。
344
+ * 句子不带行数(行数在通告的 `detail.rowCount`):同一条部署上同一种结局逐字同一句,运维能把起服行、409 与日志对上。
345
+ * 车道名以旋钮形 `REMOTE_EXEC=<词>` 出现 —— 那是调用方 / 运维写得出、查得到的名字,不是本仓对执行车道的自称。
346
+ */
347
+ export declare function buildReadDenyFloorSentence(lane: string, outcome: ReadDenyFloorOutcome): string;
333
348
  /**
334
349
  * 「部署要求读拒表的字节地板(`READ_DENY_FLOOR_REQUIRED=true`),而本部署车道的执行环境块不守地板」时起服那一行的 `note`(纯字符串 ⇒ `build*`);否则 `undefined`。
335
350
  * 判据只读部署的要求与 {@link capabilitiesFor} 的 `keepsReadFloor`(认不出的车道答不出块 ⇒ 按不守说,不静默)。`none` 的桩块守地板 ⇒ 不出。
336
- * 句子点名车道与键:这条车道上每个读拒表有行的 run(出厂读拒档在岗时就有行)都在准备期拒,一个命令都不起 —— 起服先把后果与两条出路说出来,
337
- * 不让运维从第一条 409 才知道。
351
+ * 句子 = 这条车道上每条被拒的 run 的拒句({@link buildReadDenyFloorSentence} 的 `refused`,一字不差):起服先把后果与两条出路说出来,
352
+ * 运维不必从第一条 409 才知道,且起服行与 409 是同一句。
338
353
  */
339
354
  export declare function buildReadDenyFloorUnkeptNote(deployment: CapabilitiesDeployment & {
340
355
  readonly readDenyFloorRequired: boolean;
@@ -327,14 +327,28 @@ export function buildLaneHomeBootNote(deployment) {
327
327
  return { event: LANE_HOME_UNDECLARED_EVENT, note: buildHomeAbsentNote(homeLane, "REMOTE_EXEC_HOME_DIR is unset, and this lane cannot read its execution environment's home", DECLARE_HOME_REMEDY) };
328
328
  return { event: LANE_HOME_UNMEASURED_EVENT, note: buildHomeUnmeasuredNote(homeLane, home) };
329
329
  }
330
+ export function buildReadDenyFloorSentence(lane, outcome) {
331
+ const env = `the execution environment (REMOTE_EXEC=${lane}) does not keep the read-deny byte floor`;
332
+ switch (outcome) {
333
+ case "ran":
334
+ return (`This run's read-deny rules are not byte-enforced: ${env} — a path a rule refuses is refused when a command names it, ` +
335
+ `but a program a command runs can still open it (a recursive read under a directory reads the files below it, denied ones included), ` +
336
+ `and their bytes can reach the conversation. READ_DENY_FLOOR_REQUIRED is not set, so the run went ahead; set READ_DENY_FLOOR_REQUIRED=true to refuse such runs instead.`);
337
+ case "refused":
338
+ return (`READ_DENY_FLOOR_REQUIRED=true, and ${env} (a program a command runs could open a path a read-deny rule refuses): ` +
339
+ `a run with read-deny rules is refused before any command starts (config.read_deny_floor_unkept; a synchronous submit answers 409). ` +
340
+ `Run on an execution environment that keeps the floor, or unset READ_DENY_FLOOR_REQUIRED to let such runs go ahead with a notice.`);
341
+ default: {
342
+ const unhandled = outcome;
343
+ throw new Error(`unhandled read-deny floor outcome: ${String(unhandled)}`);
344
+ }
345
+ }
346
+ }
330
347
  export function buildReadDenyFloorUnkeptNote(deployment) {
331
348
  if (!deployment.readDenyFloorRequired)
332
349
  return undefined;
333
350
  if (capabilitiesFor(deployment)?.keepsReadFloor === true)
334
351
  return undefined;
335
- return (`READ_DENY_FLOOR_REQUIRED=true, but the "${deployment.remoteExec.provider}" execution lane does not keep the read-deny byte floor (a program its commands run can open a path ` +
336
- `the read-deny table refuses). Every run whose read-deny table has rows — the shipped default tiers put rows there unless READ_DENY_BUILTIN_TIERS=none — ` +
337
- `is refused before any command starts (config.read_deny_floor_unkept; a synchronous submit answers 409). ` +
338
- `Either run on a lane that keeps the floor, or unset READ_DENY_FLOOR_REQUIRED to run with one operator notice per run instead.`);
352
+ return buildReadDenyFloorSentence(deployment.remoteExec.provider, "refused");
339
353
  }
340
354
  //# sourceMappingURL=execution-lane-caps.js.map
@@ -10,12 +10,12 @@ export interface FieldConflictCoordinates {
10
10
  readonly cascade_verify: "verify" | "cascade" | "sandboxImageProfile" | "resumeAt" | "suggestNextPrompts";
11
11
  readonly image_profile: "capabilitiesNeeded" | "sandboxImageProfile";
12
12
  readonly resume_anchor: "resumeAtMode" | "resumeAt";
13
- readonly system_prompt_fold: "appendSystemPrompt" | "settings.outputStyle";
13
+ readonly system_prompt_fold: "appendSystemPrompt" | "projectId" | "settings.outputStyle";
14
14
  readonly file_history_restore: "fileHistory" | "restoreFiles" | "rewindFilesTo";
15
15
  readonly skills_disabled: "disableSkills" | "skills" | `agents[${number}].skills`;
16
16
  readonly existing_session: "requireExistingSession" | "sessionId";
17
17
  readonly fork_target: "forkId" | "forkNonce";
18
- readonly scratchpad_root: "cwd" | "scratchpadDir";
18
+ readonly scratchpad_root: "cwd" | "projectId" | "scratchpadDir";
19
19
  readonly ask_answer: "decision" | "answer";
20
20
  readonly policy_person_ask: "decision" | "decidedBy";
21
21
  readonly plan_edit: "decision" | "editedPlan";
@@ -16,6 +16,8 @@
16
16
  * 那一形的面只有每拍一行运维 warn + 计数)。「扣着」在两出口上只有这一种读法(7.120.x 的 `/health.modelPlaneDeferred` 本版删除)。
17
17
  * 合成只在 {@link buildRestartSignal} 一处,`restartState()` 是它唯一的调用方 —— 两个出口读的是同一只取值口。
18
18
  * 4. **代际**:`generation` = env `FLEET_GENERATION` 的回声(规范十进制串;非规范在 boot 拒启,见 `config.ts`);缺席 ⇔ 非 fleet 成员。
19
+ * **围栏只有成员身份一个开关**:租约读数只有一只读者 {@link memberLeaseOf}(铸点与准入三处同读)—— 非成员恒 {@link LEASE_NONE},
20
+ * 注入了读数也不读;所以「`/health` 不报 `leaseState` 而准入照按租约拒」这一形构造不出来。
19
21
  * **身份不是引擎态**:`instanceId`(本进程起步自铸的那一只,`boot/stage-03` 的 uuidv7)是体的身份,只在两出口体的**顶层**说一次,
20
22
  * 铸点不读它、契约形里不重复它。
21
23
  * 5. **两形一读(展开 / 收缩)**:两出口今天各发两形 —— 嵌套键 {@link ENGINE_SIGNAL_KEY}(契约 `EngineSignal` 整只,{@link buildEngineSignal}),
@@ -52,8 +54,19 @@ export type ServingLeaseView = {
52
54
  };
53
55
  /** 心跳体上的 fleet 成员三键 —— 类型取自契约心跳形(拼法与值域只有契约一个写者)。 */
54
56
  export type FleetMembershipKeys = Pick<InstanceAnnouncement, "generation" | "leaseState" | "leaseUntil">;
55
- /** 非 fleet 成员 / 没装租约客户端时的读数(唯一拼法)。 */
57
+ /** 非 fleet 成员 / 没装租约客户端时的读数(唯一拼法)。成员的推定围栏只住在租约客户端里,不进这只缺省值。 */
56
58
  export declare const LEASE_NONE: ServingLeaseView;
59
+ /**
60
+ * 租约读数的**唯一读者**(规则 4;铸点 {@link mintEngineSignal} 与准入三处 —— 计费门 / a2a `message/send` / PARKED 赎回席 —— 都经它,不直读
61
+ * `deps.servingLease`):成员身份 = `config.fleetGeneration` 在场 ⇒ 租约客户端此刻的读数(没装 ⇒ {@link LEASE_NONE});非成员 ⇒ {@link LEASE_NONE}。
62
+ */
63
+ export declare function memberLeaseOf(deps: Pick<EngineSignalInputs, "config" | "servingLease">): ServingLeaseView;
64
+ /**
65
+ * 装配判的拒句(`createHttpServer` 构造期,fail-closed):租约读数只属于 fleet 成员,而成员身份只有 `config.fleetGeneration` 一个开关 ——
66
+ * 注入了 `servingLease` 却没设代际,读数永远不会被 {@link memberLeaseOf} 读到、准入永远不按租约拒。两键都是可选的,所以这是一份能编译的
67
+ * 自相矛盾的装配:响亮拒,不静默丢掉读数(本服务自己的组合根只给成员装租约客户端,走不到这里)。
68
+ */
69
+ export declare const SERVING_LEASE_MEMBERSHIP_REQUIRED = "servingLease is wired but config.fleetGeneration is not: a serving-lease reading belongs to a fleet member, and membership is config.fleetGeneration (FLEET_GENERATION) alone \u2014 without it the reading is never read and admission never refuses on the lease; set config.fleetGeneration to this instance's generation, or do not pass servingLease; refusing to start rather than ignore the lease reading";
57
70
  /** 扣着的候选(web-admin 的 `planeDeferredNoHandoff` 投影):版本、起扣时刻、被扣的重启片。 */
58
71
  export interface RetainedCandidate {
59
72
  readonly version: number;
@@ -1,6 +1,10 @@
1
1
  import { readinessOf } from "../http/readiness.js";
2
2
  import { drainingFactOf } from "./drain-entry.js";
3
3
  export const LEASE_NONE = Object.freeze({ state: "none" });
4
+ export function memberLeaseOf(deps) {
5
+ return deps.config?.fleetGeneration === undefined ? LEASE_NONE : (deps.servingLease?.() ?? LEASE_NONE);
6
+ }
7
+ export const SERVING_LEASE_MEMBERSHIP_REQUIRED = "servingLease is wired but config.fleetGeneration is not: a serving-lease reading belongs to a fleet member, and membership is config.fleetGeneration (FLEET_GENERATION) alone — without it the reading is never read and admission never refuses on the lease; set config.fleetGeneration to this instance's generation, or do not pass servingLease; refusing to start rather than ignore the lease reading";
4
8
  export function buildRestartSignal(published, retained) {
5
9
  if (published !== undefined)
6
10
  return published;
@@ -29,7 +33,7 @@ export function mintEngineSignal(deps) {
29
33
  ...(draining !== undefined ? { draining } : {}),
30
34
  ...(restart !== undefined ? { restart } : {}),
31
35
  ...(deps.config?.fleetGeneration !== undefined ? { generation: deps.config.fleetGeneration } : {}),
32
- lease: deps.servingLease?.() ?? LEASE_NONE,
36
+ lease: memberLeaseOf(deps),
33
37
  ...(configApply !== undefined ? { configApply } : {}),
34
38
  };
35
39
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * [ref](docs/DESIGN-261-fleet-liveness-reconcile.md v1.2,四方零驳定稿)—— fleet 总线**存活对账腿**。
2
+ * [ref](docs/[ref]-fleet-liveness-reconcile.md v1.2,四方零驳定稿)—— fleet 总线**存活对账腿**。
3
3
  *
4
4
  * ## 它修什么(§0 病灶机制链)
5
5
  * fleet 总线是进程内纯内存聚合(`fleet-bus.ts` 头注自陈 NOT durable / NOT cross-replica),行的**唯一**
@@ -32,11 +32,26 @@ export interface ServingLeaseClientOpts {
32
32
  readonly epoch: () => number;
33
33
  };
34
34
  }
35
+ /**
36
+ * 一拍心跳听到了什么(`fleet-client.ts` 每一次公告尝试恰好交一只;读者在本模块)。
37
+ * · `reading` —— 中心的显式能力声明(契约 `declared`;位缺席 = 中心说不执行围栏);
38
+ * · `silent` —— 没有读数。`why` 的形是闭集:`HTTP <状态>`(非 2xx,不带中心体片段)/ 请求抛出的那句(不可达 / 超时 / 凭证读不出)/
39
+ * `reply-unreadable:<因>`(2xx 而不是声明,因 = `fleet-client.ts` `AnnounceReplyFlaw`)/ `not-sent:<那句>`(这一拍的引擎信号铸不出,没发)。
40
+ */
41
+ export type HeartbeatHearing = {
42
+ readonly kind: "reading";
43
+ readonly capabilities: WebAdminCapabilities;
44
+ } | {
45
+ readonly kind: "silent";
46
+ readonly why: string;
47
+ };
35
48
  export interface ServingLeaseClient {
36
- /** 一次中心能力读数(`undefined` = `undeclared`,中心没宣告 = 不支持)。每一次读数调一次;`unreadable` 不是读数,不调(`fleet-client.ts` `capabilityReadingOf`)。 */
37
- noteCenterCapabilities(caps: WebAdminCapabilities | undefined): void;
38
- /** 此刻的租约读数(铸点与准入判读它)。 */
49
+ /** 一拍心跳听到的东西(规则 1;每一次公告尝试恰好一次)。 */
50
+ noteHeartbeat(hearing: HeartbeatHearing): void;
51
+ /** 此刻的租约读数(铸点与准入判读它 —— 经 `engine-signal.ts` 的唯一读者 `memberLeaseOf`)。 */
39
52
  view(): ServingLeaseView;
53
+ /** 订阅「租约态由事件翻转」(规则 2′;一只订阅者 = 装配层的 `announceNow`,晚绑:fleet 客户端在本客户端之后造)。 */
54
+ onViewChange(listener: () => void): void;
40
55
  /** 起步读黏性拒(装配层在唯一排空入口装好之后调一次)。 */
41
56
  resumeStickyDenial(): void;
42
57
  /** 立刻续一次(测试 / 能力位刚出现时用;单飞)。 */