@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.
- package/USAGE.md +18 -0
- package/dist/adoption/plan.js +31 -192
- package/dist/adoption/quiesce.js +3 -86
- package/dist/adoption/runner.js +3 -140
- package/dist/adoption/sql.js +0 -74
- package/dist/adoption/wire.js +0 -80
- package/dist/approval-ask-machine.js +0 -75
- package/dist/approval-card.js +0 -323
- package/dist/approval-deny-reasons.js +0 -42
- package/dist/approval-hmac.js +0 -35
- package/dist/approval-reconciler.js +8 -166
- package/dist/approval.js +4 -67
- package/dist/audit.js +1 -44
- package/dist/auth-bridge.js +4 -47
- package/dist/auth-keys.js +0 -23
- package/dist/bake-runner/main.js +4 -65
- package/dist/bake-runner/protocol.js +3 -58
- package/dist/bake-runner/runner.js +5 -91
- package/dist/bench/l8/artifact.js +2 -61
- package/dist/bench/l8/escape.js +0 -25
- package/dist/bench/l8/index.js +0 -14
- package/dist/bench/l8/probes.js +0 -60
- package/dist/bench/l8/run-probes.js +2 -45
- package/dist/bench/s1/arms.js +14 -189
- package/dist/bench/s1/live-deps.js +11 -253
- package/dist/bench/s1/oracle.js +1 -36
- package/dist/bench/s1/repair-oracle-adapter.js +0 -30
- package/dist/bench/s1/reviewer.js +0 -34
- package/dist/bench/s1/row.js +0 -62
- package/dist/bench/s1/run-firm.js +4 -70
- package/dist/bench/s1/runner-ctx.js +0 -40
- package/dist/bench/s1/tasks.js +0 -115
- package/dist/boot/adoption.js +0 -20
- package/dist/boot/budget-tracing.js +3 -55
- package/dist/boot/config-center.js +43 -551
- package/dist/boot/coordinators.js +1 -69
- package/dist/boot/crash-last.js +0 -18
- package/dist/boot/deferred-sandbox-path-env.js +3 -119
- package/dist/boot/execution-env.js +5 -171
- package/dist/boot/governance-seams.js +0 -92
- package/dist/boot/leader.js +0 -69
- package/dist/boot/limit-sync.js +0 -2
- package/dist/boot/memory-boundary.js +3 -91
- package/dist/boot/org-memory.js +1 -25
- package/dist/boot/parked-revive-gate.js +0 -150
- package/dist/boot/permission-rules-audit.js +1 -56
- package/dist/boot/reapers.js +15 -273
- package/dist/boot/resolve-spec.js +9 -768
- package/dist/boot/retention-lane.js +4 -87
- package/dist/boot/runner-deps.js +3 -297
- package/dist/boot/runtime-caps.js +0 -40
- package/dist/boot/session-faces.js +2 -133
- package/dist/boot/shutdown.js +9 -83
- package/dist/boot/side-query-lane.js +2 -137
- package/dist/boot/stores.js +15 -215
- package/dist/boot/task-list-lane.js +0 -18
- package/dist/boot/webfetch-summarize-lane.js +0 -47
- package/dist/boot/workflow-orchestration.js +3 -99
- package/dist/boot-reclaim.js +0 -20
- package/dist/bounded-session-map.js +0 -19
- package/dist/brain.js +2 -139
- package/dist/budget.js +9 -244
- package/dist/capabilities/builtin-tools.js +0 -3
- package/dist/capabilities/center-plugins.js +6 -51
- package/dist/capabilities/center-prompts.js +6 -71
- package/dist/capabilities/code-review-council.js +7 -40
- package/dist/capabilities/collab-workflows.js +1 -44
- package/dist/capabilities/hands-lane.js +0 -65
- package/dist/capabilities/memory-notice.js +0 -70
- package/dist/capabilities/prompt.js +0 -14
- package/dist/capabilities/prompts/code-review.js +0 -14
- package/dist/capabilities/prompts/identity.js +0 -6
- package/dist/capabilities/prompts/team.js +0 -4
- package/dist/capabilities/repo-tools.js +0 -34
- package/dist/capabilities/sandbox-file-send.js +3 -92
- package/dist/capabilities/scenarios.d.ts +0 -1
- package/dist/capabilities/scenarios.js +18 -279
- package/dist/capabilities/select-environment-tool.js +0 -32
- package/dist/capabilities/send-user-file-tool.js +2 -66
- package/dist/capabilities/skills.d.ts +1 -2
- package/dist/capabilities/skills.js +3 -21
- package/dist/capabilities/team.d.ts +3 -11
- package/dist/capabilities/team.js +3 -51
- package/dist/capabilities/tool-defer.js +0 -3
- package/dist/config-center/apply-effective.js +15 -330
- package/dist/config-center/apply-ledger.js +5 -38
- package/dist/config-center/facade.js +0 -41
- package/dist/config-center/hot-keys-registry.js +0 -20
- package/dist/config-center/http-client.js +2 -125
- package/dist/config-center/mcp-revocation.js +2 -34
- package/dist/config-center/read-face.js +0 -59
- package/dist/config-center/restart-signal.js +1 -85
- package/dist/config-center/skills-mcp.d.ts +1 -1
- package/dist/config-center/skills-mcp.js +9 -76
- package/dist/config-center/stage-limits.js +8 -35
- package/dist/config-invariants.js +0 -16
- package/dist/config-lkg.js +0 -42
- package/dist/config-provider.js +3 -186
- package/dist/config-types.js +0 -5
- package/dist/config.js +107 -1145
- package/dist/degenerate-instrument.js +3 -67
- package/dist/deployment-governance.js +0 -124
- package/dist/digest-form.js +0 -12
- package/dist/elicitation.js +3 -86
- package/dist/env-facts.js +7 -75
- package/dist/fleet/fleet-bus.js +34 -507
- package/dist/fleet/fleet-reconciler.js +9 -149
- package/dist/fleet/fleet-terminal-window.js +10 -178
- package/dist/fleet/subagent-tail-bus.js +3 -72
- package/dist/fleet-client.js +10 -70
- package/dist/fleet-lease.js +5 -79
- package/dist/git-api-kind.js +0 -3
- package/dist/governance-ask-marks.js +2 -78
- package/dist/hooks/branch-transcript.js +0 -74
- package/dist/hooks/cc-agent-hook-prompt.js +0 -29
- package/dist/hooks/cc-stop-prompt.js +1 -46
- package/dist/hooks/hook-llm.js +1 -53
- package/dist/hooks/hook-runner.js +20 -414
- package/dist/http/active-run-conflict.js +4 -129
- package/dist/http/cursor-fingerprint.d.ts +5 -0
- package/dist/http/cursor-fingerprint.js +5 -0
- package/dist/http/idempotency.js +0 -37
- package/dist/http/principal-gate.js +3 -40
- package/dist/http/route-ctx.js +0 -9
- package/dist/http/routes/a2a-serve.js +7 -319
- package/dist/http/routes/admin-config-refresh.js +0 -4
- package/dist/http/routes/admin-drain.js +0 -10
- package/dist/http/routes/adoption.js +1 -29
- package/dist/http/routes/agents-roster.js +1 -47
- package/dist/http/routes/approvals-assistant.js +32 -395
- package/dist/http/routes/attachments.js +4 -22
- package/dist/http/routes/capabilities.js +3 -420
- package/dist/http/routes/diagnostics.js +1 -81
- package/dist/http/routes/fleet.js +9 -185
- package/dist/http/routes/images.js +14 -239
- package/dist/http/routes/leader.js +0 -13
- package/dist/http/routes/memory-bundle.js +1 -61
- package/dist/http/routes/memory-policy.js +9 -99
- package/dist/http/routes/notify-wake.js +3 -37
- package/dist/http/routes/observability.js +2 -19
- package/dist/http/routes/retention-ops.js +2 -34
- package/dist/http/routes/rules.js +1 -93
- package/dist/http/routes/runs.js +64 -873
- package/dist/http/routes/session-sync.js +19 -258
- package/dist/http/routes/sessions-list.js +17 -43
- package/dist/http/routes/sessions.js +34 -226
- package/dist/http/routes/shared-memory.js +5 -36
- package/dist/http/routes/side-query.js +1 -87
- package/dist/http/routes/tasks.js +52 -722
- package/dist/http/routes/trace-usage.js +32 -195
- package/dist/http/routes/workflows.js +19 -195
- package/dist/http/run-meta.js +0 -6
- package/dist/http/send.js +0 -32
- package/dist/http/server.js +92 -1597
- package/dist/http/sse-lifecycle.js +2 -13
- package/dist/http/sse-log.js +3 -48
- package/dist/http/tar.js +5 -21
- package/dist/http/verify-rounds.js +0 -5
- package/dist/http/wire-gate.js +0 -9
- package/dist/http/workspace-content.js +0 -10
- package/dist/images/bake-validate.js +1 -70
- package/dist/images/manifest.js +1 -6
- package/dist/index.js +0 -21
- package/dist/key-resolver.js +2 -17
- package/dist/leader/diffout.js +1 -20
- package/dist/leader/diffup.js +0 -47
- package/dist/leader/endpoint.js +2 -57
- package/dist/leader/fanout.js +3 -45
- package/dist/leader/grader-env-factory.js +3 -72
- package/dist/leader/leader.js +5 -156
- package/dist/leader/merge.js +8 -115
- package/dist/leader/planner.js +3 -54
- package/dist/leader/repair-oracle.js +1 -60
- package/dist/leader/repair-wire.js +2 -79
- package/dist/leader/wire.js +8 -307
- package/dist/lsp/e2b-bridge.js +4 -64
- package/dist/lsp/e2b-manager.js +6 -94
- package/dist/lsp/lsp-frames.js +0 -12
- package/dist/lsp/manager.js +4 -96
- package/dist/lsp/ws-transport.js +5 -55
- package/dist/lsp-evict.js +1 -15
- package/dist/main.js +57 -765
- package/dist/memory-bundle-engine.js +0 -55
- package/dist/memory-export.js +0 -4
- package/dist/memory-posture.js +1 -15
- package/dist/memory-scope.js +11 -148
- package/dist/memory-sync-client.js +2 -44
- package/dist/memory-sync.js +1 -80
- package/dist/model-select.js +3 -80
- package/dist/observability/cost-quota.js +1 -17
- package/dist/observability/cost-taxonomy.js +0 -34
- package/dist/observability/fail-open.js +7 -86
- package/dist/observability/logger.js +0 -6
- package/dist/observability/metrics.js +0 -94
- package/dist/observability/otel-exporter.js +3 -13
- package/dist/observability/principal-context.js +0 -9
- package/dist/observability/prompt-manifest.js +1 -37
- package/dist/observability/rate-limit.js +0 -4
- package/dist/observability/secret-env-scrub.js +2 -56
- package/dist/observability/tool-trace.js +1 -70
- package/dist/orchestration/hardened-vm-runner.js +4 -118
- package/dist/orchestration/hardened-vm-worker-runner.js +1 -26
- package/dist/orchestration/hardened-vm-worker.js +0 -27
- package/dist/orchestration/subagent-steer.js +1 -45
- package/dist/orchestration/workflow-agent-steer.js +1 -80
- package/dist/orchestration/workflow-completion-inbox.js +32 -285
- package/dist/orchestration/workflow-notify-journal.js +16 -259
- package/dist/org-memory-admission.js +3 -47
- package/dist/parent-watch.js +2 -48
- package/dist/parked-decide.js +1 -109
- package/dist/per-task-image.js +0 -57
- package/dist/plan-cache-probe.js +3 -27
- package/dist/plugins/adoption-log-sql.js +2 -119
- package/dist/plugins/approval-ask-store-memory.js +3 -38
- package/dist/plugins/approval-ask-store-sql.js +6 -188
- package/dist/plugins/approval-exemption-store.js +2 -28
- package/dist/plugins/background-agent-store-sql.js +4 -105
- package/dist/plugins/background-shell-support.js +14 -122
- package/dist/plugins/blob-backend.js +6 -169
- package/dist/plugins/breaker-state-sql.js +8 -46
- package/dist/plugins/caching-session-store.js +4 -106
- package/dist/plugins/checkpoint-store-sql.js +18 -505
- package/dist/plugins/e2b-orphan-reclaim.js +0 -45
- package/dist/plugins/file-outcome-sink.js +0 -9
- package/dist/plugins/file-resume-anchor-store.js +4 -43
- package/dist/plugins/file-run-store.js +26 -364
- package/dist/plugins/file-snapshot-store-sql.js +10 -181
- package/dist/plugins/fork-routing-session-store.js +8 -111
- package/dist/plugins/host-platform.js +2 -91
- package/dist/plugins/image-bake-store-sql.js +7 -250
- package/dist/plugins/image-index-sql.js +4 -123
- package/dist/plugins/k8s-bg-scripts.js +4 -88
- package/dist/plugins/k8s-exec-protocol.js +0 -41
- package/dist/plugins/leader-run-store-sql.js +0 -101
- package/dist/plugins/local-checkpoint-store.js +8 -128
- package/dist/plugins/local-session-store.js +34 -296
- package/dist/plugins/local-task-attachment-store.js +2 -16
- package/dist/plugins/mailbox-store-sql.js +8 -65
- package/dist/plugins/memory-embedder-fingerprint.js +5 -166
- package/dist/plugins/memory-embedder.js +4 -70
- package/dist/plugins/memory-engine-pg.js +6 -170
- package/dist/plugins/memory-engine-tidb.js +7 -155
- package/dist/plugins/memory-engine-vector-util.js +0 -10
- package/dist/plugins/memory-key-guards.js +0 -34
- package/dist/plugins/memory-origin-law.js +0 -187
- package/dist/plugins/memory-resume-anchor-store.js +0 -17
- package/dist/plugins/memory-run-store.js +12 -89
- package/dist/plugins/memory-session-policy-store.js +0 -17
- package/dist/plugins/memory-sync-store-pg.js +4 -49
- package/dist/plugins/memory-sync-store-tidb.js +3 -35
- package/dist/plugins/outcome-ledger-sql.js +3 -97
- package/dist/plugins/permission-rule-store-file.js +5 -133
- package/dist/plugins/permission-rule-store-sql.d.ts +3 -0
- package/dist/plugins/permission-rule-store-sql.js +50 -307
- package/dist/plugins/pg-cost-quota.js +0 -7
- package/dist/plugins/pg-pool.js +0 -92
- package/dist/plugins/pg-rate-limiter.js +2 -13
- package/dist/plugins/pg-safe-json.js +4 -40
- package/dist/plugins/pg-session-storage.js +25 -189
- package/dist/plugins/posix-shell-fs.js +1 -31
- package/dist/plugins/remote-env-adb.js +12 -101
- package/dist/plugins/remote-env-e2b.js +40 -371
- package/dist/plugins/remote-env-file-error.js +0 -37
- package/dist/plugins/remote-env-host.js +63 -483
- package/dist/plugins/remote-env-k8s.js +32 -326
- package/dist/plugins/remote-env-local-docker.js +24 -157
- package/dist/plugins/remote-env-ssh.js +20 -128
- package/dist/plugins/remote-scratchpad.js +2 -32
- package/dist/plugins/remote-shell.js +1 -32
- package/dist/plugins/resume-anchor-store-sql.js +0 -11
- package/dist/plugins/retention-lane-store-sql.js +0 -108
- package/dist/plugins/retention-store-sql.js +4 -383
- package/dist/plugins/roster-store-sql.js +0 -55
- package/dist/plugins/run-store-sql.js +14 -251
- package/dist/plugins/s3-presign.js +2 -49
- package/dist/plugins/scheduler-support.js +3 -80
- package/dist/plugins/send-file-ledger.js +4 -53
- package/dist/plugins/send-user-file.js +4 -94
- package/dist/plugins/session-placement.js +1 -89
- package/dist/plugins/session-policy-store-sql.js +3 -81
- package/dist/plugins/session-store.js +0 -57
- package/dist/plugins/shared-memory-store-sql.js +4 -167
- package/dist/plugins/sql-driver.js +0 -17
- package/dist/plugins/sql-errors.js +0 -7
- package/dist/plugins/sql-escape.js +0 -8
- package/dist/plugins/sql-row-helpers.js +0 -25
- package/dist/plugins/store-backend.js +42 -222
- package/dist/plugins/store-contracts.js +2 -46
- package/dist/plugins/task-attachment-store.js +3 -49
- package/dist/plugins/task-list-store-sql.js +0 -79
- package/dist/plugins/tidb-cost-quota.js +1 -4
- package/dist/plugins/tidb-pool.js +1 -207
- package/dist/plugins/tidb-rate-limiter.js +3 -9
- package/dist/plugins/tidb-session-storage.js +4 -70
- package/dist/plugins/tidb-session-store.js +19 -341
- package/dist/plugins/tool-result-store-sql.js +4 -179
- package/dist/plugins/usage-window-store-sql.js +0 -8
- package/dist/plugins/web-search.js +10 -132
- package/dist/plugins/workflow-journal-store-sql.js +2 -58
- package/dist/plugins/workflow-run-store-sql.js +6 -91
- package/dist/plugins/worktree-isolation.js +6 -126
- package/dist/plugins/write-behind-counter.js +16 -75
- package/dist/principal-jwt.js +5 -60
- package/dist/project-memory.js +15 -146
- package/dist/prompts-domain-validate.js +1 -51
- package/dist/question.js +2 -111
- package/dist/resource-suspend.js +0 -18
- package/dist/router/route-orchestration.js +0 -77
- package/dist/rules-consent.d.ts +44 -5
- package/dist/rules-consent.js +75 -215
- package/dist/run-local.js +14 -381
- package/dist/runs.js +29 -617
- package/dist/runtime-caps-resolver.js +6 -132
- package/dist/runtime-governance.js +1 -232
- package/dist/sandbox-pkg-source.js +0 -37
- package/dist/sealed-key.js +3 -68
- package/dist/security.js +6 -291
- package/dist/session-leaf-bus.js +0 -32
- package/dist/session-sync-content.js +1 -69
- package/dist/session-sync-kernel.js +3 -60
- package/dist/session-sync.js +3 -66
- package/dist/session-titler.js +7 -41
- package/dist/session-watch.js +9 -73
- package/dist/shared-memory-scope-authorizer.js +0 -18
- package/dist/sighup-idle.js +1 -12
- package/dist/spec-fields.js +4 -143
- package/dist/store-live-probe.js +3 -49
- package/dist/task-a2a.js +1 -126
- package/dist/task-cwd.js +1 -103
- package/dist/task-mcp.js +1 -89
- package/dist/task-settings.js +10 -300
- package/dist/task-workflow.js +8 -75
- package/dist/tool-approval.d.ts +28 -1
- package/dist/tool-approval.js +70 -1430
- package/dist/trace/artifacts.js +5 -20
- package/dist/trace/engine-notice-wire.js +6 -138
- package/dist/trace/ledger-sink.js +7 -96
- package/dist/trace/project.js +4 -448
- package/dist/trace/redact.js +9 -77
- package/dist/turn-activity.js +1 -27
- package/dist/usage-analytics.js +4 -34
- package/dist/wall-clock-jump-guard.js +1 -68
- package/package.json +3 -3
- package/dist/capabilities/scenario-alias.d.ts +0 -27
- 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*`)。
|