@sema-agent/server 7.148.0 → 7.150.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +551 -9
- package/README.md +17 -2
- package/README.zh-CN.md +5 -1
- package/USAGE.md +126 -68
- package/dist/adoption/wire.d.ts +3 -3
- package/dist/approval-card.d.ts +33 -33
- package/dist/approval-gate-currency.d.ts +1 -1
- package/dist/approval-leg-origin.d.ts +33 -0
- package/dist/approval-leg-origin.js +4 -0
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +2 -2
- package/dist/auth-bridge.d.ts +9 -1
- package/dist/auth-bridge.js +4 -4
- package/dist/auth-keys.d.ts +10 -1
- package/dist/auth-keys.js +8 -0
- package/dist/background-session-reap.d.ts +1 -1
- package/dist/boot/deferred-sandbox-path-env.d.ts +5 -3
- package/dist/boot/deferred-sandbox-path-env.js +1 -2
- package/dist/boot/execution-env.js +10 -11
- package/dist/boot/execution-lane.d.ts +6 -4
- package/dist/boot/execution-lane.js +3 -1
- package/dist/boot/org-delivery.d.ts +3 -2
- package/dist/boot/parked-revive-gate.d.ts +5 -5
- package/dist/boot/parked-revive-gate.js +2 -3
- package/dist/boot/resolve-spec.d.ts +4 -5
- package/dist/boot/resolve-spec.js +66 -28
- package/dist/boot/retention-lane.d.ts +1 -1
- package/dist/boot/runner-deps.js +3 -1
- package/dist/boot/session-faces.js +21 -21
- package/dist/boot/stage-01-config.d.ts +1 -0
- package/dist/boot/stage-01-config.js +4 -3
- package/dist/boot/stage-02-web-admin-pull.d.ts +1 -0
- package/dist/boot/stage-02-web-admin-pull.js +10 -2
- package/dist/boot/stage-03-store-backend.d.ts +1 -0
- package/dist/boot/stage-03-store-backend.js +4 -4
- package/dist/boot/stage-04-stores.d.ts +1 -0
- package/dist/boot/stage-05-execution-env.d.ts +1 -0
- package/dist/boot/stage-06-runners.d.ts +2 -1
- package/dist/boot/stage-06-runners.js +1 -2
- package/dist/boot/stage-07-capability-layer.d.ts +2 -1
- package/dist/boot/stage-07-capability-layer.js +1 -1
- package/dist/boot/stage-08-reapers.d.ts +2 -1
- package/dist/boot/stage-09-leader.d.ts +2 -1
- package/dist/boot/stage-10-http-server.d.ts +35 -2
- package/dist/boot/stage-10-http-server.js +9 -4
- package/dist/boot/stores.d.ts +3 -0
- package/dist/boot/stores.js +22 -19
- package/dist/boot/web-admin.d.ts +1 -1
- package/dist/capabilities/tool-defer.d.ts +1 -1
- package/dist/capability-facts.d.ts +70 -60
- package/dist/capability-facts.js +45 -49
- package/dist/card-settle-stored-scope.d.ts +56 -0
- package/dist/card-settle-stored-scope.js +27 -0
- package/dist/card-void.d.ts +7 -12
- package/dist/card-void.js +2 -7
- package/dist/config-catalog.d.ts +12 -0
- package/dist/config-catalog.js +37 -33
- package/dist/config-invariants.d.ts +5 -4
- package/dist/config-invariants.js +4 -4
- package/dist/config-types.d.ts +49 -16
- package/dist/config.d.ts +6 -5
- package/dist/config.js +35 -24
- package/dist/context-window-notice.d.ts +31 -0
- package/dist/context-window-notice.js +28 -0
- package/dist/deployment-governance.d.ts +7 -28
- package/dist/deployment-governance.js +1 -14
- package/dist/deployment-shape.d.ts +20 -11
- package/dist/deployment-shape.js +1 -0
- package/dist/device-ws-hub.d.ts +1 -0
- package/dist/device-ws-hub.js +64 -28
- package/dist/device-ws-protocol.d.ts +20 -6
- package/dist/device-ws-protocol.js +9 -2
- package/dist/engine-identity.d.ts +7 -1
- package/dist/engine-identity.js +5 -0
- package/dist/env-name-allowlist-knobs.d.ts +6 -5
- package/dist/env-name-allowlist-knobs.js +5 -0
- package/dist/execution-lane-caps.d.ts +20 -5
- package/dist/execution-lane-caps.js +18 -4
- package/dist/field-conflict.d.ts +2 -2
- package/dist/fleet/engine-signal.d.ts +14 -1
- package/dist/fleet/engine-signal.js +5 -1
- package/dist/fleet/fleet-reconciler.d.ts +1 -1
- package/dist/fleet/serving-lease.d.ts +18 -3
- package/dist/fleet/serving-lease.js +81 -35
- package/dist/fleet-client.d.ts +13 -11
- package/dist/fleet-client.js +53 -33
- package/dist/history-anchor.js +1 -1
- package/dist/hitl-delivery.d.ts +1 -3
- package/dist/hitl-delivery.js +1 -1
- package/dist/hooks/command-spawn.d.ts +7 -2
- package/dist/hooks/command-spawn.js +13 -6
- package/dist/hooks/hook-runner.d.ts +5 -0
- package/dist/hooks/hook-runner.js +11 -7
- package/dist/http/active-run-conflict.d.ts +3 -7
- package/dist/http/active-run-conflict.js +2 -2
- package/dist/http/admission.js +5 -5
- package/dist/http/approval-sweeps.js +5 -3
- package/dist/http/caller-trust.d.ts +2 -2
- package/dist/http/caller-trust.js +3 -3
- package/dist/http/checkpoint-ctx.d.ts +18 -63
- package/dist/http/checkpoint-ctx.js +1 -24
- package/dist/http/claim-heartbeat.d.ts +6 -6
- package/dist/http/claim-heartbeat.js +6 -6
- package/dist/http/claimed-run.d.ts +16 -9
- package/dist/http/claimed-run.js +8 -0
- package/dist/http/dispatch.js +7 -5
- package/dist/http/durable-run-leg.d.ts +8 -1
- package/dist/http/durable-run-leg.js +34 -15
- package/dist/http/execution-context.d.ts +115 -14
- package/dist/http/execution-context.js +130 -40
- package/dist/http/owner-access.d.ts +246 -21
- package/dist/http/owner-access.js +186 -8
- package/dist/http/principal-gate.d.ts +18 -11
- package/dist/http/principal-gate.js +3 -1
- package/dist/http/readiness.d.ts +4 -2
- package/dist/http/resume-ctx-read.d.ts +14 -3
- package/dist/http/resume-ctx-read.js +24 -3
- package/dist/http/resume-legs.d.ts +35 -3
- package/dist/http/resume-legs.js +262 -106
- package/dist/http/route-ctx.d.ts +29 -11
- package/dist/http/routes/a2a-serve.js +17 -14
- package/dist/http/routes/approvals-assistant.d.ts +3 -2
- package/dist/http/routes/approvals-assistant.js +11 -11
- package/dist/http/routes/capabilities.js +5 -4
- package/dist/http/routes/config-catalog.d.ts +1 -1
- package/dist/http/routes/diagnostics.d.ts +3 -1
- package/dist/http/routes/diagnostics.js +30 -5
- package/dist/http/routes/mcp-reconnect.js +2 -2
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/notify-wake.js +2 -3
- package/dist/http/routes/principal-inbox.d.ts +3 -1
- package/dist/http/routes/principal-inbox.js +3 -2
- package/dist/http/routes/projects.d.ts +1 -0
- package/dist/http/routes/projects.js +5 -3
- package/dist/http/routes/retention-ops.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.js +2 -2
- package/dist/http/routes/runs.d.ts +1 -1
- package/dist/http/routes/runs.js +33 -37
- package/dist/http/routes/session-memory-sync.js +4 -5
- package/dist/http/routes/session-sync.d.ts +24 -5
- package/dist/http/routes/session-sync.js +45 -37
- package/dist/http/routes/sessions-list.d.ts +1 -1
- package/dist/http/routes/sessions.d.ts +1 -1
- package/dist/http/routes/sessions.js +18 -44
- package/dist/http/routes/tasks.js +136 -101
- package/dist/http/routes/trace-usage.js +14 -14
- package/dist/http/routes/workflows.d.ts +1 -0
- package/dist/http/routes/workflows.js +20 -38
- package/dist/http/server.d.ts +12 -9
- package/dist/http/server.js +35 -6
- package/dist/http/stored-body-replay.d.ts +3 -24
- package/dist/http/stored-body-replay.js +2 -12
- package/dist/http/submit-ctx.d.ts +2 -2
- package/dist/http/submit-ctx.js +5 -5
- package/dist/http/submit-replay.d.ts +15 -2
- package/dist/http/submit-replay.js +10 -4
- package/dist/http/wire-types.d.ts +6 -3
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/leader/endpoint.js +9 -8
- package/dist/leg-facts.d.ts +13 -2
- package/dist/leg-facts.js +2 -0
- package/dist/local-store-declaration.d.ts +54 -0
- package/dist/local-store-declaration.js +59 -0
- package/dist/mcp-assertion-header.d.ts +1 -1
- package/dist/mcp-assertion-header.js +1 -1
- package/dist/mcp-authorization-face.d.ts +18 -14
- package/dist/mcp-authorization-face.js +3 -2
- package/dist/memory-project-layer.js +1 -1
- package/dist/memory-scope.d.ts +4 -4
- package/dist/memory-scope.js +4 -4
- package/dist/memory-store-refusal.d.ts +1 -1
- package/dist/memory-sync-client.js +2 -2
- package/dist/model-context-window.d.ts +50 -11
- package/dist/model-context-window.js +20 -1
- package/dist/model-entry-refusal.d.ts +5 -4
- package/dist/model-entry-refusal.js +17 -3
- package/dist/model-reach-scope.d.ts +2 -1
- package/dist/observability/corrupt-read-seat.d.ts +1 -1
- package/dist/observability/fail-open.d.ts +19 -7
- package/dist/observability/fail-open.js +19 -7
- package/dist/observability/logger.d.ts +7 -0
- package/dist/observability/logger.js +3 -1
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/run-terminal.d.ts +1 -1
- package/dist/observability/run-terminal.js +1 -0
- package/dist/observability/secret-env-scrub.d.ts +1 -1
- package/dist/observability/secret-env-scrub.js +1 -1
- package/dist/org-delivery-gate.d.ts +31 -6
- package/dist/org-delivery-gate.js +7 -4
- package/dist/owner-faces.d.ts +30 -5
- package/dist/owner-faces.js +2 -0
- package/dist/park-row-commit.d.ts +67 -0
- package/dist/park-row-commit.js +76 -0
- package/dist/parked-decide.d.ts +9 -7
- package/dist/parked-decide.js +25 -6
- package/dist/peer-directory.d.ts +1 -1
- package/dist/peer-seat.d.ts +1 -1
- package/dist/peer-seat.js +52 -59
- package/dist/plugins/adoption-log-sql.d.ts +3 -3
- package/dist/plugins/adoption-log-sql.js +19 -19
- package/dist/plugins/approval-ask-store-sql.d.ts +1 -1
- package/dist/plugins/approval-ask-store-sql.js +3 -5
- package/dist/plugins/approval-exemption-skill-cutoff.d.ts +64 -0
- package/dist/plugins/approval-exemption-skill-cutoff.js +122 -0
- package/dist/plugins/approval-exemption-skill-m46.d.ts +0 -6
- package/dist/plugins/approval-exemption-skill-m46.js +6 -10
- package/dist/plugins/approval-exemption-store.d.ts +26 -1
- package/dist/plugins/approval-exemption-store.js +28 -19
- package/dist/plugins/ensure-schema-lock-policy.d.ts +36 -3
- package/dist/plugins/ensure-schema-lock-policy.js +75 -9
- package/dist/plugins/exec-path-law.d.ts +34 -0
- package/dist/plugins/exec-path-law.js +13 -0
- package/dist/plugins/file-run-store.d.ts +22 -9
- package/dist/plugins/file-run-store.js +51 -23
- package/dist/plugins/local-checkpoint-store.d.ts +8 -1
- package/dist/plugins/local-checkpoint-store.js +5 -1
- package/dist/plugins/local-data-root-admission.d.ts +52 -0
- package/dist/plugins/local-data-root-admission.js +100 -0
- package/dist/plugins/local-engine-high-water.d.ts +28 -7
- package/dist/plugins/local-engine-high-water.js +27 -22
- package/dist/plugins/local-session-store.d.ts +134 -49
- package/dist/plugins/local-session-store.js +149 -108
- package/dist/plugins/memory-run-store.d.ts +14 -9
- package/dist/plugins/memory-run-store.js +48 -22
- package/dist/plugins/one-time-migration-marker.d.ts +19 -3
- package/dist/plugins/one-time-migration-marker.js +7 -1
- package/dist/plugins/one-time-migrations.d.ts +110 -59
- package/dist/plugins/one-time-migrations.js +224 -136
- package/dist/plugins/org-delivery-quota-store.d.ts +34 -11
- package/dist/plugins/org-delivery-quota-store.js +29 -14
- package/dist/plugins/permission-rule-store-sql.d.ts +1 -1
- package/dist/plugins/permission-rule-store-sql.js +5 -9
- package/dist/plugins/pg-pool.d.ts +1 -1
- package/dist/plugins/pg-pool.js +14 -12
- package/dist/plugins/posix-shell-fs.js +4 -2
- package/dist/plugins/remote-env-adb.js +3 -2
- package/dist/plugins/remote-env-device.d.ts +3 -2
- package/dist/plugins/remote-env-device.js +8 -6
- package/dist/plugins/remote-env-e2b.d.ts +4 -8
- package/dist/plugins/remote-env-e2b.js +21 -15
- package/dist/plugins/remote-env-host.d.ts +51 -10
- package/dist/plugins/remote-env-host.js +97 -31
- package/dist/plugins/remote-env-k8s.js +7 -4
- package/dist/plugins/remote-env-local-docker.d.ts +6 -3
- package/dist/plugins/remote-env-local-docker.js +11 -25
- package/dist/plugins/remote-env-ssh.js +4 -3
- package/dist/plugins/remote-shell.d.ts +3 -1
- package/dist/plugins/remote-shell.js +3 -3
- package/dist/plugins/replica-registration.d.ts +35 -0
- package/dist/plugins/replica-registration.js +48 -0
- package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
- package/dist/plugins/run-store-sql.d.ts +27 -8
- package/dist/plugins/run-store-sql.js +46 -18
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +8 -12
- package/dist/plugins/scenario-prefix-switch-m42.js +9 -6
- package/dist/plugins/schema-consistency.d.ts +91 -5
- package/dist/plugins/schema-consistency.js +189 -7
- package/dist/plugins/schema-drift-sentence.d.ts +6 -5
- package/dist/plugins/schema-drift-sentence.js +13 -5
- package/dist/plugins/serving-requirement.d.ts +49 -0
- package/dist/plugins/serving-requirement.js +53 -0
- package/dist/plugins/session-placement.d.ts +5 -4
- package/dist/plugins/shell-sentinel-owner-m48.d.ts +22 -0
- package/dist/plugins/shell-sentinel-owner-m48.js +6 -0
- package/dist/plugins/stop-then-start-sentence.d.ts +55 -0
- package/dist/plugins/stop-then-start-sentence.js +51 -0
- package/dist/plugins/store-backend.d.ts +23 -9
- package/dist/plugins/store-backend.js +58 -24
- package/dist/plugins/store-contracts.d.ts +45 -5
- package/dist/plugins/store-contracts.js +19 -0
- package/dist/plugins/tidb-pool.d.ts +11 -6
- package/dist/plugins/tidb-pool.js +22 -12
- package/dist/plugins/workspace-custody.d.ts +44 -0
- package/dist/plugins/workspace-custody.js +47 -0
- package/dist/process-instance.d.ts +3 -0
- package/dist/process-instance.js +7 -0
- package/dist/project-context.d.ts +66 -0
- package/dist/project-context.js +70 -0
- package/dist/project-identity.d.ts +8 -7
- package/dist/project-identity.js +40 -17
- package/dist/project-layer-key.d.ts +13 -2
- package/dist/project-layer-key.js +9 -1
- package/dist/question.d.ts +9 -21
- package/dist/question.js +28 -19
- package/dist/read-deny-floor-notice.d.ts +36 -0
- package/dist/read-deny-floor-notice.js +40 -0
- package/dist/{plain-string-record.d.ts → request-declaration-disposition.d.ts} +9 -23
- package/dist/request-declaration-disposition.js +39 -0
- package/dist/run-cancel-card.d.ts +28 -0
- package/dist/run-cancel-card.js +20 -0
- package/dist/run-cancel-context.d.ts +10 -0
- package/dist/run-cancel-context.js +1 -0
- package/dist/run-local.js +28 -13
- package/dist/runs.d.ts +31 -7
- package/dist/runs.js +34 -16
- package/dist/security.d.ts +3 -3
- package/dist/server-secret-env.d.ts +34 -20
- package/dist/server-secret-env.js +61 -18
- package/dist/session-agent.d.ts +4 -12
- package/dist/session-agent.js +0 -6
- package/dist/session-children-retire.d.ts +6 -3
- package/dist/session-children-retire.js +2 -5
- package/dist/session-incarnation.d.ts +18 -4
- package/dist/session-incarnation.js +4 -1
- package/dist/session-notify-door.d.ts +4 -4
- package/dist/session-notify-door.js +5 -6
- package/dist/session-rules-seat.d.ts +4 -3
- package/dist/session-rules-seat.js +3 -11
- package/dist/session-sync.js +3 -3
- package/dist/session-workspace.d.ts +3 -3
- package/dist/store-admission.d.ts +33 -0
- package/dist/store-admission.js +49 -0
- package/dist/store-posture.d.ts +5 -0
- package/dist/store-posture.js +18 -1
- package/dist/stores-sql/checkpoint-store-sql.d.ts +22 -3
- package/dist/stores-sql/checkpoint-store-sql.js +109 -23
- package/dist/stores-sql/file-history-store-sql.d.ts +1 -1
- package/dist/stores-sql/file-history-store-sql.js +3 -5
- package/dist/stores-sql/retention-store-sql.d.ts +1 -1
- package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
- package/dist/stores-sql/tool-result-store-sql.js +4 -6
- package/dist/task-a2a.d.ts +3 -8
- package/dist/task-a2a.js +25 -27
- package/dist/task-cwd.d.ts +27 -10
- package/dist/task-cwd.js +3 -0
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-mcp.js +1 -1
- package/dist/task-settings.d.ts +13 -0
- package/dist/task-settings.js +14 -7
- package/dist/terminal.d.ts +2 -0
- package/dist/terminal.js +21 -6
- package/dist/tool-approval.d.ts +50 -41
- package/dist/tool-approval.js +96 -73
- package/dist/trace/engine-notice-wire.d.ts +38 -21
- package/dist/trace/engine-notice-wire.js +25 -4
- package/dist/trace/ledger-sink.d.ts +3 -1
- package/dist/trace/project.d.ts +8 -5
- package/dist/trace/project.js +11 -9
- package/dist/trace/projection-table.d.ts +33 -2
- package/dist/trace/redact.d.ts +12 -0
- package/dist/trace/redact.js +5 -1
- package/dist/trace/self-minted-wire.d.ts +268 -56
- package/dist/trace/self-minted-wire.js +110 -40
- package/dist/trace/tool-card.d.ts +3 -0
- package/dist/trace/tool-card.js +24 -0
- package/dist/trace/tool-output-media.d.ts +2 -1
- package/dist/unattended-permission-mode.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.js +22 -9
- package/dist/web-admin-client/effective-keys.d.ts +1 -1
- package/dist/web-admin-client/skills-mcp.d.ts +1 -1
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -29
- package/docs/error-text-lexicon.json +317 -0
- package/package.json +4 -2
- package/scripts/embed-minimal.mjs +183 -0
- package/wire-changes/server@7.149.0.json +372 -0
- package/wire-changes/server@7.150.0.json +335 -0
- package/dist/plain-string-record.js +0 -70
|
@@ -18,20 +18,43 @@ export interface OrgDeliveryQuotaPolicy {
|
|
|
18
18
|
/** 一个收件人在一个窗里能收的封数上界(全部发件人合计)。 */
|
|
19
19
|
readonly perRecipient: number;
|
|
20
20
|
}
|
|
21
|
+
/** 一次记账的判决:放行,或拒 + 到店钟当前窗结束的整秒数(头注「拒的判决带重试指引」)。 */
|
|
22
|
+
export type OrgDeliveryQuotaVerdict = {
|
|
23
|
+
readonly granted: true;
|
|
24
|
+
} | {
|
|
25
|
+
readonly granted: false;
|
|
26
|
+
readonly retryAfterSec: number;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* 店读不出自己的状态(File 腿:快照坏了)⇒ **拒用**的那一只错。fail-closed:每一次记账都抛它,绝不当成「放行」。
|
|
30
|
+
* 两句话各有读者,所以分开存:`message` = 运维句(点名文件与坏处、出路 —— 只进运维日志);{@link ORG_DELIVERY_QUOTA_UNREADABLE_SENTENCE} = 上线的
|
|
31
|
+
* 固定句(不点名宿主路径、不带坏处原文 —— 调用方是组织里的任何成员,不是运维)。HTTP 兜底(`http/server.ts`)按本类映射成带因的 500
|
|
32
|
+
* (码字面量只写在那一处发送点,wire 码目录的扫描面看得见它)。
|
|
33
|
+
*/
|
|
34
|
+
export declare const ORG_DELIVERY_QUOTA_UNREADABLE_SENTENCE = "the cross-principal delivery quota state on this server cannot be read, so every delivery is refused until an operator repairs it \u2014 nothing was delivered, and retrying will not change the answer";
|
|
35
|
+
export declare class OrgDeliveryQuotaUnreadableError extends Error {
|
|
36
|
+
constructor(operatorSentence: string);
|
|
37
|
+
}
|
|
21
38
|
export interface OrgDeliveryQuotaStore {
|
|
22
39
|
/**
|
|
23
|
-
* 原子地把这位发件人的一次投递**尝试**算进店钟当前窗:未满 ⇒ +1
|
|
40
|
+
* 原子地把这位发件人的一次投递**尝试**算进店钟当前窗:未满 ⇒ +1、答放行;已满 ⇒ 什么都不记、答拒(带重试指引)。
|
|
24
41
|
* 店读不出 / 写不进 ⇒ **抛**(调用方按失败处置,绝不当成「放行」)。
|
|
25
42
|
*/
|
|
26
|
-
admitAttempt(fromScope: string, policy: OrgDeliveryQuotaPolicy): Promise<
|
|
43
|
+
admitAttempt(fromScope: string, policy: OrgDeliveryQuotaPolicy): Promise<OrgDeliveryQuotaVerdict>;
|
|
27
44
|
/**
|
|
28
|
-
* 原子地把一封 (fromScope → toScope) 的信算进**店钟当前窗**的两只计数器:两界都未满 ⇒ 两只各 +1
|
|
29
|
-
* 任一界已满 ⇒
|
|
45
|
+
* 原子地把一封 (fromScope → toScope) 的信算进**店钟当前窗**的两只计数器:两界都未满 ⇒ 两只各 +1、答放行;
|
|
46
|
+
* 任一界已满 ⇒ 什么都不记、答拒(带重试指引)。店读不出 / 写不进 ⇒ **抛**。
|
|
30
47
|
*/
|
|
31
|
-
take(fromScope: string, toScope: string, policy: OrgDeliveryQuotaPolicy): Promise<
|
|
48
|
+
take(fromScope: string, toScope: string, policy: OrgDeliveryQuotaPolicy): Promise<OrgDeliveryQuotaVerdict>;
|
|
32
49
|
}
|
|
33
50
|
/** 窗起点(一处算法,三条腿共用)。 */
|
|
34
51
|
export declare function quotaWindowStart(nowMs: number, windowMs: number): number;
|
|
52
|
+
/**
|
|
53
|
+
* 拒的判决的退避秒数(三条腿共用的**唯一**算式):店钟 `nowMs` 到当前窗结束,向上取整。≥ 1 是桶公式的推论、不另设下限:`nowMs` 严格早于窗末
|
|
54
|
+
* (`floor(now / w)` 之下 `(桶 + 1) × w − now ∈ (0, w]`),正数向上取整至少是 1 —— 窗末前最后 1 ms 也答 1,不叫客户端「立刻重试」。
|
|
55
|
+
* 桶与退避秒数的公式不在这里写第二份:都读 `observability/cost-quota.ts` 的 `alignedWindow` / `retryAfterSecUntil`(成本配额、速率限制器同锚)。
|
|
56
|
+
*/
|
|
57
|
+
export declare function quotaRetryAfterSec(nowMs: number, windowMs: number): number;
|
|
35
58
|
/** 店里记着的那个窗(`heldStart`)的计数此刻还算不算数 —— 头注那条律的**唯一**写法:此刻的窗,或此刻的下一个窗。 */
|
|
36
59
|
export declare function heldWindowCounts(heldStart: number, at: number, windowMs: number): boolean;
|
|
37
60
|
/** 一位发件人的当前窗(`windowMs` = 开窗那一次的窗宽:窗何时结束是条目自己的事实,File 腿据它丢已过窗的条目)。 */
|
|
@@ -58,8 +81,8 @@ export declare class MemoryOrgDeliveryQuotaStore implements OrgDeliveryQuotaStor
|
|
|
58
81
|
protected state: QuotaWindows;
|
|
59
82
|
/** @param nowMs 店钟(单进程腿:店 = 这个进程,缺省本进程墙钟)。 */
|
|
60
83
|
constructor(nowMs?: () => number);
|
|
61
|
-
admitAttempt(fromScope: string, policy: OrgDeliveryQuotaPolicy): Promise<
|
|
62
|
-
take(fromScope: string, toScope: string, policy: OrgDeliveryQuotaPolicy): Promise<
|
|
84
|
+
admitAttempt(fromScope: string, policy: OrgDeliveryQuotaPolicy): Promise<OrgDeliveryQuotaVerdict>;
|
|
85
|
+
take(fromScope: string, toScope: string, policy: OrgDeliveryQuotaPolicy): Promise<OrgDeliveryQuotaVerdict>;
|
|
63
86
|
/**
|
|
64
87
|
* 落新的整份状态,只留窗还没结束的条目(按条目自己的窗宽判;已结束的发件人 / 收件人整个丢掉 —— 有界:量 = 本窗活跃的主体数)。
|
|
65
88
|
* 丢掉的条目按头注那条律本来就不再算数(过去的窗),所以剪枝不改任何判决;剪枝写在**这里**而不是 File 腿里,Memory 与 File
|
|
@@ -89,16 +112,16 @@ export declare class FileOrgDeliveryQuotaStore extends MemoryOrgDeliveryQuotaSto
|
|
|
89
112
|
nowMs?: () => number;
|
|
90
113
|
warn?: (event: string, fields: Record<string, unknown>) => void;
|
|
91
114
|
});
|
|
92
|
-
admitAttempt(fromScope: string, policy: OrgDeliveryQuotaPolicy): Promise<
|
|
93
|
-
take(fromScope: string, toScope: string, policy: OrgDeliveryQuotaPolicy): Promise<
|
|
115
|
+
admitAttempt(fromScope: string, policy: OrgDeliveryQuotaPolicy): Promise<OrgDeliveryQuotaVerdict>;
|
|
116
|
+
take(fromScope: string, toScope: string, policy: OrgDeliveryQuotaPolicy): Promise<OrgDeliveryQuotaVerdict>;
|
|
94
117
|
protected persist(next: QuotaWindows): void;
|
|
95
118
|
}
|
|
96
119
|
export declare class SqlOrgDeliveryQuotaStore implements OrgDeliveryQuotaStore {
|
|
97
120
|
private readonly db;
|
|
98
121
|
constructor(db: SqlDriver);
|
|
99
122
|
private q;
|
|
100
|
-
admitAttempt(fromScope: string, policy: OrgDeliveryQuotaPolicy): Promise<
|
|
101
|
-
take(fromScope: string, toScope: string, policy: OrgDeliveryQuotaPolicy): Promise<
|
|
123
|
+
admitAttempt(fromScope: string, policy: OrgDeliveryQuotaPolicy): Promise<OrgDeliveryQuotaVerdict>;
|
|
124
|
+
take(fromScope: string, toScope: string, policy: OrgDeliveryQuotaPolicy): Promise<OrgDeliveryQuotaVerdict>;
|
|
102
125
|
/**
|
|
103
126
|
* 一个记账事务:库钟先读(池上一条值语句,不在事务里留普通 SELECT),判过 ⇒ 提交,判拒 ⇒ 回滚(零残留)。
|
|
104
127
|
* 🔴 **引擎判了死锁 ⇒ 整事务重来**(`retryOnDeadlock`:全仓唯一的重来写法、唯一的上界与判据):被挑中的一方已整事务回滚、锁全放,
|
|
@@ -4,13 +4,25 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
4
4
|
import { atomicWriteFile, ensureDir } from "@sema-agent/core";
|
|
5
5
|
import { mysqlDriver, pgDriver, sqlDbNowMs } from "./sql-driver.js";
|
|
6
6
|
import { retryOnDeadlock } from "./sql-errors.js";
|
|
7
|
-
import { alignedWindow } from "../observability/cost-quota.js";
|
|
7
|
+
import { alignedWindow, retryAfterSecUntil } from "../observability/cost-quota.js";
|
|
8
8
|
export const ORG_DELIVERY_SENDER_QUOTA_TABLE = "org_delivery_sender_quota";
|
|
9
9
|
export const ORG_DELIVERY_RECIPIENT_QUOTA_TABLE = "org_delivery_recipient_quota";
|
|
10
10
|
export const ORG_DELIVERY_PAIR_QUOTA_TABLE = "org_delivery_pair_quota";
|
|
11
|
+
export const ORG_DELIVERY_QUOTA_UNREADABLE_SENTENCE = "the cross-principal delivery quota state on this server cannot be read, so every delivery is refused until an operator repairs it — nothing was delivered, and retrying will not change the answer";
|
|
12
|
+
export class OrgDeliveryQuotaUnreadableError extends Error {
|
|
13
|
+
constructor(operatorSentence) {
|
|
14
|
+
super(operatorSentence);
|
|
15
|
+
this.name = "OrgDeliveryQuotaUnreadableError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
11
18
|
export function quotaWindowStart(nowMs, windowMs) {
|
|
12
19
|
return alignedWindow(nowMs, windowMs).bucket * windowMs;
|
|
13
20
|
}
|
|
21
|
+
const GRANTED = Object.freeze({ granted: true });
|
|
22
|
+
export function quotaRetryAfterSec(nowMs, windowMs) {
|
|
23
|
+
return retryAfterSecUntil(alignedWindow(nowMs, windowMs));
|
|
24
|
+
}
|
|
25
|
+
const refused = (nowMs, windowMs) => ({ granted: false, retryAfterSec: quotaRetryAfterSec(nowMs, windowMs) });
|
|
14
26
|
export function heldWindowCounts(heldStart, at, windowMs) {
|
|
15
27
|
return heldStart === at || heldStart === at + windowMs;
|
|
16
28
|
}
|
|
@@ -21,25 +33,27 @@ export class MemoryOrgDeliveryQuotaStore {
|
|
|
21
33
|
this.nowMs = nowMs;
|
|
22
34
|
}
|
|
23
35
|
async admitAttempt(fromScope, policy) {
|
|
24
|
-
const
|
|
36
|
+
const now = this.nowMs();
|
|
37
|
+
const at = quotaWindowStart(now, policy.windowMs);
|
|
25
38
|
const held = this.state.senders.get(fromScope);
|
|
26
39
|
const current = held !== undefined && heldWindowCounts(held.windowStart, at, policy.windowMs) ? held : { windowStart: at, windowMs: policy.windowMs, attempts: 0 };
|
|
27
40
|
if (current.attempts >= policy.attemptsPerSender)
|
|
28
|
-
return
|
|
41
|
+
return refused(now, policy.windowMs);
|
|
29
42
|
const senders = new Map(this.state.senders).set(fromScope, { ...current, attempts: current.attempts + 1 });
|
|
30
43
|
this.commit({ senders, recipients: this.state.recipients });
|
|
31
|
-
return
|
|
44
|
+
return GRANTED;
|
|
32
45
|
}
|
|
33
46
|
async take(fromScope, toScope, policy) {
|
|
34
|
-
const
|
|
47
|
+
const now = this.nowMs();
|
|
48
|
+
const at = quotaWindowStart(now, policy.windowMs);
|
|
35
49
|
const held = this.state.recipients.get(toScope);
|
|
36
50
|
const current = held !== undefined && heldWindowCounts(held.windowStart, at, policy.windowMs) ? held : { windowStart: at, windowMs: policy.windowMs, total: 0, pairs: new Map() };
|
|
37
51
|
const pair = current.pairs.get(fromScope) ?? 0;
|
|
38
52
|
if (current.total >= policy.perRecipient || pair >= policy.perPair)
|
|
39
|
-
return
|
|
53
|
+
return refused(now, policy.windowMs);
|
|
40
54
|
const next = { ...current, total: current.total + 1, pairs: new Map(current.pairs).set(fromScope, pair + 1) };
|
|
41
55
|
this.commit({ senders: this.state.senders, recipients: new Map(this.state.recipients).set(toScope, next) });
|
|
42
|
-
return
|
|
56
|
+
return GRANTED;
|
|
43
57
|
}
|
|
44
58
|
commit(next) {
|
|
45
59
|
const now = this.nowMs();
|
|
@@ -97,7 +111,7 @@ export class FileOrgDeliveryQuotaStore extends MemoryOrgDeliveryQuotaStore {
|
|
|
97
111
|
parsed = { ok: false, problem: err instanceof Error ? err.message : String(err) };
|
|
98
112
|
}
|
|
99
113
|
if (!parsed.ok) {
|
|
100
|
-
this.unusable = `the cross-principal delivery quota file ${this.path} cannot be read (${parsed.problem}) — every delivery is refused until an operator moves it away (moving it resets the current window's counts)`;
|
|
114
|
+
this.unusable = `the cross-principal delivery quota file ${this.path} cannot be read (${parsed.problem}) — every delivery is refused until an operator repairs or moves it away and restarts this server — the file is read once at startup (moving it away resets the current window's counts)`;
|
|
101
115
|
(opts?.warn ?? createLogger().warn)("org_delivery_quota_corrupt_read", { path: this.path, problem: parsed.problem });
|
|
102
116
|
return;
|
|
103
117
|
}
|
|
@@ -105,12 +119,12 @@ export class FileOrgDeliveryQuotaStore extends MemoryOrgDeliveryQuotaStore {
|
|
|
105
119
|
}
|
|
106
120
|
async admitAttempt(fromScope, policy) {
|
|
107
121
|
if (this.unusable !== undefined)
|
|
108
|
-
throw new
|
|
122
|
+
throw new OrgDeliveryQuotaUnreadableError(this.unusable);
|
|
109
123
|
return super.admitAttempt(fromScope, policy);
|
|
110
124
|
}
|
|
111
125
|
async take(fromScope, toScope, policy) {
|
|
112
126
|
if (this.unusable !== undefined)
|
|
113
|
-
throw new
|
|
127
|
+
throw new OrgDeliveryQuotaUnreadableError(this.unusable);
|
|
114
128
|
return super.take(fromScope, toScope, policy);
|
|
115
129
|
}
|
|
116
130
|
persist(next) {
|
|
@@ -141,16 +155,17 @@ export class SqlOrgDeliveryQuotaStore {
|
|
|
141
155
|
return retryOnDeadlock(this.db.dialect, () => this.inTxOnce(table, policy, body));
|
|
142
156
|
}
|
|
143
157
|
async inTxOnce(table, policy, body) {
|
|
144
|
-
const
|
|
158
|
+
const now = await sqlDbNowMs(this.db, table);
|
|
159
|
+
const at = quotaWindowStart(now, policy.windowMs);
|
|
145
160
|
const conn = await this.db.connect();
|
|
146
161
|
try {
|
|
147
162
|
await conn.begin();
|
|
148
|
-
const
|
|
149
|
-
if (
|
|
163
|
+
const ok = await body(conn, at);
|
|
164
|
+
if (ok)
|
|
150
165
|
await conn.commit();
|
|
151
166
|
else
|
|
152
167
|
await conn.rollback();
|
|
153
|
-
return
|
|
168
|
+
return ok ? GRANTED : refused(now, policy.windowMs);
|
|
154
169
|
}
|
|
155
170
|
catch (err) {
|
|
156
171
|
await conn.rollback().catch((rollbackErr) => {
|
|
@@ -121,7 +121,7 @@ export declare function assertPermissionRuleApprovalSchema(query: (sql: string)
|
|
|
121
121
|
*
|
|
122
122
|
* 判据同款:发一条恒空的 `WHERE 1=0` 读;**只有可证的缺列**才给「缺列」的拒因(其余错误原样 rethrow ——
|
|
123
123
|
* 超时/连接重置/权限/表不在都会让这条读抛,把它们诊断成「缺列」是一条比缺陷更贵的诊断)。出路是**闭集三条**
|
|
124
|
-
* (与整库对账同一份,{@link
|
|
124
|
+
* (与整库对账同一份,{@link probedMissingColumnRefusal}),没有销毁性的一条。
|
|
125
125
|
*
|
|
126
126
|
* 文案照实说本表的分量:票是分钟级 TTL 的治理瞬态(过期即死),持久规则在 `permission_rule` 里,一行都不动。
|
|
127
127
|
*/
|
|
@@ -3,7 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
import { applyTombstones, assertDeleteDeltaCarriesNoAdd, assertRedemptionNotQuarantined, assertWriteDeltaScopeDurable, foldDelta, parseRuleText, readRowBehavior, screenRuleSyncState, PERMISSION_RULE_WRITER, RULE_ADD_ORIGINS, RULE_APPROVAL_KINDS, RULE_APPROVAL_RECORD_SCHEMA, RULE_APPROVAL_STATES, RULE_BEHAVIORS, RULE_SYNC_DROP_CODES, EDITED_RULE_BREADTH_WARNING_CODES, PERSISTED_RULE_MATCHES, EMPTY_DURABLE_RULE_PARTITION, PERMISSION_RULES_LATER_GRAMMAR_CODE, SESSION_RULES_GRAMMAR, readRuleGrammarStamp, readRuleOwner, principalNameOf, readRuleOffer2, } from "@sema-agent/core";
|
|
4
4
|
import { dialectProtocolJsonEncoder, sqlDbNowMs, SQL_DB_NOW_MS } from "./sql-driver.js";
|
|
5
5
|
import { isMissingColumnError } from "./sql-errors.js";
|
|
6
|
-
import {
|
|
6
|
+
import { probedMissingColumnRefusal } from "./schema-drift-sentence.js";
|
|
7
7
|
import { canonicalJsonStringify } from "@sema-agent/core";
|
|
8
8
|
import { ensureIndexes } from "./ensure-index.js";
|
|
9
9
|
import { createZodColumnReader, decodeJsonColumn, foldJsonColumn, jsonColumnText, readJsonObjectColumn, StoreCorruptError } from "./sql-json-column.js";
|
|
@@ -234,15 +234,13 @@ export async function assertPermissionRuleApprovalSchema(query, dialect) {
|
|
|
234
234
|
catch (err) {
|
|
235
235
|
if (!isMissingColumnError(err, dialect))
|
|
236
236
|
throw err;
|
|
237
|
-
throw
|
|
237
|
+
throw await probedMissingColumnRefusal(query, dialect, [PERMISSION_RULE_APPROVAL_TABLE], `${PERMISSION_RULE_APPROVAL_TABLE} is missing required columns — refusing to start. This build needs the ` +
|
|
238
238
|
`#340 card-edit columns (command / edited_json) and the design/375 record-form columns ` +
|
|
239
239
|
`(version / offers_json / selected_offer): the approval record now stores its OPTION structure and the ` +
|
|
240
240
|
`chosen offer, and the store refuses to read rows whose record-form version it cannot vouch for. ` +
|
|
241
241
|
`This table holds pending/settled approval RECORDS (the audit trail of who said yes to which ` +
|
|
242
242
|
`rule), not the rules themselves — persisted rules live in ${PERMISSION_RULE_TABLE} and are untouched; ` +
|
|
243
|
-
`an in-place ALTER keeps the record trail
|
|
244
|
-
`Underlying probe error: ${err instanceof Error ? err.message : String(err)}\n\n` +
|
|
245
|
-
(await describeProbedTableDrift(query, dialect, [PERMISSION_RULE_APPROVAL_TABLE])));
|
|
243
|
+
`an in-place ALTER keeps the record trail.`, err);
|
|
246
244
|
}
|
|
247
245
|
}
|
|
248
246
|
export async function assertPermissionRuleTicketSchema(query, dialect) {
|
|
@@ -252,14 +250,12 @@ export async function assertPermissionRuleTicketSchema(query, dialect) {
|
|
|
252
250
|
catch (err) {
|
|
253
251
|
if (!isMissingColumnError(err, dialect))
|
|
254
252
|
throw err;
|
|
255
|
-
throw
|
|
253
|
+
throw await probedMissingColumnRefusal(query, dialect, [PERMISSION_RULE_TICKET_TABLE], `${PERMISSION_RULE_TICKET_TABLE} is missing required columns (redeemed_outcome / claim_id / purpose / settled_at_ms) — refusing to start. This build needs ` +
|
|
256
254
|
`the #265 A7 three-state redemption columns (MINTED → CLAIMED → SETTLED, the claim generation that fences a superseded ` +
|
|
257
255
|
`claimant, and the lane binding that keeps cc-import and local-import tickets from being interchangeable): without them a ` +
|
|
258
256
|
`local-import ticket can be claimed but never settled, so a redemption that already wrote rules to the store answers its ` +
|
|
259
257
|
`owner with a retry-later it can never satisfy. This table holds minute-TTL single-use import ` +
|
|
260
|
-
`tickets (a governance transient that dies on expiry); persisted rules live in ${PERMISSION_RULE_TABLE} and are untouched
|
|
261
|
-
`Underlying probe error: ${err instanceof Error ? err.message : String(err)}\n\n` +
|
|
262
|
-
(await describeProbedTableDrift(query, dialect, [PERMISSION_RULE_TICKET_TABLE])));
|
|
258
|
+
`tickets (a governance transient that dies on expiry); persisted rules live in ${PERMISSION_RULE_TABLE} and are untouched.`, err);
|
|
263
259
|
}
|
|
264
260
|
}
|
|
265
261
|
export const PERMISSION_RULE_INDEXES = [
|
|
@@ -51,7 +51,7 @@ export declare function createPgPool(opts: string | pg.PoolConfig, onIdleClientE
|
|
|
51
51
|
export declare const ENSURE_SCHEMA_LOCK_KEY = 4906;
|
|
52
52
|
/**
|
|
53
53
|
* {@link ENSURE_SCHEMA_LOCK_KEY} 的**非阻塞**获取(轮询 + 抖动退避)—— MySQL 孪生
|
|
54
|
-
* `tidb-pool.ts acquireEnsureSchemaLock` 的逐条同形(
|
|
54
|
+
* `tidb-pool.ts acquireEnsureSchemaLock` 的逐条同形(两只都是 `ensure-schema-lock-policy.ts` 取锁器的薄壳:语句 / 读法 / 循环共用)。轮到拿到为止;坏连接连续抛上抛
|
|
55
55
|
* (每条 DDL 本来就各自幂等),而不是把启动挂死。
|
|
56
56
|
*
|
|
57
57
|
* 🔴 **为什么不能再用阻塞的 `pg_advisory_lock()`**([ref] 复审 H1,对 7.82.1 的回归):本仓自 [ref] 起在
|
package/dist/plugins/pg-pool.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { createLogger
|
|
1
|
+
import { createLogger } from "../observability/logger.js";
|
|
2
2
|
import pg from "pg";
|
|
3
3
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
4
|
-
import {
|
|
4
|
+
import { acquireAdvisoryLock, releaseAdvisoryLock } from "./ensure-schema-lock-policy.js";
|
|
5
5
|
import { RUN_IDENTITY_COLUMNS } from "../identity-source.js";
|
|
6
6
|
import { ensureSchema as ensureSessionSchema } from "../stores-sql/pg-session-storage.js";
|
|
7
7
|
import { sessionExtDdl } from "./session-ext-table.js";
|
|
@@ -26,6 +26,9 @@ import { SESSION_RULES_COLUMN } from "./session-rules-column.js";
|
|
|
26
26
|
import { INBOX_PAYLOAD_COLUMN } from "./inbox-payload-column.js";
|
|
27
27
|
import { CENTRAL_SCHEMA_INDEXES } from "./schema-indexes.js";
|
|
28
28
|
import { PRINCIPAL_MAX_BYTES } from "../principal-shape.js";
|
|
29
|
+
import { SKILL_EXEMPTION_CUTOFF_ID, markIfAbsentSql, migrationMarkerDdl } from "./one-time-migration-marker.js";
|
|
30
|
+
import { replicaRegistrationDdl } from "./replica-registration.js";
|
|
31
|
+
import { servingRequirementDdl } from "./serving-requirement.js";
|
|
29
32
|
export const PG_SCHEMA_STATEMENTS = [
|
|
30
33
|
`CREATE TABLE IF NOT EXISTS task_run (
|
|
31
34
|
task_id VARCHAR(64) COLLATE "C" NOT NULL,
|
|
@@ -36,6 +39,8 @@ export const PG_SCHEMA_STATEMENTS = [
|
|
|
36
39
|
error TEXT COLLATE "C",
|
|
37
40
|
error_code VARCHAR(64) COLLATE "C",
|
|
38
41
|
instance_id VARCHAR(64) COLLATE "C",
|
|
42
|
+
-- leg_id: the HOLDING LEG minted at every claim (semantics in the MySQL twin, tidb-pool.ts task_run).
|
|
43
|
+
leg_id VARCHAR(36) COLLATE "C",
|
|
39
44
|
job_id VARCHAR(64) COLLATE "C",
|
|
40
45
|
source VARCHAR(64) COLLATE "C",
|
|
41
46
|
-- identity_*: the run's identity tuple (semantics in the MySQL twin, tidb-pool.ts task_run; column definitions' single owner =
|
|
@@ -417,6 +422,9 @@ export const PG_SCHEMA_STATEMENTS = [
|
|
|
417
422
|
updated_at_ms BIGINT NOT NULL,
|
|
418
423
|
PRIMARY KEY (store_id, path)
|
|
419
424
|
)`,
|
|
425
|
+
migrationMarkerDdl("pg"),
|
|
426
|
+
replicaRegistrationDdl("pg"),
|
|
427
|
+
servingRequirementDdl("pg"),
|
|
420
428
|
];
|
|
421
429
|
export function pgPoolOptions(pgCfg, dbQueryTimeoutMs) {
|
|
422
430
|
return {
|
|
@@ -475,19 +483,12 @@ export function createPgPool(opts, onIdleClientError) {
|
|
|
475
483
|
return pool;
|
|
476
484
|
}
|
|
477
485
|
export const ENSURE_SCHEMA_LOCK_KEY = 4906;
|
|
486
|
+
const ENSURE_SCHEMA_LOCK_ID = { dialect: "pg", keys: [ENSURE_SCHEMA_LOCK_KEY] };
|
|
478
487
|
export async function acquirePgEnsureSchemaLock(client, tag) {
|
|
479
|
-
await
|
|
480
|
-
const res = await client.query("SELECT pg_try_advisory_lock($1) AS got", [ENSURE_SCHEMA_LOCK_KEY]);
|
|
481
|
-
return res.rows[0]?.got === true;
|
|
482
|
-
}, { tag, label: `pg advisory lock ${ENSURE_SCHEMA_LOCK_KEY}` });
|
|
488
|
+
await acquireAdvisoryLock(client, ENSURE_SCHEMA_LOCK_ID, tag);
|
|
483
489
|
}
|
|
484
490
|
export async function releasePgEnsureSchemaLock(client, tag) {
|
|
485
|
-
|
|
486
|
-
await client.query("SELECT pg_advisory_unlock($1)", [ENSURE_SCHEMA_LOCK_KEY]);
|
|
487
|
-
}
|
|
488
|
-
catch (err) {
|
|
489
|
-
writeLogText("stderr", `[${tag}] pg_advisory_unlock(${ENSURE_SCHEMA_LOCK_KEY}) failed (lock auto-frees on connection close):`, err);
|
|
490
|
-
}
|
|
491
|
+
await releaseAdvisoryLock(client, ENSURE_SCHEMA_LOCK_ID, tag);
|
|
491
492
|
}
|
|
492
493
|
export async function ensurePgSchema(pool) {
|
|
493
494
|
const client = await pool.connect();
|
|
@@ -497,6 +498,7 @@ export async function ensurePgSchema(pool) {
|
|
|
497
498
|
locked = true;
|
|
498
499
|
for (const stmt of PG_SCHEMA_STATEMENTS)
|
|
499
500
|
await client.query(stmt);
|
|
501
|
+
await client.query(markIfAbsentSql("pg"), [SKILL_EXEMPTION_CUTOFF_ID, Date.now()]);
|
|
500
502
|
await ensureSessionSchema(client);
|
|
501
503
|
await client.query(sessionExtDdl("pg"));
|
|
502
504
|
await ensureToolResultSchema(client);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { anchorUnder } from "./exec-path-law.js";
|
|
2
3
|
import { FileError, } from "@sema-agent/core";
|
|
3
4
|
import { runSymlinkChain, shellQuote, kindFromMode } from "./remote-shell.js";
|
|
4
5
|
import { classifyFsStderr, fileErrorFromExec } from "./remote-env-file-error.js";
|
|
@@ -60,11 +61,12 @@ export function createPosixShellFs(deps) {
|
|
|
60
61
|
const names = r.value.stdout.split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
61
62
|
const out = [];
|
|
62
63
|
for (const name of names) {
|
|
63
|
-
const
|
|
64
|
+
const entry = anchorUnder(path.posix, abs, name);
|
|
65
|
+
const info = await fs.statFileInfo(entry, abortSignal);
|
|
64
66
|
if (info.ok)
|
|
65
67
|
out.push(info.value);
|
|
66
68
|
else
|
|
67
|
-
out.push({ name, path:
|
|
69
|
+
out.push({ name, path: entry, kind: "file", size: 0, mtimeMs: 0 });
|
|
68
70
|
}
|
|
69
71
|
return ok(out);
|
|
70
72
|
},
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { anchoredPath, joinedPath } from "./exec-path-law.js";
|
|
2
3
|
import os from "node:os";
|
|
3
4
|
import fs from "node:fs/promises";
|
|
4
5
|
import { spawn } from "node:child_process";
|
|
@@ -65,7 +66,7 @@ export class RemoteAdbExecutionEnv {
|
|
|
65
66
|
this.injectedConnectOnce = deps?.connectOnce;
|
|
66
67
|
}
|
|
67
68
|
resolve(p) {
|
|
68
|
-
return
|
|
69
|
+
return anchoredPath(path.posix, this.cwd, p);
|
|
69
70
|
}
|
|
70
71
|
workspaceHandle() {
|
|
71
72
|
return { sandboxId: this.cfg.serial, provider: PROVIDER, mountPath: this.cwd };
|
|
@@ -328,7 +329,7 @@ export class RemoteAdbExecutionEnv {
|
|
|
328
329
|
return ok(this.resolve(p));
|
|
329
330
|
}
|
|
330
331
|
async joinPath(parts) {
|
|
331
|
-
return ok(path.posix
|
|
332
|
+
return ok(joinedPath(path.posix, parts));
|
|
332
333
|
}
|
|
333
334
|
async fsGate(p) {
|
|
334
335
|
if (this.destroyed)
|
|
@@ -331,14 +331,15 @@ export declare function deviceExecutionEnvFactory(deps: DeviceEnvFactoryDeps): E
|
|
|
331
331
|
/**
|
|
332
332
|
* §4.3.3 的 cwd 优先序 —— 与 host 腿的 `effectiveHostWorkspace` **同源**:
|
|
333
333
|
* ① 本 session 显式注册的 cwd(部署形表行 `callerCwd` 闸下由 resolve-spec 写);
|
|
334
|
-
* ② `ctx.parentCwd`(
|
|
334
|
+
* ② `ctx.parentCwd`(交活方的工作目录:委派子代继承父的;组合腿 —— 梯子的级、验证器腿,跑在引擎现铸的会话里 —— 由组合入口交提交登记的 cwd;
|
|
335
|
+
* 少了它这些腿会丢工作目录);
|
|
335
336
|
* ③ 设备入籍时登记并落库的 `workspaceRoot`(缺 cwd 时的解析基准,有明确 wire 契约,不是「executor
|
|
336
337
|
* 默认根」这种空话)。
|
|
337
338
|
*
|
|
338
339
|
* 🔴 **这一只解析源同时守它的后置条件:结果必是 POSIX 绝对路径,否则响亮抛 typed 拒(`.code` = `config.device_cwd_invalid`)。** 协议文档对 executor 的承诺是
|
|
339
340
|
* 「exec / execStream 的指令帧恒带绝对 `cwd`」—— 不带或带相对的,都会把「用哪个目录」这件事留给 executor
|
|
340
341
|
* 自己猜(同一个事实两种读法)。判据是入籍口那**同一只**谓词 `isDeviceAbsolutePath`(`device-store.ts`):入籍口用它拒相对的
|
|
341
|
-
* `workspaceRoot`;这里的判留作存量行守卫(入籍口收紧之前落库的相对根)并守另两个来源 ——
|
|
342
|
+
* `workspaceRoot`;这里的判留作存量行守卫(入籍口收紧之前落库的相对根)并守另两个来源 —— 第 ② 臂的交活方工作目录不经入籍口。
|
|
342
343
|
*/
|
|
343
344
|
export declare function effectiveDeviceCwd(sessionCwd: string | undefined, parentCwd: string | undefined, row: Pick<DeviceRow, "workspaceRoot">): string;
|
|
344
345
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { posix } from "node:path";
|
|
2
|
+
import { anchoredPath, anchorUnder, joinedPath } from "./exec-path-law.js";
|
|
2
3
|
import { ExecutionError, FileError, RemoteExecutionError, } from "@sema-agent/core";
|
|
3
4
|
import { capabilitiesFor } from "../execution-lane-caps.js";
|
|
4
5
|
import { DEVICE_ERROR_CODES, isDeviceAbsolutePath, } from "../device-store.js";
|
|
@@ -174,7 +175,7 @@ export class RemoteDeviceExecutionEnv {
|
|
|
174
175
|
"performing a NON-atomic write here is exactly the silent downgrade guarded writes exist to prevent (#157). Refusing; the per-task factory mints a correctly-shaped env on the next task.", absPath);
|
|
175
176
|
}
|
|
176
177
|
resolve(p) {
|
|
177
|
-
return
|
|
178
|
+
return anchoredPath(DEVICE_PATH_FAMILY, this.cwd, p);
|
|
178
179
|
}
|
|
179
180
|
instructionCwd(requested) {
|
|
180
181
|
return requested === undefined ? this.cwd : this.resolve(requested);
|
|
@@ -183,7 +184,7 @@ export class RemoteDeviceExecutionEnv {
|
|
|
183
184
|
return ok(this.resolve(p));
|
|
184
185
|
}
|
|
185
186
|
async joinPath(parts) {
|
|
186
|
-
return ok(
|
|
187
|
+
return ok(joinedPath(DEVICE_PATH_FAMILY, parts));
|
|
187
188
|
}
|
|
188
189
|
workspaceHandle() {
|
|
189
190
|
return {
|
|
@@ -557,7 +558,7 @@ export class RemoteDeviceExecutionEnv {
|
|
|
557
558
|
return this.wrongOutcome("stat", o.kind, abs);
|
|
558
559
|
if (!o.info)
|
|
559
560
|
return { ok: false, error: new FileError("unknown", "device returned a stat outcome without info — protocol violation", abs) };
|
|
560
|
-
return ok(toFileInfo(o.info));
|
|
561
|
+
return ok(toFileInfo(o.info, abs));
|
|
561
562
|
});
|
|
562
563
|
}
|
|
563
564
|
async doReadLink(p, abortSignal) {
|
|
@@ -642,7 +643,7 @@ export class RemoteDeviceExecutionEnv {
|
|
|
642
643
|
return this.wrongOutcome("stat", o.kind, abs);
|
|
643
644
|
if (!o.entries)
|
|
644
645
|
return { ok: false, error: new FileError("unknown", "device returned a stat outcome without entries — protocol violation", abs) };
|
|
645
|
-
return ok(o.entries.map(toFileInfo));
|
|
646
|
+
return ok(o.entries.map((w) => toFileInfo(w, anchorUnder(DEVICE_PATH_FAMILY, abs, posix.basename(w.path)))));
|
|
646
647
|
});
|
|
647
648
|
}
|
|
648
649
|
async writeFile(p, content, abortSignal) {
|
|
@@ -738,8 +739,9 @@ function mergedEnv(taskEnv, commandEnv) {
|
|
|
738
739
|
function markTruncated(text, truncated) {
|
|
739
740
|
return truncated === true ? `${text}\n[output truncated by the device executor]` : text;
|
|
740
741
|
}
|
|
741
|
-
|
|
742
|
-
|
|
742
|
+
const DEVICE_PATH_FAMILY = { sep: posix.sep, isAbsolute: isDeviceAbsolutePath };
|
|
743
|
+
function toFileInfo(w, at) {
|
|
744
|
+
return { name: posix.basename(at), path: at, kind: w.kind === "dir" ? "directory" : w.kind === "symlink" ? "symlink" : "file", size: w.size, mtimeMs: w.mtimeMs };
|
|
743
745
|
}
|
|
744
746
|
function toWireExpectation(e) {
|
|
745
747
|
return {
|
|
@@ -45,7 +45,7 @@ export interface RemoteContainerEnvConfig extends RemoteEnvObservers, LaneHomeCo
|
|
|
45
45
|
template?: string;
|
|
46
46
|
/** Sandbox lifetime in ms (E2B billing window). Default {@link DEFAULT_TIMEOUT_MS}. */
|
|
47
47
|
timeoutMs?: number;
|
|
48
|
-
/** Workspace root inside the VM;
|
|
48
|
+
/** Workspace root inside the VM; a relative path is anchored at it (`exec-path-law.ts`: anchored, never folded). Default {@link DEFAULT_MOUNT_PATH}. */
|
|
49
49
|
mountPath?: string;
|
|
50
50
|
/** Outbound network for the sandbox (clay: service needs external-network capability). Default `true`. */
|
|
51
51
|
allowInternetAccess?: boolean;
|
|
@@ -244,13 +244,7 @@ export declare class RemoteContainerExecutionEnv implements RemoteExecutionEnv,
|
|
|
244
244
|
private execInternal;
|
|
245
245
|
private execAs;
|
|
246
246
|
execStream(command: string, options?: ExecStreamOptions): AsyncIterable<OutputChunk>;
|
|
247
|
-
readonly backgroundCapabilities:
|
|
248
|
-
readonly supported: true;
|
|
249
|
-
readonly maxConcurrent: number;
|
|
250
|
-
readonly defaultBgTimeoutSec: number;
|
|
251
|
-
readonly maxBgTimeoutSec: number;
|
|
252
|
-
readonly supportsDetach: true;
|
|
253
|
-
};
|
|
247
|
+
readonly backgroundCapabilities: BackgroundShellCapability["backgroundCapabilities"];
|
|
254
248
|
private _bgManager?;
|
|
255
249
|
private get bgManager();
|
|
256
250
|
private makeBgDriver;
|
|
@@ -371,6 +365,8 @@ export declare class RemoteContainerExecutionEnv implements RemoteExecutionEnv,
|
|
|
371
365
|
private ensureConnected;
|
|
372
366
|
private fsReady;
|
|
373
367
|
private tempResult;
|
|
368
|
+
/** 提供方的条目 → `FileInfo`。`path` 取本环境的拼法(`at`:被问的那只路径 / 列目录时锚在它之下的条目),不取提供方回报的那一份
|
|
369
|
+
* —— 提供方可能已把 `..` 折掉,而执行缝路径律(`exec-path-law.ts`)要求条目名在交来的路径之下、能原样再交回来。 */
|
|
374
370
|
private toFileInfo;
|
|
375
371
|
private fileError;
|
|
376
372
|
/** A thrown provider error → this exec's error. The two cuts (aborted, the provider's own command deadline) are a command that RAN: they carry what it had
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { anchoredPath, anchorUnder, joinedPath } from "./exec-path-law.js";
|
|
2
3
|
import { Sandbox, CommandExitError, FileType } from "e2b";
|
|
3
4
|
import { FileError, ExecutionError, RemoteExecutionError, RollingTailBuffer, markTruncated, } from "@sema-agent/core";
|
|
4
5
|
import { capabilitiesFor } from "../execution-lane-caps.js";
|
|
6
|
+
import { DEPLOYMENT_SHAPE_PREDICATES } from "../deployment-shape.js";
|
|
5
7
|
import { ADAPTER_START, BOOTSTRAP_START, createSandboxReadFloor, e2bFloorCommand, engineStart, } from "./sandbox-read-floor.js";
|
|
6
8
|
import { LANE_HOME_PROBE_COMMAND, LaneHomeSeat } from "../lane-home-probe.js";
|
|
7
9
|
import { fileErrorFromExec } from "./remote-env-file-error.js";
|
|
@@ -55,6 +57,14 @@ export class RemoteContainerExecutionEnv {
|
|
|
55
57
|
this.sandboxApi = deps.sandboxApi ?? Sandbox;
|
|
56
58
|
this.floor = deps.readFloor ?? createSandboxReadFloor({ lane: PROVIDER, knob: config.sandboxReadFloor, ...(config.logger !== undefined ? { logger: config.logger } : {}) });
|
|
57
59
|
this.capabilities = capabilitiesFor({ remoteExec: { provider: PROVIDER }, sandboxReadFloor: config.sandboxReadFloor });
|
|
60
|
+
const backgroundShellOn = DEPLOYMENT_SHAPE_PREDICATES.backgroundShell.holds({ remoteExec: { provider: PROVIDER } });
|
|
61
|
+
this.backgroundCapabilities = {
|
|
62
|
+
supported: backgroundShellOn,
|
|
63
|
+
maxConcurrent: E2B_BG_MAX_CONCURRENT,
|
|
64
|
+
defaultBgTimeoutSec: E2B_BG_DEFAULT_TIMEOUT_SEC,
|
|
65
|
+
maxBgTimeoutSec: E2B_BG_MAX_TIMEOUT_SEC,
|
|
66
|
+
supportsDetach: backgroundShellOn,
|
|
67
|
+
};
|
|
58
68
|
}
|
|
59
69
|
capabilities;
|
|
60
70
|
floor;
|
|
@@ -764,13 +774,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
764
774
|
options?.signal?.removeEventListener("abort", onAbort);
|
|
765
775
|
}
|
|
766
776
|
}
|
|
767
|
-
backgroundCapabilities
|
|
768
|
-
supported: true,
|
|
769
|
-
maxConcurrent: E2B_BG_MAX_CONCURRENT,
|
|
770
|
-
defaultBgTimeoutSec: E2B_BG_DEFAULT_TIMEOUT_SEC,
|
|
771
|
-
maxBgTimeoutSec: E2B_BG_MAX_TIMEOUT_SEC,
|
|
772
|
-
supportsDetach: true,
|
|
773
|
-
};
|
|
777
|
+
backgroundCapabilities;
|
|
774
778
|
_bgManager;
|
|
775
779
|
get bgManager() {
|
|
776
780
|
return (this._bgManager ??= new BackgroundShellManager(this.makeBgDriver(), this.backgroundCapabilities));
|
|
@@ -859,7 +863,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
859
863
|
return ok(this.resolve(p));
|
|
860
864
|
}
|
|
861
865
|
async joinPath(parts) {
|
|
862
|
-
return ok(path.posix
|
|
866
|
+
return ok(joinedPath(path.posix, parts));
|
|
863
867
|
}
|
|
864
868
|
async readTextFile(p, abortSignal) {
|
|
865
869
|
const sbx = await this.fsReady(p);
|
|
@@ -931,8 +935,9 @@ export class RemoteContainerExecutionEnv {
|
|
|
931
935
|
if (!sbx.ok)
|
|
932
936
|
return sbx;
|
|
933
937
|
try {
|
|
934
|
-
const
|
|
935
|
-
|
|
938
|
+
const abs = this.resolve(p);
|
|
939
|
+
const info = await this.rpc("files.getInfo", (signal) => sbx.value.files.getInfo(abs, { signal }), abortSignal);
|
|
940
|
+
return ok(this.toFileInfo(info, abs));
|
|
936
941
|
}
|
|
937
942
|
catch (e) {
|
|
938
943
|
return { ok: false, error: this.fileError(e, this.resolve(p), abortSignal) };
|
|
@@ -943,8 +948,9 @@ export class RemoteContainerExecutionEnv {
|
|
|
943
948
|
if (!sbx.ok)
|
|
944
949
|
return sbx;
|
|
945
950
|
try {
|
|
946
|
-
const
|
|
947
|
-
|
|
951
|
+
const abs = this.resolve(p);
|
|
952
|
+
const entries = await this.rpc("files.list", (signal) => sbx.value.files.list(abs, { signal }), abortSignal);
|
|
953
|
+
return ok(entries.map((e) => this.toFileInfo(e, anchorUnder(path.posix, abs, e.name))));
|
|
948
954
|
}
|
|
949
955
|
catch (e) {
|
|
950
956
|
return { ok: false, error: this.fileError(e, this.resolve(p), abortSignal) };
|
|
@@ -1041,7 +1047,7 @@ export class RemoteContainerExecutionEnv {
|
|
|
1041
1047
|
return this.tempResult(r, "mktemp");
|
|
1042
1048
|
}
|
|
1043
1049
|
resolve(p) {
|
|
1044
|
-
return
|
|
1050
|
+
return anchoredPath(path.posix, this.cwd, p);
|
|
1045
1051
|
}
|
|
1046
1052
|
async rpc(label, op, userSignal, timeoutMs = this.cfg.rpcTimeoutMs) {
|
|
1047
1053
|
const deadline = new AbortController();
|
|
@@ -1160,11 +1166,11 @@ export class RemoteContainerExecutionEnv {
|
|
|
1160
1166
|
return { ok: false, error: new FileError("unknown", r.value.stderr.trim() || `${op} failed`) };
|
|
1161
1167
|
return ok(r.value.stdout.trim());
|
|
1162
1168
|
}
|
|
1163
|
-
toFileInfo(e) {
|
|
1169
|
+
toFileInfo(e, at) {
|
|
1164
1170
|
const kind = e.symlinkTarget ? "symlink" : e.type === FileType.DIR ? "directory" : "file";
|
|
1165
1171
|
return {
|
|
1166
1172
|
name: e.name,
|
|
1167
|
-
path:
|
|
1173
|
+
path: at,
|
|
1168
1174
|
kind,
|
|
1169
1175
|
size: e.size ?? 0,
|
|
1170
1176
|
mtimeMs: e.modifiedTime ? e.modifiedTime.getTime() : 0,
|