@sema-agent/server 7.131.0 → 7.133.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 +575 -0
- package/README.md +12 -9
- package/README.zh-CN.md +9 -6
- package/USAGE.md +326 -98
- package/deploy/sema-up/README.md +19 -1
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -2
- package/deploy/sema-up/chart/templates/server.yaml +5 -2
- package/deploy/sema-up/stack/compose.yaml +3 -0
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
- package/dist/adoption/plan.d.ts +3 -2
- package/dist/adoption/plan.js +7 -5
- package/dist/adoption/runner.js +3 -10
- package/dist/adoption/sql.d.ts +3 -2
- package/dist/adoption/sql.js +3 -5
- package/dist/adoption/wire.d.ts +4 -1
- package/dist/adoption/wire.js +1 -0
- package/dist/approval-ask-audit-store.d.ts +31 -13
- package/dist/approval-ask-audit-store.js +272 -74
- package/dist/approval-ask-machine.d.ts +15 -0
- package/dist/approval-ask-machine.js +6 -0
- package/dist/approval-ask-retention.d.ts +136 -0
- package/dist/approval-ask-retention.js +102 -0
- package/dist/approval-card.d.ts +82 -20
- package/dist/approval-card.js +46 -16
- package/dist/approval-deny-reasons.d.ts +1 -1
- package/dist/approval.d.ts +9 -0
- package/dist/approval.js +24 -3
- package/dist/audit.d.ts +33 -19
- package/dist/audit.js +12 -16
- package/dist/auth-bridge.d.ts +4 -0
- package/dist/auth-bridge.js +10 -11
- package/dist/bake-runner/main.js +3 -2
- package/dist/boot/deferred-sandbox-path-env.js +1 -1
- package/dist/boot/deployment-mods.d.ts +31 -0
- package/dist/boot/deployment-mods.js +26 -0
- package/dist/boot/execution-env.d.ts +1 -1
- package/dist/boot/execution-env.js +27 -12
- package/dist/boot/execution-lane.js +11 -0
- package/dist/boot/leader.js +2 -0
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/memory-boundary.js +2 -2
- package/dist/boot/memory-consolidation.d.ts +5 -4
- package/dist/boot/memory-consolidation.js +7 -6
- package/dist/boot/org-delivery.d.ts +28 -0
- package/dist/boot/org-delivery.js +20 -0
- package/dist/boot/read-deny-anchor-audit.d.ts +17 -0
- package/dist/boot/read-deny-anchor-audit.js +36 -0
- package/dist/boot/reapers.d.ts +3 -0
- package/dist/boot/reapers.js +21 -1
- package/dist/boot/resolve-spec.d.ts +4 -5
- package/dist/boot/resolve-spec.js +74 -123
- package/dist/boot/runner-deps.d.ts +19 -8
- package/dist/boot/runner-deps.js +15 -2
- package/dist/boot/session-faces.d.ts +2 -7
- package/dist/boot/session-faces.js +4 -2
- package/dist/boot/stage-02-web-admin-pull.js +4 -1
- package/dist/boot/stage-03-store-backend.d.ts +1 -1
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +4 -4
- package/dist/boot/stage-05-execution-env.js +7 -10
- package/dist/boot/stage-06-runners.d.ts +4 -2
- package/dist/boot/stage-06-runners.js +11 -7
- package/dist/boot/stage-07-capability-layer.d.ts +4 -2
- package/dist/boot/stage-07-capability-layer.js +27 -6
- package/dist/boot/stage-08-reapers.d.ts +4 -2
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +6 -9
- package/dist/boot/stage-10-http-server.d.ts +6 -9
- package/dist/boot/stage-10-http-server.js +7 -9
- package/dist/boot/stores.d.ts +1 -1
- package/dist/boot/stores.js +7 -8
- package/dist/boot/web-admin.d.ts +4 -3
- package/dist/boot/web-admin.js +186 -98
- package/dist/boot/workflow-orchestration.d.ts +2 -0
- package/dist/boot/workflow-orchestration.js +2 -1
- package/dist/brain.js +25 -25
- package/dist/breaker-key.d.ts +6 -0
- package/dist/breaker-key.js +29 -0
- package/dist/budget.js +5 -4
- package/dist/caller-text-echo.d.ts +23 -0
- package/dist/caller-text-echo.js +21 -0
- package/dist/capabilities/brand-identity.d.ts +26 -0
- package/dist/capabilities/brand-identity.js +27 -0
- package/dist/capabilities/center-plugins.d.ts +7 -0
- package/dist/capabilities/center-plugins.js +1 -1
- package/dist/capabilities/center-prompts.d.ts +32 -59
- package/dist/capabilities/center-prompts.js +18 -32
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/engine-capabilities.js +2 -1
- package/dist/capabilities/execution-lane.js +2 -2
- package/dist/capabilities/hands-lane.d.ts +30 -6
- package/dist/capabilities/hands-lane.js +11 -1
- package/dist/capabilities/mcp-probe.d.ts +48 -3
- package/dist/capabilities/mcp-probe.js +47 -135
- package/dist/capabilities/scenarios.d.ts +95 -45
- package/dist/capabilities/scenarios.js +53 -38
- package/dist/capabilities/skills.d.ts +19 -4
- package/dist/capabilities/skills.js +30 -10
- package/dist/capability-facts.d.ts +34 -4
- package/dist/capability-facts.js +28 -2
- package/dist/center-config-tier.d.ts +69 -0
- package/dist/center-config-tier.js +42 -0
- package/dist/checkpoint-identity.d.ts +16 -0
- package/dist/checkpoint-identity.js +19 -0
- package/dist/config-catalog.d.ts +17 -10
- package/dist/config-catalog.js +47 -32
- package/dist/config-d-migration.d.ts +3 -1
- package/dist/config-d-migration.js +2 -2
- package/dist/config-dir-trust.d.ts +114 -0
- package/dist/config-dir-trust.js +388 -0
- package/dist/config-invariants.d.ts +18 -5
- package/dist/config-invariants.js +35 -3
- package/dist/config-lkg.d.ts +9 -9
- package/dist/config-lkg.js +20 -4
- package/dist/config-provider.d.ts +9 -2
- package/dist/config-provider.js +18 -6
- package/dist/config-types.d.ts +75 -20
- package/dist/config-types.js +8 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.js +137 -62
- package/dist/delegated-session-owner.d.ts +185 -0
- package/dist/delegated-session-owner.js +119 -0
- package/dist/device-protocol.d.ts +5 -3
- package/dist/device-protocol.js +1 -1
- package/dist/device-ws-hub.js +21 -2
- package/dist/device-ws-protocol.d.ts +70 -6
- package/dist/device-ws-protocol.js +50 -22
- package/dist/elicitation.js +3 -2
- package/dist/entry-problems.d.ts +34 -0
- package/dist/entry-problems.js +14 -0
- package/dist/env-name-allowlist-knobs.d.ts +12 -2
- package/dist/env-name-allowlist-knobs.js +5 -4
- package/dist/exec-bounds.d.ts +15 -3
- package/dist/exec-bounds.js +4 -0
- package/dist/execution-lane-caps.d.ts +56 -10
- package/dist/execution-lane-caps.js +50 -0
- package/dist/field-conflict.d.ts +43 -0
- package/dist/field-conflict.js +20 -0
- package/dist/fleet/fleet-bus.d.ts +80 -6
- package/dist/fleet/fleet-bus.js +41 -9
- package/dist/hooks/classic-stations.d.ts +91 -0
- package/dist/hooks/classic-stations.js +27 -0
- package/dist/hooks/command-spawn.d.ts +57 -0
- package/dist/hooks/command-spawn.js +139 -0
- package/dist/hooks/hook-llm.d.ts +8 -5
- package/dist/hooks/hook-llm.js +79 -36
- package/dist/hooks/hook-runner.d.ts +349 -95
- package/dist/hooks/hook-runner.js +855 -568
- package/dist/hooks/hook-source.d.ts +44 -0
- package/dist/hooks/hook-source.js +40 -0
- package/dist/http/active-run-conflict.d.ts +5 -13
- package/dist/http/active-run-conflict.js +17 -27
- package/dist/http/admission.d.ts +8 -2
- package/dist/http/admission.js +188 -101
- package/dist/http/approval-sweeps.js +99 -21
- package/dist/http/caller-trust.d.ts +77 -0
- package/dist/http/caller-trust.js +143 -0
- package/dist/http/checkpoint-ctx.d.ts +41 -24
- package/dist/http/checkpoint-ctx.js +23 -16
- package/dist/http/claimed-run.d.ts +14 -0
- package/dist/http/claimed-run.js +15 -0
- package/dist/http/device-placement.d.ts +2 -4
- package/dist/http/device-placement.js +7 -11
- package/dist/http/dispatch.d.ts +0 -4
- package/dist/http/dispatch.js +15 -13
- package/dist/http/durable-run-leg.d.ts +6 -33
- package/dist/http/durable-run-leg.js +36 -10
- package/dist/http/health-self-report.d.ts +7 -5
- package/dist/http/health-self-report.js +4 -18
- package/dist/http/owner-access.d.ts +56 -0
- package/dist/http/owner-access.js +42 -0
- package/dist/http/principal-gate.d.ts +70 -28
- package/dist/http/principal-gate.js +61 -15
- package/dist/http/readiness.d.ts +11 -5
- package/dist/http/readiness.js +10 -3
- package/dist/http/refusal-body.d.ts +21 -0
- package/dist/http/refusal-body.js +4 -0
- package/dist/http/request-guards.d.ts +43 -23
- package/dist/http/request-guards.js +53 -17
- package/dist/http/resume-ctx-read.d.ts +2 -5
- package/dist/http/resume-ctx-read.js +7 -4
- package/dist/http/resume-legs.d.ts +28 -4
- package/dist/http/resume-legs.js +169 -91
- package/dist/http/retired-service-deps.d.ts +43 -0
- package/dist/http/retired-service-deps.js +18 -0
- package/dist/http/route-ctx.d.ts +44 -28
- package/dist/http/route-ctx.js +4 -0
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/a2a-serve.js +3 -4
- package/dist/http/routes/admin-config-refresh.js +1 -1
- package/dist/http/routes/admin-drain.js +1 -1
- package/dist/http/routes/admin-memory-optout.js +5 -1
- package/dist/http/routes/adoption.js +2 -9
- package/dist/http/routes/approvals-assistant.js +49 -48
- package/dist/http/routes/background.js +3 -2
- package/dist/http/routes/capabilities.js +21 -5
- package/dist/http/routes/config-catalog.d.ts +3 -3
- package/dist/http/routes/config-catalog.js +1 -1
- package/dist/http/routes/devices.js +3 -17
- package/dist/http/routes/diagnostics.js +6 -2
- package/dist/http/routes/images.js +6 -7
- package/dist/http/routes/leader.js +1 -8
- package/dist/http/routes/mcp-reconnect.d.ts +1 -1
- package/dist/http/routes/mcp-reconnect.js +3 -2
- package/dist/http/routes/memory-bundle.js +1 -1
- package/dist/http/routes/memory-compliance.js +1 -1
- package/dist/http/routes/memory-consolidation.js +1 -1
- package/dist/http/routes/memory-origin.js +1 -1
- package/dist/http/routes/memory-policy.d.ts +1 -1
- package/dist/http/routes/memory-policy.js +3 -2
- package/dist/http/routes/notify-wake.js +8 -21
- package/dist/http/routes/observability.js +2 -2
- package/dist/http/routes/principal-inbox.d.ts +39 -0
- package/dist/http/routes/principal-inbox.js +76 -0
- package/dist/http/routes/retention-ops.js +2 -9
- package/dist/http/routes/rules.js +5 -18
- package/dist/http/routes/runs.d.ts +5 -0
- package/dist/http/routes/runs.js +34 -107
- package/dist/http/routes/session-sync.js +15 -26
- package/dist/http/routes/sessions.js +30 -40
- package/dist/http/routes/shared-memory.js +2 -13
- package/dist/http/routes/side-query.js +8 -7
- package/dist/http/routes/tasks.js +67 -21
- package/dist/http/routes/workflows.d.ts +351 -0
- package/dist/http/routes/workflows.js +153 -119
- package/dist/http/send.d.ts +33 -10
- package/dist/http/send.js +21 -4
- package/dist/http/server.d.ts +27 -18
- package/dist/http/server.js +34 -6
- package/dist/http/stored-body-replay.js +17 -4
- package/dist/http/submit-ctx.d.ts +25 -0
- package/dist/http/submit-ctx.js +40 -0
- package/dist/http/submit-replay.d.ts +4 -3
- package/dist/http/submit-replay.js +5 -4
- package/dist/http/wire-types.d.ts +11 -8
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -2
- package/dist/lane-home-probe.d.ts +112 -0
- package/dist/lane-home-probe.js +101 -0
- package/dist/leader/endpoint.d.ts +4 -1
- package/dist/leader/endpoint.js +11 -10
- package/dist/limit-refusal.d.ts +59 -0
- package/dist/limit-refusal.js +15 -0
- package/dist/main.js +1 -1
- package/dist/mcp-assertion-header.d.ts +32 -19
- package/dist/mcp-assertion-header.js +10 -9
- package/dist/mcp-tool-faces.d.ts +5 -0
- package/dist/mcp-tool-faces.js +6 -4
- package/dist/memory-project-layer.d.ts +37 -0
- package/dist/memory-project-layer.js +46 -0
- package/dist/memory-scope.d.ts +24 -17
- package/dist/memory-scope.js +24 -8
- package/dist/memory-sync-client.d.ts +27 -13
- package/dist/memory-sync-client.js +107 -18
- package/dist/model-entry-refusal.d.ts +9 -1
- package/dist/model-entry-refusal.js +6 -1
- package/dist/model-plane-face.d.ts +51 -0
- package/dist/model-plane-face.js +24 -0
- package/dist/model-provider.d.ts +44 -12
- package/dist/model-provider.js +21 -2
- package/dist/model-route-endpoint.d.ts +9 -12
- package/dist/model-route-endpoint.js +8 -11
- package/dist/model-route-env.d.ts +22 -0
- package/dist/model-route-env.js +2 -0
- package/dist/model-route-gap.d.ts +60 -30
- package/dist/model-route-gap.js +21 -15
- package/dist/observability/corrupt-read-seat.d.ts +7 -0
- package/dist/observability/corrupt-read-seat.js +9 -0
- package/dist/observability/cost-taxonomy.d.ts +7 -7
- package/dist/observability/err-text.d.ts +6 -0
- package/dist/observability/err-text.js +18 -4
- package/dist/observability/fail-open.d.ts +76 -14
- package/dist/observability/fail-open.js +76 -14
- package/dist/observability/metrics.js +4 -1
- package/dist/observability/prompt-manifest.d.ts +33 -82
- package/dist/observability/prompt-manifest.js +122 -17
- package/dist/observability/run-terminal.js +14 -6
- package/dist/observability/secret-env-scrub.d.ts +13 -1
- package/dist/observability/secret-env-scrub.js +13 -1
- package/dist/observability/tool-trace.d.ts +16 -21
- package/dist/observability/tool-trace.js +58 -49
- package/dist/operator-ask.d.ts +10 -0
- package/dist/operator-ask.js +3 -0
- package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
- package/dist/orchestration/workflow-agent-session-index.js +9 -13
- package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
- package/dist/orchestration/workflow-completion-inbox.js +13 -0
- package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
- package/dist/orchestration/workflow-notify-journal.js +27 -34
- package/dist/orchestration/workflow-park-decision.d.ts +89 -0
- package/dist/orchestration/workflow-park-decision.js +118 -0
- package/dist/org-delivery-gate.d.ts +81 -0
- package/dist/org-delivery-gate.js +59 -0
- package/dist/panel-tool-names.d.ts +23 -0
- package/dist/panel-tool-names.js +8 -0
- package/dist/parked-decide.d.ts +39 -6
- package/dist/parked-decide.js +98 -51
- package/dist/parked-revive-surface.d.ts +9 -2
- package/dist/parked-revive-surface.js +11 -8
- package/dist/per-task-image.d.ts +7 -1
- package/dist/per-task-image.js +3 -3
- package/dist/permission-rule-list.d.ts +1 -1
- package/dist/permission-rule-list.js +2 -2
- package/dist/plain-string-record.d.ts +25 -0
- package/dist/plain-string-record.js +32 -0
- package/dist/plugins/approval-ask-store-file.d.ts +16 -1
- package/dist/plugins/approval-ask-store-file.js +21 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
- package/dist/plugins/approval-ask-store-memory.js +34 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
- package/dist/plugins/approval-ask-store-sql.js +37 -1
- package/dist/plugins/blob-backend.d.ts +83 -15
- package/dist/plugins/blob-backend.js +68 -15
- package/dist/plugins/breaker-state-sql.d.ts +2 -2
- package/dist/plugins/breaker-state-sql.js +4 -4
- package/dist/plugins/caching-session-store.d.ts +3 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +28 -4
- package/dist/plugins/checkpoint-store-sql.js +59 -28
- package/dist/plugins/file-history-store-sql.d.ts +5 -2
- package/dist/plugins/file-history-store-sql.js +3 -1
- package/dist/plugins/file-run-store.d.ts +5 -13
- package/dist/plugins/file-run-store.js +9 -0
- package/dist/plugins/fork-routing-session-store.d.ts +9 -1
- package/dist/plugins/fork-routing-session-store.js +12 -1
- package/dist/plugins/host-platform.d.ts +2 -0
- package/dist/plugins/host-platform.js +2 -1
- package/dist/plugins/k8s-bg-scripts.d.ts +11 -0
- package/dist/plugins/k8s-bg-scripts.js +22 -0
- package/dist/plugins/local-checkpoint-store.d.ts +2 -0
- package/dist/plugins/local-checkpoint-store.js +11 -3
- package/dist/plugins/local-session-store.d.ts +1 -1
- package/dist/plugins/local-session-store.js +1 -1
- package/dist/plugins/local-session-window.d.ts +39 -0
- package/dist/plugins/local-session-window.js +54 -0
- package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
- package/dist/plugins/mailbox-store-sql.d.ts +30 -48
- package/dist/plugins/mailbox-store-sql.js +77 -52
- package/dist/plugins/memory-embedder-fingerprint.js +2 -1
- package/dist/plugins/memory-run-store.d.ts +5 -13
- package/dist/plugins/memory-run-store.js +8 -0
- package/dist/plugins/one-time-migrations.d.ts +245 -93
- package/dist/plugins/one-time-migrations.js +668 -207
- package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
- package/dist/plugins/org-delivery-quota-store.js +228 -0
- package/dist/plugins/permission-rule-store-sql.d.ts +13 -7
- package/dist/plugins/permission-rule-store-sql.js +4 -18
- package/dist/plugins/pg-pool.js +39 -7
- package/dist/plugins/pg-session-storage.d.ts +20 -8
- package/dist/plugins/pg-session-storage.js +34 -21
- package/dist/plugins/remote-env-adb.d.ts +12 -12
- package/dist/plugins/remote-env-adb.js +21 -6
- package/dist/plugins/remote-env-device.js +3 -0
- package/dist/plugins/remote-env-e2b.d.ts +1 -1
- package/dist/plugins/remote-env-e2b.js +21 -9
- package/dist/plugins/remote-env-host.d.ts +9 -9
- package/dist/plugins/remote-env-host.js +10 -32
- package/dist/plugins/remote-env-k8s.d.ts +103 -38
- package/dist/plugins/remote-env-k8s.js +288 -95
- package/dist/plugins/remote-env-local-docker.d.ts +27 -13
- package/dist/plugins/remote-env-local-docker.js +82 -11
- package/dist/plugins/remote-env-ssh.d.ts +21 -12
- package/dist/plugins/remote-env-ssh.js +117 -5
- package/dist/plugins/remote-shell.d.ts +0 -1
- package/dist/plugins/remote-shell.js +1 -2
- package/dist/plugins/retention-store-sql.js +6 -2
- package/dist/plugins/run-store-sql.d.ts +16 -14
- package/dist/plugins/run-store-sql.js +22 -2
- package/dist/plugins/schema-consistency.d.ts +54 -0
- package/dist/plugins/schema-consistency.js +52 -0
- package/dist/plugins/schema-indexes.js +2 -0
- package/dist/plugins/send-user-file.js +2 -2
- package/dist/plugins/session-epoch-anchor.d.ts +39 -0
- package/dist/plugins/session-epoch-anchor.js +22 -0
- package/dist/plugins/session-store.d.ts +18 -8
- package/dist/plugins/session-store.js +15 -4
- package/dist/plugins/shared-memory-store-sql.d.ts +9 -3
- package/dist/plugins/shared-memory-store-sql.js +5 -16
- package/dist/plugins/sql-driver.d.ts +205 -1
- package/dist/plugins/sql-driver.js +325 -13
- package/dist/plugins/sql-errors.d.ts +64 -0
- package/dist/plugins/sql-errors.js +57 -0
- package/dist/plugins/store-backend.d.ts +36 -1
- package/dist/plugins/store-backend.js +42 -15
- package/dist/plugins/store-contracts.d.ts +42 -0
- package/dist/plugins/store-contracts.js +1 -0
- package/dist/plugins/tidb-pool.d.ts +6 -1
- package/dist/plugins/tidb-pool.js +44 -10
- package/dist/plugins/tidb-session-storage.d.ts +8 -11
- package/dist/plugins/tidb-session-storage.js +6 -16
- package/dist/plugins/tidb-session-store.d.ts +24 -4
- package/dist/plugins/tidb-session-store.js +29 -5
- package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
- package/dist/plugins/workflow-journal-store-sql.js +19 -6
- package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
- package/dist/plugins/workflow-run-store-sql.js +50 -9
- package/dist/posture-source.d.ts +18 -10
- package/dist/posture-source.js +4 -1
- package/dist/project-identity.d.ts +45 -6
- package/dist/project-identity.js +162 -8
- package/dist/project-layer-key.d.ts +28 -0
- package/dist/project-layer-key.js +29 -0
- package/dist/prompts-domain-validate.d.ts +17 -61
- package/dist/prompts-domain-validate.js +9 -119
- package/dist/question.js +3 -2
- package/dist/read-deny-entry.d.ts +25 -0
- package/dist/read-deny-entry.js +12 -0
- package/dist/read-face-posture.d.ts +37 -11
- package/dist/read-face-posture.js +32 -3
- package/dist/request-key-closure.d.ts +9 -2
- package/dist/request-key-closure.js +11 -5
- package/dist/request-value-closure.d.ts +5 -0
- package/dist/request-value-closure.js +11 -3
- package/dist/rule-entry-list.d.ts +38 -11
- package/dist/rule-entry-list.js +106 -30
- package/dist/rules-consent.js +3 -4
- package/dist/run-acceptance.d.ts +19 -3
- package/dist/run-acceptance.js +13 -1
- package/dist/run-local.js +54 -24
- package/dist/runs.d.ts +15 -8
- package/dist/runs.js +35 -1
- package/dist/runtime-caps-resolver.d.ts +16 -6
- package/dist/runtime-caps-resolver.js +18 -5
- package/dist/sandbox-pkg-source.d.ts +19 -1
- package/dist/sandbox-pkg-source.js +29 -7
- package/dist/security.d.ts +87 -9
- package/dist/security.js +52 -9
- package/dist/server-secret-env.d.ts +44 -18
- package/dist/server-secret-env.js +49 -8
- package/dist/session-error-wire.d.ts +19 -2
- package/dist/session-error-wire.js +5 -1
- package/dist/session-incarnation.d.ts +15 -5
- package/dist/session-incarnation.js +16 -9
- package/dist/session-titled-frame.d.ts +33 -0
- package/dist/session-titled-frame.js +4 -0
- package/dist/session-titler.d.ts +9 -1
- package/dist/session-titler.js +27 -6
- package/dist/spec-fields.d.ts +28 -16
- package/dist/spec-fields.js +66 -54
- package/dist/sql-engine-posture.d.ts +31 -4
- package/dist/sql-engine-posture.js +36 -1
- package/dist/stored-request-tool-axes-m19.d.ts +19 -4
- package/dist/stored-request-tool-axes-m19.js +30 -2
- package/dist/task-a2a.d.ts +9 -1
- package/dist/task-a2a.js +73 -47
- package/dist/task-cwd.d.ts +1 -1
- package/dist/task-mcp.d.ts +46 -58
- package/dist/task-mcp.js +82 -107
- package/dist/task-settings.d.ts +95 -108
- package/dist/task-settings.js +77 -98
- package/dist/text-bidi.d.ts +1 -48
- package/dist/text-bidi.js +3 -5
- package/dist/tighten-only-seats.d.ts +150 -0
- package/dist/tighten-only-seats.js +196 -0
- package/dist/tool-approval.d.ts +304 -88
- package/dist/tool-approval.js +623 -239
- package/dist/trace/core-keyset-guard.d.ts +122 -20
- package/dist/trace/engine-notice-wire.d.ts +11 -3
- package/dist/trace/engine-notice-wire.js +8 -1
- package/dist/trace/exit-seat.d.ts +28 -0
- package/dist/trace/exit-seat.js +76 -0
- package/dist/trace/ledger-events.d.ts +6 -3
- package/dist/trace/ledger-sink.js +4 -1
- package/dist/trace/model-segment.js +1 -1
- package/dist/trace/project.d.ts +98 -17
- package/dist/trace/project.js +98 -50
- package/dist/trace/projection-table.d.ts +100 -0
- package/dist/trace/projection-table.js +130 -0
- package/dist/trace/redact.d.ts +54 -0
- package/dist/trace/redact.js +778 -152
- package/dist/trace/self-minted-wire.d.ts +345 -1
- package/dist/trace/self-minted-wire.js +117 -1
- package/dist/trace/wire-projection-faces.d.ts +377 -3
- package/dist/trace/wire-projection-faces.js +164 -1
- package/dist/url-refusal.js +2 -0
- package/dist/web-admin-client/apply-effective.d.ts +12 -0
- package/dist/web-admin-client/apply-effective.js +56 -5
- package/dist/web-admin-client/candidate-gate.d.ts +6 -6
- package/dist/web-admin-client/candidate-gate.js +3 -3
- package/dist/web-admin-client/facade.d.ts +1 -1
- package/dist/web-admin-client/facade.js +1 -1
- package/dist/web-admin-client/http-client.js +0 -6
- package/dist/web-admin-client/read-face.js +5 -9
- package/dist/web-admin-client/read-warnings.d.ts +13 -0
- package/dist/web-admin-client/read-warnings.js +10 -0
- package/dist/web-admin-client/skills-mcp.d.ts +3 -0
- package/dist/web-admin-client/skills-mcp.js +11 -9
- package/dist/web-admin-client/types.d.ts +2 -3
- package/dist/workspace-cache.d.ts +35 -0
- package/dist/workspace-cache.js +36 -0
- package/dist/workspace-space.d.ts +3 -2
- package/dist/workspace-space.js +2 -0
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +65 -10
- package/package.json +8 -4
- package/scripts/drain-check-local.mjs +34 -1
- package/scripts/drain-check.mysql.sql +30 -2
- package/scripts/drain-check.pg.sql +29 -2
- package/dist/capabilities/memory-notice.d.ts +0 -138
- package/dist/capabilities/memory-notice.js +0 -64
- package/dist/capabilities/prompt.d.ts +0 -17
- package/dist/capabilities/prompt.js +0 -6
- package/dist/mcp-content-origin.d.ts +0 -34
- package/dist/mcp-content-origin.js +0 -10
- package/dist/tool-axis-words.d.ts +0 -27
- package/dist/tool-axis-words.js +0 -9
- package/dist/wire-name-bound.d.ts +0 -14
- package/dist/wire-name-bound.js +0 -13
|
@@ -1,24 +1,16 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { type LaneHomeConfig } from "../lane-home-probe.js";
|
|
2
3
|
import { FileError, ExecutionError, RemoteExecutionError, type ExecutionEnv, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type SymlinkChain, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type VmLifecycleOptions, type ExecutionEnvFactory } from "@sema-agent/core";
|
|
3
4
|
/** Options accepted by `ExecutionEnv.exec` (core does not re-export the type; derive it from the seam). */
|
|
4
5
|
type ExecOpts = Parameters<ExecutionEnv["exec"]>[1];
|
|
5
6
|
/** Construction config for {@link RemoteLocalDockerExecutionEnv}. */
|
|
6
|
-
export interface LocalDockerEnvConfig {
|
|
7
|
+
export interface LocalDockerEnvConfig extends LaneHomeConfig {
|
|
7
8
|
/**
|
|
8
9
|
* Base container image to run the task in. **REQUIRED — no default** (domestic-images iron rule: the registry
|
|
9
10
|
* is the operator's choice, never a hardcoded `docker.io` origin). e.g. the docker.io/claybobby pool or an
|
|
10
11
|
* in-network `node:20` mirror (SWR deprecated).
|
|
11
12
|
*/
|
|
12
13
|
image: string;
|
|
13
|
-
/**
|
|
14
|
-
* S-213④ / core [ref] —— 本执行环境的 **home 目录**(`ExecutionEnv.homeDir` 座,绝对路径,本环境自己的
|
|
15
|
-
* 命名空间里)。`~/…` 形权限规则(`Edit(~/.ssh/**)`)对**跑在本 env 里的调用**就以它为基。
|
|
16
|
-
* 缺席 ⇒ 本 env 声明「我没有 home」,core 对 `~/` 规则判 `unreadable`(fail-closed 的 ask),
|
|
17
|
-
* 绝不回落引擎进程自己的 home(那在远端腿上是另一个用户的另一个目录 —— 静默守错目录正是 [ref] 的病)。
|
|
18
|
-
* 值由 `boot/execution-env.ts` 从**唯一属主** `execution-lane-caps.ts` 的 `executionLaneHomeDir` 递进来;
|
|
19
|
-
* adapter 不自算(两处各算一份 = 422 门与引擎对同一条规则给相反答案)。
|
|
20
|
-
*/
|
|
21
|
-
homeDir?: string;
|
|
22
14
|
/** Workspace root INSIDE the container; relative paths resolve against it. Default {@link DEFAULT_MOUNT_PATH}. */
|
|
23
15
|
mountPath?: string;
|
|
24
16
|
/** Path to the docker binary (or a docker-compatible CLI). Default "docker" (must be on PATH in the worker). */
|
|
@@ -77,8 +69,8 @@ export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv
|
|
|
77
69
|
};
|
|
78
70
|
/** Working directory inside the container; relative paths resolve against it (ExecutionEnv contract). */
|
|
79
71
|
cwd: string;
|
|
80
|
-
/** core `ExecutionEnv.homeDir`([ref])
|
|
81
|
-
|
|
72
|
+
/** core `ExecutionEnv.homeDir`([ref]):本容器里执行用户的 home —— 声明胜,否则开容器那一拍实测的 `$HOME`,见 {@link LaneHomeSeat}。读时才取(没声明时连上之前缺席)。 */
|
|
73
|
+
get homeDir(): string | undefined;
|
|
82
74
|
/** core 7.49.0 #1554:shell 子进程真拿到的 `CDPATH` 条目 —— 本车道的命令跑在容器里(镜像的 env),本类不读那份 env ⇒ `"unknown"`(core 契约:说不出就说 unknown,
|
|
83
75
|
* 不许报一张没读过的空表;删除守卫因此对裸 `cd <相对名>` 之后的删除问人,而不是按「没有 CDPATH」放行)。 */
|
|
84
76
|
readonly cdPath: "unknown";
|
|
@@ -93,6 +85,10 @@ export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv
|
|
|
93
85
|
private destroyed;
|
|
94
86
|
/** In-flight connect, memoized so concurrent lazy first-use starts exactly one container (no double-run). */
|
|
95
87
|
private connecting?;
|
|
88
|
+
/** 家目录:环境答了而与声明不一致 ⇒ 这只环境的拒,记一次、此后每次连接原样回它(同一镜像同一答案:不再起容器、不再问)。 */
|
|
89
|
+
private homeRefusal?;
|
|
90
|
+
/** 家目录的座(声明胜 · 否则开容器那一拍实测 · 实测缺席 ⇒ 缺席 + 一行 warn)。本车道对声明对证。 */
|
|
91
|
+
private readonly homeSeat;
|
|
96
92
|
constructor(config: LocalDockerEnvConfig, deps?: LocalDockerEnvDeps);
|
|
97
93
|
private resolve;
|
|
98
94
|
workspaceHandle(): WorkspaceHandle;
|
|
@@ -104,6 +100,13 @@ export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv
|
|
|
104
100
|
error: RemoteExecutionError;
|
|
105
101
|
}>;
|
|
106
102
|
private doConnect;
|
|
103
|
+
/**
|
|
104
|
+
* 家目录:座要问({@link LaneHomeSeat.asks}:声明在场 ⇒ 对证;没声明 ⇒ 实测)⇒ 在本容器里问一次 `$HOME`(与命令同一条 `docker exec` 通道、同一份 `-e` env),读数交座。
|
|
105
|
+
* 声明在场:环境答了而不一致 / 不是绝对路径 ⇒ 回拒并记在环境上(同一镜像同一答案:此后每次连接原样回它,不再起容器、不再问);没答上(exec 失败 / 超时 / 非零退出)⇒ 这一次同样不开,
|
|
106
|
+
* 但不记(与任何一次起容器失败同:下一次连接重问)。没声明:座收下绝对路径;答不上 / 不是绝对路径 ⇒ 座缺席 + 一行 warn,环境照开(没声明就没有声明可拒)。
|
|
107
|
+
* 调用方中止 ⇒ `aborted`、不记、不交座。容器由调用方收。
|
|
108
|
+
*/
|
|
109
|
+
private homeVerdict;
|
|
107
110
|
suspendVM(_options?: VmLifecycleOptions): Promise<{
|
|
108
111
|
ok: true;
|
|
109
112
|
value: SnapshotId;
|
|
@@ -183,6 +186,12 @@ export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv
|
|
|
183
186
|
suffix?: string;
|
|
184
187
|
abortSignal?: AbortSignal;
|
|
185
188
|
}): Promise<Result<string, FileError>>;
|
|
189
|
+
/**
|
|
190
|
+
* 交给宿主 `docker` CLI 的 env —— 宿主子进程 env 的唯一组合(`server-secret-env.ts` `hostSubprocessEnv`),继承词 `"all"`:本服务自有凭据(起服声明的名与值)
|
|
191
|
+
* 任何词都不交,CLI 与它拉起的凭据助手 / CLI 插件要读的变量(`DOCKER_*` / `AWS_*` …)照交 —— 形状剥会剥 `AWS_SECRET_ACCESS_KEY` 一类,ECR / GCR 凭据助手因此断。
|
|
192
|
+
* 命令本身跑在容器里,容器的 env 只由 `execArgv` 的 `-e K=V` 显式给,本 env 到不了容器。每次起进程现算一次(与 host shell 同)。
|
|
193
|
+
*/
|
|
194
|
+
private cliEnv;
|
|
186
195
|
/** Prepend `-H <dockerHost>` to a docker argv when configured (per-invocation, not the process env). */
|
|
187
196
|
private withHostFlag;
|
|
188
197
|
/** Build the `docker exec` argv for a command, applying cwd (`-w`) and per-command env (`-e K=V`).
|
|
@@ -198,8 +207,13 @@ export declare class RemoteLocalDockerExecutionEnv implements RemoteExecutionEnv
|
|
|
198
207
|
* ⇒ 保 sh(修前字节形,诚实降级);探测自身失败同。容器**创建**引导命令(mkdir && tail)不走
|
|
199
208
|
* 本 shell——无 bash 语法且探测尚不可能。 */
|
|
200
209
|
private containerShell;
|
|
201
|
-
|
|
210
|
+
/** shell 探测的**一只在飞承诺**:并发的调用方(首用 exec / fs、connect、reconnect)都 join 它 —— 修前是先置真的布尔,第二个调用方在探测落定之前就拿 /bin/sh 往下走,
|
|
211
|
+
* 探测随后才把命令切到 bash(家目录对证因此可能问的是另一只 shell)。 */
|
|
212
|
+
private containerShellReady?;
|
|
213
|
+
/** 等一只共享的承诺,调用方的取消只退**它自己的**等待(承诺照常落定、照常服务其余等待者)。`false` = 取消了。 */
|
|
214
|
+
private untilOrAborted;
|
|
202
215
|
private probeContainerShell;
|
|
216
|
+
private detectContainerShell;
|
|
203
217
|
private ensureConnectedExec;
|
|
204
218
|
/** Lazy connect for a FileSystem path → FileError on failure (fail closed, never throws). */
|
|
205
219
|
private fsReady;
|
|
@@ -2,10 +2,12 @@ import path from "node:path";
|
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
|
+
import { hostSubprocessEnv } from "../server-secret-env.js";
|
|
6
|
+
import { LANE_HOME_PROBE_COMMAND, LaneHomeSeat } from "../lane-home-probe.js";
|
|
5
7
|
import { randomBytes } from "node:crypto";
|
|
6
8
|
import { shellQuote, armPipeDestroyGrace } from "./remote-shell.js";
|
|
7
9
|
import { signalNumber } from "./host-platform.js";
|
|
8
|
-
import {
|
|
10
|
+
import { buildLivenessCut, commandBoundsOf } from "../exec-bounds.js";
|
|
9
11
|
import { FileError, ExecutionError, RemoteExecutionError, RollingTailBuffer, markTruncated, } from "@sema-agent/core";
|
|
10
12
|
import { fileErrorFromExec, classifyFsStderr } from "./remote-env-file-error.js";
|
|
11
13
|
import { createPosixShellFs } from "./posix-shell-fs.js";
|
|
@@ -21,7 +23,9 @@ const unsupported = (op) => ({
|
|
|
21
23
|
export class RemoteLocalDockerExecutionEnv {
|
|
22
24
|
capabilities = { isolation: true, suspendable: false, canonicalPathAuthoritative: true };
|
|
23
25
|
cwd;
|
|
24
|
-
homeDir
|
|
26
|
+
get homeDir() {
|
|
27
|
+
return this.homeSeat.home;
|
|
28
|
+
}
|
|
25
29
|
cdPath = "unknown";
|
|
26
30
|
cfg;
|
|
27
31
|
spawnFn;
|
|
@@ -30,6 +34,8 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
30
34
|
handle;
|
|
31
35
|
destroyed = false;
|
|
32
36
|
connecting;
|
|
37
|
+
homeRefusal;
|
|
38
|
+
homeSeat;
|
|
33
39
|
constructor(config, deps = {}) {
|
|
34
40
|
if (!config.image || !config.image.trim()) {
|
|
35
41
|
config = { ...config, image: config.image ?? "" };
|
|
@@ -43,7 +49,7 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
43
49
|
controlTimeoutMs: config.controlTimeoutMs ?? DEFAULT_CONTROL_TIMEOUT_MS,
|
|
44
50
|
};
|
|
45
51
|
this.cwd = this.cfg.mountPath;
|
|
46
|
-
this.
|
|
52
|
+
this.homeSeat = new LaneHomeSeat({ lane: PROVIDER, declared: config.homeDir, verifiesDeclared: true, onAbsent: config.onHomeAbsent });
|
|
47
53
|
this.spawnFn = deps.spawn ?? spawn;
|
|
48
54
|
const id = config.id ?? randomBytes(6).toString("hex");
|
|
49
55
|
const suffix = randomBytes(4).toString("hex");
|
|
@@ -62,6 +68,8 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
62
68
|
return unsupported("connect(snapshotId)");
|
|
63
69
|
if (this.destroyed)
|
|
64
70
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env already destroyed") };
|
|
71
|
+
if (this.homeRefusal)
|
|
72
|
+
return { ok: false, error: this.homeRefusal };
|
|
65
73
|
if (config?.abortSignal?.aborted)
|
|
66
74
|
return { ok: false, error: new RemoteExecutionError("aborted", "connect aborted") };
|
|
67
75
|
if (this.containerId)
|
|
@@ -112,12 +120,39 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
112
120
|
await this.forceRemove().catch(() => { });
|
|
113
121
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during connect") };
|
|
114
122
|
}
|
|
123
|
+
if (this.homeSeat.asks && !(await this.untilOrAborted(this.probeContainerShell(), config?.abortSignal))) {
|
|
124
|
+
await this.forceRemove().catch(() => { });
|
|
125
|
+
return { ok: false, error: new RemoteExecutionError("aborted", "connect aborted while detecting the container's shell") };
|
|
126
|
+
}
|
|
127
|
+
const home = await this.homeVerdict(config?.abortSignal);
|
|
128
|
+
if (home !== undefined) {
|
|
129
|
+
await this.forceRemove().catch(() => { });
|
|
130
|
+
return { ok: false, error: home };
|
|
131
|
+
}
|
|
132
|
+
if (this.destroyed) {
|
|
133
|
+
await this.forceRemove().catch(() => { });
|
|
134
|
+
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during connect") };
|
|
135
|
+
}
|
|
115
136
|
this.containerId = run.value.stdout.trim() || this.containerName;
|
|
116
137
|
this.handle = { sandboxId: this.containerName, provider: PROVIDER, mountPath: this.cfg.mountPath, sessionToken: this.containerName };
|
|
117
138
|
if (config?.secrets?.length) {
|
|
118
139
|
}
|
|
119
140
|
return ok(this.handle);
|
|
120
141
|
}
|
|
142
|
+
async homeVerdict(signal) {
|
|
143
|
+
if (!this.homeSeat.asks)
|
|
144
|
+
return undefined;
|
|
145
|
+
const probe = await this.docker(this.execRaw(LANE_HOME_PROBE_COMMAND), { signal, timeoutMs: this.cfg.controlTimeoutMs });
|
|
146
|
+
if (!probe.ok && probe.error.code === "aborted")
|
|
147
|
+
return new RemoteExecutionError("aborted", "connect aborted while reading the environment's home");
|
|
148
|
+
const verdict = this.homeSeat.settle(probe.ok && probe.value.exitCode === 0 ? { ok: true, stdout: probe.value.stdout } : { ok: false, reason: probe.ok ? `exit ${probe.value.exitCode}` : probe.error.message });
|
|
149
|
+
if (verdict === undefined)
|
|
150
|
+
return undefined;
|
|
151
|
+
const error = new RemoteExecutionError("connect_failed", verdict.refusal);
|
|
152
|
+
if (verdict.answered)
|
|
153
|
+
this.homeRefusal = error;
|
|
154
|
+
return error;
|
|
155
|
+
}
|
|
121
156
|
async suspendVM(_options) {
|
|
122
157
|
return unsupported("suspendVM");
|
|
123
158
|
}
|
|
@@ -130,11 +165,25 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
130
165
|
async reconnect(sessionToken) {
|
|
131
166
|
if (this.destroyed)
|
|
132
167
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env already destroyed") };
|
|
168
|
+
if (this.homeRefusal)
|
|
169
|
+
return { ok: false, error: this.homeRefusal };
|
|
133
170
|
if (sessionToken && sessionToken !== this.containerName) {
|
|
134
171
|
return { ok: false, error: new RemoteExecutionError("connect_failed", `reconnect token '${String(sessionToken)}' does not match this env's container '${this.containerName}'`) };
|
|
135
172
|
}
|
|
173
|
+
if (this.connecting !== undefined && this.containerId === undefined) {
|
|
174
|
+
const joined = await this.connecting;
|
|
175
|
+
if (!joined.ok || this.containerId !== undefined)
|
|
176
|
+
return joined;
|
|
177
|
+
}
|
|
136
178
|
const insp = await this.docker(["inspect", "-f", "{{.State.Running}}", this.containerName], { timeoutMs: this.cfg.controlTimeoutMs });
|
|
137
179
|
if (insp.ok && insp.value.exitCode === 0 && insp.value.stdout.trim() === "true") {
|
|
180
|
+
if (this.containerId === undefined && this.homeSeat.asks)
|
|
181
|
+
await this.probeContainerShell();
|
|
182
|
+
const home = this.containerId === undefined ? await this.homeVerdict() : undefined;
|
|
183
|
+
if (home !== undefined)
|
|
184
|
+
return { ok: false, error: home };
|
|
185
|
+
if (this.destroyed || this.homeRefusal)
|
|
186
|
+
return { ok: false, error: this.homeRefusal ?? new RemoteExecutionError("connect_failed", "execution env destroyed during reconnect") };
|
|
138
187
|
this.containerId = this.containerName;
|
|
139
188
|
this.handle ??= { sandboxId: this.containerName, provider: PROVIDER, mountPath: this.cfg.mountPath, sessionToken: this.containerName };
|
|
140
189
|
return ok(this.handle);
|
|
@@ -179,7 +228,7 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
179
228
|
if (!ready.ok)
|
|
180
229
|
throw new RemoteExecutionError("connect_failed", ready.error.message, ready.error);
|
|
181
230
|
const execArgs = this.execArgv(command, options?.cwd, options?.env);
|
|
182
|
-
const child = this.spawnFn(this.cfg.dockerPath, this.withHostFlag(execArgs), { stdio: ["ignore", "pipe", "pipe"] });
|
|
231
|
+
const child = this.spawnFn(this.cfg.dockerPath, this.withHostFlag(execArgs), { stdio: ["ignore", "pipe", "pipe"], env: this.cliEnv() });
|
|
183
232
|
const queue = [];
|
|
184
233
|
let finished = false;
|
|
185
234
|
let failure;
|
|
@@ -286,7 +335,8 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
286
335
|
child.kill("SIGKILL");
|
|
287
336
|
}
|
|
288
337
|
catch { }
|
|
289
|
-
|
|
338
|
+
const cut = buildLivenessCut(liveness);
|
|
339
|
+
throw new RemoteExecutionError(cut.code, cut.message);
|
|
290
340
|
}
|
|
291
341
|
}
|
|
292
342
|
while (queue.length)
|
|
@@ -427,6 +477,9 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
427
477
|
async createTempFile(options) {
|
|
428
478
|
return this.posixFs.createTempFile(options);
|
|
429
479
|
}
|
|
480
|
+
cliEnv() {
|
|
481
|
+
return hostSubprocessEnv({ site: "server.remote-env-local-docker.spawn-env", policy: "all", allow: [] });
|
|
482
|
+
}
|
|
430
483
|
withHostFlag(args) {
|
|
431
484
|
return this.cfg.dockerHost ? ["-H", this.cfg.dockerHost, ...args] : args;
|
|
432
485
|
}
|
|
@@ -447,7 +500,7 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
447
500
|
return new Promise((resolve) => {
|
|
448
501
|
let settled = false;
|
|
449
502
|
let forceSettleTimer;
|
|
450
|
-
const child = this.spawnFn(this.cfg.dockerPath, this.withHostFlag(args), { stdio: ["ignore", "pipe", "pipe"] });
|
|
503
|
+
const child = this.spawnFn(this.cfg.dockerPath, this.withHostFlag(args), { stdio: ["ignore", "pipe", "pipe"], env: this.cliEnv() });
|
|
451
504
|
const killGrace = () => {
|
|
452
505
|
try {
|
|
453
506
|
child.kill("SIGKILL");
|
|
@@ -505,11 +558,29 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
505
558
|
});
|
|
506
559
|
}
|
|
507
560
|
containerShell = "/bin/sh";
|
|
508
|
-
|
|
509
|
-
async
|
|
510
|
-
if (
|
|
511
|
-
|
|
512
|
-
|
|
561
|
+
containerShellReady;
|
|
562
|
+
async untilOrAborted(shared, signal) {
|
|
563
|
+
if (!signal) {
|
|
564
|
+
await shared;
|
|
565
|
+
return true;
|
|
566
|
+
}
|
|
567
|
+
if (signal.aborted)
|
|
568
|
+
return false;
|
|
569
|
+
let onAbort;
|
|
570
|
+
const aborted = new Promise((res) => {
|
|
571
|
+
onAbort = () => res(false);
|
|
572
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
573
|
+
});
|
|
574
|
+
const won = await Promise.race([shared.then(() => true), aborted]);
|
|
575
|
+
if (onAbort)
|
|
576
|
+
signal.removeEventListener("abort", onAbort);
|
|
577
|
+
return won;
|
|
578
|
+
}
|
|
579
|
+
probeContainerShell() {
|
|
580
|
+
this.containerShellReady ??= this.detectContainerShell();
|
|
581
|
+
return this.containerShellReady;
|
|
582
|
+
}
|
|
583
|
+
async detectContainerShell() {
|
|
513
584
|
try {
|
|
514
585
|
const r = await this.docker(["exec", this.containerName, "/bin/sh", "-c", "command -v bash"], { timeoutMs: this.cfg.controlTimeoutMs });
|
|
515
586
|
if (r.ok && r.value.exitCode === 0 && r.value.stdout.trim().length > 0)
|
|
@@ -1,22 +1,14 @@
|
|
|
1
1
|
import { type SshHostKeyPolicy } from "../ssh-host-key.js";
|
|
2
2
|
import { FileError, ExecutionError, RemoteExecutionError, type ExecutionEnv, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type SymlinkChain, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type VmLifecycleOptions, type ExecutionEnvFactory } from "@sema-agent/core";
|
|
3
|
+
import { type LaneHomeConfig } from "../lane-home-probe.js";
|
|
3
4
|
type ExecOpts = Parameters<ExecutionEnv["exec"]>[1];
|
|
4
|
-
export interface SshEnvConfig {
|
|
5
|
+
export interface SshEnvConfig extends LaneHomeConfig {
|
|
5
6
|
host: string;
|
|
6
7
|
port?: number;
|
|
7
8
|
username: string;
|
|
8
9
|
/** PEM private key — from the adapter-held secret env (NEVER the workspace). [ref] §5 #2. */
|
|
9
10
|
privateKey: string;
|
|
10
11
|
passphrase?: string;
|
|
11
|
-
/**
|
|
12
|
-
* S-213④ / core [ref] —— 本执行环境的 **home 目录**(`ExecutionEnv.homeDir` 座,绝对路径,本环境自己的
|
|
13
|
-
* 命名空间里)。`~/…` 形权限规则(`Edit(~/.ssh/**)`)对**跑在本 env 里的调用**就以它为基。
|
|
14
|
-
* 缺席 ⇒ 本 env 声明「我没有 home」,core 对 `~/` 规则判 `unreadable`(fail-closed 的 ask),
|
|
15
|
-
* 绝不回落引擎进程自己的 home(那在远端腿上是另一个用户的另一个目录 —— 静默守错目录正是 [ref] 的病)。
|
|
16
|
-
* 值由 `boot/execution-env.ts` 从**唯一属主** `execution-lane-caps.ts` 的 `executionLaneHomeDir` 递进来;
|
|
17
|
-
* adapter 不自算(两处各算一份 = 422 门与引擎对同一条规则给相反答案)。
|
|
18
|
-
*/
|
|
19
|
-
homeDir?: string;
|
|
20
12
|
/** Workspace root; relative paths resolve against it. Default "." (the login dir). */
|
|
21
13
|
mountPath?: string;
|
|
22
14
|
/** Connect handshake bound (ms). */
|
|
@@ -92,8 +84,14 @@ export declare class RemoteSshExecutionEnv implements RemoteExecutionEnv {
|
|
|
92
84
|
* =重连风暴);②共享尝试**不携带任何 caller 信号**(首创者的 pre-abort 不得毒化 joiner;单 caller
|
|
93
85
|
* 取消只退它自己的等待,底层握手余命 ≤ readyTimeout 有界,彻底取消归 destroy 代际闸)。 */
|
|
94
86
|
private inFlight?;
|
|
95
|
-
/** core `ExecutionEnv.homeDir`([ref])
|
|
96
|
-
|
|
87
|
+
/** core `ExecutionEnv.homeDir`([ref]):目标机上登录用户的 home —— 声明胜,否则连上之后实测的 `$HOME`,见 {@link LaneHomeSeat}。读时才取(没声明时连上之前缺席)。 */
|
|
88
|
+
get homeDir(): string | undefined;
|
|
89
|
+
/** 家目录的座(声明胜 · 否则连上之后实测 · 实测缺席 ⇒ 缺席 + 一行 warn)。本车道对声明对证。 */
|
|
90
|
+
private readonly homeSeat;
|
|
91
|
+
/** 家目录声明 × 实测的判定,按连接记(同一条连接只问一次;重连换了连接再问 —— 登录用户不变时答案相同,代价一次往返;没声明且已量到绝对路径之后不再问)。 */
|
|
92
|
+
private homeChecked?;
|
|
93
|
+
/** 目标机答了而与声明不一致 ⇒ 这只环境的拒,记一次、此后每个面原样回它(同一目标机同一登录用户同一答案:不再问、不再发命令)。 */
|
|
94
|
+
private homeRefusal?;
|
|
97
95
|
/** core 7.49.0 #1554:shell 子进程真拿到的 `CDPATH` 条目 —— 本车道的命令跑在远端登录 shell 里(目标机的 profile / env),本类不读那份 env ⇒ `"unknown"`(core 契约:说不出就说 unknown,
|
|
98
96
|
* 不许报一张没读过的空表;删除守卫因此对裸 `cd <相对名>` 之后的删除问人,而不是按「没有 CDPATH」放行)。 */
|
|
99
97
|
readonly cdPath: "unknown";
|
|
@@ -119,6 +117,17 @@ export declare class RemoteSshExecutionEnv implements RemoteExecutionEnv {
|
|
|
119
117
|
* caller 的 signal 只中止**它自己的等待**(共享在飞尝试继续伺服其他等待者;彻底取消归 destroy 的代际
|
|
120
118
|
* 闸管,handshake 余命 ≤ readyTimeout 有界)。 */
|
|
121
119
|
private ensureConnected;
|
|
120
|
+
/** 家目录判定的 per-caller 可中止等待(共享的判定承诺不动,只退本 caller)。 */
|
|
121
|
+
private raceVerdictAbort;
|
|
122
|
+
/**
|
|
123
|
+
* 家目录:座要问({@link LaneHomeSeat.asks}:声明在场 ⇒ 对证;没声明 ⇒ 量到绝对路径为止)⇒ 在这条连接上问一次 `$HOME`(登录用户的 shell 答的,与命令同一个用户、同一份登录 env),读数交座。
|
|
124
|
+
* 声明在场:答了而不一致 / 不是绝对路径 ⇒ 拒记在环境上(每个面原样回它),命令一条都不发;没答上(通道开不出 / 非零退出 / 超时)⇒ 这一次同样不开、不记,下一次调用重问。
|
|
125
|
+
* 没声明:座收下绝对路径;答不上 / 不是绝对路径 ⇒ 座缺席 + 一行 warn,命令照跑(没声明就没有声明可拒)—— 判定对这条连接记下,换了连接再问。
|
|
126
|
+
* 问的是裸命令(不经工作目录守卫:工作目录进不去不影响家目录的答案)。上界 = 握手的 `readyTimeoutMs`(问一个环境变量,不是跑用户命令)。
|
|
127
|
+
*/
|
|
128
|
+
private homeVerdict;
|
|
129
|
+
/** 连接本身(不含家目录判定):{@link ensureConnected} 的第一半。 */
|
|
130
|
+
private ensureTransport;
|
|
122
131
|
private connectOnce;
|
|
123
132
|
suspendVM(_options?: VmLifecycleOptions): Promise<{
|
|
124
133
|
ok: true;
|
|
@@ -3,10 +3,11 @@ import { Client } from "ssh2";
|
|
|
3
3
|
import { createSshHostKeyVerifier } from "../ssh-host-key.js";
|
|
4
4
|
import { buildCwdEnvCommand, createCwdGuardedCall, shellQuote, kindFromMode } from "./remote-shell.js";
|
|
5
5
|
import { signalNumber } from "./host-platform.js";
|
|
6
|
-
import {
|
|
6
|
+
import { buildLivenessCut, commandBoundsOf } from "../exec-bounds.js";
|
|
7
7
|
import { createPosixShellFs } from "./posix-shell-fs.js";
|
|
8
8
|
import { FileError, ExecutionError, RemoteExecutionError, withRetry, RollingTailBuffer, markTruncated, } from "@sema-agent/core";
|
|
9
9
|
import { fileErrorFromExec } from "./remote-env-file-error.js";
|
|
10
|
+
import { LANE_HOME_PROBE_COMMAND, LaneHomeSeat } from "../lane-home-probe.js";
|
|
10
11
|
const PROVIDER = "ssh";
|
|
11
12
|
const ok = (value) => ({ ok: true, value });
|
|
12
13
|
const unsupported = (op) => ({
|
|
@@ -24,7 +25,12 @@ export class RemoteSshExecutionEnv {
|
|
|
24
25
|
destroyed = false;
|
|
25
26
|
connEpoch = 0;
|
|
26
27
|
inFlight;
|
|
27
|
-
homeDir
|
|
28
|
+
get homeDir() {
|
|
29
|
+
return this.homeSeat.home;
|
|
30
|
+
}
|
|
31
|
+
homeSeat;
|
|
32
|
+
homeChecked;
|
|
33
|
+
homeRefusal;
|
|
28
34
|
cdPath = "unknown";
|
|
29
35
|
cfg;
|
|
30
36
|
injectedConnectOnce;
|
|
@@ -44,7 +50,7 @@ export class RemoteSshExecutionEnv {
|
|
|
44
50
|
hostKey: config.hostKey,
|
|
45
51
|
};
|
|
46
52
|
this.cwd = this.cfg.mountPath;
|
|
47
|
-
this.
|
|
53
|
+
this.homeSeat = new LaneHomeSeat({ lane: PROVIDER, declared: config.homeDir, verifiesDeclared: true, onAbsent: config.onHomeAbsent });
|
|
48
54
|
}
|
|
49
55
|
resolve(p) {
|
|
50
56
|
return path.posix.isAbsolute(p) ? path.posix.normalize(p) : path.posix.normalize(path.posix.join(this.cwd, p));
|
|
@@ -103,6 +109,110 @@ export class RemoteSshExecutionEnv {
|
|
|
103
109
|
return record.promise;
|
|
104
110
|
}
|
|
105
111
|
async ensureConnected(signal) {
|
|
112
|
+
for (let round = 0; round < 3; round++) {
|
|
113
|
+
if (this.homeRefusal)
|
|
114
|
+
return { ok: false, error: this.homeRefusal };
|
|
115
|
+
const transport = await this.ensureTransport(signal);
|
|
116
|
+
if (!transport.ok || !this.homeSeat.asks)
|
|
117
|
+
return transport;
|
|
118
|
+
const conn = this.conn;
|
|
119
|
+
if (!conn)
|
|
120
|
+
return { ok: false, error: new ExecutionError("shell_unavailable", "SSH connection dropped right after connect") };
|
|
121
|
+
if (this.homeChecked?.conn !== conn) {
|
|
122
|
+
const checked = { conn, verdict: this.homeVerdict(conn) };
|
|
123
|
+
this.homeChecked = checked;
|
|
124
|
+
void checked.verdict.then((r) => {
|
|
125
|
+
if (!r.ok && this.homeRefusal === undefined && this.homeChecked === checked)
|
|
126
|
+
this.homeChecked = undefined;
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
const verdict = await this.raceVerdictAbort(this.homeChecked.verdict, signal);
|
|
130
|
+
if (signal?.aborted)
|
|
131
|
+
return { ok: false, error: new ExecutionError("aborted", "aborted while checking the environment's home") };
|
|
132
|
+
if (!verdict.ok)
|
|
133
|
+
return verdict;
|
|
134
|
+
if (this.conn === conn)
|
|
135
|
+
return verdict;
|
|
136
|
+
}
|
|
137
|
+
return { ok: false, error: new ExecutionError("shell_unavailable", "SSH connection kept being replaced while the environment's home was being checked") };
|
|
138
|
+
}
|
|
139
|
+
async raceVerdictAbort(shared, signal) {
|
|
140
|
+
if (!signal)
|
|
141
|
+
return shared;
|
|
142
|
+
if (signal.aborted)
|
|
143
|
+
return { ok: false, error: new ExecutionError("aborted", "aborted while checking the environment's home") };
|
|
144
|
+
let onAbort;
|
|
145
|
+
const aborted = new Promise((res) => {
|
|
146
|
+
onAbort = () => res({ ok: false, error: new ExecutionError("aborted", "aborted while checking the environment's home") });
|
|
147
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
148
|
+
});
|
|
149
|
+
const raced = await Promise.race([shared, aborted]);
|
|
150
|
+
if (onAbort)
|
|
151
|
+
signal.removeEventListener("abort", onAbort);
|
|
152
|
+
return raced;
|
|
153
|
+
}
|
|
154
|
+
homeVerdict(conn) {
|
|
155
|
+
return new Promise((resolve) => {
|
|
156
|
+
const chunks = [];
|
|
157
|
+
let outBytes = 0;
|
|
158
|
+
let settled = false;
|
|
159
|
+
let channel;
|
|
160
|
+
let channelClosed = false;
|
|
161
|
+
const closeChannel = (ch) => {
|
|
162
|
+
if (ch === undefined || channelClosed)
|
|
163
|
+
return undefined;
|
|
164
|
+
try {
|
|
165
|
+
ch.close();
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
catch (e) {
|
|
169
|
+
return `the probe channel could not be closed: ${e instanceof Error ? e.message : String(e)}`;
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
const settle = (probe) => {
|
|
173
|
+
if (settled)
|
|
174
|
+
return;
|
|
175
|
+
settled = true;
|
|
176
|
+
clearTimeout(timer);
|
|
177
|
+
const closeTrouble = closeChannel(channel);
|
|
178
|
+
if (closeTrouble !== undefined && !probe.ok)
|
|
179
|
+
probe = { ok: false, reason: `${probe.reason}; ${closeTrouble}` };
|
|
180
|
+
const verdict = this.homeSeat.settle(probe);
|
|
181
|
+
if (verdict === undefined)
|
|
182
|
+
return resolve(ok(undefined));
|
|
183
|
+
const error = new ExecutionError("shell_unavailable", verdict.refusal);
|
|
184
|
+
if (verdict.answered)
|
|
185
|
+
this.homeRefusal = error;
|
|
186
|
+
resolve({ ok: false, error });
|
|
187
|
+
};
|
|
188
|
+
const timer = setTimeout(() => settle({ ok: false, reason: `no answer within ${this.cfg.readyTimeoutMs}ms` }), this.cfg.readyTimeoutMs);
|
|
189
|
+
try {
|
|
190
|
+
conn.exec(LANE_HOME_PROBE_COMMAND, (err, stream) => {
|
|
191
|
+
if (err)
|
|
192
|
+
return settle({ ok: false, reason: err.message });
|
|
193
|
+
if (settled)
|
|
194
|
+
return void closeChannel(stream);
|
|
195
|
+
channel = stream;
|
|
196
|
+
stream
|
|
197
|
+
.on("data", (d) => {
|
|
198
|
+
if (outBytes < 4096) {
|
|
199
|
+
chunks.push(d);
|
|
200
|
+
outBytes += d.length;
|
|
201
|
+
}
|
|
202
|
+
})
|
|
203
|
+
.on("close", (code) => {
|
|
204
|
+
channelClosed = true;
|
|
205
|
+
settle(code === 0 ? { ok: true, stdout: Buffer.concat(chunks).toString("utf8") } : { ok: false, reason: code == null ? "the channel closed without an exit status" : `exit ${code}` });
|
|
206
|
+
});
|
|
207
|
+
stream.stderr.on("data", () => { });
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
catch (e) {
|
|
211
|
+
settle({ ok: false, reason: e instanceof Error ? e.message : String(e) });
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
async ensureTransport(signal) {
|
|
106
216
|
if (this.destroyed)
|
|
107
217
|
return { ok: false, error: new ExecutionError("shell_unavailable", "SSH env destroyed — no lazy reconnect after teardown") };
|
|
108
218
|
if (signal?.aborted)
|
|
@@ -435,8 +545,10 @@ export class RemoteSshExecutionEnv {
|
|
|
435
545
|
if (waitTimer !== undefined)
|
|
436
546
|
clearTimeout(waitTimer);
|
|
437
547
|
}
|
|
438
|
-
if (liveness !== undefined && !finished && Date.now() - lastChunk >= liveness.ms)
|
|
439
|
-
|
|
548
|
+
if (liveness !== undefined && !finished && Date.now() - lastChunk >= liveness.ms) {
|
|
549
|
+
const cut = buildLivenessCut(liveness);
|
|
550
|
+
throw new RemoteExecutionError(cut.code, cut.message);
|
|
551
|
+
}
|
|
440
552
|
}
|
|
441
553
|
while (queue.length)
|
|
442
554
|
yield queue.shift();
|
|
@@ -134,7 +134,6 @@ export declare function drainNumEnvWarnings(): Array<{
|
|
|
134
134
|
raw: string;
|
|
135
135
|
}>;
|
|
136
136
|
export declare function numEnvOr(name: string, def: number, min: number): number;
|
|
137
|
-
export declare const SYMLINK_CHAIN_MAX_HOPS = 64;
|
|
138
137
|
/**
|
|
139
138
|
* 一次往返走完叶 symlink 链的 POSIX sh 脚本(**纯数据**:返回一个命令串 ⇒ `build*`,CLAUDE.md 工厂律)。
|
|
140
139
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ExecutionError } from "@sema-agent/core";
|
|
1
|
+
import { ExecutionError, SYMLINK_CHAIN_MAX_HOPS } from "@sema-agent/core";
|
|
2
2
|
import { classifyFsStderr, fileErrorFromExec } from "./remote-env-file-error.js";
|
|
3
3
|
import { randomBytes } from "node:crypto";
|
|
4
4
|
export const EXEC_FORCE_SETTLE_GRACE_MS = 3000;
|
|
@@ -120,7 +120,6 @@ export function numEnvOr(name, def, min) {
|
|
|
120
120
|
}
|
|
121
121
|
return Math.max(min, (Number.isFinite(n) ? n : 0) || def);
|
|
122
122
|
}
|
|
123
|
-
export const SYMLINK_CHAIN_MAX_HOPS = 64;
|
|
124
123
|
export function buildSymlinkChainCommand(absPath) {
|
|
125
124
|
return (`{ if ! command -v readlink >/dev/null 2>&1; then printf 'readlink: not found\\n' >&2; exit 127; fi; ` +
|
|
126
125
|
`c=${shellQuote(absPath)}; n=0; ` +
|
|
@@ -2,6 +2,7 @@ import { mysqlDriver, pgDriver } from "./sql-driver.js";
|
|
|
2
2
|
import { TASK_LIST_ITEM_TABLE, TASK_LIST_META_TABLE, taskListKeyFor } from "./task-list-store-sql.js";
|
|
3
3
|
import { USER_INPUT_ACCEPTANCE_TABLE } from "./user-input-ledger-sql.js";
|
|
4
4
|
import { ensureIndexes } from "./ensure-index.js";
|
|
5
|
+
import { incarnationFromCell } from "../session-incarnation.js";
|
|
5
6
|
export const MANAGED_RETENTION = "managed";
|
|
6
7
|
export const UNMANAGED_RETENTION = "none";
|
|
7
8
|
export const RETENTION_AUDIT_TABLE = "retention_audit";
|
|
@@ -302,7 +303,10 @@ export class SqlRetentionStore {
|
|
|
302
303
|
const { rows } = await exec.query(this.q(`SELECT sm.session_id, sm.incarnation FROM session_meta sm WHERE ${w.sql} AND sm.updated_at < ? AND NOT ${this.liveReferenceExists()} ` +
|
|
303
304
|
`ORDER BY sm.updated_at ASC LIMIT ?${suffix}`, `SELECT sm.session_id, sm.incarnation FROM session_meta sm WHERE ${w.sql} AND sm.updated_at < $2 AND NOT ${this.liveReferenceExists()} ` +
|
|
304
305
|
`ORDER BY sm.updated_at ASC LIMIT $3${suffix}`), [...w.params, new Date(input.cutoffMs), RETENTION_SESSION_BATCH]);
|
|
305
|
-
return rows.map((r) =>
|
|
306
|
+
return rows.map((r) => {
|
|
307
|
+
const id = String(r.session_id);
|
|
308
|
+
return { id, incarnation: incarnationFromCell(id, r.incarnation, "absent") };
|
|
309
|
+
});
|
|
306
310
|
}
|
|
307
311
|
async countOrphanToolResultCandidates(exec, input) {
|
|
308
312
|
return (await this.orphanToolResultCandidates(exec, input)).length;
|
|
@@ -337,7 +341,7 @@ export class SqlRetentionStore {
|
|
|
337
341
|
tombstones = await this.writeTombstones(conn, input.domain, "session", ids);
|
|
338
342
|
}
|
|
339
343
|
await this.writeAuditRow(conn, { domain: input.domain, action: "deleted_sessions", audit, deleted, skipped, tombstones });
|
|
340
|
-
const endedSpaces = doomed.
|
|
344
|
+
const endedSpaces = doomed.flatMap((d) => (d.incarnation === undefined ? [] : [{ sessionId: d.id, spaceKey: d.incarnation }]));
|
|
341
345
|
return { domain: input.domain, deleted, skipped, tombstones, ...(endedSpaces.length > 0 ? { endedSpaces } : {}) };
|
|
342
346
|
});
|
|
343
347
|
}
|
|
@@ -2,13 +2,14 @@ import type { TaskStatus } from "@sema-agent/core";
|
|
|
2
2
|
import type { Pool as MySqlPool } from "mysql2/promise";
|
|
3
3
|
import type { Pool as PgPool } from "pg";
|
|
4
4
|
import { type UsageRow } from "../usage-analytics.js";
|
|
5
|
-
import { type CreateRunOutcome, type NewRunMeta, type RunIdemBinding, type RunRecord, type SessionSummary, type RunEvent, type PersistedTaskResult, type LatestRunRef } from "./store-contracts.js";
|
|
6
|
-
import { type SqlDriver } from "./sql-driver.js";
|
|
5
|
+
import { type ClaimFenced, type CreateRunOutcome, type NewRunMeta, type RunIdemBinding, type RunListQuery, type RunRecord, type SessionSummary, type RunEvent, type PersistedTaskResult, type LatestRunRef } from "./store-contracts.js";
|
|
6
|
+
import { type SqlDriver, type SqlTxConn } from "./sql-driver.js";
|
|
7
7
|
import type { LedgerEventType } from "../trace/ledger-events.js";
|
|
8
8
|
import { type SpaceCommitClaim, type SpaceCommitReading, type SpaceCommitState } from "../workspace-space-commit.js";
|
|
9
9
|
export type { RunRecord, SessionSummary, RunEvent, LatestRunRef } from "./store-contracts.js";
|
|
10
10
|
export declare class SqlRunStore {
|
|
11
|
-
|
|
11
|
+
readonly db: SqlDriver;
|
|
12
|
+
/** `db` 公开只读:会话认领住在这只池背后的库里,写在认领栅栏里的店(workflow 子代决定行)读写都走它 —— 那只店的池只有这一处来源。 */
|
|
12
13
|
constructor(db: SqlDriver);
|
|
13
14
|
/** Pick the dialect's SQL text. Both statements stay written out at the call site ON PURPOSE. */
|
|
14
15
|
private q;
|
|
@@ -159,6 +160,17 @@ export declare class SqlRunStore {
|
|
|
159
160
|
* (一个输掉的认领不许覆盖赢家的持有记录——同一条条件 UPDATE 天然保证)。
|
|
160
161
|
*/
|
|
161
162
|
markResuming(taskId: string, instanceId: string): Promise<boolean>;
|
|
163
|
+
/**
|
|
164
|
+
* 认领当写栅栏用(进程内两孪生的契约 = `store-contracts.ts` 的 `InProcessClaimFence`;本孪生是它的事务形):一个事务 ——
|
|
165
|
+
* ① 锁读这条 run 行且它在跑(`task_run … FOR UPDATE`);② 锁读会话的认领行且它是这条 run 的(`task_active … FOR UPDATE`);
|
|
166
|
+
* ③ 刷新这条 run 的活性戳;④ `write` 在**同一个事务连接**上跑;提交即放锁。任一没读到 ⇒ 不持有,不刷新、`write` 不调。`write` 抛或提交失败 ⇒ 整只抛。
|
|
167
|
+
* 🔴 **取锁序 = task_run → task_active**,与 `setTerminal` / `reapStale` / `reapSuspended` 同序(它们先改 run 行、再删认领行):两行用两条语句按序锁,
|
|
168
|
+
* 不用连表锁读(那一形的先后由计划器定,与终局 / 收割相反时两只事务各攥一行成环)。`createRun` 只插认领行、`deleteBySession` 见认领行在就中止,
|
|
169
|
+
* 都不与本序成环。锁住之后:收割的改行 / 终局与收割的删认领 / 别人的建行都排在本事务之后,收割器提交后重判 `updated_at` 看到的是刚刷的。
|
|
170
|
+
* 锁读没命中时 InnoDB 可能取一把间隙锁;本事务此后不往这两张表插任何行(见 space-commit 那条锁形注)。
|
|
171
|
+
* 担保止于提交:判出「持有」的是这只事务;提交确认在路上迟到、这一跑随后失去认领,不在本栅栏的射程里(调用方的已知边界)。
|
|
172
|
+
*/
|
|
173
|
+
whileHoldingClaim<T>(sessionId: string, taskId: string, write: (tx: SqlTxConn) => Promise<T>): Promise<ClaimFenced<T>>;
|
|
162
174
|
/** The active run's taskId for a session (the `task_active` claim) — lets resume find the suspended run row. */
|
|
163
175
|
getActiveTaskId(sessionId: string): Promise<string | undefined>;
|
|
164
176
|
/** Shared row→record mapper — byte-identical between dialects (both drivers hand back the same column
|
|
@@ -194,17 +206,7 @@ export declare class SqlRunStore {
|
|
|
194
206
|
* built with plain string pushes in call order. PG's `$n` needs a NUMBERED placeholder per param, so that arm
|
|
195
207
|
* keeps its own positional-counter closure (`p()`) — collapsing the two into one shared counter would hide
|
|
196
208
|
* the very placeholder-numbering divergence this file exists to keep visible. */
|
|
197
|
-
listRuns(opts:
|
|
198
|
-
status?: string;
|
|
199
|
-
jobId?: string;
|
|
200
|
-
source?: string;
|
|
201
|
-
owner?: string;
|
|
202
|
-
cursor?: {
|
|
203
|
-
createdAt: string;
|
|
204
|
-
taskId: string;
|
|
205
|
-
};
|
|
206
|
-
limit: number;
|
|
207
|
-
}): Promise<RunRecord[]>;
|
|
209
|
+
listRuns(opts: RunListQuery): Promise<RunRecord[]>;
|
|
208
210
|
/**
|
|
209
211
|
* S-297 —— 这个会话**最近一条腿**的窄指针(`/mcp` 面板的 `lastLegMcp` 与任何「上一条 run 是谁」的读面共用)。
|
|
210
212
|
*
|