@sema-agent/server 7.130.0 → 7.132.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 (294) hide show
  1. package/MIGRATION.md +396 -0
  2. package/README.md +13 -6
  3. package/README.zh-CN.md +9 -5
  4. package/USAGE.md +187 -50
  5. package/dist/approval-card.d.ts +3 -1
  6. package/dist/approval-card.js +2 -3
  7. package/dist/audit.d.ts +7 -10
  8. package/dist/audit.js +4 -1
  9. package/dist/auth-bridge.d.ts +4 -0
  10. package/dist/auth-bridge.js +10 -11
  11. package/dist/bench/s1/live-deps.js +2 -0
  12. package/dist/boot/deployment-mods.d.ts +31 -0
  13. package/dist/boot/deployment-mods.js +26 -0
  14. package/dist/boot/execution-env.d.ts +1 -1
  15. package/dist/boot/execution-env.js +19 -6
  16. package/dist/boot/memory-boundary.d.ts +2 -2
  17. package/dist/boot/read-deny-anchor-audit.d.ts +17 -0
  18. package/dist/boot/read-deny-anchor-audit.js +36 -0
  19. package/dist/boot/resolve-spec.d.ts +1 -5
  20. package/dist/boot/resolve-spec.js +56 -61
  21. package/dist/boot/runner-deps.d.ts +19 -8
  22. package/dist/boot/runner-deps.js +14 -2
  23. package/dist/boot/session-faces.d.ts +1 -7
  24. package/dist/boot/stage-02-web-admin-pull.js +9 -1
  25. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  26. package/dist/boot/stage-03-store-backend.js +2 -2
  27. package/dist/boot/stage-04-stores.d.ts +1 -1
  28. package/dist/boot/stage-05-execution-env.d.ts +4 -4
  29. package/dist/boot/stage-05-execution-env.js +7 -10
  30. package/dist/boot/stage-06-runners.d.ts +2 -2
  31. package/dist/boot/stage-06-runners.js +5 -4
  32. package/dist/boot/stage-07-capability-layer.d.ts +2 -2
  33. package/dist/boot/stage-07-capability-layer.js +3 -3
  34. package/dist/boot/stage-08-reapers.d.ts +2 -2
  35. package/dist/boot/stage-09-leader.d.ts +3 -9
  36. package/dist/boot/stage-10-http-server.d.ts +3 -9
  37. package/dist/boot/stage-10-http-server.js +12 -10
  38. package/dist/boot/stores.d.ts +1 -1
  39. package/dist/boot/stores.js +5 -6
  40. package/dist/boot/web-admin.d.ts +0 -3
  41. package/dist/boot/web-admin.js +35 -35
  42. package/dist/brain.js +17 -22
  43. package/dist/budget.js +5 -4
  44. package/dist/caller-text-echo.d.ts +20 -0
  45. package/dist/caller-text-echo.js +24 -0
  46. package/dist/capabilities/brand-identity.d.ts +26 -0
  47. package/dist/capabilities/brand-identity.js +27 -0
  48. package/dist/capabilities/builtin-tools.js +2 -1
  49. package/dist/capabilities/center-plugins.js +1 -1
  50. package/dist/capabilities/center-prompts.d.ts +32 -59
  51. package/dist/capabilities/center-prompts.js +18 -32
  52. package/dist/capabilities/composite-members.d.ts +1 -0
  53. package/dist/capabilities/composite-members.js +1 -0
  54. package/dist/capabilities/engine-capabilities.js +2 -1
  55. package/dist/capabilities/hands-lane.d.ts +9 -6
  56. package/dist/capabilities/hands-lane.js +3 -3
  57. package/dist/capabilities/host-tool-names.d.ts +17 -0
  58. package/dist/capabilities/host-tool-names.js +15 -0
  59. package/dist/capabilities/mcp-probe.d.ts +14 -1
  60. package/dist/capabilities/mcp-probe.js +22 -133
  61. package/dist/capabilities/repo-tools.js +4 -3
  62. package/dist/capabilities/scenarios.d.ts +42 -47
  63. package/dist/capabilities/scenarios.js +19 -35
  64. package/dist/capabilities/select-environment-tool.js +2 -1
  65. package/dist/capabilities/send-user-file-tool.d.ts +0 -1
  66. package/dist/capabilities/send-user-file-tool.js +2 -2
  67. package/dist/capabilities/skills.d.ts +19 -4
  68. package/dist/capabilities/skills.js +30 -10
  69. package/dist/capabilities/tool-defer.js +2 -1
  70. package/dist/config-catalog.js +22 -11
  71. package/dist/config-invariants.js +2 -2
  72. package/dist/config-lkg.d.ts +9 -9
  73. package/dist/config-lkg.js +20 -4
  74. package/dist/config-provider.d.ts +3 -1
  75. package/dist/config-provider.js +14 -6
  76. package/dist/config-types.d.ts +13 -9
  77. package/dist/config.d.ts +2 -2
  78. package/dist/config.js +34 -20
  79. package/dist/device-ws-protocol.d.ts +1 -1
  80. package/dist/device-ws-protocol.js +1 -0
  81. package/dist/elicitation.d.ts +7 -0
  82. package/dist/elicitation.js +20 -5
  83. package/dist/env-name-allowlist-knobs.d.ts +12 -2
  84. package/dist/env-name-allowlist-knobs.js +5 -4
  85. package/dist/exec-bounds.d.ts +15 -3
  86. package/dist/exec-bounds.js +4 -0
  87. package/dist/execution-lane-caps.d.ts +9 -2
  88. package/dist/execution-lane-caps.js +11 -0
  89. package/dist/hooks/classic-stations.d.ts +86 -0
  90. package/dist/hooks/classic-stations.js +27 -0
  91. package/dist/hooks/hook-llm.d.ts +8 -5
  92. package/dist/hooks/hook-llm.js +80 -37
  93. package/dist/hooks/hook-runner.d.ts +273 -75
  94. package/dist/hooks/hook-runner.js +293 -317
  95. package/dist/http/admission.d.ts +8 -2
  96. package/dist/http/admission.js +103 -59
  97. package/dist/http/approval-sweeps.js +59 -18
  98. package/dist/http/checkpoint-ctx.d.ts +36 -18
  99. package/dist/http/checkpoint-ctx.js +14 -10
  100. package/dist/http/claimed-run.d.ts +13 -0
  101. package/dist/http/claimed-run.js +15 -0
  102. package/dist/http/device-placement.js +5 -10
  103. package/dist/http/dispatch.d.ts +0 -4
  104. package/dist/http/dispatch.js +6 -10
  105. package/dist/http/durable-run-leg.d.ts +2 -1
  106. package/dist/http/durable-run-leg.js +5 -3
  107. package/dist/http/health-self-report.d.ts +7 -5
  108. package/dist/http/health-self-report.js +4 -18
  109. package/dist/http/principal-gate.d.ts +23 -6
  110. package/dist/http/principal-gate.js +24 -5
  111. package/dist/http/refusal-body.d.ts +21 -0
  112. package/dist/http/refusal-body.js +4 -0
  113. package/dist/http/request-guards.d.ts +27 -0
  114. package/dist/http/request-guards.js +24 -3
  115. package/dist/http/resume-legs.d.ts +25 -0
  116. package/dist/http/resume-legs.js +48 -26
  117. package/dist/http/routes/approvals-assistant.js +1 -1
  118. package/dist/http/routes/capabilities.js +7 -17
  119. package/dist/http/routes/diagnostics.js +1 -1
  120. package/dist/http/routes/rules.js +2 -2
  121. package/dist/http/routes/runs.js +13 -17
  122. package/dist/http/routes/session-sync.js +4 -2
  123. package/dist/http/routes/sessions.js +23 -11
  124. package/dist/http/routes/shared-memory.js +2 -13
  125. package/dist/http/routes/side-query.js +2 -3
  126. package/dist/http/routes/tasks.js +34 -19
  127. package/dist/http/scenario-read-face.d.ts +14 -0
  128. package/dist/http/scenario-read-face.js +5 -0
  129. package/dist/http/send.d.ts +13 -1
  130. package/dist/http/send.js +12 -1
  131. package/dist/http/server.d.ts +37 -23
  132. package/dist/http/server.js +30 -4
  133. package/dist/http/stored-body-replay.d.ts +10 -3
  134. package/dist/http/stored-body-replay.js +27 -6
  135. package/dist/http/submit-ctx.d.ts +25 -0
  136. package/dist/http/submit-ctx.js +39 -0
  137. package/dist/http/wire-types.d.ts +18 -5
  138. package/dist/index.d.ts +3 -2
  139. package/dist/index.js +3 -2
  140. package/dist/lane-home-probe.d.ts +43 -0
  141. package/dist/lane-home-probe.js +35 -0
  142. package/dist/limit-refusal.d.ts +47 -0
  143. package/dist/limit-refusal.js +12 -0
  144. package/dist/main.js +1 -1
  145. package/dist/mcp-assertion-header.d.ts +3 -11
  146. package/dist/mcp-assertion-header.js +3 -9
  147. package/dist/mcp-tool-faces.d.ts +5 -0
  148. package/dist/mcp-tool-faces.js +5 -1
  149. package/dist/memory-scope.d.ts +1 -1
  150. package/dist/model-entry-refusal.d.ts +1 -7
  151. package/dist/model-provider.d.ts +39 -12
  152. package/dist/model-provider.js +19 -2
  153. package/dist/model-route-endpoint.d.ts +52 -12
  154. package/dist/model-route-endpoint.js +48 -26
  155. package/dist/model-route-gap.d.ts +5 -4
  156. package/dist/model-route-gap.js +1 -1
  157. package/dist/model-select.d.ts +58 -0
  158. package/dist/model-select.js +31 -0
  159. package/dist/namespaced-rule-name.d.ts +7 -4
  160. package/dist/namespaced-rule-name.js +4 -3
  161. package/dist/observability/cost-taxonomy.d.ts +7 -7
  162. package/dist/observability/fail-open.d.ts +53 -12
  163. package/dist/observability/fail-open.js +47 -7
  164. package/dist/observability/metrics.js +3 -1
  165. package/dist/observability/prompt-manifest.d.ts +47 -82
  166. package/dist/observability/prompt-manifest.js +119 -17
  167. package/dist/observability/run-terminal.js +14 -6
  168. package/dist/observability/secret-env-scrub.d.ts +13 -1
  169. package/dist/observability/secret-env-scrub.js +13 -1
  170. package/dist/observability/tool-trace.d.ts +16 -21
  171. package/dist/observability/tool-trace.js +51 -42
  172. package/dist/per-task-image.d.ts +7 -1
  173. package/dist/per-task-image.js +3 -3
  174. package/dist/plain-string-record.d.ts +25 -0
  175. package/dist/plain-string-record.js +32 -0
  176. package/dist/plugins/blob-backend.d.ts +68 -13
  177. package/dist/plugins/blob-backend.js +53 -10
  178. package/dist/plugins/checkpoint-store-sql.d.ts +14 -4
  179. package/dist/plugins/checkpoint-store-sql.js +39 -26
  180. package/dist/plugins/k8s-bg-scripts.d.ts +11 -0
  181. package/dist/plugins/k8s-bg-scripts.js +22 -0
  182. package/dist/plugins/local-checkpoint-store.js +5 -2
  183. package/dist/plugins/local-session-store.js +3 -3
  184. package/dist/plugins/one-time-migrations.d.ts +147 -91
  185. package/dist/plugins/one-time-migrations.js +372 -208
  186. package/dist/plugins/permission-rule-store-sql.d.ts +13 -7
  187. package/dist/plugins/permission-rule-store-sql.js +4 -18
  188. package/dist/plugins/pg-session-storage.d.ts +4 -5
  189. package/dist/plugins/pg-session-storage.js +7 -17
  190. package/dist/plugins/remote-env-adb.d.ts +6 -0
  191. package/dist/plugins/remote-env-adb.js +9 -4
  192. package/dist/plugins/remote-env-device.js +3 -0
  193. package/dist/plugins/remote-env-e2b.d.ts +1 -1
  194. package/dist/plugins/remote-env-e2b.js +21 -9
  195. package/dist/plugins/remote-env-host.d.ts +9 -9
  196. package/dist/plugins/remote-env-host.js +10 -32
  197. package/dist/plugins/remote-env-k8s.d.ts +95 -26
  198. package/dist/plugins/remote-env-k8s.js +265 -90
  199. package/dist/plugins/remote-env-local-docker.d.ts +20 -1
  200. package/dist/plugins/remote-env-local-docker.js +77 -9
  201. package/dist/plugins/remote-env-ssh.d.ts +15 -0
  202. package/dist/plugins/remote-env-ssh.js +109 -3
  203. package/dist/plugins/remote-shell.d.ts +0 -1
  204. package/dist/plugins/remote-shell.js +1 -2
  205. package/dist/plugins/retention-store-sql.js +6 -2
  206. package/dist/plugins/schema-consistency.d.ts +54 -0
  207. package/dist/plugins/schema-consistency.js +52 -0
  208. package/dist/plugins/session-epoch-anchor.d.ts +13 -0
  209. package/dist/plugins/session-epoch-anchor.js +23 -0
  210. package/dist/plugins/shared-memory-store-sql.d.ts +9 -3
  211. package/dist/plugins/shared-memory-store-sql.js +5 -16
  212. package/dist/plugins/sql-driver.d.ts +141 -0
  213. package/dist/plugins/sql-driver.js +115 -1
  214. package/dist/plugins/sql-errors.d.ts +41 -0
  215. package/dist/plugins/sql-errors.js +36 -0
  216. package/dist/plugins/store-backend.js +2 -1
  217. package/dist/plugins/tidb-session-storage.d.ts +7 -11
  218. package/dist/plugins/tidb-session-storage.js +6 -16
  219. package/dist/plugins/tidb-session-store.js +1 -1
  220. package/dist/prompts-domain-validate.d.ts +17 -61
  221. package/dist/prompts-domain-validate.js +9 -119
  222. package/dist/question.d.ts +18 -9
  223. package/dist/question.js +21 -13
  224. package/dist/request-key-closure.d.ts +4 -4
  225. package/dist/request-key-closure.js +18 -13
  226. package/dist/rule-entry-list.d.ts +134 -24
  227. package/dist/rule-entry-list.js +162 -30
  228. package/dist/run-local.d.ts +3 -3
  229. package/dist/run-local.js +26 -25
  230. package/dist/runs.d.ts +48 -2
  231. package/dist/runs.js +61 -2
  232. package/dist/server-secret-env.d.ts +44 -18
  233. package/dist/server-secret-env.js +49 -8
  234. package/dist/session-incarnation.d.ts +15 -5
  235. package/dist/session-incarnation.js +16 -9
  236. package/dist/session-titler.js +12 -2
  237. package/dist/spec-fields.d.ts +34 -18
  238. package/dist/spec-fields.js +46 -53
  239. package/dist/sql-engine-posture.d.ts +29 -4
  240. package/dist/sql-engine-posture.js +36 -1
  241. package/dist/stored-request-hooks-m20.d.ts +23 -0
  242. package/dist/stored-request-hooks-m20.js +124 -0
  243. package/dist/stored-request-tool-axes-m19.d.ts +20 -5
  244. package/dist/stored-request-tool-axes-m19.js +30 -2
  245. package/dist/task-a2a.d.ts +9 -1
  246. package/dist/task-a2a.js +73 -47
  247. package/dist/task-mcp.d.ts +54 -102
  248. package/dist/task-mcp.js +194 -92
  249. package/dist/task-settings.d.ts +47 -25
  250. package/dist/task-settings.js +46 -61
  251. package/dist/text-bidi.d.ts +3 -46
  252. package/dist/text-bidi.js +3 -3
  253. package/dist/tool-approval.d.ts +1 -1
  254. package/dist/trace/core-keyset-guard.d.ts +24 -4
  255. package/dist/trace/engine-notice-wire.d.ts +11 -3
  256. package/dist/trace/engine-notice-wire.js +8 -1
  257. package/dist/trace/ledger-events.d.ts +3 -1
  258. package/dist/trace/ledger-sink.d.ts +29 -0
  259. package/dist/trace/ledger-sink.js +15 -1
  260. package/dist/trace/model-segment.js +1 -1
  261. package/dist/trace/project.d.ts +25 -6
  262. package/dist/trace/project.js +68 -22
  263. package/dist/trace/wire-projection-faces.d.ts +80 -2
  264. package/dist/trace/wire-projection-faces.js +23 -1
  265. package/dist/user-authored-text.d.ts +7 -0
  266. package/dist/user-authored-text.js +3 -0
  267. package/dist/web-admin-client/apply-effective.js +10 -5
  268. package/dist/web-admin-client/candidate-gate.d.ts +6 -6
  269. package/dist/web-admin-client/candidate-gate.js +3 -3
  270. package/dist/web-admin-client/http-client.js +0 -6
  271. package/dist/web-admin-client/read-warnings.d.ts +13 -0
  272. package/dist/web-admin-client/read-warnings.js +10 -0
  273. package/dist/web-admin-client/skills-mcp.d.ts +3 -0
  274. package/dist/web-admin-client/skills-mcp.js +9 -6
  275. package/dist/web-admin-client/types.d.ts +3 -4
  276. package/dist/workspace-cache.d.ts +35 -0
  277. package/dist/workspace-cache.js +36 -0
  278. package/dist/workspace-space.d.ts +3 -2
  279. package/dist/workspace-space.js +2 -0
  280. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +8 -1
  281. package/package.json +4 -4
  282. package/scripts/drain-check-local.mjs +37 -3
  283. package/scripts/drain-check.mysql.sql +30 -2
  284. package/scripts/drain-check.pg.sql +29 -2
  285. package/dist/capabilities/memory-notice.d.ts +0 -138
  286. package/dist/capabilities/memory-notice.js +0 -64
  287. package/dist/capabilities/prompt.d.ts +0 -17
  288. package/dist/capabilities/prompt.js +0 -6
  289. package/dist/mcp-content-origin.d.ts +0 -34
  290. package/dist/mcp-content-origin.js +0 -10
  291. package/dist/tool-axis-words.d.ts +0 -27
  292. package/dist/tool-axis-words.js +0 -9
  293. package/dist/wire-name-bound.d.ts +0 -14
  294. package/dist/wire-name-bound.js +0 -13
package/dist/config.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { readFileSync } from "node:fs";
2
- import { DEFAULT_AT_MENTION, DEFAULT_MODEL_REF } from "./model-select.js";
2
+ import { DEFAULT_AT_MENTION, DEFAULT_MODEL_REF, mintCapabilityKeys } from "./model-select.js";
3
3
  import { homedir } from "node:os";
4
4
  import { join, posix as posixPath } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
- import { BUILTIN_COMPLIANCE_DENIES, COMPLIANCE_CAPABILITIES, CROSS_SESSION_INBOUND_SETTINGS, CROSS_SESSION_DIALOG_EXPIRY_VALUES, compileReadDeny, resolveReadDenyBuiltins, CODE_AGENT_PROMPT, isModelPriced, PROTOCOL_TABLE, RECOMMENDED_SENSITIVE_PATTERNS, judgeRuleToolName, resolveFileHistoryRetention, resolveLockedKeys, validatePermissionRules, WRITE_PROTECTED_DEFAULT_TABLE, resolveWriteProtectedTable } from "@sema-agent/core";
6
+ import { compileAllowList, inheritEnvPolicyProblem, BUILTIN_COMPLIANCE_DENIES, COMPLIANCE_CAPABILITIES, CROSS_SESSION_INBOUND_SETTINGS, CROSS_SESSION_DIALOG_EXPIRY_VALUES, compileReadDeny, resolveReadDenyBuiltins, CODE_AGENT_PROMPT, isModelPriced, PROTOCOL_TABLE, RECOMMENDED_SENSITIVE_PATTERNS, judgeRuleToolName, resolveFileHistoryRetention, resolveLockedKeys, validatePermissionRules, WRITE_PROTECTED_DEFAULT_TABLE, resolveWriteProtectedTable } from "@sema-agent/core";
7
7
  import { ROSTER_PRIMARY_ROLES, ROSTER_CHEAP_ROLES, WEB_ADMIN_ENV, retiredEnvRefusal } from "@sema-agent/settings-schema";
8
8
  import { parseApprovalHmacKeys, parsePrincipalJwks } from "./auth-keys.js";
9
9
  import { DEFAULT_ELICITATION_THROTTLE } from "./elicitation.js";
@@ -22,25 +22,25 @@ import { THINKING_LEVELS, THINKING_FORMATS, buildModelCompat, isThinkingFormat,
22
22
  import {} from "./posture-source.js";
23
23
  import { COST_QUOTA_WINDOW_SEC_RANGE, costQuotaWindowSecInRange } from "./observability/cost-quota.js";
24
24
  import { CONTROL_AND_BIDI_STRIP_RE } from "./text-bidi.js";
25
- import { describeUnmatchableRuleName, ruleEntryToolName, unmatchableRuleNameOf } from "./namespaced-rule-name.js";
25
+ import { TOOL_NAME_ROSTER, describeUnmatchableRuleName, ruleEntryToolName, unmatchableRuleNameOf } from "./namespaced-rule-name.js";
26
26
  import { bakeOperatorPrincipalsRefusal, bakeRunnerCredentialRefusal, centerIdentityRefusal, halfOpenDirectDoorRefusal, leaderDurableStoreRefusal, operatorPrincipalsRequiredRefusal } from "./config-invariants.js";
27
27
  import { declaredSemaConfigDir } from "./sema-config-dir.js";
28
28
  import { lkgPathOverrideOf } from "./config-lkg.js";
29
29
  import { K8S_WORKSPACE_MOUNT_DEFAULT, WORKSPACE_PERSIST_DEFAULT, WORKSPACE_PERSIST_WORDS, WORKSPACE_SNAPSHOT_KEEP_DEFAULT, WORKSPACE_SNAPSHOT_KEEP_RANGE, WORKSPACE_SNAPSHOT_TIMEOUT_MS_DEFAULT, WORKSPACE_SNAPSHOT_TIMEOUT_MS_RANGE, parseWorkspaceSnapshotExclude } from "./workspace-space.js";
30
30
  import { laneLivenessOf } from "./exec-bounds.js";
31
31
  import { SANDBOX_IPV6_DEFAULT, SANDBOX_IPV6_WORDS } from "./sandbox-egress-policy.js";
32
- import { WORKSPACE_CACHE_DEFAULT, WORKSPACE_CACHE_MOUNT_DEFAULT, WORKSPACE_CACHE_SIZE_DEFAULT, WORKSPACE_CACHE_WORDS, isK8sQuantity, mountsOverlap } from "./workspace-cache.js";
32
+ import { WORKSPACE_CACHE_DEFAULT, WORKSPACE_CACHE_MOUNT_DEFAULT, WORKSPACE_CACHE_MOUNT_RESERVED, WORKSPACE_CACHE_SIZE_DEFAULT, WORKSPACE_CACHE_WORDS, isK8sQuantity, mountsOverlap, reservedMountCollision } from "./workspace-cache.js";
33
33
  import { REMOTE_EXEC_PROVIDER_WORDS, executionLaneOf, executionLaneRequiredRefusal, isSingleMachineDefaultLane, laneRequiredEnv } from "./execution-lane-caps.js";
34
34
  import { MEMORY_ENGINE_BACKENDS, SESSION_BACKENDS, STORE_BACKENDS } from "@sema-agent/settings-schema/execution-lanes";
35
35
  import { AUTONOMY_MODES } from "./runtime-governance.js";
36
- import { allowLayerEntryCountIssue, describeInertRuleEntries, inertRuleEntriesOf, ruleEntryListShapeOk } from "./rule-entry-list.js";
36
+ import { MAX_NAMED_INERT_ENTRIES, allowLayerEntryCountIssue, describeInertRuleEntries, inertRuleEntriesOf, inertRuleEntryGuidance, ruleEntryListShapeOk } from "./rule-entry-list.js";
37
37
  import { createCenterCredentialSource, readCenterCredentialDeclaration } from "./center-credential.js";
38
38
  import { parseCenterCredentialRenewLeadMs } from "./center-credential-renewer.js";
39
39
  import { modelProviderRefusal } from "./model-provider.js";
40
40
  import { modelRouteUrlRefusal } from "./model-route-url.js";
41
41
  import { httpUrlFlaws } from "@sema-agent/settings-schema";
42
42
  import { buildHttpUrlRefusal } from "./url-refusal.js";
43
- import { csvOf, envLaneTable, judgeModelRouteGap, mintedCheapId, readModelRouteEnv } from "./model-route-gap.js";
43
+ import { csvOf, envLaneTable, mintedCheapId, readModelRouteEnv } from "./model-route-gap.js";
44
44
  import { displayListEntry } from "./list-entry-display.js";
45
45
  import { buildDisplaySafeUrl, redactSecrets } from "./trace/redact.js";
46
46
  import { allowlistedEnv } from "./server-secret-env.js";
@@ -467,6 +467,12 @@ function parseNameListEnv(name, raw, opts) {
467
467
  }
468
468
  const ENV_VAR_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
469
469
  const ENV_NAME_ALLOWLIST_WITHHELD = "<withheld: entries are not echoed — a value pasted in place of a name can pass the name check>";
470
+ function ownCredentialPutBackProblem(name) {
471
+ const engine = inheritEnvPolicyProblem([name]);
472
+ return engine === undefined
473
+ ? undefined
474
+ : `this deployment's own credential — a put-back list hands the named variable back, as written, to the child the engine withheld it from (the engine refuses it on any allow list: ${engine})`;
475
+ }
470
476
  export function parseEnvNameAllowlist(knob, singleUserTurnkey) {
471
477
  const raw = process.env[knob];
472
478
  if (raw === undefined || raw === "")
@@ -480,7 +486,9 @@ export function parseEnvNameAllowlist(knob, singleUserTurnkey) {
480
486
  ? 'not an environment-variable name (letters, digits and "_", not starting with a digit)'
481
487
  : ENV_NAME_ALLOWLIST_KNOB_NAMES.has(seg.toUpperCase())
482
488
  ? `the name of a name-list knob (${[...ENV_NAME_ALLOWLIST_KNOB_NAMES].join(" / ")}: their raw text is withheld from every child process and sandbox; naming one would put that text back)`
483
- : undefined;
489
+ : spec.channel === "host-put-back"
490
+ ? ownCredentialPutBackProblem(seg)
491
+ : undefined;
484
492
  if (problem === undefined)
485
493
  return;
486
494
  throw new Error(`env ${knob}: entry #${i + 1} of ${segments.length} is ${problem}` +
@@ -684,7 +692,7 @@ function parseHooksTimeoutEnv() {
684
692
  return undefined;
685
693
  const n = parseNumOrFail("HOOKS_TIMEOUT_MS", raw);
686
694
  if (!Number.isInteger(n) || n < 0 || n > 2147483647) {
687
- throw new Error(`env HOOKS_TIMEOUT_MS="${raw}" must be an integer in [0, 2147483647] ms (0 = every hook seat expires immediately; unset = core's own default)`);
695
+ throw new Error(`env HOOKS_TIMEOUT_MS="${raw}" must be an integer in [0, 2147483647] ms (0 = a zero budget for every request-hook handler; unset = 600000)`);
688
696
  }
689
697
  return n;
690
698
  }
@@ -925,14 +933,14 @@ function parseModelDomain() {
925
933
  thinkingFormat: parseThinkingFormat(process.env.MODEL_THINKING_FORMAT),
926
934
  });
927
935
  const envCompat = provider === "anthropic" ? undefined : envCompatDeclared;
936
+ const modelCapability = { reasoning: parseBoolWord("MODEL_REASONING", process.env.MODEL_REASONING), vision: parseBoolWord("MODEL_VISION", process.env.MODEL_VISION) };
928
937
  const model = {
929
938
  id: modelId,
930
939
  name: modelId,
931
940
  api: provider === "anthropic" ? "anthropic-messages" : "openai-completions",
932
941
  provider,
933
942
  baseUrl: "",
934
- reasoning: boolEnv("MODEL_REASONING", true),
935
- input: boolEnv("MODEL_VISION", true) ? ["text", "image"] : ["text"],
943
+ ...mintCapabilityKeys(modelCapability),
936
944
  ...buildModelCostKey(buildCostOrAbsent({
937
945
  input: costEnv("MODEL_COST_INPUT", "unset"),
938
946
  output: costEnv("MODEL_COST_OUTPUT", "unset"),
@@ -983,7 +991,7 @@ function parseModelDomain() {
983
991
  ...model,
984
992
  id: cheapMintedId,
985
993
  name: cheapMintedId,
986
- input: ((v) => (v === undefined ? model.input : v ? ["text", "image"] : ["text"]))(parseBoolWord("MODEL_CHEAP_VISION", process.env.MODEL_CHEAP_VISION)),
994
+ ...mintCapabilityKeys({ reasoning: parseBoolWord("MODEL_CHEAP_REASONING", process.env.MODEL_CHEAP_REASONING), vision: parseBoolWord("MODEL_CHEAP_VISION", process.env.MODEL_CHEAP_VISION) }),
987
995
  ...buildModelCostKey(buildCostOrAbsent({
988
996
  input: costEnv("MODEL_CHEAP_COST_INPUT", "declares-zero"),
989
997
  output: costEnv("MODEL_CHEAP_COST_OUTPUT", "declares-zero"),
@@ -993,7 +1001,6 @@ function parseModelDomain() {
993
1001
  contextWindow: numEnvOr("MODEL_CHEAP_CONTEXT_WINDOW", model.contextWindow),
994
1002
  maxTokens: numEnvOr("MODEL_CHEAP_MAX_TOKENS", model.maxTokens),
995
1003
  ...(optFinitePositiveEnv("MODEL_CHEAP_CHARS_PER_TOKEN") !== undefined ? { charsPerToken: optFinitePositiveEnv("MODEL_CHEAP_CHARS_PER_TOKEN") } : {}),
996
- reasoning: parseBoolWord("MODEL_CHEAP_REASONING", process.env.MODEL_CHEAP_REASONING) ?? model.reasoning,
997
1004
  }
998
1005
  : undefined;
999
1006
  const mainAct = optFinitePositiveEnv("MODEL_AUTO_COMPACT_TOKENS");
@@ -1183,8 +1190,15 @@ function findUnmatchableToolNames(names, opts) {
1183
1190
  out.push({ name, guidance: uncompilable });
1184
1191
  continue;
1185
1192
  }
1186
- if (verdict !== undefined)
1193
+ if (verdict !== undefined) {
1187
1194
  out.push({ name, guidance: describeUnmatchableRuleName(verdict, subject) });
1195
+ continue;
1196
+ }
1197
+ const nearMiss = compileAllowList([subject], "deny", TOOL_NAME_ROSTER).inert.find((i) => i.reason === "near_miss");
1198
+ if (nearMiss?.currentName !== undefined) {
1199
+ const rest = name.startsWith(subject) ? name.slice(subject.length) : "";
1200
+ out.push({ name, guidance: inertRuleEntryGuidance({ ...nearMiss, currentName: `${nearMiss.currentName}${rest}` }) });
1201
+ }
1188
1202
  }
1189
1203
  return out;
1190
1204
  }
@@ -1192,9 +1206,10 @@ export function unmatchableToolNamesRefusal(source, names, judgment) {
1192
1206
  const bad = findUnmatchableToolNames(names, judgment);
1193
1207
  if (bad.length === 0)
1194
1208
  return undefined;
1209
+ const named = bad.slice(0, MAX_NAMED_INERT_ENTRIES).map((b) => `${displayListEntry(b.name)} → ${b.guidance}`).join("; ");
1195
1210
  const message = (`${source} has ${bad.length === 1 ? "an entry" : "entries"} that can never take effect — ${bad.length === 1 ? "it" : "each"} would never match a live tool or cannot be compiled into a rule ` +
1196
1211
  `(names are read exactly as written: no alias folding, no protocol prefix added): ` +
1197
- bad.map((b) => `${displayListEntry(b.name)} → ${b.guidance}`).join("; ")).replace(CONTROL_AND_BIDI_STRIP_RE, "");
1212
+ (bad.length > MAX_NAMED_INERT_ENTRIES ? `${named}; and ${bad.length - MAX_NAMED_INERT_ENTRIES} more` : named)).replace(CONTROL_AND_BIDI_STRIP_RE, "");
1198
1213
  return { message, names: bad.map((b) => b.name) };
1199
1214
  }
1200
1215
  const APPROVAL_GRANT_ENV = "APPROVAL_GRANT";
@@ -2454,6 +2469,11 @@ function k8sWorkspaceCache() {
2454
2469
  throw new Error(`env WORKSPACE_CACHE_MOUNT=${mount} overlaps the workspace mount ${workspace} (K8S_MOUNT_PATH) — the cache volume must sit OUTSIDE the workspace ` +
2455
2470
  "(the workspace is snapshotted between runs, the cache is not); pick a separate absolute path such as /cache");
2456
2471
  }
2472
+ const reserved = reservedMountCollision(mount);
2473
+ if (reserved !== undefined) {
2474
+ throw new Error(`env WORKSPACE_CACHE_MOUNT=${mount} collides with the reserved image directory ${reserved} (a volume at, under or above it hides what the sandbox image keeps there) — ` +
2475
+ `pick a separate absolute path such as /cache; reserved: ${WORKSPACE_CACHE_MOUNT_RESERVED.join(" ")}`);
2476
+ }
2457
2477
  return { mount, size };
2458
2478
  }
2459
2479
  export function loadConfig() {
@@ -2521,12 +2541,6 @@ export function loadConfig() {
2521
2541
  if (laneRequiredRefusal !== undefined) {
2522
2542
  throw new Error(laneRequiredRefusal);
2523
2543
  }
2524
- {
2525
- const routeGap = judgeModelRouteGap(process.env, { envLaneDispatchable: !isRosterGateArmed(integrations.webAdmin) });
2526
- if (routeGap.gap !== "none") {
2527
- throw new Error(routeGap.reason);
2528
- }
2529
- }
2530
2544
  EXEC_LANE_NOTICE = buildExecLaneNotice(orchestration.remoteExec);
2531
2545
  return attachConfigGroups({
2532
2546
  ...store,
@@ -62,7 +62,7 @@ export declare function asInstructionKind(v: string): DeviceInstructionKind | nu
62
62
  * 结果帧的错误码闭集 = core 的 `FileErrorCode ∪ ExecutionErrorCode`(§5.1「error code 全闭集」:
63
63
  * 未知值映射为协议错误而非透传 string)。`satisfies` 保证这里没有 core 不认识的词。
64
64
  */
65
- export declare const DEVICE_OUTCOME_ERROR_CODES: readonly ["aborted", "already_exists", "auth_failed", "callback_error", "invalid", "is_directory", "not_directory", "not_found", "not_supported", "outcome_unknown", "permission_denied", "precondition_failed", "shell_unavailable", "spawn_error", "suspended", "target_unavailable", "timeout", "transport_lost", "unknown"];
65
+ export declare const DEVICE_OUTCOME_ERROR_CODES: readonly ["aborted", "already_exists", "auth_failed", "callback_error", "invalid", "is_directory", "liveness_no_output", "not_directory", "not_found", "not_supported", "outcome_unknown", "permission_denied", "precondition_failed", "shell_unavailable", "spawn_error", "suspended", "target_unavailable", "timeout", "transport_lost", "unknown"];
66
66
  export type DeviceOutcomeErrorCode = (typeof DEVICE_OUTCOME_ERROR_CODES)[number];
67
67
  /**
68
68
  * **编译期**对账的另一半:core 往 `FileErrorCode`/`ExecutionErrorCode` 加一个词而本表没跟 ⇒ `Exclude`
@@ -49,6 +49,7 @@ export const DEVICE_OUTCOME_ERROR_CODES = [
49
49
  "callback_error",
50
50
  "invalid",
51
51
  "is_directory",
52
+ "liveness_no_output",
52
53
  "not_directory",
53
54
  "not_found",
54
55
  "not_supported",
@@ -19,6 +19,13 @@ export interface ElicitationFrame {
19
19
  * no core-stream anchor, so no `eventId` (absence is honest, not an omission); this is the frame's own time
20
20
  * coordinate instead, same posture as the stream-approval frames' `serverNowMs`. */
21
21
  serverNowMs?: number;
22
+ /** "elicitation" only (additive; the same window pair `question` carries): the coordinator's OWN answer window —
23
+ * at expiry the ask releases as `decline`. Minted from the SAME `ttlMs` the `setTimeout` below arms (one source), so
24
+ * a form replayed from the ledger can be judged still-waiting (no `elicitation_complete` with this id ∧
25
+ * `expiresAtMs` not reached) or lapsed even when the close row never landed (a lost write, a crashed replica). */
26
+ expiresInMs?: number;
27
+ /** "elicitation" only: `serverNowMs + expiresInMs` — the absolute deadline on the server's clock. */
28
+ expiresAtMs?: number;
22
29
  }
23
30
  /** The per-run context `onElicit` recovers via ALS. `emit` delivers a frame to the run's live stream;
24
31
  * `abortSignal` (the run's own cancel signal) lets a run-abort promptly cancel an elicitation parked awaiting a
@@ -112,18 +112,33 @@ export class ElicitationCoordinator {
112
112
  signal?.addEventListener("abort", onAbort, { once: true });
113
113
  ctx.abortSignal?.addEventListener("abort", onAbort, { once: true });
114
114
  this.pending.set(id, { settle, owner: ctx.owner, taskId: ctx.taskId });
115
- try {
116
- await ctx.emit({ type: "elicitation", elicitationId: id, mcpServerName: req.server, message, ...(requestedSchema !== undefined ? { requestedSchema } : {}), mode: "form", serverNowMs: this.now() });
115
+ const emitted = (async () => {
116
+ const now = this.now();
117
+ return ctx.emit({ type: "elicitation", elicitationId: id, mcpServerName: req.server, message, ...(requestedSchema !== undefined ? { requestedSchema } : {}), mode: "form", serverNowMs: now, expiresInMs: this.throttle.ttlMs, expiresAtMs: now + this.throttle.ttlMs });
118
+ })().then(() => "ok", () => "failed");
119
+ const delivery = await Promise.race([emitted, answerP.then(() => "stalled")]);
120
+ if (delivery === "ok") {
117
121
  rc.total += 1;
118
122
  rc.lastByServer.set(req.server, t);
119
123
  }
120
- catch {
124
+ else if (delivery === "failed") {
121
125
  recordFailOpen("server.elicitation.open-frame-undelivered", `elicitation=${id} server=${req.server}`);
122
126
  settle({ action: "decline" });
123
127
  }
124
128
  const answer = await answerP;
125
- void Promise.resolve()
126
- .then(() => ctx.emit({ type: "elicitation_complete", elicitationId: id, mcpServerName: req.server, action: answer.action, serverNowMs: this.now() }))
129
+ void emitted
130
+ .then((result) => {
131
+ if (result === "failed") {
132
+ if (delivery === "stalled")
133
+ recordFailOpen("server.elicitation.open-frame-undelivered", `elicitation=${id} server=${req.server}`);
134
+ return undefined;
135
+ }
136
+ if (delivery === "stalled") {
137
+ rc.total += 1;
138
+ rc.lastByServer.set(req.server, t);
139
+ }
140
+ return ctx.emit({ type: "elicitation_complete", elicitationId: id, mcpServerName: req.server, action: answer.action, serverNowMs: this.now() });
141
+ })
127
142
  .catch(() => recordFailOpen("server.elicitation.complete-breadcrumb-dropped", `elicitation=${id}`));
128
143
  return answer;
129
144
  };
@@ -10,6 +10,12 @@
10
10
  * 带外凭据(e2b / docker / k8s 车道本来就是多租户 fleet 的主形),与 LSP 那条「本机子进程」的形不同;多租户下起服说一句。
11
11
  * · `BAKE_ENV_ALLOW`(S-684 残余,7.103.0)由 **bake-runner 进程**读(构建宿主守护进程:没有主体、没有租户 ⇒ 没有姿态列,
12
12
  * 不进 {@link describeAllowlistPostures} 的姿态句)。它与服务侧四只旋钮同一只解析器、同一只「点名放行」谓词、同一条「原文按凭据类」律。
13
+ * · `channel` = 这张名单**交给谁、在谁的减法之上**(闭集两词,解析器按它定「不许点哪些名」):
14
+ * - `host-put-back`(`LSP_ENV_ALLOW` / `BAKE_ENV_ALLOW`)—— 剥后放回形:宿主子进程的 env 先经唯一组合(引擎扣掉本服务自有凭据 + 形状剥),
15
+ * 名单点到的键再从本进程环境**原样**取回叠上去。点到本服务自有凭据名 = 把引擎刚扣下的那枚交回去 ⇒ 起服拒,判官 = 引擎同一只
16
+ * (`inheritEnvPolicyProblem`,读起服声明;与引擎拒嵌入方白名单同句)。
17
+ * - `sandbox-grant`(三只沙箱名单)—— 沙箱 env 的唯一来源(沙箱不从本进程继承任何东西),部署方显式交出的带外凭据(S-715 照转发);
18
+ * 本列不在「自有凭据」律的射程里,只拒点名名单型旋钮(原文按凭据类)。
13
19
  * 表是 `Record<旋钮, …>`:闭集加一只旋钮而不补行 = 编译红;行形随读它的进程定(服务进程 ⇒ 必须写姿态列)。
14
20
  *
15
21
  * 🔴 **姿态列只在这里写一次**([ref];7.101.0 合并复审 O9):凡要对人说「多租户下哪只旋钮忽略、哪只照转发」的句子,一律取
@@ -28,14 +34,18 @@ export type EnvNameAllowlistPosture = {
28
34
  readonly kind: "ignored";
29
35
  readonly why: string;
30
36
  };
31
- /** 服务侧旋钮一行:拒句示例 + 多租户姿态。 */
37
+ /** 名单交给谁、在谁的减法之上(闭集;规则见表头注 `channel` 一条)。 */
38
+ export type EnvNameAllowlistChannel = "host-put-back" | "sandbox-grant";
39
+ /** 服务侧旋钮一行:拒句示例 + 交付形 + 多租户姿态。 */
32
40
  export interface ServerEnvNameAllowlistKnobRow {
33
41
  readonly example: string;
42
+ readonly channel: EnvNameAllowlistChannel;
34
43
  readonly multiTenant: EnvNameAllowlistPosture;
35
44
  }
36
- /** runner 旋钮一行:只有拒句示例(没有姿态可言)。 */
45
+ /** runner 旋钮一行:拒句示例 + 交付形(没有姿态可言)。 */
37
46
  export interface RunnerEnvNameAllowlistKnobRow {
38
47
  readonly example: string;
48
+ readonly channel: EnvNameAllowlistChannel;
39
49
  }
40
50
  export type EnvNameAllowlistKnobTable = {
41
51
  readonly [K in EnvNameAllowlistKnob]: K extends ServerEnvNameAllowlistKnob ? ServerEnvNameAllowlistKnobRow : RunnerEnvNameAllowlistKnobRow;
@@ -1,12 +1,13 @@
1
1
  export const ENV_NAME_ALLOWLIST_KNOBS = {
2
2
  LSP_ENV_ALLOW: {
3
3
  example: "LSP_ENV_ALLOW=NPM_TOKEN,CARGO_REGISTRIES_MY_REG_TOKEN",
4
+ channel: "host-put-back",
4
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" },
5
6
  },
6
- E2B_SANDBOX_ENV: { example: "E2B_SANDBOX_ENV=GIT_TOKEN,NPM_TOKEN", multiTenant: { kind: "honored" } },
7
- DOCKER_SANDBOX_ENV: { example: "DOCKER_SANDBOX_ENV=GIT_TOKEN,NPM_TOKEN", multiTenant: { kind: "honored" } },
8
- K8S_SANDBOX_ENV: { example: "K8S_SANDBOX_ENV=GIT_TOKEN,NPM_TOKEN", multiTenant: { kind: "honored" } },
9
- BAKE_ENV_ALLOW: { example: "BAKE_ENV_ALLOW=REGISTRY_PASSWORD,NPM_TOKEN" },
7
+ E2B_SANDBOX_ENV: { example: "E2B_SANDBOX_ENV=GIT_TOKEN,NPM_TOKEN", channel: "sandbox-grant", multiTenant: { kind: "honored" } },
8
+ DOCKER_SANDBOX_ENV: { example: "DOCKER_SANDBOX_ENV=GIT_TOKEN,NPM_TOKEN", channel: "sandbox-grant", multiTenant: { kind: "honored" } },
9
+ K8S_SANDBOX_ENV: { example: "K8S_SANDBOX_ENV=GIT_TOKEN,NPM_TOKEN", channel: "sandbox-grant", multiTenant: { kind: "honored" } },
10
+ BAKE_ENV_ALLOW: { example: "BAKE_ENV_ALLOW=REGISTRY_PASSWORD,NPM_TOKEN", channel: "host-put-back" },
10
11
  };
11
12
  export const ENV_NAME_ALLOWLIST_KNOB_NAMES = new Set(Object.keys(ENV_NAME_ALLOWLIST_KNOBS));
12
13
  const POSTURE_PHRASE = {
@@ -12,8 +12,10 @@
12
12
  * 是它报的那一界。
13
13
  *
14
14
  * 与 core 远端契约(`ExecStreamOptions.readTimeoutMs`:「缺省也 SHOULD 有活性界,一条命令不得等到环境死」)的对齐:
15
- * 说了墙钟的命令被墙钟兜住,不会无限等;两界都没说的命令,在有活性界的车道(k8s / e2b)上仍由它兜底。切断码沿用 core 的 `timeout`(core 远端码表
16
- * 把墙钟与活性两种超界都归这一词);两者靠句子区分 —— 独立的活性码属于 core 的码表。
15
+ * 说了墙钟的命令被墙钟兜住,不会无限等;两界都没说的命令,在有活性界的车道(k8s / e2b)上仍由它兜底。**切断码按触发的那一界**(core 7.52.0 #1795:
16
+ * 两套执行码闭集各有一词):墙钟 ⇒ `timeout`;静默界(调用方的 `readTimeoutMs` 或车道活性界)⇒ `liveness_no_output`,带窗口秒数 `noOutputSec`(车道的界 /
17
+ * 调用方说的静默界,从不是请求的预算)—— 两者解释自己用的是两个数,消费方(core 的 Bash 工具:「no output for N s」对「timed out after N s」)按码分。
18
+ * 静默切断的码、句、秒数只在 {@link buildLivenessCut} 一处铸,六车道同读。
17
19
  *
18
20
  * 不在本律里的界(adapter 自己的上限,不是调用方说的话,不关活性界):k8s 文件读写的数据上限 `dataTimeoutMs`、e2b 交给
19
21
  * 供应商的沙箱寿命上限。adapter 自己的整段数据搬运(k8s 快照 tar 上 / 下)天生静默,它们**自己说**一个墙钟(数据上限),
@@ -64,6 +66,16 @@ export declare function firstBoundOf(bounds: CommandBounds): {
64
66
  readonly ms: number;
65
67
  readonly cut: "wall" | LivenessBound;
66
68
  } | undefined;
67
- /** 活性切断的句子 —— 六条车道(host / e2b / k8s / ssh / adb / local-docker)唯一铸点(车道兜底的界点名旋钮与出路;调用方自己说的界点名那一参数)。 */
69
+ /**
70
+ * 🔴 **一次静默切断 —— 唯一铸点**(六条车道 host / e2b / k8s / ssh / adb / local-docker 同读;纯数据,车道用它构造自己那一型的错误):
71
+ * 码恒为 `liveness_no_output`(core 7.52.0 #1795;墙钟切断照旧 `timeout`,不经本函数),句子 = {@link livenessCutMessage},`noOutputSec` = 静默窗口的整秒数
72
+ * (core `ExecutionError` 第五构造参;core 读它时向下取整、不足 1 秒不说 —— 本函数同读:不足 1 秒的窗口不带这一位)。远端流式错误(`RemoteExecutionError`)没有这一位的座,只带码与句。
73
+ */
74
+ export declare function buildLivenessCut(bound: LivenessBound): {
75
+ readonly code: "liveness_no_output";
76
+ readonly message: string;
77
+ readonly noOutputSec?: number;
78
+ };
79
+ /** 活性切断的句子 —— {@link buildLivenessCut} 的句子半(车道兜底的界点名旋钮与出路;调用方自己说的界点名那一参数)。车道不直调它:码与句一处铸。 */
68
80
  export declare function livenessCutMessage(bound: LivenessBound): string;
69
81
  //# sourceMappingURL=exec-bounds.d.ts.map
@@ -26,6 +26,10 @@ function spoken(ms) {
26
26
  return `${ms} ms`;
27
27
  return ms % 1000 === 0 ? `${ms / 1000} s` : `${(ms / 1000).toFixed(1)} s`;
28
28
  }
29
+ export function buildLivenessCut(bound) {
30
+ const sec = Math.floor(bound.ms / 1000);
31
+ return { code: "liveness_no_output", message: livenessCutMessage(bound), ...(sec >= 1 ? { noOutputSec: sec } : {}) };
32
+ }
29
33
  export function livenessCutMessage(bound) {
30
34
  switch (bound.setBy) {
31
35
  case "lane":
@@ -58,8 +58,8 @@ export interface ExecutionLaneCaps {
58
58
  * `lane === undefined || lane === "host"` 的同义形,分叉过就是记忆边界判错盘)。读本位的真装配点:
59
59
  * `boot/deferred-sandbox-path-env.ts` 的 `isSandboxPathAdjudicationLane`(resolve-spec 写门 / parked 赎回腿 /
60
60
  * 执行环境装配三处的唯一属主)、`memory-scope.ts` 的 `memoryEngineRemoteLanePosture`、
61
- * `boot/memory-boundary.ts` 的 `buildMemoryBoundaryLaneFacts`(stores)、`capabilities/memory-notice.ts` 的
62
- * `buildNoticeLaneFacts`(resolve-spec)。⚠️ `in-process` 在本位上是 YES(hooks/进程内读确实在本机盘上),
61
+ * `boot/memory-boundary.ts` 的 `buildMemoryBoundaryLaneFacts`(stores)。(「本会话没有持久记忆」的披露归引擎判、引擎渲染 ——
62
+ * 目录条目 `core/memory.no-persistent-store`,本仓只交 spec 上的事实,不再读本位做判别。)⚠️ `in-process` 在本位上是 YES(hooks/进程内读确实在本机盘上),
63
63
  * 但它**没有手** —— 问「手在不在本机盘上」要读 {@link handsOnWorkerFilePlane},不是只读本位。 */
64
64
  readonly hostFilePlane: LaneCapability;
65
65
  /** core 的 `isRemoteExecutionEnv` 对本车道的判决(鸭子类型,**含 host**)= core 拿没拿到执行环境 = 手带挂没挂。
@@ -297,4 +297,11 @@ export interface LaneHomeDeployment {
297
297
  * 认不出的车道 ⇒ `undefined`(调用方 fail-closed)。生产链上不可达:`loadConfig` 的 [ref] 拒启门先咬。
298
298
  */
299
299
  export declare function executionLaneHomeDir(deployment: LaneHomeDeployment): string | undefined;
300
+ /**
301
+ * 「这条部署的执行车道**有手**、而家目录答不出」时起服那一行的 `note`(纯字符串 ⇒ `build*`);否则 `undefined`(不出这一行)。
302
+ * 判据只读 {@link executionLaneHomeDir}(家目录的唯一属主)与能力表 `coreRemoteExecutionEnv` 位(有没有手):不另写车道清单。
303
+ * 代价如实:引擎 7.52.0 起家锚拒读行放不下 ⇒ 每一次泄内容的递归读在全 shell 面强制问人(allow / 模式 / bypass 都放不掉)、只读面拒;`~/` 形规则在下单时
304
+ * 就被 422 拒。出路只有一条:声明执行环境的家目录(`$HOME` 读出来的那个绝对路径)。这句话陈述的是事实,不是告警 —— 要它消失就声明家目录。
305
+ */
306
+ export declare function buildUndeclaredHomeNote(deployment: LaneHomeDeployment): string | undefined;
300
307
  //# sourceMappingURL=execution-lane-caps.d.ts.map
@@ -261,4 +261,15 @@ export function executionLaneHomeDir(deployment) {
261
261
  return undefined;
262
262
  }
263
263
  }
264
+ export function buildUndeclaredHomeNote(deployment) {
265
+ if (executionLaneHomeDir(deployment) !== undefined)
266
+ return undefined;
267
+ const lane = executionLaneOf(deployment.remoteExec?.provider);
268
+ if (lane === undefined || executionLaneCaps(lane).coreRemoteExecutionEnv !== "supported")
269
+ return undefined;
270
+ return (`the ${lane} lane declares no home for its execution environment (REMOTE_EXEC_HOME_DIR is unset, and on this lane the home belongs to the image / target user): ` +
271
+ `the engine cannot place its home-anchored read-deny rows, so every contents-disclosing recursive read (grep -r, rg, git grep, tar c, …) asks a person on the full shell — ` +
272
+ `no allow rule, mode or bypass releases that question — and is refused on the read-only face, so unattended tasks cannot search code; "~/" permission rules are refused at submission. ` +
273
+ `Declare the home: REMOTE_EXEC_HOME_DIR=<the absolute path the environment's $HOME reads>`);
274
+ }
264
275
  //# sourceMappingURL=execution-lane-caps.js.map
@@ -0,0 +1,86 @@
1
+ /**
2
+ * 引擎的 `classic.*` 站 —— 本仓挂 handler 的唯一入口(core 7.52.0 起扩展点 = mods 注册,`Hooks` 记录退役)。
3
+ *
4
+ * 两件事只写在这里:
5
+ * ① **事件名 → { `e` 型, 答案型 }**:core 逐个导出了每站的 `e` 型与答案型,但没有导出二者的映射(宿主侧配对是今天的唯一读法)。
6
+ * 这张对位表是那一配对的唯一一份;core 导出映射型的那一版,本表改读它、删掉手写的十一行。
7
+ * ② **handler 怎么挂**:链成员「无意见 ⇒ `next(e)`」(链 handler 返回 `undefined` 是站点违约,refuse 站上即 fail-closed 拒),
8
+ * 观察者「恒返回 `undefined`」(观察者的判词不采纳、被引擎报告)。两条都在 {@link hangClassic} / {@link observeClassic} 里成形,
9
+ * 调用方只写「这一站我答什么」或「这一站我看什么」,不再各自记得这两条。
10
+ *
11
+ * 站的集合 = 引擎事件表里有站的 `classic.*` 名(一条钉从 `MOD_EVENT_TABLE` 派生对拍,不手抄第二份)。
12
+ * 观察站(`StopFailure` / `PostCompact` / `PermissionDenied`)只许观察者:答案形是「无」,core 的迁移配方要求挂 `{ observe: true }`。
13
+ */
14
+ import type { EngineDollar, On, PermissionDeniedPayload, PostCompactEvent, PostToolBatchEvent, PostToolBatchResult, PostToolUseEvent, PostToolUseFailureEvent, PostToolUseFailureResult, PostToolUseResult, PreCompactEvent, PreCompactResult, PreToolUseEvent, PreToolUseResult, StopEvent, StopFailureEvent, StopHookResult, UserPromptSubmitEvent, UserPromptSubmitResult } from "@sema-agent/core";
15
+ /** 每一站的 `e` 型与答案型(答案 `void` = 观察站)。 */
16
+ export interface ClassicStationTypes {
17
+ "classic.PreToolUse": {
18
+ e: PreToolUseEvent;
19
+ answer: PreToolUseResult;
20
+ };
21
+ "classic.PostToolUse": {
22
+ e: PostToolUseEvent;
23
+ answer: PostToolUseResult;
24
+ };
25
+ "classic.PostToolUseFailure": {
26
+ e: PostToolUseFailureEvent;
27
+ answer: PostToolUseFailureResult;
28
+ };
29
+ "classic.PostToolBatch": {
30
+ e: PostToolBatchEvent;
31
+ answer: PostToolBatchResult;
32
+ };
33
+ "classic.UserPromptSubmit": {
34
+ e: UserPromptSubmitEvent;
35
+ answer: UserPromptSubmitResult;
36
+ };
37
+ "classic.Stop": {
38
+ e: StopEvent;
39
+ answer: StopHookResult;
40
+ };
41
+ "classic.SubagentStop": {
42
+ e: StopEvent;
43
+ answer: StopHookResult;
44
+ };
45
+ "classic.StopFailure": {
46
+ e: StopFailureEvent;
47
+ answer: void;
48
+ };
49
+ "classic.PreCompact": {
50
+ e: PreCompactEvent;
51
+ answer: PreCompactResult;
52
+ };
53
+ "classic.PostCompact": {
54
+ e: PostCompactEvent;
55
+ answer: void;
56
+ };
57
+ "classic.PermissionDenied": {
58
+ e: PermissionDeniedPayload;
59
+ answer: void;
60
+ };
61
+ }
62
+ export type ClassicStation = keyof ClassicStationTypes;
63
+ /** 每一站能挂什么:`chain` = 链成员(会作答)与观察者都可;`observe` = 只许观察者。 */
64
+ export declare const CLASSIC_STATION_ROLE: {
65
+ readonly "classic.PreToolUse": "chain";
66
+ readonly "classic.PostToolUse": "chain";
67
+ readonly "classic.PostToolUseFailure": "chain";
68
+ readonly "classic.PostToolBatch": "chain";
69
+ readonly "classic.UserPromptSubmit": "chain";
70
+ readonly "classic.Stop": "chain";
71
+ readonly "classic.SubagentStop": "chain";
72
+ readonly "classic.StopFailure": "observe";
73
+ readonly "classic.PreCompact": "chain";
74
+ readonly "classic.PostCompact": "observe";
75
+ readonly "classic.PermissionDenied": "observe";
76
+ };
77
+ /** 一站的 handler 体:读 `e`,答这一站的答案;`undefined` = 无意见(链成员由 {@link hangClassic} 交给 `next(e)`)。 */
78
+ export type ClassicAnswer<K extends ClassicStation> = (e: ClassicStationTypes[K]["e"]) => Promise<ClassicStationTypes[K]["answer"] | undefined>;
79
+ /**
80
+ * 按站的角色挂一只 handler:链站 ⇒ 链成员 `(await answer(e)) ?? next(e)`;观察站 ⇒ 观察者(体照跑、恒返回 `undefined`)。
81
+ * `e` 的型由 {@link ClassicStationTypes} 给(引擎交来的是本站的 `e`;配对见头注 ①)。
82
+ */
83
+ export declare function hangClassic<K extends ClassicStation>(on: On<EngineDollar>, station: K, answer: ClassicAnswer<K>): void;
84
+ /** 挂一只观察者(任何站都可):拿分离副本、不进链、恒返回 `undefined`。 */
85
+ export declare function observeClassic<K extends ClassicStation>(on: On<EngineDollar>, station: K, watch: (e: ClassicStationTypes[K]["e"]) => void | Promise<void>): void;
86
+ //# sourceMappingURL=classic-stations.d.ts.map
@@ -0,0 +1,27 @@
1
+ export const CLASSIC_STATION_ROLE = {
2
+ "classic.PreToolUse": "chain",
3
+ "classic.PostToolUse": "chain",
4
+ "classic.PostToolUseFailure": "chain",
5
+ "classic.PostToolBatch": "chain",
6
+ "classic.UserPromptSubmit": "chain",
7
+ "classic.Stop": "chain",
8
+ "classic.SubagentStop": "chain",
9
+ "classic.StopFailure": "observe",
10
+ "classic.PreCompact": "chain",
11
+ "classic.PostCompact": "observe",
12
+ "classic.PermissionDenied": "observe",
13
+ };
14
+ export function hangClassic(on, station, answer) {
15
+ if (CLASSIC_STATION_ROLE[station] === "observe") {
16
+ observeClassic(on, station, async (e) => void (await answer(e)));
17
+ return;
18
+ }
19
+ on(station, async (_$, e, next) => (await answer(e)) ?? next(e));
20
+ }
21
+ export function observeClassic(on, station, watch) {
22
+ on(station, async (_$, e) => {
23
+ await watch(e);
24
+ return undefined;
25
+ }, { observe: true });
26
+ }
27
+ //# sourceMappingURL=classic-stations.js.map
@@ -1,6 +1,6 @@
1
1
  import type { ModelKeyRef } from "../key-resolver.js";
2
2
  import type { ServiceConfig } from "../config-types.js";
3
- import type { HookLlmCall } from "./hook-runner.js";
3
+ import type { HookLlmCall, HookLlmFailureCode } from "./hook-runner.js";
4
4
  /**
5
5
  * hookLlm(prompt 条目/session titler 的模型载体)= 直连一次非流式 completion,从 main.ts 抽出成可注入
6
6
  * 单元(fetchImpl/keyResolver 可假),因为这条 wire 在每个默认部署上都活(titler),必须可单测。
@@ -16,13 +16,13 @@ import type { HookLlmCall } from "./hook-runner.js";
16
16
  *
17
17
  * 🔴 **选线 = 引擎主路由同一只判词**(S-1630):「这只模型走 openai-completions 还是 anthropic-messages」不是本面的事,
18
18
  * 是引擎主路由的事 —— `brain.ts` 按 `model.provider` 在「anthropic 路由(仅当 ANTHROPIC 凭据把它装上)/ 网关栈」之间选,
19
- * 路由没装时整台机器只有网关这一只 brain,**连 `provider:"anthropic"` 的模型也落网关**(`dispatchBrainLane` 的合取,
19
+ * 路由没装时整台机器只有网关这一只 brain,**连 `provider:"anthropic"` 的模型也落网关**(判词 `brainLaneFor` = 引擎 `brainLaneOf` 对装上的路由表的答案,
20
20
  * 端点判官 / 降级腿 / 启动摘要读的是同一只)。本面此前自己按 `provider === "anthropic"` / `api === "anthropic-messages"`
21
21
  * 字面判线 ⇒ 在 `MODEL_PROVIDER=anthropic` 而只配了网关的部署上,主请求去网关、标题与 hooks 的 llm 面却要找一条没装的
22
22
  * anthropic 路由,整条拒发(零请求,只落 fail-open 标签)。现在本面只问那一只判词,不留第二个读法 —— 含 `api` 词:
23
23
  * 引擎不按 `api` 选线(core 的 `createRoutingBrain` 缺省按 `provider` 键),settings-schema 的 `ModelEntry` 又强制两个词同真同假。
24
- * (core 目前只导出 `createRoutingBrain` 这个组合子,没有「给定模型与已装路由 → 哪条腿 / 哪个根」的判官;它导出之日,
25
- * `dispatchBrainLane` 连同本调用点一并改为问它。)
24
+ * (S-1630 的 (a) 路已兑现:core 7.53.0 #1842 根导出了那只判官 `brainLaneOf(model, routes)` —— `createRoutingBrain` 对每个请求问的就是它;
25
+ * 本仓自写的合取 `dispatchBrainLane` 随之退役,本调用点与另三处一并改问它。)
26
26
  */
27
27
  export type HookModelPick = {
28
28
  ok: true;
@@ -30,9 +30,12 @@ export type HookModelPick = {
30
30
  providerModelId: string;
31
31
  baseUrl: string;
32
32
  api: "openai-completions" | "anthropic-messages";
33
- } | {
33
+ }
34
+ /** 选不出来的那一臂自带失败码(S-1635):两个载体(prompt 直连 / agent 子代理)共用这一只选模闸,同一只判词同一个码。 */
35
+ | {
34
36
  ok: false;
35
37
  error: string;
38
+ code: Extract<HookLlmFailureCode, "model_unresolved">;
36
39
  };
37
40
  /**
38
41
  * 🔴 **hook 失败展示文本的唯一铸点**(S-494;`build*` = 返回纯数据的一只纯函数)。