@sema-agent/server 7.43.0 → 7.44.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 (345) hide show
  1. package/USAGE.md +18 -0
  2. package/dist/adoption/plan.js +31 -192
  3. package/dist/adoption/quiesce.js +3 -86
  4. package/dist/adoption/runner.js +3 -140
  5. package/dist/adoption/sql.js +0 -74
  6. package/dist/adoption/wire.js +0 -80
  7. package/dist/approval-ask-machine.js +0 -75
  8. package/dist/approval-card.js +0 -323
  9. package/dist/approval-deny-reasons.js +0 -42
  10. package/dist/approval-hmac.js +0 -35
  11. package/dist/approval-reconciler.js +8 -166
  12. package/dist/approval.js +4 -67
  13. package/dist/audit.js +1 -44
  14. package/dist/auth-bridge.js +4 -47
  15. package/dist/auth-keys.js +0 -23
  16. package/dist/bake-runner/main.js +4 -65
  17. package/dist/bake-runner/protocol.js +3 -58
  18. package/dist/bake-runner/runner.js +5 -91
  19. package/dist/bench/l8/artifact.js +2 -61
  20. package/dist/bench/l8/escape.js +0 -25
  21. package/dist/bench/l8/index.js +0 -14
  22. package/dist/bench/l8/probes.js +0 -60
  23. package/dist/bench/l8/run-probes.js +2 -45
  24. package/dist/bench/s1/arms.js +14 -189
  25. package/dist/bench/s1/live-deps.js +11 -253
  26. package/dist/bench/s1/oracle.js +1 -36
  27. package/dist/bench/s1/repair-oracle-adapter.js +0 -30
  28. package/dist/bench/s1/reviewer.js +0 -34
  29. package/dist/bench/s1/row.js +0 -62
  30. package/dist/bench/s1/run-firm.js +4 -70
  31. package/dist/bench/s1/runner-ctx.js +0 -40
  32. package/dist/bench/s1/tasks.js +0 -115
  33. package/dist/boot/adoption.js +0 -20
  34. package/dist/boot/budget-tracing.js +3 -55
  35. package/dist/boot/config-center.js +43 -551
  36. package/dist/boot/coordinators.js +1 -69
  37. package/dist/boot/crash-last.js +0 -18
  38. package/dist/boot/deferred-sandbox-path-env.js +3 -119
  39. package/dist/boot/execution-env.js +5 -171
  40. package/dist/boot/governance-seams.js +0 -92
  41. package/dist/boot/leader.js +0 -69
  42. package/dist/boot/limit-sync.js +0 -2
  43. package/dist/boot/memory-boundary.js +3 -91
  44. package/dist/boot/org-memory.js +1 -25
  45. package/dist/boot/parked-revive-gate.js +0 -150
  46. package/dist/boot/permission-rules-audit.js +1 -56
  47. package/dist/boot/reapers.js +15 -273
  48. package/dist/boot/resolve-spec.js +9 -768
  49. package/dist/boot/retention-lane.js +4 -87
  50. package/dist/boot/runner-deps.js +3 -297
  51. package/dist/boot/runtime-caps.js +0 -40
  52. package/dist/boot/session-faces.js +2 -133
  53. package/dist/boot/shutdown.js +9 -83
  54. package/dist/boot/side-query-lane.js +2 -137
  55. package/dist/boot/stores.js +15 -215
  56. package/dist/boot/task-list-lane.js +0 -18
  57. package/dist/boot/webfetch-summarize-lane.js +0 -47
  58. package/dist/boot/workflow-orchestration.js +3 -99
  59. package/dist/boot-reclaim.js +0 -20
  60. package/dist/bounded-session-map.js +0 -19
  61. package/dist/brain.js +2 -139
  62. package/dist/budget.js +9 -244
  63. package/dist/capabilities/builtin-tools.js +0 -3
  64. package/dist/capabilities/center-plugins.js +6 -51
  65. package/dist/capabilities/center-prompts.js +6 -71
  66. package/dist/capabilities/code-review-council.js +7 -40
  67. package/dist/capabilities/collab-workflows.js +1 -44
  68. package/dist/capabilities/hands-lane.js +0 -65
  69. package/dist/capabilities/memory-notice.js +0 -70
  70. package/dist/capabilities/prompt.js +0 -14
  71. package/dist/capabilities/prompts/code-review.js +0 -14
  72. package/dist/capabilities/prompts/identity.js +0 -6
  73. package/dist/capabilities/prompts/team.js +0 -4
  74. package/dist/capabilities/repo-tools.js +0 -34
  75. package/dist/capabilities/sandbox-file-send.js +3 -92
  76. package/dist/capabilities/scenarios.d.ts +0 -1
  77. package/dist/capabilities/scenarios.js +18 -279
  78. package/dist/capabilities/select-environment-tool.js +0 -32
  79. package/dist/capabilities/send-user-file-tool.js +2 -66
  80. package/dist/capabilities/skills.d.ts +1 -2
  81. package/dist/capabilities/skills.js +3 -21
  82. package/dist/capabilities/team.d.ts +3 -11
  83. package/dist/capabilities/team.js +3 -51
  84. package/dist/capabilities/tool-defer.js +0 -3
  85. package/dist/config-center/apply-effective.js +15 -330
  86. package/dist/config-center/apply-ledger.js +5 -38
  87. package/dist/config-center/facade.js +0 -41
  88. package/dist/config-center/hot-keys-registry.js +0 -20
  89. package/dist/config-center/http-client.js +2 -125
  90. package/dist/config-center/mcp-revocation.js +2 -34
  91. package/dist/config-center/read-face.js +0 -59
  92. package/dist/config-center/restart-signal.js +1 -85
  93. package/dist/config-center/skills-mcp.d.ts +1 -1
  94. package/dist/config-center/skills-mcp.js +9 -76
  95. package/dist/config-center/stage-limits.js +8 -35
  96. package/dist/config-invariants.js +0 -16
  97. package/dist/config-lkg.js +0 -42
  98. package/dist/config-provider.js +3 -186
  99. package/dist/config-types.js +0 -5
  100. package/dist/config.js +107 -1145
  101. package/dist/degenerate-instrument.js +3 -67
  102. package/dist/deployment-governance.js +0 -124
  103. package/dist/digest-form.js +0 -12
  104. package/dist/elicitation.js +3 -86
  105. package/dist/env-facts.js +7 -75
  106. package/dist/fleet/fleet-bus.js +34 -507
  107. package/dist/fleet/fleet-reconciler.js +9 -149
  108. package/dist/fleet/fleet-terminal-window.js +10 -178
  109. package/dist/fleet/subagent-tail-bus.js +3 -72
  110. package/dist/fleet-client.js +10 -70
  111. package/dist/fleet-lease.js +5 -79
  112. package/dist/git-api-kind.js +0 -3
  113. package/dist/governance-ask-marks.js +2 -78
  114. package/dist/hooks/branch-transcript.js +0 -74
  115. package/dist/hooks/cc-agent-hook-prompt.js +0 -29
  116. package/dist/hooks/cc-stop-prompt.js +1 -46
  117. package/dist/hooks/hook-llm.js +1 -53
  118. package/dist/hooks/hook-runner.js +20 -414
  119. package/dist/http/active-run-conflict.js +4 -129
  120. package/dist/http/cursor-fingerprint.d.ts +5 -0
  121. package/dist/http/cursor-fingerprint.js +5 -0
  122. package/dist/http/idempotency.js +0 -37
  123. package/dist/http/principal-gate.js +3 -40
  124. package/dist/http/route-ctx.js +0 -9
  125. package/dist/http/routes/a2a-serve.js +7 -319
  126. package/dist/http/routes/admin-config-refresh.js +0 -4
  127. package/dist/http/routes/admin-drain.js +0 -10
  128. package/dist/http/routes/adoption.js +1 -29
  129. package/dist/http/routes/agents-roster.js +1 -47
  130. package/dist/http/routes/approvals-assistant.js +32 -395
  131. package/dist/http/routes/attachments.js +4 -22
  132. package/dist/http/routes/capabilities.js +3 -420
  133. package/dist/http/routes/diagnostics.js +1 -81
  134. package/dist/http/routes/fleet.js +9 -185
  135. package/dist/http/routes/images.js +14 -239
  136. package/dist/http/routes/leader.js +0 -13
  137. package/dist/http/routes/memory-bundle.js +1 -61
  138. package/dist/http/routes/memory-policy.js +9 -99
  139. package/dist/http/routes/notify-wake.js +3 -37
  140. package/dist/http/routes/observability.js +2 -19
  141. package/dist/http/routes/retention-ops.js +2 -34
  142. package/dist/http/routes/rules.js +1 -93
  143. package/dist/http/routes/runs.js +64 -873
  144. package/dist/http/routes/session-sync.js +19 -258
  145. package/dist/http/routes/sessions-list.js +17 -43
  146. package/dist/http/routes/sessions.js +34 -226
  147. package/dist/http/routes/shared-memory.js +5 -36
  148. package/dist/http/routes/side-query.js +1 -87
  149. package/dist/http/routes/tasks.js +52 -722
  150. package/dist/http/routes/trace-usage.js +32 -195
  151. package/dist/http/routes/workflows.js +19 -195
  152. package/dist/http/run-meta.js +0 -6
  153. package/dist/http/send.js +0 -32
  154. package/dist/http/server.js +92 -1597
  155. package/dist/http/sse-lifecycle.js +2 -13
  156. package/dist/http/sse-log.js +3 -48
  157. package/dist/http/tar.js +5 -21
  158. package/dist/http/verify-rounds.js +0 -5
  159. package/dist/http/wire-gate.js +0 -9
  160. package/dist/http/workspace-content.js +0 -10
  161. package/dist/images/bake-validate.js +1 -70
  162. package/dist/images/manifest.js +1 -6
  163. package/dist/index.js +0 -21
  164. package/dist/key-resolver.js +2 -17
  165. package/dist/leader/diffout.js +1 -20
  166. package/dist/leader/diffup.js +0 -47
  167. package/dist/leader/endpoint.js +2 -57
  168. package/dist/leader/fanout.js +3 -45
  169. package/dist/leader/grader-env-factory.js +3 -72
  170. package/dist/leader/leader.js +5 -156
  171. package/dist/leader/merge.js +8 -115
  172. package/dist/leader/planner.js +3 -54
  173. package/dist/leader/repair-oracle.js +1 -60
  174. package/dist/leader/repair-wire.js +2 -79
  175. package/dist/leader/wire.js +8 -307
  176. package/dist/lsp/e2b-bridge.js +4 -64
  177. package/dist/lsp/e2b-manager.js +6 -94
  178. package/dist/lsp/lsp-frames.js +0 -12
  179. package/dist/lsp/manager.js +4 -96
  180. package/dist/lsp/ws-transport.js +5 -55
  181. package/dist/lsp-evict.js +1 -15
  182. package/dist/main.js +57 -765
  183. package/dist/memory-bundle-engine.js +0 -55
  184. package/dist/memory-export.js +0 -4
  185. package/dist/memory-posture.js +1 -15
  186. package/dist/memory-scope.js +11 -148
  187. package/dist/memory-sync-client.js +2 -44
  188. package/dist/memory-sync.js +1 -80
  189. package/dist/model-select.js +3 -80
  190. package/dist/observability/cost-quota.js +1 -17
  191. package/dist/observability/cost-taxonomy.js +0 -34
  192. package/dist/observability/fail-open.js +7 -86
  193. package/dist/observability/logger.js +0 -6
  194. package/dist/observability/metrics.js +0 -94
  195. package/dist/observability/otel-exporter.js +3 -13
  196. package/dist/observability/principal-context.js +0 -9
  197. package/dist/observability/prompt-manifest.js +1 -37
  198. package/dist/observability/rate-limit.js +0 -4
  199. package/dist/observability/secret-env-scrub.js +2 -56
  200. package/dist/observability/tool-trace.js +1 -70
  201. package/dist/orchestration/hardened-vm-runner.js +4 -118
  202. package/dist/orchestration/hardened-vm-worker-runner.js +1 -26
  203. package/dist/orchestration/hardened-vm-worker.js +0 -27
  204. package/dist/orchestration/subagent-steer.js +1 -45
  205. package/dist/orchestration/workflow-agent-steer.js +1 -80
  206. package/dist/orchestration/workflow-completion-inbox.js +32 -285
  207. package/dist/orchestration/workflow-notify-journal.js +16 -259
  208. package/dist/org-memory-admission.js +3 -47
  209. package/dist/parent-watch.js +2 -48
  210. package/dist/parked-decide.js +1 -109
  211. package/dist/per-task-image.js +0 -57
  212. package/dist/plan-cache-probe.js +3 -27
  213. package/dist/plugins/adoption-log-sql.js +2 -119
  214. package/dist/plugins/approval-ask-store-memory.js +3 -38
  215. package/dist/plugins/approval-ask-store-sql.js +6 -188
  216. package/dist/plugins/approval-exemption-store.js +2 -28
  217. package/dist/plugins/background-agent-store-sql.js +4 -105
  218. package/dist/plugins/background-shell-support.js +14 -122
  219. package/dist/plugins/blob-backend.js +6 -169
  220. package/dist/plugins/breaker-state-sql.js +8 -46
  221. package/dist/plugins/caching-session-store.js +4 -106
  222. package/dist/plugins/checkpoint-store-sql.js +18 -505
  223. package/dist/plugins/e2b-orphan-reclaim.js +0 -45
  224. package/dist/plugins/file-outcome-sink.js +0 -9
  225. package/dist/plugins/file-resume-anchor-store.js +4 -43
  226. package/dist/plugins/file-run-store.js +26 -364
  227. package/dist/plugins/file-snapshot-store-sql.js +10 -181
  228. package/dist/plugins/fork-routing-session-store.js +8 -111
  229. package/dist/plugins/host-platform.js +2 -91
  230. package/dist/plugins/image-bake-store-sql.js +7 -250
  231. package/dist/plugins/image-index-sql.js +4 -123
  232. package/dist/plugins/k8s-bg-scripts.js +4 -88
  233. package/dist/plugins/k8s-exec-protocol.js +0 -41
  234. package/dist/plugins/leader-run-store-sql.js +0 -101
  235. package/dist/plugins/local-checkpoint-store.js +8 -128
  236. package/dist/plugins/local-session-store.js +34 -296
  237. package/dist/plugins/local-task-attachment-store.js +2 -16
  238. package/dist/plugins/mailbox-store-sql.js +8 -65
  239. package/dist/plugins/memory-embedder-fingerprint.js +5 -166
  240. package/dist/plugins/memory-embedder.js +4 -70
  241. package/dist/plugins/memory-engine-pg.js +6 -170
  242. package/dist/plugins/memory-engine-tidb.js +7 -155
  243. package/dist/plugins/memory-engine-vector-util.js +0 -10
  244. package/dist/plugins/memory-key-guards.js +0 -34
  245. package/dist/plugins/memory-origin-law.js +0 -187
  246. package/dist/plugins/memory-resume-anchor-store.js +0 -17
  247. package/dist/plugins/memory-run-store.js +12 -89
  248. package/dist/plugins/memory-session-policy-store.js +0 -17
  249. package/dist/plugins/memory-sync-store-pg.js +4 -49
  250. package/dist/plugins/memory-sync-store-tidb.js +3 -35
  251. package/dist/plugins/outcome-ledger-sql.js +3 -97
  252. package/dist/plugins/permission-rule-store-file.js +5 -133
  253. package/dist/plugins/permission-rule-store-sql.d.ts +3 -0
  254. package/dist/plugins/permission-rule-store-sql.js +50 -307
  255. package/dist/plugins/pg-cost-quota.js +0 -7
  256. package/dist/plugins/pg-pool.js +0 -92
  257. package/dist/plugins/pg-rate-limiter.js +2 -13
  258. package/dist/plugins/pg-safe-json.js +4 -40
  259. package/dist/plugins/pg-session-storage.js +25 -189
  260. package/dist/plugins/posix-shell-fs.js +1 -31
  261. package/dist/plugins/remote-env-adb.js +12 -101
  262. package/dist/plugins/remote-env-e2b.js +40 -371
  263. package/dist/plugins/remote-env-file-error.js +0 -37
  264. package/dist/plugins/remote-env-host.js +63 -483
  265. package/dist/plugins/remote-env-k8s.js +32 -326
  266. package/dist/plugins/remote-env-local-docker.js +24 -157
  267. package/dist/plugins/remote-env-ssh.js +20 -128
  268. package/dist/plugins/remote-scratchpad.js +2 -32
  269. package/dist/plugins/remote-shell.js +1 -32
  270. package/dist/plugins/resume-anchor-store-sql.js +0 -11
  271. package/dist/plugins/retention-lane-store-sql.js +0 -108
  272. package/dist/plugins/retention-store-sql.js +4 -383
  273. package/dist/plugins/roster-store-sql.js +0 -55
  274. package/dist/plugins/run-store-sql.js +14 -251
  275. package/dist/plugins/s3-presign.js +2 -49
  276. package/dist/plugins/scheduler-support.js +3 -80
  277. package/dist/plugins/send-file-ledger.js +4 -53
  278. package/dist/plugins/send-user-file.js +4 -94
  279. package/dist/plugins/session-placement.js +1 -89
  280. package/dist/plugins/session-policy-store-sql.js +3 -81
  281. package/dist/plugins/session-store.js +0 -57
  282. package/dist/plugins/shared-memory-store-sql.js +4 -167
  283. package/dist/plugins/sql-driver.js +0 -17
  284. package/dist/plugins/sql-errors.js +0 -7
  285. package/dist/plugins/sql-escape.js +0 -8
  286. package/dist/plugins/sql-row-helpers.js +0 -25
  287. package/dist/plugins/store-backend.js +42 -222
  288. package/dist/plugins/store-contracts.js +2 -46
  289. package/dist/plugins/task-attachment-store.js +3 -49
  290. package/dist/plugins/task-list-store-sql.js +0 -79
  291. package/dist/plugins/tidb-cost-quota.js +1 -4
  292. package/dist/plugins/tidb-pool.js +1 -207
  293. package/dist/plugins/tidb-rate-limiter.js +3 -9
  294. package/dist/plugins/tidb-session-storage.js +4 -70
  295. package/dist/plugins/tidb-session-store.js +19 -341
  296. package/dist/plugins/tool-result-store-sql.js +4 -179
  297. package/dist/plugins/usage-window-store-sql.js +0 -8
  298. package/dist/plugins/web-search.js +10 -132
  299. package/dist/plugins/workflow-journal-store-sql.js +2 -58
  300. package/dist/plugins/workflow-run-store-sql.js +6 -91
  301. package/dist/plugins/worktree-isolation.js +6 -126
  302. package/dist/plugins/write-behind-counter.js +16 -75
  303. package/dist/principal-jwt.js +5 -60
  304. package/dist/project-memory.js +15 -146
  305. package/dist/prompts-domain-validate.js +1 -51
  306. package/dist/question.js +2 -111
  307. package/dist/resource-suspend.js +0 -18
  308. package/dist/router/route-orchestration.js +0 -77
  309. package/dist/rules-consent.d.ts +44 -5
  310. package/dist/rules-consent.js +75 -215
  311. package/dist/run-local.js +14 -381
  312. package/dist/runs.js +29 -617
  313. package/dist/runtime-caps-resolver.js +6 -132
  314. package/dist/runtime-governance.js +1 -232
  315. package/dist/sandbox-pkg-source.js +0 -37
  316. package/dist/sealed-key.js +3 -68
  317. package/dist/security.js +6 -291
  318. package/dist/session-leaf-bus.js +0 -32
  319. package/dist/session-sync-content.js +1 -69
  320. package/dist/session-sync-kernel.js +3 -60
  321. package/dist/session-sync.js +3 -66
  322. package/dist/session-titler.js +7 -41
  323. package/dist/session-watch.js +9 -73
  324. package/dist/shared-memory-scope-authorizer.js +0 -18
  325. package/dist/sighup-idle.js +1 -12
  326. package/dist/spec-fields.js +4 -143
  327. package/dist/store-live-probe.js +3 -49
  328. package/dist/task-a2a.js +1 -126
  329. package/dist/task-cwd.js +1 -103
  330. package/dist/task-mcp.js +1 -89
  331. package/dist/task-settings.js +10 -300
  332. package/dist/task-workflow.js +8 -75
  333. package/dist/tool-approval.d.ts +28 -1
  334. package/dist/tool-approval.js +70 -1430
  335. package/dist/trace/artifacts.js +5 -20
  336. package/dist/trace/engine-notice-wire.js +6 -138
  337. package/dist/trace/ledger-sink.js +7 -96
  338. package/dist/trace/project.js +4 -448
  339. package/dist/trace/redact.js +9 -77
  340. package/dist/turn-activity.js +1 -27
  341. package/dist/usage-analytics.js +4 -34
  342. package/dist/wall-clock-jump-guard.js +1 -68
  343. package/package.json +3 -3
  344. package/dist/capabilities/scenario-alias.d.ts +0 -27
  345. package/dist/capabilities/scenario-alias.js +0 -61
@@ -1,62 +1,8 @@
1
- /**
2
- * #203 §1(design/203 v2 §6 F1)—— 持久化权限规则店的 **local(File)三面束**。
3
- *
4
- * 车二在 `store-backend.ts` 上写下的那句「local 车道诚实缺席」有一条**明写的解除条件**:「要在 local
5
- * 真上,先落 File 形(core 现成 `FilePermissionRuleStoreProvider` 即可当模子)」。本文件就是那一件 ——
6
- * 三面里**规则桶那一面直接接线 core 的现成件**(不是照抄:它自带符号链接拒收、写锁、整文件校验和、
7
- * 损坏即整份拒读,那几样都不是能顺手复刻对的东西),另外两面(审批记录 / 导入票)core 只给了
8
- * `InMemory` 参照物,所以在这里落 File 形。
9
- *
10
- * ─────────────────────────────────────────────────────────────────────────────────────────────────
11
- * 🔴 为什么 File 形的「单进程内 CAS」是**够的**(而不是一次偷工)
12
- * ─────────────────────────────────────────────────────────────────────────────────────────────────
13
- * SQL 形把 CAS 交给引擎的行锁,是因为多副本共享一张表。local 车道不是那个形状:`LocalBackend` 的构造
14
- * 函数在数据根上取 `root/LOCK` 这只 boot pidfile 锁,**同主机第二个实例起不来**(store-backend.ts 的
15
- * `LocalBackend` 头注逐字);core 的 `FilePermissionRuleStoreProvider` 自己还在规则目录上另取一把写锁,
16
- * 第二个持有者被响亮拒绝而不是交错写。⇒ 在这条车道上「同一时刻只有一个写者」是**被强制**的,不是被
17
- * 假设的,于是进程内的 `rev` 比较就是一次真 compare-and-set。
18
- * 这条推理有一个已登记的边界(与 core 的 File 规则店同源、不是本文件新增的):跨 PID 命名空间或 NFS
19
- * 上 `process.kill(pid,0)` 的活体判据会失效(见 `docs/DEPLOY-PREREQS.md`)。那时该换 SQL 后端 ——
20
- * 这正是 store seam 存在的理由。
21
- *
22
- * ─────────────────────────────────────────────────────────────────────────────────────────────────
23
- * 🔴 落盘形:一票据/一记录一行 JSONL 追加日志 + boot 重放,**不是**整文件覆写
24
- * ─────────────────────────────────────────────────────────────────────────────────────────────────
25
- * 与 `FileApprovalExemptionStore` / `FileSendFileLedger` 同一个模子(core 的 `AppendLog` /
26
- * `readJsonlRecords`:追加 + fsync,撕裂的尾行在重放时被丢掉而不是被猜出来)。选它而不是「整份 JSON
27
- * 原子改名」的理由是**这两面的写都是逐条的**(一次审批一条、一张票一条),整份覆写会让一次写的代价随
28
- * 历史长度线性涨,而且把「两条无关记录」放进同一次 CAS 窗口。
29
- * 代价如实登记:日志只增不减(没有紧凑腿)。票有 TTL、记录是审计事实,单用户一台机器上的量级是每天
30
- * 几条到几十条 —— 真长到要紧凑时,该做的是紧凑腿(后续件),不是现在为它牺牲崩溃安全。
31
- *
32
- * ─────────────────────────────────────────────────────────────────────────────────────────────────
33
- * 🔴 状态在**内存索引**里,磁盘是它的重放源
34
- * ─────────────────────────────────────────────────────────────────────────────────────────────────
35
- * 判决(CAS 成不成、票能不能认领)一律读内存索引,写成功后**先追加日志再改索引** —— 反过来(先改索引
36
- * 再写盘)会在写失败时留下一个「进程认为已经发生、盘上没有」的事实,重启即回滚,而中间那段时间里
37
- * 一次已经被消费掉的票会被当成还能用。
38
- */
39
1
  import { join } from "node:path";
40
2
  import { readdirSync } from "node:fs";
41
3
  import { FilePermissionRuleStoreProvider, AppendLog, ensureDir, readJsonlRecords, } from "@sema-agent/core";
42
4
  import { z } from "zod";
43
5
  import { buildRulePayloadHash } from "./permission-rule-store-sql.js";
44
- // ─────────────────────────────────────────────────────────────────────────────────────────────────
45
- // 落盘记录的边界 schema(宪法 [2704]:边界必 schema,禁裸 as-cast)
46
- // ─────────────────────────────────────────────────────────────────────────────────────────────────
47
- //
48
- // 🔴 这**是**一条边界:磁盘上的字节可能来自上一个版本、来自一次手改、来自一次撕裂写。读回来的东西
49
- // 若被 as-cast 成域类型,一条缺字段的记录会带着 `undefined` 走进 CAS 与兑付判决。判据用 zod。
50
- //
51
- // 🔴 读不出形的**内部**行 ⇒ 整面 fail-closed(codex 对抗复审 R1-F4,验真后修)。
52
- // 本文件的初版写的是「坏行跳过 —— 一行是一条独立事实」,那句话是**错的**,而且错在最贵的地方:
53
- // 票日志上的 mint / consume / release 是**同一张票的状态迁移**。一条 `consume` 坏掉而它前面的 `mint`
54
- // 还读得出 ⇒ 重启后那张票复活成**未认领**,「一次性消费」这条信任边界当场失效(SQL 形靠引擎行锁,
55
- // 永远不会有这种形)。审批记录同族:一条坏掉的快照会把记录连同 `rev` 回滚到更早的状态。
56
- // 处置与 core 对**规则文件**的姿势对齐 ——「refusing the whole bucket rather than reporting a partial
57
- // rule set」:整面拒 + 响亮留痕。失败方向是收紧(兑不动 ⇒ 多问几次),这正是这条轴该倒的方向。
58
- // **撕裂的尾行不算**:core 的 `readJsonlRecords` 按崩溃尾丢弃它并且**不**报 `onCorrupt` —— 那是每次
59
- // 非优雅退出的正常落盘形,把它算成损坏会让一次 kill -9 永久锁死这条车道。
60
6
  const RuleScopeSchema = z.union([
61
7
  z.object({ kind: z.literal("global") }).strict(),
62
8
  z.object({ kind: z.literal("project"), root: z.string().min(1) }).strict(),
@@ -74,20 +20,13 @@ const ApprovalRecordSchema = z
74
20
  createdAt: z.string(),
75
21
  toolCallId: z.string().optional(),
76
22
  boundInputHash: z.string().optional(),
23
+ command: z.string().optional(),
24
+ edited: z.object({ index: z.number().int().nonnegative().safe(), text: z.string(), at: z.string() }).strict().optional(),
77
25
  rev: z.number().int().nonnegative().safe(),
78
26
  selectedCandidate: z.number().int().nonnegative().safe().optional(),
79
27
  redeemedDots: z.record(z.string(), RuleDotSchema).optional(),
80
28
  })
81
29
  .strict();
82
- /**
83
- * 校验产物 → 域类型的**显式**投影。
84
- *
85
- * 🔴 为什么是一个函数而不是 `.transform(...)` 上挂一个断言:`RuleApprovalRecord.redeemedDots` 的键是
86
- * `number`,而 JSON 对象的键恒是字符串 —— zod 只表达得出 `Record<string, …>`,于是「用 zod 直接声明成
87
- * 域类型」必然要一次 `as unknown as`,那正是宪法禁的裸断言。逐字段抄写换来的是:core 给
88
- * `RuleApprovalRecord` 加一个必填字段时,**这里编译红**(而断言形会静默放行一条缺字段的记录)。
89
- * 数字键的还原与 SQL 侧 `redeemed_dots_json` 的回读逐字同一处置。
90
- */
91
30
  function toApprovalRecord(row) {
92
31
  return {
93
32
  id: row.id,
@@ -99,6 +38,8 @@ function toApprovalRecord(row) {
99
38
  createdAt: row.createdAt,
100
39
  ...(row.toolCallId !== undefined ? { toolCallId: row.toolCallId } : {}),
101
40
  ...(row.boundInputHash !== undefined ? { boundInputHash: row.boundInputHash } : {}),
41
+ ...(row.command !== undefined ? { command: row.command } : {}),
42
+ ...(row.edited !== undefined ? { edited: row.edited } : {}),
102
43
  rev: row.rev,
103
44
  ...(row.selectedCandidate !== undefined ? { selectedCandidate: row.selectedCandidate } : {}),
104
45
  ...(row.redeemedDots !== undefined
@@ -106,12 +47,10 @@ function toApprovalRecord(row) {
106
47
  : {}),
107
48
  };
108
49
  }
109
- /** 审批记录日志的一行:整条记录的快照(last-wins 重放)或一条丢弃墓碑。 */
110
50
  const ApprovalLineSchema = z.union([
111
51
  z.object({ op: z.literal("put"), record: ApprovalRecordSchema }).strict(),
112
52
  z.object({ op: z.literal("discard"), id: z.string().min(1) }).strict(),
113
53
  ]);
114
- /** 票日志的一行:铸票 / 认领 / 放回。三个动作各一行,重放顺序即真相。 */
115
54
  const TicketLineSchema = z.union([
116
55
  z
117
56
  .object({
@@ -126,10 +65,6 @@ const TicketLineSchema = z.union([
126
65
  z.object({ op: z.literal("consume"), ticketId: z.string().min(1), atMs: z.number().int().nonnegative().safe() }).strict(),
127
66
  z.object({ op: z.literal("release"), ticketId: z.string().min(1) }).strict(),
128
67
  ]);
129
- /**
130
- * 一面的**损坏闸**。置位之后该面的每一个方法都响亮拒绝 —— 读与写都拒:一份不完整的授权账既不能用来
131
- * 判决,也不能在它上面继续追加(追加只会让下一次重启读到同样残缺的历史)。
132
- */
133
68
  class CorruptionGate {
134
69
  face;
135
70
  path;
@@ -140,7 +75,6 @@ class CorruptionGate {
140
75
  this.path = path;
141
76
  this.onError = onError;
142
77
  }
143
- /** 记一次内部损坏(幂等:第一条原因就是要报告的那条)。 */
144
78
  trip(reason) {
145
79
  this.reason ??= reason;
146
80
  this.onError?.(`${this.face} at ${this.path} is corrupt: ${reason}`);
@@ -148,7 +82,6 @@ class CorruptionGate {
148
82
  get tripped() {
149
83
  return this.reason !== undefined;
150
84
  }
151
- /** 每个方法的第一行。文案里带上文件路径与处置 —— 一个运维读到它要知道去看哪个文件。 */
152
85
  assertUsable() {
153
86
  if (this.reason === undefined)
154
87
  return;
@@ -156,12 +89,6 @@ class CorruptionGate {
156
89
  "the permission-rule lane is fail-closed until a person inspects the file (moving it aside restarts the lane with an empty log)");
157
90
  }
158
91
  }
159
- /**
160
- * `RuleApprovalRecordStore` 的 File 形。
161
- *
162
- * CAS 按 `rev`(core 硬条款,理由逐字见 SQL 侧同名类的头注:只比 state 会让批记录的第二个候选上两次
163
- * 并发重试都以为自己赢了)。
164
- */
165
92
  export class FileRuleApprovalRecordStore {
166
93
  rows = new Map();
167
94
  log;
@@ -170,12 +97,9 @@ export class FileRuleApprovalRecordStore {
170
97
  ensureDir(dir);
171
98
  const path = join(dir, "approvals.jsonl");
172
99
  this.gate = new CorruptionGate("permission-rule approval log", path, onError);
173
- // `onCorrupt` = core 对**内部**不可解析行的报告口(崩溃尾它自己丢弃且不报)。不接它就是把一次
174
- // 「历史被削掉一块」变成静默 —— #191 门② 说的正是这个形。
175
100
  for (const raw of readJsonlRecords(path, (info) => this.gate.trip(info.reason))) {
176
101
  const parsed = ApprovalLineSchema.safeParse(raw);
177
102
  if (!parsed.success) {
178
- // 形不对 = 与「解析不出」同一类事实(版本漂/手改),同样是历史缺了一块 ⇒ 同样 fail-closed。
179
103
  this.gate.trip(`a replayed record does not carry a readable shape: ${parsed.error.message}`);
180
104
  continue;
181
105
  }
@@ -186,29 +110,22 @@ export class FileRuleApprovalRecordStore {
186
110
  }
187
111
  this.log = new AppendLog(path);
188
112
  }
189
- /** 取证/自证用:本面是否因内部损坏而 fail-closed。 */
190
113
  get corrupt() {
191
114
  return this.gate.tripped;
192
115
  }
193
- /** 归还本面 eager 持有的日志描述符(束的 `dispose()` 唯一调用点)。`AppendLog` 上没有 finalizer,
194
- * 不显式关就是一只跟到进程末尾的 fd —— `LocalBackend` 反复开合(热重载/多根)时按次泄漏。
195
- * 关后写面抛 `log_closed`(core 语义):**不重开**,因为「这只店已经交还」与「这条命还能写」
196
- * 不能两立,静默重开会让一次 dispose 之后的写落进一份没人再读的日志。 */
197
116
  close() {
198
117
  this.log.close();
199
118
  }
200
119
  async get(id) {
201
120
  this.gate.assertUsable();
202
121
  const r = this.rows.get(id);
203
- // 深拷贝出门:调用方(core 的兑付腿)会就地改它再交回 `cas`,共享同一个对象会让 CAS 比的是
204
- // 「自己改过的那份」——那等于没有 CAS。
205
122
  return r === undefined ? undefined : structuredClone(r);
206
123
  }
207
124
  async create(record) {
208
125
  this.gate.assertUsable();
209
126
  if (this.rows.has(record.id))
210
127
  throw new Error(`rule approval record ${record.id} already exists`);
211
- this.log.append({ op: "put", record }, true); // 先盘后索引(顶注)
128
+ this.log.append({ op: "put", record }, true);
212
129
  this.rows.set(record.id, structuredClone(record));
213
130
  }
214
131
  async cas(id, expectRev, next) {
@@ -223,8 +140,6 @@ export class FileRuleApprovalRecordStore {
223
140
  this.rows.set(id, structuredClone(next));
224
141
  return true;
225
142
  }
226
- /** 与 SQL 侧同名方法同义(超帽拒绝时收掉 `prepareCcImport` 已落盘的那条 pending 记录)。
227
- * `state === "pending"` 是硬的:已确认/已兑付的记录是一次真人同意的审计事实。 */
228
143
  async discardPendingRecord(recordId) {
229
144
  this.gate.assertUsable();
230
145
  const cur = this.rows.get(recordId);
@@ -235,10 +150,6 @@ export class FileRuleApprovalRecordStore {
235
150
  return true;
236
151
  }
237
152
  }
238
- /**
239
- * CC 导入票的 File 形。四条信任边界(principal 绑定 / TTL / 一次性原子消费 / 载荷绑定)与 SQL 形
240
- * **同语义**;唯一不同的是「原子」由谁保证 —— 那边是引擎行锁,这边是单进程 + 单写者(顶注)。
241
- */
242
153
  export class FileRuleImportTicketStore {
243
154
  rows = new Map();
244
155
  log;
@@ -248,8 +159,6 @@ export class FileRuleImportTicketStore {
248
159
  ensureDir(dir);
249
160
  const path = join(dir, "import-tickets.jsonl");
250
161
  this.gate = new CorruptionGate("permission-rule import-ticket log", path, onError);
251
- // 🔴 这一面是四条信任边界里「一次性原子消费」的**唯一**载体(SQL 形靠引擎行锁,File 形靠这份日志)。
252
- // 内部坏行 ⇒ 整面 fail-closed:一张票复活成未认领,代价是一次人的同意被重复兑付。
253
162
  for (const raw of readJsonlRecords(path, (info) => this.gate.trip(info.reason))) {
254
163
  const parsed = TicketLineSchema.safeParse(raw);
255
164
  if (!parsed.success) {
@@ -272,28 +181,20 @@ export class FileRuleImportTicketStore {
272
181
  this.log = new AppendLog(path);
273
182
  }
274
183
  now;
275
- /** 取证/自证用:本面是否因内部损坏而 fail-closed。 */
276
184
  get corrupt() {
277
185
  return this.gate.tripped;
278
186
  }
279
- /** 归还本面 eager 持有的日志描述符(理由与姊妹面 {@link FileRuleApprovalRecordStore.close} 逐字同源)。 */
280
187
  close() {
281
188
  this.log.close();
282
189
  }
283
190
  async mint(input) {
284
191
  this.gate.assertUsable();
285
192
  const expiresAtMs = this.now() + input.ttlMs;
286
- // 摘要函数与 SQL 形**同一个**(载荷绑定的等式两侧同源;两份实现必然各自漂)。
287
193
  const payloadHash = buildRulePayloadHash(input.candidates);
288
- // owner 键:本车道只铸 principal 形的票(local-owner 桶没有跨网络的导入口)。刻意存**明文
289
- // principal** 而不是 SQL 侧那把 sha —— 那把 hash 的两条理由(列宽静默截断、local-owner 需要定长
290
- // 同域表示)在一份进程内 Map 上都不成立,而明文让一次取证直接读得懂。
291
194
  this.log.append({ op: "mint", ticketId: input.ticketId, ownerKey: input.principal, approvalId: input.approvalId, payloadHash, expiresAtMs }, true);
292
195
  this.rows.set(input.ticketId, { ownerKey: input.principal, approvalId: input.approvalId, payloadHash, expiresAtMs });
293
196
  return { ticketId: input.ticketId, approvalId: input.approvalId, payloadHash, expiresAtMs };
294
197
  }
295
- /** 一次性**认领**。四条否定项的判序与 SQL 形逐字相同(unknown → wrong-principal → consumed → expired),
296
- * 于是两形的服务端日志归因可比;wire 面把四类折成同一个 404(零存在性 oracle)。 */
297
198
  async consume(ticketId, principal, opts) {
298
199
  this.gate.assertUsable();
299
200
  const row = this.rows.get(ticketId);
@@ -303,7 +204,6 @@ export class FileRuleImportTicketStore {
303
204
  return { ok: false, reason: "wrong-principal" };
304
205
  if (row.consumedAtMs !== undefined)
305
206
  return { ok: false, reason: "consumed" };
306
- // [4232]③:判定钟(可被同意车道的单调锚覆写)与记账钟(恒真墙钟,写进日志/行)分家 —— 逐字同 SQL 形。
307
207
  const stampMs = this.now();
308
208
  if (row.expiresAtMs <= (opts?.decisionNowMs ?? stampMs))
309
209
  return { ok: false, reason: "expired" };
@@ -311,8 +211,6 @@ export class FileRuleImportTicketStore {
311
211
  row.consumedAtMs = stampMs;
312
212
  return { ok: true, approvalId: row.approvalId, payloadHash: row.payloadHash };
313
213
  }
314
- /** 把认领**放回去**。`mustRemainValidMs` = 放回之后至少还要能用多久 —— 撑不过就不算放回成功
315
- * (理由逐字见 SQL 侧 `release` 的头注:承诺一次必然兑现不了的重试比不承诺更坏)。 */
316
214
  async release(ticketId, principal, mustRemainValidMs = 0, opts) {
317
215
  this.gate.assertUsable();
318
216
  const row = this.rows.get(ticketId);
@@ -325,43 +223,17 @@ export class FileRuleImportTicketStore {
325
223
  return true;
326
224
  }
327
225
  }
328
- /**
329
- * 装配 local 三面束。
330
- *
331
- * 🔴 `provider` 必须是**单例**(F1):core 的 `FilePermissionRuleStoreProvider` 在第一次取写面时对规则
332
- * 目录取一把进程级写锁,每次 `new` 一个就是第二个持有者 —— 而它对第二个持有者是**响亮拒绝**,不是
333
- * 排队。所以束在 `LocalBackend` 上按字段持有,`LocalBackend.close()` 调 `dispose()` 释放
334
- * (不释放 ⇒ 一次优雅重启会被自己上一条命留下的锁挡在门外,与数据根 `root/LOCK` 同一个病)。
335
- *
336
- * `onError` 接的是 core 规则文件的**披露面**(读不出来 / 校验和不符 / 撞上符号链接时它答零规则并
337
- * 说出来)。接住它打一条 warn 是**必须**的:那条路径上「零规则」与「真的没有规则」在读面上同形,
338
- * 不留痕就变成一次静默的 fail-closed(用户会突然被反复询问,却没有任何线索)。
339
- */
340
226
  export function createFilePermissionRuleStores(root, opts) {
341
227
  const dir = join(root, "permission-rules");
342
228
  ensureDir(dir);
343
229
  const provider = opts?.onError ? new FilePermissionRuleStoreProvider(dir, opts.onError) : new FilePermissionRuleStoreProvider(dir);
344
- // 三面共用**同一个**告警口:core 规则文件的披露与本仓两份日志的损坏对运维是同一件事
345
- // (「这台机器上的规则面出问题了,去看这个目录」),分成两个 sink 只会让其中一个没人接。
346
230
  const approvals = new FileRuleApprovalRecordStore(dir, opts?.onError);
347
231
  const tickets = new FileRuleImportTicketStore(dir, opts?.now, opts?.onError);
348
232
  return {
349
233
  provider,
350
234
  approvals,
351
235
  tickets,
352
- /** 桶数 = 规则目录里的桶文件数(core 的命名:`<64 hex>.json` = 一只 principal 桶,
353
- * `local-owner.json` = 身份缺席桶)。**刻意不数**审批/票的日志文件与收编标记文件 ——
354
- * 审计问的是「有没有既有的规则状态」,不是「这个目录里有几个文件」。
355
- *
356
- * 🔴 读不出目录就**抛**(不 catch 成 0)。目录在装配时刚 `ensureDir` 过,读不动只可能是被外力
357
- * 删掉/权限被改 —— 那是「不知道」,不是「零」。回 0 会被休眠行审计读成「确认没有休眠行」,把一次
358
- * 读失败伪装成一个结论;审计那侧本来就有 fail-open 臂(warn + 不拒启),让它去处置才是对的分工。 */
359
236
  countBuckets: async () => readdirSync(dir).filter((n) => n === "local-owner.json" || /^[0-9a-f]{64}\.json$/.test(n)).length,
360
- /** 三面各自的释放,**两只日志先于 provider**:provider 那步释放的是规则目录的进程级写锁,
361
- * 一旦它先松手,同一个根就可能被下一位持有者开起来 —— 而此刻本束的两只 fd 还开着。顺序写死
362
- * 在这里,`LocalBackend.close()` 只需调这一只口(与它对其余 file 店逐行关闭的既有纪律同形)。
363
- * 幂等:两只 `close()` 与 `provider.dispose()` 都可重入(重复调用是常态 —— 兜底路径与
364
- * `LocalBackend.close()` 会各调一次)。 */
365
237
  dispose: () => {
366
238
  approvals.close();
367
239
  tickets.close();
@@ -34,6 +34,9 @@ export declare const TIDB_PERMISSION_RULE_STATEMENTS: readonly string[];
34
34
  /** {@link TIDB_PERMISSION_RULE_STATEMENTS} 的遍历壳(生产路径走 `tidb-pool.ts` 中央 `ensureSchema`;
35
35
  * 本函数留给只需要这三张表的集成测试)。 */
36
36
  export declare function ensureTiDBPermissionRuleSchema(pool: MySqlPool): Promise<void>;
37
+ export declare function assertPermissionRuleApprovalSchema(query: (sql: string) => Promise<{
38
+ rows: Record<string, unknown>[];
39
+ }>, dialect: "tidb" | "pg"): Promise<void>;
37
40
  export declare function ensurePgPermissionRuleSchema(q: PgQueryFn): Promise<void>;
38
41
  /**
39
42
  * 一只桶的**存储键**(纯数据 ⇒ `build*`)。