@sema-agent/server 7.132.0 → 7.134.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 (473) hide show
  1. package/MIGRATION.md +353 -0
  2. package/README.md +8 -9
  3. package/README.zh-CN.md +7 -6
  4. package/USAGE.md +301 -64
  5. package/deploy/sema-up/README.md +35 -1
  6. package/deploy/sema-up/chart/Chart.yaml +1 -1
  7. package/deploy/sema-up/chart/templates/NOTES.txt +15 -0
  8. package/deploy/sema-up/chart/templates/_helpers.tpl +129 -0
  9. package/deploy/sema-up/chart/templates/sealed-key.yaml +24 -0
  10. package/deploy/sema-up/chart/templates/server-v4pro.yaml +19 -2
  11. package/deploy/sema-up/chart/templates/server.yaml +19 -2
  12. package/deploy/sema-up/chart/values-full-single.yaml +5 -1
  13. package/deploy/sema-up/chart/values.yaml +34 -0
  14. package/deploy/sema-up/stack/compose.yaml +3 -0
  15. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
  16. package/dist/adoption/plan.d.ts +3 -2
  17. package/dist/adoption/plan.js +7 -5
  18. package/dist/adoption/runner.js +3 -10
  19. package/dist/adoption/sql.d.ts +3 -2
  20. package/dist/adoption/sql.js +3 -5
  21. package/dist/adoption/wire.d.ts +4 -1
  22. package/dist/adoption/wire.js +1 -0
  23. package/dist/approval-ask-audit-store.d.ts +32 -14
  24. package/dist/approval-ask-audit-store.js +272 -74
  25. package/dist/approval-ask-machine.d.ts +15 -0
  26. package/dist/approval-ask-machine.js +6 -0
  27. package/dist/approval-ask-retention.d.ts +136 -0
  28. package/dist/approval-ask-retention.js +102 -0
  29. package/dist/approval-card.d.ts +83 -23
  30. package/dist/approval-card.js +45 -15
  31. package/dist/approval-content-kind.d.ts +5 -2
  32. package/dist/approval-content-kind.js +16 -3
  33. package/dist/approval-deny-reasons.d.ts +1 -1
  34. package/dist/approval-gate-currency.d.ts +72 -0
  35. package/dist/approval-gate-currency.js +94 -0
  36. package/dist/approval.d.ts +15 -0
  37. package/dist/approval.js +55 -17
  38. package/dist/audit.d.ts +27 -10
  39. package/dist/audit.js +12 -16
  40. package/dist/bake-runner/main.js +3 -2
  41. package/dist/boot/coordinators.d.ts +6 -1
  42. package/dist/boot/coordinators.js +6 -3
  43. package/dist/boot/deferred-sandbox-path-env.js +1 -1
  44. package/dist/boot/execution-env.js +9 -7
  45. package/dist/boot/execution-lane.js +11 -0
  46. package/dist/boot/leader.d.ts +2 -0
  47. package/dist/boot/leader.js +4 -1
  48. package/dist/boot/memory-boundary.js +2 -2
  49. package/dist/boot/memory-consolidation.d.ts +5 -4
  50. package/dist/boot/memory-consolidation.js +7 -6
  51. package/dist/boot/org-delivery.d.ts +28 -0
  52. package/dist/boot/org-delivery.js +20 -0
  53. package/dist/boot/read-deny-anchor-audit.js +2 -2
  54. package/dist/boot/reapers.d.ts +3 -0
  55. package/dist/boot/reapers.js +21 -1
  56. package/dist/boot/resolve-spec.d.ts +3 -0
  57. package/dist/boot/resolve-spec.js +60 -81
  58. package/dist/boot/runner-deps.d.ts +18 -5
  59. package/dist/boot/runner-deps.js +10 -0
  60. package/dist/boot/session-faces.d.ts +1 -0
  61. package/dist/boot/session-faces.js +4 -2
  62. package/dist/boot/stage-02-web-admin-pull.js +4 -1
  63. package/dist/boot/stage-06-runners.d.ts +6 -3
  64. package/dist/boot/stage-06-runners.js +20 -4
  65. package/dist/boot/stage-07-capability-layer.d.ts +4 -1
  66. package/dist/boot/stage-07-capability-layer.js +24 -3
  67. package/dist/boot/stage-08-reapers.d.ts +4 -1
  68. package/dist/boot/stage-08-reapers.js +2 -2
  69. package/dist/boot/stage-09-leader.d.ts +5 -1
  70. package/dist/boot/stage-09-leader.js +2 -2
  71. package/dist/boot/stage-10-http-server.d.ts +5 -1
  72. package/dist/boot/stage-10-http-server.js +6 -6
  73. package/dist/boot/stores.d.ts +8 -0
  74. package/dist/boot/stores.js +10 -14
  75. package/dist/boot/web-admin.d.ts +10 -0
  76. package/dist/boot/web-admin.js +162 -65
  77. package/dist/boot/workflow-orchestration.d.ts +2 -0
  78. package/dist/boot/workflow-orchestration.js +2 -1
  79. package/dist/brain.js +8 -3
  80. package/dist/breaker-key.d.ts +6 -0
  81. package/dist/breaker-key.js +29 -0
  82. package/dist/budget.js +5 -1
  83. package/dist/caller-text-echo.d.ts +11 -6
  84. package/dist/caller-text-echo.js +10 -12
  85. package/dist/canonical-json.d.ts +2 -41
  86. package/dist/canonical-json.js +2 -13
  87. package/dist/capabilities/center-plugins.d.ts +7 -0
  88. package/dist/capabilities/center-plugins.js +1 -1
  89. package/dist/capabilities/composite-members.d.ts +1 -1
  90. package/dist/capabilities/composite-members.js +1 -1
  91. package/dist/capabilities/execution-lane.js +2 -2
  92. package/dist/capabilities/hands-lane.d.ts +21 -0
  93. package/dist/capabilities/hands-lane.js +10 -0
  94. package/dist/capabilities/mcp-probe.d.ts +36 -4
  95. package/dist/capabilities/mcp-probe.js +29 -6
  96. package/dist/capabilities/scenarios.d.ts +63 -7
  97. package/dist/capabilities/scenarios.js +39 -7
  98. package/dist/capability-facts.d.ts +36 -4
  99. package/dist/capability-facts.js +30 -4
  100. package/dist/center-config-tier.d.ts +69 -0
  101. package/dist/center-config-tier.js +42 -0
  102. package/dist/checkpoint-ctx-seal-m28.d.ts +42 -0
  103. package/dist/checkpoint-ctx-seal-m28.js +19 -0
  104. package/dist/checkpoint-identity.d.ts +16 -0
  105. package/dist/checkpoint-identity.js +19 -0
  106. package/dist/config-catalog.d.ts +17 -10
  107. package/dist/config-catalog.js +43 -28
  108. package/dist/config-d-migration.d.ts +3 -1
  109. package/dist/config-d-migration.js +2 -2
  110. package/dist/config-dir-trust.d.ts +114 -0
  111. package/dist/config-dir-trust.js +388 -0
  112. package/dist/config-invariants.d.ts +18 -5
  113. package/dist/config-invariants.js +35 -3
  114. package/dist/config-provider.d.ts +6 -1
  115. package/dist/config-provider.js +6 -2
  116. package/dist/config-types.d.ts +71 -14
  117. package/dist/config-types.js +8 -0
  118. package/dist/config.d.ts +13 -0
  119. package/dist/config.js +121 -59
  120. package/dist/delegated-session-owner.d.ts +185 -0
  121. package/dist/delegated-session-owner.js +119 -0
  122. package/dist/device-protocol.d.ts +5 -3
  123. package/dist/device-protocol.js +1 -1
  124. package/dist/device-ws-hub.js +21 -2
  125. package/dist/device-ws-protocol.d.ts +70 -6
  126. package/dist/device-ws-protocol.js +50 -23
  127. package/dist/elicitation.js +3 -2
  128. package/dist/entry-problems.d.ts +34 -0
  129. package/dist/entry-problems.js +14 -0
  130. package/dist/execution-lane-caps.d.ts +49 -10
  131. package/dist/execution-lane-caps.js +43 -4
  132. package/dist/field-conflict.d.ts +44 -0
  133. package/dist/field-conflict.js +21 -0
  134. package/dist/file-history-disclosure.d.ts +34 -5
  135. package/dist/file-history-disclosure.js +2 -2
  136. package/dist/fleet/fleet-bus.d.ts +84 -6
  137. package/dist/fleet/fleet-bus.js +42 -9
  138. package/dist/hooks/classic-stations.d.ts +10 -5
  139. package/dist/hooks/classic-stations.js +4 -4
  140. package/dist/hooks/command-spawn.d.ts +57 -0
  141. package/dist/hooks/command-spawn.js +139 -0
  142. package/dist/hooks/hook-llm.js +2 -2
  143. package/dist/hooks/hook-runner.d.ts +127 -25
  144. package/dist/hooks/hook-runner.js +668 -287
  145. package/dist/hooks/hook-source.d.ts +44 -0
  146. package/dist/hooks/hook-source.js +40 -0
  147. package/dist/http/active-run-conflict.d.ts +5 -13
  148. package/dist/http/active-run-conflict.js +17 -27
  149. package/dist/http/admission.js +111 -60
  150. package/dist/http/approval-sweeps.js +58 -19
  151. package/dist/http/caller-trust.d.ts +77 -0
  152. package/dist/http/caller-trust.js +143 -0
  153. package/dist/http/checkpoint-ctx.d.ts +173 -18
  154. package/dist/http/checkpoint-ctx.js +171 -12
  155. package/dist/http/claimed-run.d.ts +4 -3
  156. package/dist/http/device-placement.d.ts +2 -4
  157. package/dist/http/device-placement.js +2 -1
  158. package/dist/http/dispatch.js +13 -7
  159. package/dist/http/durable-run-leg.d.ts +4 -32
  160. package/dist/http/durable-run-leg.js +37 -12
  161. package/dist/http/idempotency.d.ts +2 -2
  162. package/dist/http/idempotency.js +2 -2
  163. package/dist/http/owner-access.d.ts +56 -0
  164. package/dist/http/owner-access.js +42 -0
  165. package/dist/http/principal-gate.d.ts +78 -27
  166. package/dist/http/principal-gate.js +64 -14
  167. package/dist/http/readiness.d.ts +11 -5
  168. package/dist/http/readiness.js +10 -3
  169. package/dist/http/refusal-body.d.ts +12 -0
  170. package/dist/http/refusal-body.js +11 -0
  171. package/dist/http/request-guards.d.ts +16 -32
  172. package/dist/http/request-guards.js +31 -30
  173. package/dist/http/resume-ctx-read.d.ts +50 -6
  174. package/dist/http/resume-ctx-read.js +33 -7
  175. package/dist/http/resume-legs.d.ts +5 -5
  176. package/dist/http/resume-legs.js +163 -91
  177. package/dist/http/retired-service-deps.d.ts +43 -0
  178. package/dist/http/retired-service-deps.js +18 -0
  179. package/dist/http/route-ctx.d.ts +44 -37
  180. package/dist/http/route-ctx.js +4 -0
  181. package/dist/http/route-table.js +2 -0
  182. package/dist/http/routes/a2a-serve.js +3 -4
  183. package/dist/http/routes/admin-config-refresh.js +1 -1
  184. package/dist/http/routes/admin-drain.js +1 -1
  185. package/dist/http/routes/admin-memory-optout.js +5 -1
  186. package/dist/http/routes/adoption.js +2 -9
  187. package/dist/http/routes/agents-roster.js +2 -3
  188. package/dist/http/routes/approvals-assistant.js +91 -56
  189. package/dist/http/routes/background.js +3 -2
  190. package/dist/http/routes/capabilities.js +20 -4
  191. package/dist/http/routes/config-catalog.d.ts +3 -3
  192. package/dist/http/routes/config-catalog.js +1 -1
  193. package/dist/http/routes/devices.js +3 -17
  194. package/dist/http/routes/diagnostics.d.ts +3 -3
  195. package/dist/http/routes/diagnostics.js +6 -2
  196. package/dist/http/routes/fleet.js +4 -4
  197. package/dist/http/routes/images.js +6 -7
  198. package/dist/http/routes/leader.js +1 -8
  199. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  200. package/dist/http/routes/mcp-reconnect.js +3 -2
  201. package/dist/http/routes/memory-bundle.js +1 -1
  202. package/dist/http/routes/memory-compliance.js +1 -1
  203. package/dist/http/routes/memory-consolidation.js +1 -1
  204. package/dist/http/routes/memory-origin.d.ts +1 -1
  205. package/dist/http/routes/memory-origin.js +1 -1
  206. package/dist/http/routes/memory-policy.d.ts +1 -1
  207. package/dist/http/routes/memory-policy.js +3 -2
  208. package/dist/http/routes/notify-wake.js +8 -21
  209. package/dist/http/routes/observability.js +2 -2
  210. package/dist/http/routes/principal-inbox.d.ts +39 -0
  211. package/dist/http/routes/principal-inbox.js +76 -0
  212. package/dist/http/routes/retention-ops.js +2 -9
  213. package/dist/http/routes/rules.js +9 -22
  214. package/dist/http/routes/runs.d.ts +5 -0
  215. package/dist/http/routes/runs.js +63 -115
  216. package/dist/http/routes/session-sync.d.ts +3 -2
  217. package/dist/http/routes/session-sync.js +53 -48
  218. package/dist/http/routes/sessions-list.d.ts +1 -1
  219. package/dist/http/routes/sessions-list.js +3 -4
  220. package/dist/http/routes/sessions.js +33 -43
  221. package/dist/http/routes/side-query.js +6 -4
  222. package/dist/http/routes/tasks.js +71 -30
  223. package/dist/http/routes/trace-usage.js +7 -9
  224. package/dist/http/routes/workflows.d.ts +351 -0
  225. package/dist/http/routes/workflows.js +153 -119
  226. package/dist/http/run-declared-families.d.ts +16 -0
  227. package/dist/http/run-declared-families.js +12 -0
  228. package/dist/http/send.d.ts +24 -3
  229. package/dist/http/send.js +14 -2
  230. package/dist/http/server.d.ts +23 -18
  231. package/dist/http/server.js +20 -15
  232. package/dist/http/stored-body-replay.js +17 -4
  233. package/dist/http/submit-ctx.d.ts +4 -3
  234. package/dist/http/submit-ctx.js +23 -6
  235. package/dist/http/submit-replay.d.ts +4 -3
  236. package/dist/http/submit-replay.js +5 -4
  237. package/dist/http/wire-types.d.ts +17 -10
  238. package/dist/index.d.ts +3 -1
  239. package/dist/index.js +1 -1
  240. package/dist/lane-home-probe.d.ts +78 -9
  241. package/dist/lane-home-probe.js +78 -12
  242. package/dist/leader/endpoint.d.ts +4 -1
  243. package/dist/leader/endpoint.js +11 -10
  244. package/dist/leader/wire.d.ts +4 -0
  245. package/dist/leader/wire.js +8 -7
  246. package/dist/limit-refusal.d.ts +17 -5
  247. package/dist/limit-refusal.js +4 -1
  248. package/dist/main.js +1 -1
  249. package/dist/mcp-assertion-header.d.ts +31 -10
  250. package/dist/mcp-assertion-header.js +10 -3
  251. package/dist/memory-origin-fence.js +2 -2
  252. package/dist/memory-project-layer.d.ts +37 -0
  253. package/dist/memory-project-layer.js +46 -0
  254. package/dist/memory-scope.d.ts +23 -16
  255. package/dist/memory-scope.js +24 -8
  256. package/dist/memory-sync-client.d.ts +27 -13
  257. package/dist/memory-sync-client.js +107 -18
  258. package/dist/model-compat.d.ts +1 -1
  259. package/dist/model-entry-refusal.d.ts +9 -1
  260. package/dist/model-entry-refusal.js +6 -1
  261. package/dist/model-plane-face.d.ts +51 -0
  262. package/dist/model-plane-face.js +24 -0
  263. package/dist/model-provider.d.ts +5 -0
  264. package/dist/model-provider.js +4 -2
  265. package/dist/model-route-endpoint.d.ts +8 -11
  266. package/dist/model-route-endpoint.js +4 -7
  267. package/dist/model-route-env.d.ts +22 -0
  268. package/dist/model-route-env.js +2 -0
  269. package/dist/model-route-gap.d.ts +60 -30
  270. package/dist/model-route-gap.js +21 -15
  271. package/dist/observability/corrupt-read-seat.d.ts +7 -0
  272. package/dist/observability/corrupt-read-seat.js +9 -0
  273. package/dist/observability/err-text.d.ts +6 -0
  274. package/dist/observability/err-text.js +18 -4
  275. package/dist/observability/fail-open.d.ts +35 -9
  276. package/dist/observability/fail-open.js +35 -9
  277. package/dist/observability/metrics.js +1 -0
  278. package/dist/observability/prompt-manifest.d.ts +22 -25
  279. package/dist/observability/prompt-manifest.js +54 -50
  280. package/dist/observability/tool-trace.js +9 -10
  281. package/dist/operator-ask.d.ts +10 -0
  282. package/dist/operator-ask.js +3 -0
  283. package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
  284. package/dist/orchestration/workflow-agent-session-index.js +9 -13
  285. package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
  286. package/dist/orchestration/workflow-completion-inbox.js +13 -0
  287. package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
  288. package/dist/orchestration/workflow-notify-journal.js +27 -34
  289. package/dist/orchestration/workflow-park-decision.d.ts +89 -0
  290. package/dist/orchestration/workflow-park-decision.js +119 -0
  291. package/dist/org-delivery-gate.d.ts +81 -0
  292. package/dist/org-delivery-gate.js +59 -0
  293. package/dist/panel-tool-names.d.ts +23 -0
  294. package/dist/panel-tool-names.js +8 -0
  295. package/dist/parked-decide.d.ts +43 -11
  296. package/dist/parked-decide.js +100 -51
  297. package/dist/parked-revive-surface.d.ts +9 -2
  298. package/dist/parked-revive-surface.js +11 -8
  299. package/dist/permission-rule-list.d.ts +1 -1
  300. package/dist/permission-rule-list.js +2 -2
  301. package/dist/permission-rule-vocab.d.ts +1 -23
  302. package/dist/permission-rule-vocab.js +0 -13
  303. package/dist/plugins/approval-ask-store-file.d.ts +16 -1
  304. package/dist/plugins/approval-ask-store-file.js +21 -0
  305. package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
  306. package/dist/plugins/approval-ask-store-memory.js +34 -2
  307. package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
  308. package/dist/plugins/approval-ask-store-sql.js +37 -1
  309. package/dist/plugins/approval-payload-fingerprint.d.ts +14 -6
  310. package/dist/plugins/approval-payload-fingerprint.js +1 -1
  311. package/dist/plugins/blob-backend.d.ts +38 -25
  312. package/dist/plugins/blob-backend.js +29 -19
  313. package/dist/plugins/breaker-state-sql.d.ts +2 -2
  314. package/dist/plugins/breaker-state-sql.js +4 -4
  315. package/dist/plugins/caching-session-store.d.ts +4 -1
  316. package/dist/plugins/caching-session-store.js +7 -3
  317. package/dist/plugins/checkpoint-store-sql.d.ts +36 -1
  318. package/dist/plugins/checkpoint-store-sql.js +65 -3
  319. package/dist/plugins/file-history-store-sql.d.ts +5 -2
  320. package/dist/plugins/file-history-store-sql.js +3 -1
  321. package/dist/plugins/file-run-store.d.ts +5 -13
  322. package/dist/plugins/file-run-store.js +9 -0
  323. package/dist/plugins/fork-routing-session-store.d.ts +9 -1
  324. package/dist/plugins/fork-routing-session-store.js +12 -1
  325. package/dist/plugins/host-platform.d.ts +2 -0
  326. package/dist/plugins/host-platform.js +2 -1
  327. package/dist/plugins/local-checkpoint-store.d.ts +15 -2
  328. package/dist/plugins/local-checkpoint-store.js +32 -1
  329. package/dist/plugins/local-session-store.d.ts +13 -10
  330. package/dist/plugins/local-session-store.js +23 -14
  331. package/dist/plugins/local-session-window.d.ts +45 -0
  332. package/dist/plugins/local-session-window.js +38 -0
  333. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
  334. package/dist/plugins/mailbox-store-sql.d.ts +30 -48
  335. package/dist/plugins/mailbox-store-sql.js +77 -52
  336. package/dist/plugins/memory-embedder-fingerprint.js +2 -1
  337. package/dist/plugins/memory-run-store.d.ts +5 -13
  338. package/dist/plugins/memory-run-store.js +8 -0
  339. package/dist/plugins/one-time-migrations.d.ts +121 -5
  340. package/dist/plugins/one-time-migrations.js +332 -8
  341. package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
  342. package/dist/plugins/org-delivery-quota-store.js +228 -0
  343. package/dist/plugins/permission-rule-store-file.js +10 -6
  344. package/dist/plugins/permission-rule-store-sql.js +8 -8
  345. package/dist/plugins/pg-pool.js +39 -7
  346. package/dist/plugins/pg-session-storage.d.ts +18 -5
  347. package/dist/plugins/pg-session-storage.js +68 -23
  348. package/dist/plugins/remote-env-adb.d.ts +6 -12
  349. package/dist/plugins/remote-env-adb.js +12 -2
  350. package/dist/plugins/remote-env-device.d.ts +14 -7
  351. package/dist/plugins/remote-env-device.js +23 -15
  352. package/dist/plugins/remote-env-k8s.d.ts +8 -12
  353. package/dist/plugins/remote-env-k8s.js +23 -5
  354. package/dist/plugins/remote-env-local-docker.d.ts +10 -15
  355. package/dist/plugins/remote-env-local-docker.js +12 -9
  356. package/dist/plugins/remote-env-ssh.d.ts +10 -16
  357. package/dist/plugins/remote-env-ssh.js +17 -11
  358. package/dist/plugins/run-store-sql.d.ts +16 -14
  359. package/dist/plugins/run-store-sql.js +22 -2
  360. package/dist/plugins/schema-indexes.js +2 -0
  361. package/dist/plugins/send-user-file.js +2 -2
  362. package/dist/plugins/session-epoch-anchor.d.ts +32 -6
  363. package/dist/plugins/session-epoch-anchor.js +2 -3
  364. package/dist/plugins/session-ownership.d.ts +11 -0
  365. package/dist/plugins/session-ownership.js +11 -0
  366. package/dist/plugins/session-placement.d.ts +12 -14
  367. package/dist/plugins/session-placement.js +2 -15
  368. package/dist/plugins/session-store.d.ts +18 -8
  369. package/dist/plugins/session-store.js +15 -4
  370. package/dist/plugins/sql-driver.d.ts +74 -11
  371. package/dist/plugins/sql-driver.js +210 -12
  372. package/dist/plugins/sql-errors.d.ts +23 -0
  373. package/dist/plugins/sql-errors.js +21 -0
  374. package/dist/plugins/store-backend.d.ts +36 -1
  375. package/dist/plugins/store-backend.js +40 -14
  376. package/dist/plugins/store-contracts.d.ts +42 -0
  377. package/dist/plugins/store-contracts.js +1 -0
  378. package/dist/plugins/tidb-pool.d.ts +6 -1
  379. package/dist/plugins/tidb-pool.js +44 -10
  380. package/dist/plugins/tidb-session-storage.d.ts +3 -2
  381. package/dist/plugins/tidb-session-storage.js +2 -2
  382. package/dist/plugins/tidb-session-store.d.ts +25 -5
  383. package/dist/plugins/tidb-session-store.js +67 -21
  384. package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
  385. package/dist/plugins/workflow-journal-store-sql.js +19 -6
  386. package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
  387. package/dist/plugins/workflow-run-store-sql.js +50 -9
  388. package/dist/posture-source.d.ts +18 -10
  389. package/dist/posture-source.js +4 -1
  390. package/dist/project-identity.d.ts +45 -6
  391. package/dist/project-identity.js +162 -8
  392. package/dist/project-layer-key.d.ts +28 -0
  393. package/dist/project-layer-key.js +29 -0
  394. package/dist/question.js +3 -2
  395. package/dist/read-deny-entry.d.ts +25 -0
  396. package/dist/read-deny-entry.js +12 -0
  397. package/dist/read-face-posture.d.ts +37 -11
  398. package/dist/read-face-posture.js +32 -3
  399. package/dist/request-key-closure.d.ts +7 -0
  400. package/dist/request-key-closure.js +9 -1
  401. package/dist/request-tool-axes.d.ts +12 -0
  402. package/dist/request-tool-axes.js +20 -0
  403. package/dist/request-value-closure.d.ts +5 -0
  404. package/dist/request-value-closure.js +11 -3
  405. package/dist/rule-entry-list.d.ts +26 -2
  406. package/dist/rule-entry-list.js +72 -12
  407. package/dist/rules-consent.js +3 -4
  408. package/dist/run-acceptance.d.ts +19 -3
  409. package/dist/run-acceptance.js +13 -1
  410. package/dist/run-local.js +37 -6
  411. package/dist/runs.d.ts +12 -10
  412. package/dist/runs.js +25 -6
  413. package/dist/runtime-caps-resolver.d.ts +16 -6
  414. package/dist/runtime-caps-resolver.js +18 -5
  415. package/dist/sandbox-pkg-source.d.ts +19 -1
  416. package/dist/sandbox-pkg-source.js +29 -7
  417. package/dist/sealed-key.d.ts +32 -0
  418. package/dist/sealed-key.js +55 -1
  419. package/dist/security.d.ts +95 -15
  420. package/dist/security.js +52 -9
  421. package/dist/session-error-wire.d.ts +31 -7
  422. package/dist/session-error-wire.js +9 -2
  423. package/dist/session-sync-kernel.d.ts +37 -10
  424. package/dist/session-sync-kernel.js +10 -0
  425. package/dist/session-titled-frame.d.ts +33 -0
  426. package/dist/session-titled-frame.js +4 -0
  427. package/dist/session-titler.d.ts +9 -1
  428. package/dist/session-titler.js +15 -4
  429. package/dist/spec-fields.js +21 -2
  430. package/dist/sql-engine-posture.d.ts +3 -1
  431. package/dist/task-a2a.js +4 -3
  432. package/dist/task-cwd.d.ts +1 -1
  433. package/dist/task-mcp.d.ts +5 -5
  434. package/dist/task-mcp.js +27 -74
  435. package/dist/task-settings.d.ts +93 -88
  436. package/dist/task-settings.js +71 -63
  437. package/dist/text-bidi.d.ts +0 -4
  438. package/dist/text-bidi.js +1 -3
  439. package/dist/tighten-only-seats.d.ts +150 -0
  440. package/dist/tighten-only-seats.js +196 -0
  441. package/dist/tool-approval.d.ts +451 -136
  442. package/dist/tool-approval.js +733 -256
  443. package/dist/tool-rule-names.d.ts +6 -0
  444. package/dist/trace/core-keyset-guard.d.ts +108 -25
  445. package/dist/trace/exit-seat.d.ts +40 -0
  446. package/dist/trace/exit-seat.js +130 -0
  447. package/dist/trace/ledger-events.d.ts +6 -3
  448. package/dist/trace/project.d.ts +98 -13
  449. package/dist/trace/project.js +57 -32
  450. package/dist/trace/projection-table.d.ts +100 -0
  451. package/dist/trace/projection-table.js +130 -0
  452. package/dist/trace/redact.d.ts +57 -0
  453. package/dist/trace/redact.js +962 -168
  454. package/dist/trace/self-minted-wire.d.ts +349 -1
  455. package/dist/trace/self-minted-wire.js +118 -1
  456. package/dist/trace/wire-projection-faces.d.ts +304 -2
  457. package/dist/trace/wire-projection-faces.js +160 -13
  458. package/dist/url-refusal.js +2 -0
  459. package/dist/web-admin-client/apply-effective.d.ts +12 -0
  460. package/dist/web-admin-client/apply-effective.js +56 -5
  461. package/dist/web-admin-client/facade.d.ts +1 -1
  462. package/dist/web-admin-client/facade.js +1 -1
  463. package/dist/web-admin-client/read-face.js +5 -9
  464. package/dist/web-admin-client/skills-mcp.d.ts +1 -1
  465. package/dist/web-admin-client/skills-mcp.js +6 -8
  466. package/dist/web-admin-client/types.d.ts +1 -1
  467. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
  468. package/package.json +8 -4
  469. package/scripts/drain-check-local.mjs +34 -2
  470. package/scripts/drain-check.mysql.sql +20 -2
  471. package/scripts/drain-check.pg.sql +20 -2
  472. package/dist/mcp-tool-faces.d.ts +0 -69
  473. package/dist/mcp-tool-faces.js +0 -106
@@ -27,12 +27,12 @@
27
27
  * `APPROVAL_REQUIRE` (an ask rule), `APPROVAL_NEVER_AUTO` (a person, mandated), `MANUAL_MODE_SHELL_GATE=always` (shell).
28
28
  * A request-carried skill's `allowedTools` is the same member's twin (same grammar, same predicate, same admission judge
29
29
  * `rule-entry-list.ts`). Pinned on the real assembly: `test/allow-layer-operator-knobs.test.ts`.
30
- * - permissionMode(轴B #2 注释保鲜,1.254——[ref]/[ref] 后的真实现):`defaultMode` 收 core `PERMISSION_MODES` **全集**
31
- * (default | acceptEdits | plan | auto | bypassPermissions | dontAsk),bypass/auto 被 HONOR 为 gate-shape 选择
32
- * ——但深层不变量未变:bypass=「不加 ask 门」,恒不越部署基线(tightenTaskSpec deny-wins,基线 deny/
33
- * ask 照压);精化语义见 :2xx 行内注释。旧头注的「NEVER honored/三模式白名单」是 pre-[ref] 拍照。
30
+ * - permissionMode:`defaultMode` 收 core `PERMISSION_MODES` **全集**(default | acceptEdits | plan | auto | bypassPermissions | dontAsk),
31
+ * 生效词原样过境 `TaskSpec.permissionMode`,模式**做什么**只在引擎里答(core `modePolicyOf` / `arbitrateByMode`)。本模块的折叠
32
+ * **不读**模式词:deny / ask 两张表在每一个词下编出同一只策略,部署基线照压(tightenTaskSpec deny-wins);bypass 放行的只是引擎
33
+ * 能放行的那几类问,部署 / 请求的 deny 与 ask 规则它一条都掀不掉。
34
34
  *
35
- * 🔴 SYNC WITH sema-cli(壳仓)的 `src/sema/settings/seam.ts`: the permissions→toolPolicy + §6.4 permissionMode derive MIRRORS
35
+ * 🔴 SYNC WITH sema-cli(壳仓)的 `src/sema/settings/seam.ts`: the permissions→toolPolicy compile MIRRORS
36
36
  * the shell's LOCAL-Runner resolver — both compose the SAME core primitives (`createAllowDenyPolicy` /
37
37
  * `combinePolicies` / `tightenTaskSpec`), so the deny-wins ENFORCEMENT is core-single-source. Only the COMPOSITION
38
38
  * is duplicated for the remote path; a proposed follow-up extracts it to `@sema-agent/sdk` for true
@@ -47,27 +47,29 @@
47
47
  * - (`hooks` NO LONGER deferred either — 轴B #2 注释保鲜:applied 形已接线(本文件 hooks 分片 +
48
48
  * main.ts 单用户闸),仅 malformed 才报 deferred;旧「需要 remote hook-runner」是接线前拍照。)
49
49
  */
50
- import { type PathRuleBases, type ExecutionEnv, type TaskSpec, type ThinkingLevel, type ToolPolicy, type PermissionMode } from "@sema-agent/core";
50
+ import { type PathRuleBases, type TaskSpec, type ThinkingLevel, type ToolPolicy, type PermissionMode } from "@sema-agent/core";
51
+ import { type EntryProblem } from "./entry-problems.js";
51
52
  import { type KeyClosureIssue } from "./request-key-closure.js";
52
53
  import { type RunnableHooksConfig } from "./hooks/hook-runner.js";
53
54
  import type { StoredHooksRereadM20 } from "./stored-request-hooks-m20.js";
54
55
  import { type EntryPermissionMode } from "./runtime-governance.js";
56
+ import { type TightenOnlySeatValues } from "./tighten-only-seats.js";
55
57
  /**
56
58
  * 请求面 `permissionMode` 的闭集 = core `PERMISSION_MODES` **全集**(顶层 `permissionMode` / `settings.permissions.defaultMode` /
57
59
  * `?permissionMode=` 查询串三处同读)。本仓不持有第二份词表,也不持有「收 / 不收」的表态:判据 = core 的 `isPermissionMode`,型 = core 的
58
- * `PermissionMode`,wire 句子里的词表只从这里取词({@link PERMISSION_MODE_WORDS})。core 加一个词 ⇒ 请求面自动收它,它在派生腿上的去向由
59
- * {@link deriveSettingsPolicy} 的穷举 `switch` 逼出来(缺一臂 ⇒ 编译红);core 删 / 改名一个词 ⇒ 本文件里按名写出它的那一臂编译红。
60
+ * `PermissionMode`,wire 句子里的词表只从这里取词({@link PERMISSION_MODE_WORDS})。core 加一个词 ⇒ 请求面自动收它、原样过境,本仓没有
61
+ * 按词分的臂要补;core 删 / 改名一个词 ⇒ 本仓按名写出它的地方(`PLAN_APPROVE_PERMISSION_MODES_AFTER` 等)编译红。
60
62
  * 生效模式原样过境 `TaskSpec.permissionMode`(S-877):引擎自己解释模式 —— 含 `dontAsk`(CC 的「自动拒」档:凡是要问的一律由模式拒,零卡,
61
- * 门记录 `deniedBy:"mode"`),本仓不另写判。
63
+ * 门记录 `deniedBy:"mode"`)与 acceptEdits 的免问写域(引擎的写根:任务根 + `additionalDirectories` + 宣告的可写目录),本仓不另写判。
62
64
  */
63
65
  /** 请求面闭集的 wire 文案形(`"a" | "b" | …`,core 序)—— 三处 400(顶层 / bundle / 查询串)的句子从这里取词,不再各抄一份。 */
64
66
  export declare const PERMISSION_MODE_WORDS: string;
65
67
  /**
66
68
  * R4: coerce a raw top-level `body.permissionMode` (the LIGHT per-turn wire — the shell sends
67
69
  * the CC permission mode RAW, axis-agnostic; the service interprets) to a service-honored mode, or undefined.
68
- * 🔴 TIGHTEN-ONLY vs the DEPLOYMENT baseline still holds for every value: the mode only selects the CLIENT-derived
69
- * gate ({@link deriveSettingsPolicy}); it can never subtract from the deployment/operator policy (applyTaskSettings
70
- * folds via tightenTaskSpec, deny-wins). The honored set is core's `PERMISSION_MODES` in full — every word passes
70
+ * 🔴 TIGHTEN-ONLY vs the DEPLOYMENT baseline still holds for every value: the word rides verbatim into `TaskSpec.permissionMode`
71
+ * and only the engine interprets it; no mode subtracts from the deployment/operator policy or from the request's own
72
+ * deny / ask rules (applyTaskSettings folds them via tightenTaskSpec, deny-wins, under every word alike). The honored set is core's `PERMISSION_MODES` in full — every word passes
71
73
  * through verbatim (`dontAsk` included: folding the auto-deny mode to `default`, the asking mode, would turn a refusal
72
74
  * into a card). An UNKNOWN string coerces to `default` (fail-safe: the most-asking mode).
73
75
  * [ref]-②: fresh submits can no longer REACH the unknown-word arm — the HTTP gate 400s a non-member value
@@ -147,19 +149,13 @@ export declare function storedBodyPermissionMode(body: {
147
149
  * (= "max"), never a hardcoded literal — so an explicit higher tier still wins (none exists above max today;
148
150
  * future-proof). Awareness rides for free: core composes ORCHESTRATION_AWARENESS from thinking∈{xhigh,max}, no field. */
149
151
  export declare function effectiveThinking(reasoningEffort: unknown, ultracode: boolean): ThinkingLevel | undefined;
150
- /** R4: fold a top-level `body.permissionMode` onto the parsed settings as `permissions.defaultMode` (the top-level
151
- * field is the explicit per-turn intent → it WINS over a bundle defaultMode). Creates a minimal settings object when
152
- * no `body.settings` bundle was sent. The result flows through {@link applyTaskSettings} (tighten-only). */
153
- export declare function withPermissionMode(settings: ParsedTaskSettings | undefined, mode: PermissionMode): ParsedTaskSettings;
154
152
  /**
155
- * [ref] §6-1 —— 本请求的**生效** permission mode,单点。优先序逐字同 {@link withPermissionMode}:
156
- * 顶层 `body.permissionMode`(本轮显式表态)赢过 bundle 的 `settings.permissions.defaultMode`;两处
157
- * 都没有 ⇒ `undefined` = **无表态**(调用点据此不写键,而不是替调用方选一个默认值)。
153
+ * [ref] §6-1 —— 本请求的**生效** permission mode,单点。优先序:顶层 `body.permissionMode`(本轮显式表态)赢过 bundle 的
154
+ * `settings.permissions.defaultMode`;两处都没有 ⇒ `undefined` = **无表态**(调用点据此不写键,而不是替调用方选一个默认值;引擎把缺席读成 `default`)。
158
155
  *
159
- * 🔴 为什么必须是一只函数:同一个「生效模式」此前在 resolve-spec 里被算了两次(hooks 腿的
160
- * `permission_mode` 载荷、settings 折叠腿的 `withPermissionMode`),三审同点判定翻译表**不得**成为
161
- * 第三个算点 —— 三处各算各的,任何一次优先序修订都会让三面分家,而分家在这条轴上的形态是
162
- * 「壳发的 bundle bypass 在 A 面生效、在 B 面没生效」这种最难被外部发现的静默偏差。
156
+ * 🔴 为什么必须是一只函数:同一个「生效模式」此前在 resolve-spec 里被算过两次(hooks 腿的 `permission_mode` 载荷、settings 折叠腿),
157
+ * 两处各算各的,任何一次优先序修订都会让两面分家,而分家在这条轴上的形态是「壳发的 bundle bypass 在 A 面生效、在 B 面没生效」这种
158
+ * 最难被外部发现的静默偏差。settings 折叠今天不再读模式词,这只函数的读者是 spec 过境点、托管天花板与存储体读法。
163
159
  */
164
160
  export declare function effectivePermissionMode(body: {
165
161
  permissionMode?: unknown;
@@ -225,6 +221,10 @@ export interface ParsedTaskSettings {
225
221
  skillListingBudgetFraction?: number;
226
222
  /** 同族第二键:每条技能描述在清单里的字符帽(正整数;CC 默认 1536)。超出由引擎**截断**,不是拒。 */
227
223
  skillListingMaxDescChars?: number;
224
+ /** S-1351 —— 「只收紧」座位族(`tighten-only-seats.ts` 的四座:读拒模式 / 写保护名的加法 / 合规额外禁项 / 永不自动放行名单)的归一值,**一个键**而不是四个散字段:
225
+ * wire 位置由座位表说(三座在 `settings` 顶层,`neverAuto` 在 `settings.permissions`),解析后与位置无关。空数组 ≡ 缺席(不铸键)。
226
+ * 去处:三座经 {@link applyTaskSettings} 落 core 任务层席;`neverAuto` 经 {@link deriveSettingsPolicy} 落请求叶策略。 */
227
+ tightenOnly?: TightenOnlySeatValues;
228
228
  }
229
229
  /** The result of parsing an untrusted `body.settings`: the applied subset + the names of present-but-deferred
230
230
  * fields (so the caller can log/advertise them — no silent drop). `null` settings ⇒ `{ settings: undefined }`. */
@@ -285,13 +285,21 @@ export declare function settingsPermissionBucketIssue(perms: unknown): SettingsP
285
285
  * {@link parseTaskSettings};`webSearch` 在 `capabilities/scenarios.ts`(判决 `judgeRequestWebSearch`,单用户闸;形错在受理面 400,S-199)。
286
286
  * 加键必须同时加消费点,否则就是往闭集里塞一个新的静默丢。
287
287
  *
288
+ * 🔴 `readDenyPatterns` / `writeProtectedExtra` / `complianceAdditionalDenies` 与 `permissions.neverAuto`(S-1351)= **「只收紧」座位族**:消费点 = `tighten-only-seats.ts`
289
+ * 的座位表(位置、条目律、去处都由那张表说),读入在 {@link parseTaskSettings},投影在 {@link applyTaskSettings} / {@link deriveSettingsPolicy}。这四个键不是 CC settings 键
290
+ * (sdk 的 `SemaSettings` 尚未声明 —— 对账门 `test/task-settings-sdk-key-parity.test.ts` 的「server 先于 sdk」登记表记着它们)。
291
+ *
292
+ * 🔴 `approvalFrameFamilies`(S-1914)= 这条 run 的客户端**声明**渲染得了哪些审批开卡帧族 —— 不进引擎,不是 CC settings 键。消费点 = 三条执行腿的审批装配
293
+ * (`tool-approval.ts` 的唯一读者 `declaredApprovalFrameFamilies` → `resolveApprovalLeg`),判官 `approvalFrameFamiliesIssue`(fresh 受理 400 与宽容读者同一只)。
294
+ * `parseTaskSettings` 刻意不读它(它管的是落到 `TaskSpec` 的设置)。sdk 型面待声明(对账门的「server 先于 sdk」登记表记着)。
295
+ *
288
296
  * 🔴 两个 `skillListing*`([ref],7.77.0)= **CC settings 同名键**,值域抄 CC 的 schema 声明
289
297
  * (`skillListingBudgetFraction` 是 `gt(0).lte(1)`、`skillListingMaxDescChars` 是 `int().positive()`);
290
298
  * 消费点 = 本文件的 parse + `boot/resolve-spec.ts` 的 `TaskSpec` 透传。语义(预算怎么花、描述怎么裁、
291
299
  * 溢出怎么退成 name-only)整个归引擎,本仓一个字节都不渲染,也**不复刻默认值**——缺席即整键不写。 */
292
- export declare const TASK_SETTINGS_KEYS: readonly ["env", "hooks", "model", "outputStyle", "permissions", "skillListingBudgetFraction", "skillListingMaxDescChars", "ultracode", "webSearch"];
300
+ export declare const TASK_SETTINGS_KEYS: readonly ["approvalFrameFamilies", "complianceAdditionalDenies", "env", "hooks", "model", "outputStyle", "permissions", "readDenyPatterns", "skillListingBudgetFraction", "skillListingMaxDescChars", "ultracode", "webSearch", "writeProtectedExtra"];
293
301
  /** 本 service 消费的 `settings.permissions` 子键 —— 闭集(值形校验另有既有门,本门只判键名)。 */
294
- export declare const TASK_SETTINGS_PERMISSION_KEYS: readonly ["allow", "ask", "defaultMode", "deny", "disableAutoMode"];
302
+ export declare const TASK_SETTINGS_PERMISSION_KEYS: readonly ["allow", "ask", "defaultMode", "deny", "disableAutoMode", "neverAuto"];
295
303
  /** CC/SDK 合约里合法、本 service **不接线**的顶层键。词表外的 CC 键落 `unknown` —— 两列都是 400,标签只影响
296
304
  * 文案,不影响判决。前三个的出处 = `@sema-agent/sdk` `SemaSettings` 尾注逐字点名的 deferred CC 键。
297
305
  *
@@ -354,53 +362,35 @@ export declare function parseTaskSettings(raw: unknown, seats?: ParseTaskSetting
354
362
  * A well-formed rider always mounts: the engine (core 7.52.0) lands it in its own task-append band whatever the role
355
363
  * text is — there is no "already-assembled" pass-through arm left that could drop it. */
356
364
  export declare function acceptAppendSystemPrompt(v: unknown, warn?: (detail: string) => void): string | undefined;
365
+ export declare function createWorkflowAskPolicy(isExempt?: WorkflowGateWiring["isExempt"]): ToolPolicy;
357
366
  /** [ref]②/codex F2 — what the workflow ask leg needs from the deployment, on EVERY lane. It is name-keyed and
358
- * fs-independent, so it never had the lane split {@link FsWriteGateWiring} carried (that split is itself gone
359
- * since [ref] — the sandbox lanes wire a gate of their own shape instead of no gate). */
367
+ * fs-independent: one shape on every execution lane. */
360
368
  export interface WorkflowGateWiring {
361
- /** The session "don't ask again" probe (approvalExemptionStore.has, canonical toolName key) — same store and
362
- * key space as the fs-write gate's probe; one remember="session" grant serves both. */
369
+ /** The session "don't ask again" probe (approvalExemptionStore.has, raw toolName key) — the same store and key space the
370
+ * approval seat's standing grants read; one remember="session" grant serves them all. */
363
371
  isExempt?: (toolName: string) => boolean | Promise<boolean>;
364
372
  }
365
- /** [ref]/[ref]① — everything the mode-derived fs-write ask gate needs from the deployment, provided by
366
- * `resolve-spec.ts`. Absent ⇒ no gate is derived (the pre-[ref] behavior).
367
- *
368
- * WHY the `env` matters: core's `createFsWriteGatePolicy` canonicalizes every target/dir through the given `env`
369
- * (real `exists`/`canonicalPath`/`readLink` fs access — read in dist, fs-write-gate-policy.js), so on a
370
- * HOST-SEMANTICS lane (`REMOTE_EXEC` unset or "host") the env MUST be the fs the hand tools write.
373
+ /**
374
+ * 请求的 deny / ask 两张表解析路径形规则用的**基**(`resolve-spec.ts` 每请求供)。只有这两件事:这条 task 的真根、执行环境的 home。
375
+ * 缺席 ⇒ 不声明(规则锚在装入这只策略的那条腿的真根,`~/` 形由 {@link rejectUnmatchableSettingsNames} 响亮拒)。
371
376
  *
372
- * [ref]/[ref] — the sandbox lanes (e2b/k8s/ssh/adb/local-docker) wire a gate TOO, but a different-shaped one: the
373
- * tools run OFF this box and the per-task sandbox env is minted inside core (executionEnvFactory) AFTER spec
374
- * build, so a worker-local env would adjudicate against the WRONG fs (a wrong ALLOW is worse than no gate — that
375
- * is why [ref] left those lanes gate-less). They supply a `DeferredSandboxPathEnv`
376
- * (`src/boot/deferred-sandbox-path-env.ts`) instead: a proxy that forwards the fs READ primitives to the task's
377
- * REAL sandbox env at adjudication time (a per-session slot the factory decorator fills), keeping only
378
- * `absolutePath` lexical so no relative path is resolved against the wrong base. Empty slot ⇒ fail-closed. */
377
+ * 修前本型还承运本仓自己的 acceptEdits cwd 域写门的四件(裁决 env / cwd / scratchpad 豁免域 / 会话豁免探针):acceptEdits 能免问写哪里
378
+ * 现在只由引擎的模式门答(写根 = 任务根 + `additionalDirectories` + 宣告的可写目录),本仓不再构造写门,那四件随之退役。
379
+ * 部署级旋钮(`SENSITIVE_WRITE_PATTERNS` 守卫集、`MANUAL_MODE_SHELL_GATE` 地板)早已不经本型:它们在治理层无条件施加
380
+ * (`runtime-governance.ts` `applyRuntimeGovernance`),client 表态掀不掉([ref] / [ref])。
381
+ */
379
382
  export interface FsWriteGateWiring {
380
- /** The env the gate canonicalizes against — the worker host env on the host lane, the
381
- * `DeferredSandboxPathEnv` proxy over the task's real sandbox env on the sandbox lanes ([ref]). */
382
- env: ExecutionEnv;
383
- /** The task's working directory: the factory's `rootPath` (relative-path base) AND the acceptEdits accept domain.
384
- * ABSENT on the sandbox lanes ([ref]/[ref]): the sandbox cwd is the ENGINE's tracked cwd, not the env's own, so
385
- * neither spec time nor the env proxy can supply the right base — inventing one would mint a bogus auto-allow
386
- * domain. With it absent the gate gets no `rootPath` and no `acceptDirs`, so relative paths fail to resolve
387
- * (⇒ ask) and `acceptEdits` degrades to the `default` arm — the same fail-safe direction as the host lane's
388
- * never-created sentinel dir (resolve-spec 修5). */
389
- cwd?: string;
390
383
  /**
391
- * 🔴 S-177 / codex r1 [high](验真后修)—— **权限规则**的路径基,与上面那个 `cwd` **刻意分成两个字段**。
384
+ * 🔴 S-177 / codex r1 [high](验真后修)—— **权限规则**的路径基(core `PathRuleBases.root`),**只在真任务根已知时**在场。
392
385
  *
393
- * 两者在 host 腿上常常同值,但它们回答的不是同一个问题,而混用一个字段会让其中一个静默失效:
394
- * · `cwd` 是**写门**的基。它在「有 remoteExec 但这条 session 还没登记工作目录」时取的是一个
395
- * **永不创建的哨兵目录**(`resolve-spec` 的 `fs-write-gate-unrooted`)。对写门那是 fail-SAFE 的:
396
- * 相对目标在哨兵下解析不出真身 ⇒ 落 ask。
397
- * · `taskRoot` 是**规则模式**的基(core `PathRuleBases.root`)。规则编译器按**词法**匹配,不问目录
398
- * 存不存在 ⇒ 把哨兵递给它,`deny Edit(src/**)` 会编译成功、指向一个谁也不会写的目录,对真实工作区
399
- * 的 `<工作区>/src/secret.ts` 这类目标判 allow —— 一条运维亲手写下的收紧规则**静默失效**,方向与写门那条正相反。
386
+ * host 腿上「这条 session 还没登记工作目录」时,`resolve-spec` 的路径裁决 env 落在一个**永不创建的哨兵目录**上
387
+ * (`fs-write-gate-unrooted`,治理层守卫集的 cwd)。那对守卫是 fail-SAFE 的(相对目标在哨兵下解析不出真身);但规则编译器按**词法**匹配、
388
+ * 不问目录存不存在 ⇒ 把哨兵当根递进来,`deny Edit(src/**)` 会编译成功、指向一个谁也不会写的目录,对真实工作区的
389
+ * `<工作区>/src/secret.ts` 判 allow —— 一条亲手写下的收紧规则**静默失效**。所以哨兵从不被声明成基。
400
390
  *
401
- * ⇒ 本字段**只在真任务根已知时**在场。缺席 ⇒ 不声明根 ⇒ 需要该基的拼法(`Edit(src/**)` / `Edit(/etc/**)`)锚在**装入这只策略的那条腿**
402
- * 的真根(core 7.46.0 #1383 车 B:锚装一次、在被装入处;`unsupported.path_base` 只剩「声明了一个用不了的基」)—— 哨兵从不被声明成基。
403
- * 修前(core ≤7.45)缺席 ⇒ 整表拒(→ 422):沙箱车道上相对 / `/x` 形规则恒 422。绝对形(`//abs`)不需要基;`~/` 形见下一字段。
391
+ * 缺席 ⇒ 不声明根 ⇒ 需要该基的拼法(`Edit(src/**)` / `Edit(/etc/**)`)锚在**装入这只策略的那条腿**的真根(core 7.46.0 #1383 车 B:
392
+ * 锚装一次、在被装入处;`unsupported.path_base` 只剩「声明了一个用不了的基」)。修前(core ≤7.45)缺席 ⇒ 整表拒(→ 422):沙箱车道上
393
+ * 相对 / `/x` 形规则恒 422。绝对形(`//abs`)不需要基;`~/` 形见下一字段。
404
394
  */
405
395
  taskRoot?: string;
406
396
  /**
@@ -430,29 +420,20 @@ export interface FsWriteGateWiring {
430
420
  * 运维在**下单那一刻**就知道这条规则这条车道读不了,而不是等到跑起来每次都弹一张 ask。
431
421
  */
432
422
  taskHome?: string;
433
- /** The session scratchpad dir (envFacts.scratchpadDir, [ref]③) — writes there are always auto-allowed. */
434
- scratchpadDir?: string;
435
- /** [ref]① / core 1.294 exemption seam: the session "don't ask again" probe (approvalExemptionStore.has),
436
- * called by core as `(canonicalToolName, canonicalPath)`. The host arm ignores the second argument (the key
437
- * comes from a real-fs canonicalize and the grant is deliberately name-keyed); the sandbox arm ([ref]) uses it
438
- * to confine the exemption to POSIX-absolute canonical keys — core's `canonicalizeTarget` short-circuits
439
- * backslash-UNC forms to `ok:true, key=raw` WITHOUT consulting the env, and an unconfined name-keyed grant
440
- * would turn those unresolvable forms into an allow (codex review 2026-08-05).
441
- * 🔴 **坐标刷新(7.74.0 / core 7.17.0 [ref];结论不变,前提收窄了)**:那条短路现在**只在 `win` 家族上**
442
- * (`dist/tools/fs/safety.js` 的 `canonicalizeTarget`:`family === "win" && isUncSpelling(...)` 才折 UNC
443
- * 并直接返回);在 `posix` 家族上,同一个反斜杠 UNC 拼法在更早一步的 `win32NamespaceScreen` 上就被
444
- * **拒**(`unc_on_posix_tree`),压根到不了短路。⇒ 今日部署形(posix 树)这条腿的暴露面比当年更小,
445
- * 而本臂的 POSIX-absolute 收敛**继续是对的**:它挡的是「未经 env 解析的 key 拿到 name-keyed 放行」,
446
- * 在两个家族上都成立,且方向仍是 fail-closed。不改实现。
447
- * The probe is consulted by the gate RIGHT BEFORE it would ask (after the exempt/accept dir layering — dist 亲读:true ⇒
448
- * allow with decisionReason "rule", a THROWN probe ⇒ not exempt = fail-closed to ask). Same canonical
449
- * toolName key space as the ask-policy layer's exemption probe — ONE grant serves both layers; the gate-level
450
- * check is what makes "allow all session" bite SAME-TURN for the parent and inherited child tasks (the ask
451
- * path is never re-entered). (codex M1 的边界注记:sensitive-path DENY 腿与本探针的「豁免越不过 deny」
452
- * 保证仍成立——但那条腿已随 [ref] 搬到 governance 层,deny-wins 是 tightenTaskSpec 折叠给的,不再依赖
453
- * 本 wiring 的组合点。) */
454
- isExempt?: (toolName: string, canonicalPath: string) => boolean | Promise<boolean>;
455
423
  }
424
+ /**
425
+ * 请求的 `settings.permissions.deny` / `ask` 有永远不生效的条目 ⇒ 拒点({@link rejectUnmatchableSettingsNames})抛的错:句子(`message`)与这一遍判下来的**全部**问题(`problems`,机读位的原料)。
426
+ * `resolveSpec` 的折叠口把它装成 422 体(句子照旧、码 {@link SETTINGS_RULE_REFUSAL_CODE}、体带 `field` + `detail.problems`);其余出口(收紧不得放宽)仍抛普通 `Error`。
427
+ */
428
+ export declare class SettingsRuleRefusalError extends Error {
429
+ readonly problems: readonly EntryProblem[];
430
+ constructor(message: string, problems: readonly EntryProblem[]);
431
+ }
432
+ /**
433
+ * 请求设置里 deny / ask 规则拒的**码**:422 在折叠口上的状态派生粗码(`http/send.ts` 的 `httpErrorCode(422)`;`test/entry-problems.test.ts` 钉两者同值)。拒点铸 422 体、存体预判铸 409 的 `blockedBy`、
434
+ * 机读位每条问题的 `code` 三处读这一只常量,不各写一份字面量。
435
+ */
436
+ export declare const SETTINGS_RULE_REFUSAL_CODE = "request.unprocessable";
456
437
  /**
457
438
  * deny / ask 两桶(core 规则编译器读的收紧表)的**问序,单表**:{@link rulePolicyBucketsRefusal} 的两段循环(名字层 + 文法 · `~/` 要 home)都迭代它 ——
458
439
  * 两桶都有坏条目时,拒点与存体预判点名同一个桶、说同一句。表里每个词同时是 core 规则的 `behavior`。
@@ -461,7 +442,8 @@ export declare const RULE_POLICY_BUCKETS: readonly ["ask", "deny"];
461
442
  export type RulePolicyBucket = (typeof RULE_POLICY_BUCKETS)[number];
462
443
  /**
463
444
  * deny / ask 两桶的**完整规则判**,唯一一只(拒点 {@link rejectUnmatchableSettingsNames} 与存体预判 `http/stored-body-replay.ts` 同调):
464
- * ② 按 {@link RULE_POLICY_BUCKETS} 的序逐桶问 `unmatchableToolNamesRefusal`(名字层 + core 规则文法);③ 都过了,再逐桶判 `~/` 形要 home 的那一拒。第一个坏处答 `{ bucket, message }`。
445
+ * ② 按 {@link RULE_POLICY_BUCKETS} 的序逐桶问 `judgeUnmatchableToolNames`(名字层 + core 规则文法);③ 再逐桶判 `~/` 形要 home 的那一拒。答 `{ bucket, message, problems }`:`bucket` 与 `message` 是**第一处**坏处的
446
+ * (句子冻结,先撞上的那一条),`problems` 是**两段、两只桶判下来的全部**坏条目(机读位的原料,形的属主 `entry-problems.ts`)。
465
447
  * 入参:桶、{@link RulePolicyBases}。**home 同源**:拒点的 home 是 `resolve-spec.ts` 的 `laneHomeBase()` 经 `executionLaneHomeDir(config)` 算出的,预判传同一个函数对同一份部署配置算出的。
466
448
  * **声明给文法的基**只有拒点有(根 + home 的并集,执行车道才知道根):core 的规则文法对**没声明**的基不下判词(见 `config.ts` `uncompilableRuleGuidance`),所以预判什么也不声明、两腿逐字同句;
467
449
  * 预判不能把 home 当「半个基」声明给文法 —— core 的路径族只从根推,缺根时一个合法的 Windows 形 home 会按默认族被判 `unsupported.path_base`(V6-k)。
@@ -476,12 +458,35 @@ export interface RulePolicyBases {
476
458
  export declare function rulePolicyBucketsRefusal(permissions: Readonly<Partial<Record<RulePolicyBucket, readonly string[]>>>, bases: RulePolicyBases): {
477
459
  readonly bucket: RulePolicyBucket;
478
460
  readonly message: string;
461
+ readonly problems: readonly EntryProblem[];
479
462
  } | undefined;
480
463
  /** 请求的 settings 编不成生效的规则 / 有永远不生效的条目 ⇒ 422 的句首(三只桶同一个出口;`resolveSpec` 的拒点与存体重放预判的 409 句子同用这一个,不各写一份)。 */
481
464
  export declare const REQUEST_SETTINGS_REFUSAL_PREFIX = "request settings cannot be applied as written: ";
482
- export declare function deriveSettingsPolicy(settings: ParsedTaskSettings, gate?: FsWriteGateWiring, workflowGate?: WorkflowGateWiring): {
465
+ /**
466
+ * Build the per-request permission ToolPolicy from the parsed settings: the two **rule lists** (`deny` / `ask`) through ONE compiler
467
+ * ({@link createRuleListPolicy} → core `createPermissionRulePolicy`) — a `deny` rule hard-blocks, an `ask` rule forces an approval
468
+ * gate, `deny` > `ask` on overlap. 两表的 **covering 语义同源**([ref]):底下是 core 的同一只 `namespacedRuleNameCovers`,本仓不持第二套 glob。
469
+ * The `allow` bucket is not here: a policy says deny / ask only (core 7.42.0); the list rides into `TaskSpec.allowedTools` at
470
+ * {@link applyTaskSettings}, the one write point.
471
+ *
472
+ * 🔴 **本函数不读模式词**:两张表在六个词与缺席下编出同一只策略(`test/settings-fold-mode-arms.test.ts` A2)。模式做什么只在引擎里答 ——
473
+ * 写门(`default` / `auto` / `dontAsk`:每次写先问;`acceptEdits`:写根内免问;`plan`:写与非只读调用以计划句问;`bypassPermissions`:不设门)
474
+ * 是引擎的模式门,`Workflow` 的问句腿在 `resolve-spec.ts` 按「这条 run 挂不挂得出 Workflow」装、由引擎的仲裁按模式处置({@link createWorkflowAskPolicy})。
475
+ * 修前这里按模式分四臂(acceptEdits 另铸一只 cwd 域写门、bypass / 缺席不装问句腿):本仓对模式的第二份解释,随之退役。
476
+ * Returns `{}` when there is no permission rule (nothing to project).
477
+ */
478
+ export declare function deriveSettingsPolicy(settings: ParsedTaskSettings, bases?: FsWriteGateWiring): {
483
479
  toolPolicy?: ToolPolicy;
484
480
  };
481
+ /**
482
+ * 请求的 `settings.permissions.neverAuto` 有永远不生效的名字 ⇒ 拒因(句子 + 机读位),与 {@link rulePolicyBucketsRefusal} 同形 —— 拒点({@link deriveSettingsPolicy},422)与存体预判
483
+ * (`http/stored-body-replay.ts`)调这一只。判据与部署 `APPROVAL_NEVER_AUTO` 的 env 腿是**同一只**(`unmatchableToolNamesRefusal` 的名表消费者:退役名 / 无协议前缀的短名 / 缺段协议名 /
484
+ * 近似名 …),一条规则一种读法;机读位的 `field` = 座位在体内的坐标。无名字 / 全合法 ⇒ `undefined`。
485
+ */
486
+ export declare function neverAutoNamesRefusal(names: readonly string[]): {
487
+ readonly message: string;
488
+ readonly problems: readonly EntryProblem[];
489
+ } | undefined;
485
490
  /**
486
491
  * Apply a client's parsed per-request settings onto a base `TaskSpec`, TIGHTEN-ONLY, in a SINGLE {@link
487
492
  * tightenTaskSpec} pass (so the permission override composes deny-wins onto the baseline — TRAP #1). `tightenTaskSpec`
@@ -492,5 +497,5 @@ export declare function deriveSettingsPolicy(settings: ParsedTaskSettings, gate?
492
497
  *
493
498
  * Returns `base` untouched when the parsed settings project nothing onto the spec.
494
499
  */
495
- export declare function applyTaskSettings(base: TaskSpec, settings: ParsedTaskSettings, gate?: FsWriteGateWiring, workflowGate?: WorkflowGateWiring): TaskSpec;
500
+ export declare function applyTaskSettings(base: TaskSpec, settings: ParsedTaskSettings, bases?: FsWriteGateWiring): TaskSpec;
496
501
  //# sourceMappingURL=task-settings.d.ts.map
@@ -1,5 +1,6 @@
1
- import { combinePolicies, createFsWriteGatePolicy, parseRuleText, resolveReasoningProfile, rankOf, isThinkingLevel, RUN_WORKFLOW_TOOL_NAME, PERMISSION_MODES, isPermissionMode, ruleToolGrammarOf, } from "@sema-agent/core";
2
- import { unmatchableToolNamesRefusal } from "./config.js";
1
+ import { combinePolicies, parseRuleText, resolveReasoningProfile, rankOf, isThinkingLevel, RUN_WORKFLOW_TOOL_NAME, PERMISSION_MODES, isPermissionMode, ruleToolGrammarOf, } from "@sema-agent/core";
2
+ import { judgeUnmatchableToolNames } from "./config.js";
3
+ import { entryProblem } from "./entry-problems.js";
3
4
  import { MAX_PERMISSION_RULES_PER_LIST, createRuleListPolicy } from "./permission-rule-list.js";
4
5
  import { allowLayerEntryCountIssue, describeAllowLayerOverCap, ruleEntryListShapeOk } from "./rule-entry-list.js";
5
6
  import { limitRefusal } from "./limit-refusal.js";
@@ -9,6 +10,8 @@ import { parseHooksConfig } from "./hooks/hook-runner.js";
9
10
  import { heldRuleName } from "./tool-rule-names.js";
10
11
  import { entryPermissionMode } from "./runtime-governance.js";
11
12
  import { policyAskStandingAnswerFacts, standingAnswerDurablyRecordable } from "./tool-approval.js";
13
+ import { createRequestNeverAutoPolicy } from "./approval.js";
14
+ import { readTightenOnlySeats, tightenOnlySeatField, tightenOnlySpecSeats } from "./tighten-only-seats.js";
12
15
  export const PERMISSION_MODE_WORDS = PERMISSION_MODES.map((m) => `"${m}"`).join(" | ");
13
16
  export function coercePermissionMode(raw) {
14
17
  const strict = coercePermissionModeStrict(raw);
@@ -48,10 +51,6 @@ export function effectiveThinking(reasoningEffort, ultracode) {
48
51
  const ultra = resolveReasoningProfile("ultra").thinking;
49
52
  return explicit && rankOf(explicit) > rankOf(ultra) ? explicit : ultra;
50
53
  }
51
- export function withPermissionMode(settings, mode) {
52
- const base = settings ?? {};
53
- return { ...base, permissions: { ...base.permissions, defaultMode: mode } };
54
- }
55
54
  export function effectivePermissionMode(body, settings) {
56
55
  const requested = coercePermissionMode(body.permissionMode) ?? settings?.permissions?.defaultMode;
57
56
  const kill = settings?.permissions?.disableAutoMode;
@@ -155,8 +154,8 @@ export function settingsPermissionBucketIssue(perms) {
155
154
  function acceptedRuleList(v) {
156
155
  return Array.isArray(v) && v.length > 0 ? v.slice() : undefined;
157
156
  }
158
- export const TASK_SETTINGS_KEYS = ["env", "hooks", "model", "outputStyle", "permissions", "skillListingBudgetFraction", "skillListingMaxDescChars", "ultracode", "webSearch"];
159
- export const TASK_SETTINGS_PERMISSION_KEYS = ["allow", "ask", "defaultMode", "deny", "disableAutoMode"];
157
+ export const TASK_SETTINGS_KEYS = ["approvalFrameFamilies", "complianceAdditionalDenies", "env", "hooks", "model", "outputStyle", "permissions", "readDenyPatterns", "skillListingBudgetFraction", "skillListingMaxDescChars", "ultracode", "webSearch", "writeProtectedExtra"];
158
+ export const TASK_SETTINGS_PERMISSION_KEYS = ["allow", "ask", "defaultMode", "deny", "disableAutoMode", "neverAuto"];
160
159
  export const TASK_SETTINGS_UNSUPPORTED_KEYS = ["apiKeyHelper", "crossSessionInbound", "dialogExpiry", "sandbox", "statusLine"];
161
160
  export const TASK_SETTINGS_UNSUPPORTED_PERMISSION_KEYS = ["additionalDirectories", "disableBypassPermissionsMode"];
162
161
  const ACCEPTED_TOP = new Set(TASK_SETTINGS_KEYS);
@@ -195,6 +194,9 @@ export function taskSettingsKeyIssue(raw) {
195
194
  export function taskHooksHonored(config) {
196
195
  return config.requirePrincipal !== true;
197
196
  }
197
+ function tightenOnlySeatDeferredName(name) {
198
+ return tightenOnlySeatField(name).replace(/^settings\./, "");
199
+ }
198
200
  export function parseTaskSettings(raw, seats = {}) {
199
201
  if (raw === null || raw === undefined || typeof raw !== "object")
200
202
  return { deferred: [] };
@@ -262,6 +264,11 @@ export function parseTaskSettings(raw, seats = {}) {
262
264
  const maxDesc = s.skillListingMaxDescChars;
263
265
  if (skillListingMaxDescOk(maxDesc))
264
266
  out.skillListingMaxDescChars = maxDesc;
267
+ const tightenSeats = readTightenOnlySeats(raw);
268
+ for (const name of tightenSeats.rejected)
269
+ deferred.push(tightenOnlySeatDeferredName(name));
270
+ if (Object.keys(tightenSeats.values).length > 0)
271
+ out.tightenOnly = tightenSeats.values;
265
272
  return { settings: Object.keys(out).length > 0 ? out : undefined, deferred, ...(hooksReread !== undefined ? { hooksReread } : {}) };
266
273
  }
267
274
  export function acceptAppendSystemPrompt(v, warn) {
@@ -280,7 +287,7 @@ export function acceptAppendSystemPrompt(v, warn) {
280
287
  const RULE_SOURCE_BY_BEHAVIOR = { ask: "settings.permissions.ask", deny: "settings.permissions.deny" };
281
288
  const WORKFLOW_ASK_NAMES = [RUN_WORKFLOW_TOOL_NAME];
282
289
  const isWorkflowName = (name) => name === RUN_WORKFLOW_TOOL_NAME;
283
- function createWorkflowAskPolicy(isExempt) {
290
+ export function createWorkflowAskPolicy(isExempt) {
284
291
  return {
285
292
  async check(req) {
286
293
  if (heldRuleName(req, isWorkflowName) === undefined)
@@ -302,17 +309,31 @@ function createWorkflowAskPolicy(isExempt) {
302
309
  function rejectUnmatchableSettingsNames(perms, pathBases) {
303
310
  const refused = rulePolicyBucketsRefusal(perms, { ...(pathBases !== undefined ? { declared: pathBases } : {}), ...(pathBases?.home !== undefined ? { home: pathBases.home } : {}) });
304
311
  if (refused !== undefined)
305
- throw new Error(refused.message);
312
+ throw new SettingsRuleRefusalError(refused.message, refused.problems);
313
+ }
314
+ export class SettingsRuleRefusalError extends Error {
315
+ problems;
316
+ constructor(message, problems) {
317
+ super(message);
318
+ this.problems = problems;
319
+ this.name = "SettingsRuleRefusalError";
320
+ }
306
321
  }
322
+ export const SETTINGS_RULE_REFUSAL_CODE = "request.unprocessable";
307
323
  export const RULE_POLICY_BUCKETS = ["ask", "deny"];
308
324
  export function rulePolicyBucketsRefusal(permissions, bases) {
325
+ let first;
326
+ const problems = [];
309
327
  for (const bucket of RULE_POLICY_BUCKETS) {
310
328
  const names = permissions[bucket];
311
329
  if (!names)
312
330
  continue;
313
- const unmatchable = unmatchableToolNamesRefusal(`permissions.${bucket}`, names, { consumer: "rule-policy", behavior: bucket, ...(bases.declared !== undefined ? { pathBases: bases.declared } : {}) });
314
- if (unmatchable !== undefined)
315
- return { bucket, message: unmatchable.message };
331
+ const judged = judgeUnmatchableToolNames(`permissions.${bucket}`, names, { consumer: "rule-policy", behavior: bucket, ...(bases.declared !== undefined ? { pathBases: bases.declared } : {}) });
332
+ if (judged === undefined)
333
+ continue;
334
+ first ??= { bucket, message: judged.message };
335
+ for (const b of judged.bad)
336
+ problems.push(entryProblem(SETTINGS_RULE_REFUSAL_CODE, `settings.permissions.${bucket}`, b.name, b.reason));
316
337
  }
317
338
  if (bases.home === undefined) {
318
339
  for (const bucket of RULE_POLICY_BUCKETS) {
@@ -320,73 +341,60 @@ export function rulePolicyBucketsRefusal(permissions, bases) {
320
341
  for (const name of permissions[bucket] ?? []) {
321
342
  const parsed = parseRuleText(name, bucket);
322
343
  if ("rule" in parsed && ruleToolGrammarOf(parsed.rule.tool) === "path" && parsed.rule.command.startsWith("~/")) {
323
- return {
344
+ first ??= {
324
345
  bucket,
325
346
  message: `${field} has a home-relative path rule (${name}) but this deployment cannot resolve the EXECUTION environment's home directory — ` +
326
347
  `the engine never guesses one: without a home base the rule resolves to "unreadable" and every matching call stops to ask, so it guards nothing. ` +
327
348
  `Spell the path absolutely (${"Edit(//abs/path/**)"} form), declare the lane's home with REMOTE_EXEC_HOME_DIR, or run the task on a lane whose home this worker knows.`,
328
349
  };
350
+ problems.push(entryProblem(SETTINGS_RULE_REFUSAL_CODE, `settings.${field}`, name, "home_unresolvable"));
329
351
  }
330
352
  }
331
353
  }
332
354
  }
333
- return undefined;
355
+ return first === undefined ? undefined : { ...first, problems };
334
356
  }
335
357
  export const REQUEST_SETTINGS_REFUSAL_PREFIX = "request settings cannot be applied as written: ";
336
- export function deriveSettingsPolicy(settings, gate, workflowGate) {
358
+ export function deriveSettingsPolicy(settings, bases) {
337
359
  const perms = settings.permissions;
338
- if (!perms)
360
+ const neverAuto = settings.tightenOnly?.neverAuto;
361
+ if (!perms && neverAuto === undefined)
339
362
  return {};
340
- const { deny, ask, defaultMode } = perms;
341
- const pathBases = gate?.taskRoot !== undefined || gate?.taskHome !== undefined
342
- ? { ...(gate.taskRoot !== undefined ? { root: gate.taskRoot } : {}), ...(gate.taskHome !== undefined ? { home: gate.taskHome } : {}) }
343
- : undefined;
344
- rejectUnmatchableSettingsNames(perms, pathBases);
345
363
  const policies = [];
346
- if (deny)
347
- policies.push(createRuleListPolicy(deny, "deny", RULE_SOURCE_BY_BEHAVIOR.deny, pathBases));
348
- if (ask)
349
- policies.push(createRuleListPolicy(ask, "ask", RULE_SOURCE_BY_BEHAVIOR.ask, pathBases));
350
- const fsWriteGate = (acceptCwd) => {
351
- if (!gate)
352
- return undefined;
353
- const gatePolicy = createFsWriteGatePolicy({
354
- env: gate.env,
355
- ...(gate.cwd !== undefined ? { rootPath: gate.cwd } : {}),
356
- ...(acceptCwd && gate.cwd !== undefined ? { acceptDirs: [gate.cwd] } : {}),
357
- ...(gate.scratchpadDir ? { exemptDirs: [gate.scratchpadDir] } : {}),
358
- ...(gate.isExempt ? { isExempt: gate.isExempt } : {}),
359
- defaultWrite: "ask",
360
- });
361
- return gatePolicy;
362
- };
363
- const compose = (...extra) => {
364
- const all = [...policies, ...extra.filter((p) => p !== undefined)];
365
- return all.length === 0 ? undefined : all.length === 1 ? all[0] : combinePolicies(...all);
366
- };
367
- const basePolicy = compose();
368
- switch (defaultMode) {
369
- case "acceptEdits": {
370
- const p = compose(fsWriteGate(true), createWorkflowAskPolicy(workflowGate?.isExempt));
371
- return p ? { toolPolicy: p } : {};
372
- }
373
- case "default":
374
- case "auto":
375
- case "dontAsk":
376
- case "plan": {
377
- const p = compose(createWorkflowAskPolicy(workflowGate?.isExempt));
378
- return p ? { toolPolicy: p } : {};
379
- }
380
- case "bypassPermissions":
381
- case undefined:
382
- return basePolicy ? { toolPolicy: basePolicy } : {};
364
+ if (perms) {
365
+ const { deny, ask } = perms;
366
+ const pathBases = bases?.taskRoot !== undefined || bases?.taskHome !== undefined
367
+ ? { ...(bases.taskRoot !== undefined ? { root: bases.taskRoot } : {}), ...(bases.taskHome !== undefined ? { home: bases.taskHome } : {}) }
368
+ : undefined;
369
+ rejectUnmatchableSettingsNames(perms, pathBases);
370
+ if (deny)
371
+ policies.push(createRuleListPolicy(deny, "deny", RULE_SOURCE_BY_BEHAVIOR.deny, pathBases));
372
+ if (ask)
373
+ policies.push(createRuleListPolicy(ask, "ask", RULE_SOURCE_BY_BEHAVIOR.ask, pathBases));
374
+ }
375
+ if (neverAuto !== undefined) {
376
+ const refused = neverAutoNamesRefusal(neverAuto);
377
+ if (refused !== undefined)
378
+ throw new SettingsRuleRefusalError(refused.message, refused.problems);
379
+ policies.push(createRequestNeverAutoPolicy(neverAuto, tightenOnlySeatField("neverAuto")));
383
380
  }
381
+ if (policies.length === 0)
382
+ return {};
383
+ return { toolPolicy: policies.length === 1 ? policies[0] : combinePolicies(...policies) };
384
+ }
385
+ export function neverAutoNamesRefusal(names) {
386
+ const field = tightenOnlySeatField("neverAuto");
387
+ const judged = judgeUnmatchableToolNames(field.replace(/^settings\./, ""), names, { consumer: "tool-name-table", behavior: "deny" });
388
+ if (judged === undefined)
389
+ return undefined;
390
+ return { message: judged.message, problems: judged.bad.map((b) => entryProblem(SETTINGS_RULE_REFUSAL_CODE, field, b.name, b.reason)) };
384
391
  }
385
- export function applyTaskSettings(base, settings, gate, workflowGate) {
386
- const { toolPolicy } = deriveSettingsPolicy(settings, gate, workflowGate);
392
+ export function applyTaskSettings(base, settings, bases) {
393
+ const { toolPolicy } = deriveSettingsPolicy(settings, bases);
394
+ const seatSpec = settings.tightenOnly !== undefined ? tightenOnlySpecSeats(settings.tightenOnly) : {};
387
395
  let next = base;
388
- if (toolPolicy !== undefined)
389
- next = tightenGoverned(next, { toolPolicy });
396
+ if (toolPolicy !== undefined || Object.keys(seatSpec).length > 0)
397
+ next = tightenGoverned(next, { ...(toolPolicy !== undefined ? { toolPolicy } : {}), ...seatSpec });
390
398
  const allow = settings.permissions?.allow;
391
399
  if (allow !== undefined)
392
400
  next = { ...next, allowedTools: allow };
@@ -1,7 +1,3 @@
1
- /** bidi ∪ C0/DEL —— **清洗**面用(见文件头注:清洗面比检测面宽是刻意的)。bidi 半场内插 core 的类,C0/DEL 半场是本仓清洗面自己的。 */
2
- export declare const CONTROL_AND_BIDI_CHARS = "\\u0000-\\u001f\\u007f\\u061C\\u200E\\u200F\\u202A-\\u202E\\u2066-\\u2069";
3
- /** 清洗用的全局正则(`String.replace` 会在返回前把 `lastIndex` 归零,故模块级常量可安全复用)。 */
4
- export declare const CONTROL_AND_BIDI_STRIP_RE: RegExp;
5
1
  /** 这串文本里**有没有** bidi 控制符(判官 = core 的 {@link carriesBidiControls})。纯谓词:不改一个字节、不做任何清洗(理由见文件头注)。 */
6
2
  export declare function hasBidiControls(text: string): boolean;
7
3
  //# sourceMappingURL=text-bidi.d.ts.map
package/dist/text-bidi.js CHANGED
@@ -1,6 +1,4 @@
1
- import { BIDI_CONTROL_CHARS, carriesBidiControls } from "@sema-agent/core";
2
- export const CONTROL_AND_BIDI_CHARS = `\\u0000-\\u001f\\u007f${BIDI_CONTROL_CHARS}`;
3
- export const CONTROL_AND_BIDI_STRIP_RE = new RegExp(`[${CONTROL_AND_BIDI_CHARS}]`, "g");
1
+ import { carriesBidiControls } from "@sema-agent/core";
4
2
  const WHOLE_TEXT_SCAN = { maxNodes: 1, maxChars: Number.MAX_SAFE_INTEGER };
5
3
  export function hasBidiControls(text) {
6
4
  return carriesBidiControls(text, WHOLE_TEXT_SCAN);