@sema-agent/server 7.150.0 → 7.152.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 +451 -0
- package/README.md +15 -3
- package/README.zh-CN.md +10 -2
- package/USAGE.md +144 -87
- package/deploy/sema-up/README.md +11 -4
- package/deploy/sema-up/chart/Chart.yaml +1 -1
- package/deploy/sema-up/chart/templates/NOTES.txt +5 -0
- package/deploy/sema-up/chart/templates/_helpers.tpl +15 -16
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -3
- package/deploy/sema-up/chart/templates/server.yaml +5 -3
- package/deploy/sema-up/chart/values-full-single.yaml +3 -1
- package/deploy/sema-up/chart/values.yaml +8 -1
- package/deploy/sema-up/cluster-up.sh +7 -6
- package/deploy/sema-up/kube-up.sh +6 -6
- package/deploy/sema-up/lib/flagshape.sh +36 -8
- package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
- package/deploy/sema-up/lib/helm-values-kube.py +2 -0
- package/deploy/sema-up/machines.example.yaml +3 -1
- package/deploy/sema-up/sema-up.sh +22 -16
- package/dist/adoption/import.js +3 -3
- package/dist/approval-ask-audit-store.d.ts +1 -1
- package/dist/approval-ask-machine.d.ts +4 -10
- package/dist/approval-ask-retention.d.ts +1 -1
- package/dist/approval-card.d.ts +12 -14
- package/dist/approval-gate-currency.d.ts +9 -9
- package/dist/approval-gate-currency.js +3 -4
- package/dist/approval-hmac.d.ts +17 -1
- package/dist/approval-hmac.js +7 -1
- package/dist/approval-queue-kind.d.ts +1 -1
- package/dist/approval.d.ts +2 -2
- package/dist/approval.js +2 -2
- package/dist/auth-bridge.d.ts +20 -0
- package/dist/auth-bridge.js +9 -0
- package/dist/background-session-reap.d.ts +1 -1
- package/dist/bake-runner/main.d.ts +4 -2
- package/dist/bind-host.d.ts +3 -6
- package/dist/bind-host.js +4 -7
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/coordinators.d.ts +1 -1
- package/dist/boot/coordinators.js +9 -10
- package/dist/boot/device-lane.js +2 -0
- package/dist/boot/engine-lease.d.ts +5 -0
- package/dist/boot/engine-lease.js +1 -0
- package/dist/boot/execution-env.d.ts +9 -14
- package/dist/boot/execution-env.js +85 -22
- package/dist/boot/execution-lane.js +32 -5
- package/dist/boot/late-binds.d.ts +8 -4
- package/dist/boot/late-binds.js +7 -1
- package/dist/boot/leader.d.ts +31 -30
- package/dist/boot/leader.js +38 -28
- package/dist/boot/leg-path-adjudication.d.ts +40 -0
- package/dist/boot/leg-path-adjudication.js +18 -0
- package/dist/boot/memory-consolidation.d.ts +3 -2
- package/dist/boot/memory-consolidation.js +6 -6
- package/dist/boot/parked-revive-gate.js +3 -15
- package/dist/boot/reapers.d.ts +6 -1
- package/dist/boot/reapers.js +13 -2
- package/dist/boot/resolve-spec.d.ts +3 -3
- package/dist/boot/resolve-spec.js +43 -48
- package/dist/boot/runner-deps.d.ts +46 -35
- package/dist/boot/runner-deps.js +94 -91
- package/dist/boot/session-age-out.d.ts +36 -0
- package/dist/boot/session-age-out.js +101 -0
- package/dist/boot/session-faces.d.ts +5 -14
- package/dist/boot/session-faces.js +9 -5
- package/dist/boot/shutdown.d.ts +6 -0
- package/dist/boot/shutdown.js +10 -4
- package/dist/boot/stage-01-config.js +2 -0
- package/dist/boot/stage-02-web-admin-pull.js +4 -5
- package/dist/boot/stage-05-execution-env.d.ts +5 -3
- package/dist/boot/stage-05-execution-env.js +3 -2
- package/dist/boot/stage-06-runners.d.ts +9 -4
- package/dist/boot/stage-06-runners.js +24 -9
- package/dist/boot/stage-07-capability-layer.d.ts +8 -4
- package/dist/boot/stage-07-capability-layer.js +3 -2
- package/dist/boot/stage-08-reapers.d.ts +8 -4
- package/dist/boot/stage-08-reapers.js +4 -2
- package/dist/boot/stage-09-leader.d.ts +12 -5
- package/dist/boot/stage-09-leader.js +14 -5
- package/dist/boot/stage-10-http-server.d.ts +19 -5
- package/dist/boot/stage-10-http-server.js +14 -21
- package/dist/boot/stores.js +7 -4
- package/dist/boot/web-admin.js +5 -8
- package/dist/boot/workflow-orchestration.d.ts +7 -2
- package/dist/boot/workflow-orchestration.js +24 -7
- package/dist/bounded-rotation.d.ts +29 -0
- package/dist/bounded-rotation.js +24 -0
- package/dist/capabilities/approvals-push.d.ts +3 -3
- package/dist/capabilities/scenarios.d.ts +28 -13
- package/dist/capabilities/scenarios.js +2 -2
- package/dist/capability-facts.d.ts +43 -32
- package/dist/capability-facts.js +45 -51
- package/dist/card-rule-offers.d.ts +32 -0
- package/dist/card-rule-offers.js +130 -0
- package/dist/center-credential.d.ts +25 -6
- package/dist/center-credential.js +25 -5
- package/dist/config-catalog.d.ts +26 -7
- package/dist/config-catalog.js +26 -22
- package/dist/config-dir-trust.js +4 -2
- package/dist/config-invariants.d.ts +20 -8
- package/dist/config-invariants.js +55 -12
- package/dist/config-lkg.d.ts +5 -19
- package/dist/config-lkg.js +8 -62
- package/dist/config-provider.d.ts +1 -1
- package/dist/config-root-migration.d.ts +2 -2
- package/dist/config-types.d.ts +38 -42
- package/dist/config.d.ts +58 -7
- package/dist/config.js +90 -40
- package/dist/control-socket.d.ts +51 -0
- package/dist/control-socket.js +115 -0
- package/dist/deployment-governance.d.ts +2 -1
- package/dist/deployment-shape.d.ts +9 -1
- package/dist/deployment-shape.js +2 -1
- package/dist/device-protocol.d.ts +5 -4
- package/dist/device-protocol.js +1 -1
- package/dist/device-ws-hub.d.ts +7 -0
- package/dist/device-ws-hub.js +10 -3
- package/dist/device-ws-protocol.d.ts +63 -10
- package/dist/device-ws-protocol.js +56 -25
- package/dist/elicitation.js +2 -2
- package/dist/engine-identity.d.ts +19 -7
- package/dist/engine-identity.js +10 -2
- package/dist/entry-mode-clamp-notice.d.ts +2 -1
- package/dist/entry-problems.d.ts +40 -3
- package/dist/entry-problems.js +3 -1
- package/dist/execution-env-refusal.d.ts +29 -0
- package/dist/execution-env-refusal.js +8 -0
- package/dist/execution-lane-caps.d.ts +3 -1
- package/dist/field-conflict.d.ts +1 -1
- package/dist/file-history-capture.d.ts +11 -4
- package/dist/file-history-capture.js +9 -6
- package/dist/file-history-disclosure.d.ts +7 -5
- package/dist/file-history-disclosure.js +7 -5
- package/dist/fleet/drain-entry.d.ts +4 -0
- package/dist/fleet/engine-signal.d.ts +12 -29
- package/dist/fleet/engine-signal.js +1 -7
- package/dist/fleet-client.js +2 -5
- package/dist/gate-settlement.d.ts +1 -8
- package/dist/gate-settlement.js +0 -4
- package/dist/history-anchor.js +1 -1
- package/dist/hitl-delivery.d.ts +2 -3
- package/dist/hitl-delivery.js +0 -2
- package/dist/hooks/hook-llm.js +4 -2
- package/dist/hooks/hook-runner.d.ts +3 -2
- package/dist/hooks/hook-runner.js +18 -3
- package/dist/host-decision.d.ts +11 -11
- package/dist/host-lsp-manager.d.ts +2 -2
- package/dist/http/active-run-conflict.d.ts +35 -2
- package/dist/http/active-run-conflict.js +48 -19
- package/dist/http/admission.js +17 -2
- package/dist/http/approval-sweeps.d.ts +1 -1
- package/dist/http/approval-sweeps.js +10 -7
- package/dist/http/checkpoint-ctx.d.ts +4 -0
- package/dist/http/checkpoint-ctx.js +2 -0
- package/dist/http/dispatch.d.ts +8 -3
- package/dist/http/dispatch.js +59 -32
- package/dist/http/durable-run-leg.js +16 -17
- package/dist/http/health-reader.d.ts +16 -9
- package/dist/http/health-reader.js +2 -1
- package/dist/http/health-self-report.d.ts +9 -1
- package/dist/http/health-self-report.js +3 -1
- package/dist/http/owner-access.d.ts +33 -14
- package/dist/http/owner-access.js +40 -10
- package/dist/http/principal-gate.d.ts +49 -21
- package/dist/http/principal-gate.js +61 -11
- package/dist/http/request-channel.d.ts +23 -0
- package/dist/http/request-channel.js +9 -0
- package/dist/http/request-guards.js +17 -2
- package/dist/http/resume-ctx-read.js +42 -3
- package/dist/http/resume-legs.d.ts +4 -3
- package/dist/http/resume-legs.js +367 -117
- package/dist/http/route-ctx.d.ts +91 -15
- package/dist/http/route-ctx.js +17 -0
- package/dist/http/route-table.d.ts +5 -1
- package/dist/http/route-table.js +4 -0
- package/dist/http/routes/admin-config-refresh.js +3 -3
- package/dist/http/routes/admin-drain.d.ts +3 -0
- package/dist/http/routes/admin-drain.js +7 -7
- package/dist/http/routes/admin-memory-optout.d.ts +1 -1
- package/dist/http/routes/admin-memory-optout.js +3 -3
- package/dist/http/routes/adoption.js +3 -5
- package/dist/http/routes/agents-roster.js +2 -3
- package/dist/http/routes/approvals-assistant.d.ts +2 -1
- package/dist/http/routes/approvals-assistant.js +99 -51
- package/dist/http/routes/background.d.ts +3 -3
- package/dist/http/routes/capabilities.d.ts +4 -0
- package/dist/http/routes/capabilities.js +38 -10
- package/dist/http/routes/config-catalog.js +2 -2
- package/dist/http/routes/devices.js +1 -1
- package/dist/http/routes/diagnostics.d.ts +3 -3
- package/dist/http/routes/diagnostics.js +19 -7
- package/dist/http/routes/fleet.js +10 -8
- package/dist/http/routes/images.js +10 -10
- package/dist/http/routes/memory-bundle.js +3 -3
- package/dist/http/routes/memory-compliance.js +3 -3
- package/dist/http/routes/memory-consolidation.js +2 -2
- package/dist/http/routes/memory-origin.js +3 -3
- package/dist/http/routes/memory-policy.js +2 -2
- package/dist/http/routes/observability.js +3 -3
- package/dist/http/routes/projects.d.ts +3 -2
- package/dist/http/routes/projects.js +4 -5
- package/dist/http/routes/retention-ops.js +3 -3
- package/dist/http/routes/rules.js +5 -5
- package/dist/http/routes/run-permission-mode.d.ts +2 -1
- package/dist/http/routes/run-permission-mode.js +2 -2
- package/dist/http/routes/runs.d.ts +4 -9
- package/dist/http/routes/runs.js +171 -65
- package/dist/http/routes/session-sync.d.ts +22 -9
- package/dist/http/routes/session-sync.js +204 -107
- package/dist/http/routes/sessions-list.js +13 -7
- package/dist/http/routes/sessions.js +30 -15
- package/dist/http/routes/tasks.js +46 -41
- package/dist/http/routes/trace-usage.js +2 -2
- package/dist/http/routes/workflows.js +1 -1
- package/dist/http/server.d.ts +30 -30
- package/dist/http/server.js +16 -4
- package/dist/http/submit-ctx.d.ts +1 -1
- package/dist/http/submit-ctx.js +7 -4
- package/dist/http/wire-types.d.ts +14 -4
- package/dist/human-facing-args.d.ts +33 -0
- package/dist/human-facing-args.js +33 -0
- package/dist/identity-source.d.ts +20 -3
- package/dist/identity-source.js +14 -0
- package/dist/index.d.ts +5 -1
- package/dist/k8s-api-credentials.d.ts +29 -0
- package/dist/k8s-api-credentials.js +25 -0
- package/dist/lane-home-probe.d.ts +3 -7
- package/dist/lane-home-probe.js +2 -2
- package/dist/leader/diffup.d.ts +19 -0
- package/dist/leader/diffup.js +7 -0
- package/dist/leader/leader.d.ts +116 -11
- package/dist/leader/leader.js +69 -5
- package/dist/leader/repair-wire.js +2 -2
- package/dist/leader/run-entry.d.ts +2 -1
- package/dist/leader/run-entry.js +1 -1
- package/dist/leader/wire.d.ts +42 -132
- package/dist/leader/wire.js +81 -67
- package/dist/leg-facts.d.ts +13 -5
- package/dist/leg-facts.js +2 -1
- package/dist/memory-scope.d.ts +23 -11
- package/dist/memory-scope.js +18 -6
- package/dist/memory-sync-client.d.ts +30 -2
- package/dist/memory-sync-client.js +16 -9
- package/dist/model-entry-headers.d.ts +9 -10
- package/dist/model-entry-headers.js +0 -4
- package/dist/model-entry-refusal.d.ts +7 -4
- package/dist/model-entry-refusal.js +11 -5
- package/dist/model-plane-face.d.ts +1 -1
- package/dist/model-plane-face.js +3 -1
- package/dist/model-route-endpoint.d.ts +13 -7
- package/dist/model-route-endpoint.js +14 -11
- package/dist/model-select.d.ts +22 -0
- package/dist/model-select.js +9 -0
- package/dist/model-unreachable-notice.d.ts +11 -0
- package/dist/model-unreachable-notice.js +4 -4
- package/dist/object-store-buckets.d.ts +640 -6
- package/dist/object-store-buckets.js +166 -0
- package/dist/observability/err-text.d.ts +7 -0
- package/dist/observability/err-text.js +5 -0
- package/dist/observability/fail-open.d.ts +25 -17
- package/dist/observability/fail-open.js +25 -17
- package/dist/observability/logger.js +3 -1
- package/dist/observability/metrics.js +1 -0
- package/dist/operator-roster.d.ts +68 -0
- package/dist/operator-roster.js +32 -0
- package/dist/orchestration/workflow-notify-journal.d.ts +18 -1
- package/dist/orchestration/workflow-notify-journal.js +12 -1
- package/dist/orchestration/workflow-park-decision.d.ts +70 -18
- package/dist/orchestration/workflow-park-decision.js +49 -10
- package/dist/orchestration/workflow-park-holder.d.ts +65 -0
- package/dist/orchestration/workflow-park-holder.js +98 -0
- package/dist/orchestration/workflow-record-fence.d.ts +36 -0
- package/dist/orchestration/workflow-record-fence.js +42 -0
- package/dist/outbound-dispatcher.d.ts +71 -8
- package/dist/outbound-dispatcher.js +48 -7
- package/dist/owner-faces.d.ts +2 -2
- package/dist/parked-decide.d.ts +106 -55
- package/dist/parked-decide.js +153 -117
- package/dist/peer-directory.d.ts +2 -2
- package/dist/peer-inbound-face.d.ts +2 -6
- package/dist/peer-inbound-face.js +0 -3
- package/dist/permission-mode-admission.d.ts +74 -5
- package/dist/permission-mode-admission.js +56 -3
- package/dist/plugins/adoption-log-sql.d.ts +3 -1
- package/dist/plugins/adoption-log-sql.js +7 -1
- package/dist/plugins/approval-ask-store-file.d.ts +14 -2
- package/dist/plugins/approval-ask-store-file.js +11 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +10 -1
- package/dist/plugins/approval-ask-store-memory.js +35 -10
- package/dist/plugins/approval-ask-store-sql.d.ts +69 -4
- package/dist/plugins/approval-ask-store-sql.js +45 -5
- package/dist/plugins/approval-exemption-store.js +3 -0
- package/dist/plugins/approval-nonce-store.js +2 -0
- package/dist/plugins/blob-backend.d.ts +83 -7
- package/dist/plugins/blob-backend.js +57 -6
- package/dist/plugins/breaker-state-sql.js +2 -0
- package/dist/plugins/caching-session-store.d.ts +9 -15
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/checkpoint-index-columns.d.ts +20 -16
- package/dist/plugins/checkpoint-index-columns.js +3 -6
- package/dist/plugins/checkpoint-store-face.d.ts +119 -61
- package/dist/plugins/checkpoint-store-face.js +134 -55
- package/dist/plugins/device-store-sql.js +6 -0
- package/dist/plugins/error-origin.d.ts +18 -0
- package/dist/plugins/error-origin.js +10 -0
- package/dist/plugins/execution-placement-sql.js +6 -6
- package/dist/plugins/image-bake-store-sql.js +6 -0
- package/dist/plugins/image-index-sql.js +4 -0
- package/dist/plugins/landed-attendants.d.ts +212 -0
- package/dist/plugins/landed-attendants.js +161 -0
- package/dist/plugins/leader-run-store-sql.js +4 -0
- package/dist/plugins/local-checkpoint-store.d.ts +13 -3
- package/dist/plugins/local-checkpoint-store.js +38 -49
- package/dist/plugins/local-session-live-reference.d.ts +40 -0
- package/dist/plugins/local-session-live-reference.js +39 -0
- package/dist/plugins/local-session-store.d.ts +71 -33
- package/dist/plugins/local-session-store.js +129 -27
- package/dist/plugins/memory-engine-pg.js +4 -0
- package/dist/plugins/memory-engine-sql-apply.js +5 -2
- package/dist/plugins/memory-engine-tidb.js +4 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +4 -0
- package/dist/plugins/memory-sync-store-pg.js +5 -0
- package/dist/plugins/memory-sync-store-tidb.js +5 -0
- package/dist/plugins/one-time-migrations.d.ts +104 -80
- package/dist/plugins/one-time-migrations.js +226 -132
- package/dist/plugins/org-delivery-quota-store.js +4 -1
- package/dist/plugins/outcome-ledger-sql.js +2 -0
- package/dist/plugins/permission-rule-store-sql.js +11 -4
- package/dist/plugins/pg-cost-quota.js +4 -0
- package/dist/plugins/pg-pool.js +35 -10
- package/dist/plugins/pg-rate-limiter.js +2 -0
- package/dist/plugins/posix-shell-fs.d.ts +6 -1
- package/dist/plugins/posix-shell-fs.js +4 -1
- package/dist/plugins/remote-env-adb.d.ts +19 -15
- package/dist/plugins/remote-env-adb.js +41 -15
- package/dist/plugins/remote-env-connect-seat.d.ts +105 -0
- package/dist/plugins/remote-env-connect-seat.js +72 -0
- package/dist/plugins/remote-env-device.d.ts +22 -5
- package/dist/plugins/remote-env-device.js +106 -8
- package/dist/plugins/remote-env-e2b.d.ts +15 -6
- package/dist/plugins/remote-env-e2b.js +42 -32
- package/dist/plugins/remote-env-file-error.js +6 -2
- package/dist/plugins/remote-env-host.d.ts +46 -10
- package/dist/plugins/remote-env-host.js +124 -52
- package/dist/plugins/remote-env-k8s.d.ts +109 -41
- package/dist/plugins/remote-env-k8s.js +160 -54
- package/dist/plugins/remote-env-local-docker.d.ts +13 -8
- package/dist/plugins/remote-env-local-docker.js +34 -41
- package/dist/plugins/remote-env-ssh.d.ts +18 -12
- package/dist/plugins/remote-env-ssh.js +60 -59
- package/dist/plugins/remote-shell.d.ts +98 -1
- package/dist/plugins/remote-shell.js +218 -0
- package/dist/plugins/replica-registration.d.ts +1 -1
- package/dist/plugins/replica-registration.js +1 -1
- package/dist/plugins/resume-anchor-store-sql.d.ts +11 -2
- package/dist/plugins/resume-anchor-store-sql.js +12 -5
- package/dist/plugins/retention-lane-store-sql.js +4 -0
- package/dist/plugins/retention-sql.d.ts +20 -2
- package/dist/plugins/retention-sql.js +11 -0
- package/dist/plugins/run-store-sql.d.ts +21 -2
- package/dist/plugins/run-store-sql.js +31 -7
- package/dist/plugins/s3-presign.d.ts +23 -0
- package/dist/plugins/s3-presign.js +37 -3
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +1 -1
- package/dist/plugins/scenario-prefix-switch-m42.js +2 -2
- package/dist/plugins/scheduler-support.d.ts +2 -2
- package/dist/plugins/scheduler-support.js +0 -3
- package/dist/plugins/schema-consistency.d.ts +4 -2
- package/dist/plugins/schema-consistency.js +19 -2
- package/dist/plugins/schema-indexes.js +2 -0
- package/dist/plugins/send-file-ledger.d.ts +2 -2
- package/dist/plugins/send-file-ledger.js +5 -2
- package/dist/plugins/send-user-file.d.ts +3 -4
- package/dist/plugins/send-user-file.js +56 -52
- package/dist/plugins/serving-requirement.d.ts +26 -7
- package/dist/plugins/serving-requirement.js +11 -4
- package/dist/plugins/session-birth.d.ts +6 -2
- package/dist/plugins/session-blob-claim-token.d.ts +15 -0
- package/dist/plugins/session-blob-claim-token.js +20 -0
- package/dist/plugins/session-blob-namespace.d.ts +46 -0
- package/dist/plugins/session-blob-namespace.js +116 -0
- package/dist/plugins/session-capture-record-store-sql.js +2 -0
- package/dist/plugins/session-ext-table.d.ts +14 -1
- package/dist/plugins/session-ext-table.js +5 -1
- package/dist/plugins/session-row-sql.d.ts +49 -2
- package/dist/plugins/session-row-sql.js +56 -13
- package/dist/plugins/session-store-sql.d.ts +34 -18
- package/dist/plugins/session-store-sql.js +98 -17
- package/dist/plugins/shared-memory-store-sql.d.ts +1 -0
- package/dist/plugins/shared-memory-store-sql.js +6 -2
- package/dist/plugins/snapshot-bucket-presence.d.ts +25 -2
- package/dist/plugins/snapshot-bucket-presence.js +8 -2
- package/dist/plugins/sql-driver.d.ts +2 -1
- package/dist/plugins/sql-driver.js +18 -3
- package/dist/plugins/sql-errors.d.ts +11 -6
- package/dist/plugins/sql-errors.js +5 -6
- package/dist/plugins/sql-json-column.d.ts +1 -1
- package/dist/plugins/stop-then-start-sentence.d.ts +10 -4
- package/dist/plugins/stop-then-start-sentence.js +14 -10
- package/dist/plugins/stop-then-start.d.ts +109 -0
- package/dist/plugins/stop-then-start.js +104 -0
- package/dist/plugins/store-backend.d.ts +84 -15
- package/dist/plugins/store-backend.js +236 -72
- package/dist/plugins/store-boundary.d.ts +57 -0
- package/dist/plugins/store-boundary.js +139 -0
- package/dist/plugins/store-contracts.d.ts +17 -0
- package/dist/plugins/store-fault-sentence-m53.d.ts +7 -0
- package/dist/plugins/store-fault-sentence-m53.js +25 -0
- package/dist/plugins/store-fault.d.ts +26 -7
- package/dist/plugins/store-fault.js +18 -2
- package/dist/plugins/task-attachment-store.d.ts +2 -1
- package/dist/plugins/task-attachment-store.js +14 -1
- package/dist/plugins/task-list-store-sql.d.ts +2 -2
- package/dist/plugins/task-list-store-sql.js +10 -8
- package/dist/plugins/tidb-cost-quota.js +4 -0
- package/dist/plugins/tidb-pool.js +21 -25
- package/dist/plugins/tidb-rate-limiter.js +4 -0
- package/dist/plugins/user-input-ledger-sql.js +4 -0
- package/dist/plugins/workflow-run-store-sql.d.ts +28 -10
- package/dist/plugins/workflow-run-store-sql.js +64 -4
- package/dist/plugins/workspace-custody.d.ts +4 -3
- package/dist/plugins/workspace-fill.d.ts +4 -7
- package/dist/plugins/workspace-fill.js +2 -1
- package/dist/plugins/write-behind-counter.js +5 -0
- package/dist/project-context.d.ts +0 -2
- package/dist/project-context.js +4 -8
- package/dist/project-registry.d.ts +46 -0
- package/dist/project-registry.js +44 -0
- package/dist/question.d.ts +2 -1
- package/dist/question.js +5 -13
- package/dist/request-form.d.ts +6 -1
- package/dist/request-form.js +4 -1
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +4 -0
- package/dist/request-value-closure.js +10 -0
- package/dist/rule-issue-reading.d.ts +1 -1
- package/dist/rules-consent.d.ts +1 -1
- package/dist/run-acceptance.d.ts +3 -2
- package/dist/run-acceptance.js +4 -6
- package/dist/run-local.js +9 -9
- package/dist/runs.d.ts +54 -16
- package/dist/runs.js +67 -13
- package/dist/runtime-governance.d.ts +5 -4
- package/dist/security.d.ts +30 -32
- package/dist/security.js +41 -7
- package/dist/sema-config-dir.d.ts +2 -1
- package/dist/server-secret-env.d.ts +12 -10
- package/dist/server-secret-env.js +24 -15
- package/dist/session-bindings.d.ts +82 -0
- package/dist/session-bindings.js +18 -0
- package/dist/session-children-retire.d.ts +2 -2
- package/dist/session-children-retire.js +2 -6
- package/dist/session-deletion.d.ts +16 -1
- package/dist/session-error-wire.d.ts +3 -3
- package/dist/session-error-wire.js +3 -3
- package/dist/session-incarnation.d.ts +10 -0
- package/dist/session-incarnation.js +10 -1
- package/dist/session-kind.d.ts +57 -0
- package/dist/session-kind.js +22 -0
- package/dist/session-row.d.ts +21 -1
- package/dist/session-row.js +7 -1
- package/dist/session-sync-kernel.d.ts +24 -14
- package/dist/session-sync-kernel.js +3 -6
- package/dist/session-sync.d.ts +25 -103
- package/dist/session-sync.js +14 -76
- package/dist/session-titler.d.ts +10 -3
- package/dist/session-titler.js +19 -6
- package/dist/ssh-host-key.d.ts +5 -0
- package/dist/ssh-host-key.js +3 -0
- package/dist/stores-sql/blob-index-sql.d.ts +30 -9
- package/dist/stores-sql/blob-index-sql.js +40 -21
- package/dist/stores-sql/checkpoint-store-sql.d.ts +54 -27
- package/dist/stores-sql/checkpoint-store-sql.js +70 -146
- package/dist/stores-sql/file-history-store-sql.d.ts +113 -15
- package/dist/stores-sql/file-history-store-sql.js +205 -95
- package/dist/stores-sql/pg-session-storage.d.ts +34 -7
- package/dist/stores-sql/pg-session-storage.js +37 -13
- package/dist/stores-sql/retention-store-sql.d.ts +1 -9
- package/dist/stores-sql/retention-store-sql.js +5 -19
- package/dist/stores-sql/session-policy-store-sql.d.ts +30 -7
- package/dist/stores-sql/session-policy-store-sql.js +61 -44
- package/dist/stores-sql/session-write-hooks.d.ts +11 -0
- package/dist/stores-sql/tidb-session-store.d.ts +58 -7
- package/dist/stores-sql/tidb-session-store.js +37 -13
- package/dist/submission-exit.d.ts +3 -2
- package/dist/submission-exit.js +9 -1
- package/dist/task-cwd.d.ts +2 -2
- package/dist/task-settings.d.ts +7 -5
- package/dist/task-settings.js +3 -3
- package/dist/terminal.d.ts +33 -2
- package/dist/terminal.js +139 -9
- package/dist/tool-approval.d.ts +465 -507
- package/dist/tool-approval.js +606 -1222
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/dist/trace/ledger-events.d.ts +3 -3
- package/dist/trace/project.d.ts +2 -3
- package/dist/trace/redact.js +3 -2
- package/dist/trace/self-minted-wire.d.ts +571 -178
- package/dist/trace/self-minted-wire.js +189 -56
- package/dist/web-admin-client/apply-effective.js +2 -2
- package/dist/web-admin-client/read-warnings.d.ts +2 -2
- package/dist/web-admin-client/read-warnings.js +1 -1
- package/dist/web-admin-client/types.d.ts +1 -1
- package/dist/workspace-space.d.ts +10 -4
- package/dist/workspace-space.js +4 -1
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +79 -28
- package/package.json +7 -3
- package/scripts/embed-minimal.mjs +3 -3
- package/wire-changes/server@7.151.0.json +762 -0
- package/wire-changes/server@7.152.0.json +900 -0
- package/dist/config-d-migration.d.ts +0 -37
- package/dist/config-d-migration.js +0 -60
- package/dist/http/session-inherit-env.d.ts +0 -36
- package/dist/http/session-inherit-env.js +0 -6
|
@@ -9,15 +9,16 @@ import { appendFileStaged, buildCwdEnvCommand, createCwdGuardedCall, shellQuote,
|
|
|
9
9
|
import { presignS3Url, presignS3ListUrl } from "./s3-presign.js";
|
|
10
10
|
import { WORKSPACE_SNAPSHOT_BUCKET_DEFAULT } from "../object-store-buckets.js";
|
|
11
11
|
import { SNAPSHOT_BUCKET_MISSING, isNoSuchBucketAnswer } from "./s3-answer.js";
|
|
12
|
-
import { K8S_WORKSPACE_MOUNT_DEFAULT, SNAPSHOT_KEY_SEGMENT,
|
|
12
|
+
import { K8S_WORKSPACE_MOUNT_DEFAULT, SNAPSHOT_KEY_SEGMENT, WORKSPACE_SNAPSHOT_TIMEOUT_MS_DEFAULT, mintSnapshotId, snapshotIdHolds, snapshotKeyPrefixProblem, snapshotNameOwnedBy, workspaceSnapshotPrefixOf } from "../workspace-space.js";
|
|
13
13
|
import { spaceCommitAlive } from "../workspace-space-commit.js";
|
|
14
|
-
import { incarnationLogPrefix, redactIncarnations } from "../session-incarnation.js";
|
|
14
|
+
import { SESSION_INCARNATION_MISSING, incarnationLogPrefix, redactIncarnations } from "../session-incarnation.js";
|
|
15
15
|
import { WORKSPACE_CACHE_SPACE_LABEL, workspaceCacheClaimOf, workspaceCacheEnv } from "../workspace-cache.js";
|
|
16
16
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
17
17
|
import { PodDeleteRefused, reportPodDeleteFailed } from "./k8s-pod-delete-failure.js";
|
|
18
18
|
import { buildLivenessCut, commandBoundsOf, laneLivenessOf, LIVENESS_MS_DEFAULT } from "../exec-bounds.js";
|
|
19
19
|
import { buildCapturedOutput, createCutError } from "../exec-cut.js";
|
|
20
20
|
import { SANDBOX_IPV6_DEFAULT, sandboxEgressGaps, sandboxPodSysctls } from "../sandbox-egress-policy.js";
|
|
21
|
+
import { describeMissingK8sCredential } from "../k8s-api-credentials.js";
|
|
21
22
|
import { FileError, ExecutionError, RemoteExecutionError, withRetry, RollingTailBuffer, markTruncated, } from "@sema-agent/core";
|
|
22
23
|
import { capabilitiesFor } from "../execution-lane-caps.js";
|
|
23
24
|
import { DEPLOYMENT_SHAPE_PREDICATES } from "../deployment-shape.js";
|
|
@@ -27,6 +28,7 @@ import { createPosixShellFs } from "./posix-shell-fs.js";
|
|
|
27
28
|
import { randomUUID } from "node:crypto";
|
|
28
29
|
import { BackgroundShellManager, seedMemStream, feedMemStream, drainMemStream } from "./background-shell-support.js";
|
|
29
30
|
import { LANE_HOME_PROBE_COMMAND, LaneHomeSeat } from "../lane-home-probe.js";
|
|
31
|
+
import { connectRefusal, createConnectSeat } from "./remote-env-connect-seat.js";
|
|
30
32
|
const PROVIDER = "k8s";
|
|
31
33
|
const K8S_BG_DIR_ROOT = "/tmp/.sema-bg";
|
|
32
34
|
const K8S_BG_MAX_CONCURRENT = numEnvOr("K8S_BG_MAX_CONCURRENT", 8, 1);
|
|
@@ -43,6 +45,42 @@ const unsupported = (op) => ({
|
|
|
43
45
|
error: new RemoteExecutionError("unsupported", `${op} is not supported on a Kata pod sandbox (no managed memory snapshot — capabilities.suspendable=false; durable suspend degrades to checkpoint + cold rebuild)`),
|
|
44
46
|
});
|
|
45
47
|
const SA_DIR = "/var/run/secrets/kubernetes.io/serviceaccount";
|
|
48
|
+
const processInCluster = () => ({
|
|
49
|
+
host: process.env.KUBERNETES_SERVICE_HOST,
|
|
50
|
+
port: process.env.KUBERNETES_SERVICE_PORT,
|
|
51
|
+
readMounted: (file) => readFileSync(`${SA_DIR}/${file}`, "utf8"),
|
|
52
|
+
});
|
|
53
|
+
export function resolveK8sApiAccess(cfg, inCluster = processInCluster()) {
|
|
54
|
+
const given = (v) => v !== undefined && v.trim() !== "";
|
|
55
|
+
const apiUrl = given(cfg.apiUrl) ? cfg.apiUrl : given(inCluster.host) ? `https://${inCluster.host}:${inCluster.port ?? "443"}` : undefined;
|
|
56
|
+
if (apiUrl === undefined)
|
|
57
|
+
return { ok: false, fact: "api_url", code: "connect_failed" };
|
|
58
|
+
let token = given(cfg.token) ? cfg.token : undefined;
|
|
59
|
+
if (token === undefined) {
|
|
60
|
+
try {
|
|
61
|
+
const mounted = inCluster.readMounted("token").trim();
|
|
62
|
+
token = mounted === "" ? undefined : mounted;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
token = undefined;
|
|
66
|
+
}
|
|
67
|
+
if (token === undefined)
|
|
68
|
+
return { ok: false, fact: "token", code: "auth_failed" };
|
|
69
|
+
}
|
|
70
|
+
let ca = given(cfg.caCert) ? cfg.caCert : undefined;
|
|
71
|
+
if (ca === undefined && !cfg.insecureTls) {
|
|
72
|
+
try {
|
|
73
|
+
const mounted = inCluster.readMounted("ca.crt");
|
|
74
|
+
ca = given(mounted) ? mounted : undefined;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
ca = undefined;
|
|
78
|
+
}
|
|
79
|
+
if (ca === undefined)
|
|
80
|
+
return { ok: false, fact: "ca", code: "auth_failed" };
|
|
81
|
+
}
|
|
82
|
+
return { ok: true, apiUrl, token, ca };
|
|
83
|
+
}
|
|
46
84
|
const EXEC_SUBPROTOCOLS = ["v5.channel.k8s.io", "v4.channel.k8s.io"];
|
|
47
85
|
const WRITE_CHUNK_BYTES = 64 * 1024;
|
|
48
86
|
import { applyPodSpecPatch, ADAPTER_VOLUME_NAMES, SANDBOX_POD_LABELS, SANDBOX_RUN_END_HOLD_ANNOTATION, SANDBOX_RUN_LABEL, SANDBOX_SECRET_SEAT_VERBS, isLabelValue } from "./k8s-exec-protocol.js";
|
|
@@ -92,6 +130,10 @@ function spaceLaneOf(policy, occupant) {
|
|
|
92
130
|
function spaceReadFailed(what, detail, cause) {
|
|
93
131
|
return { ok: false, error: new RemoteExecutionError("connect_failed", `workspace space ${what} read failed${detail}`, cause instanceof Error ? cause : undefined) };
|
|
94
132
|
}
|
|
133
|
+
function isQuotaExceeded(json) {
|
|
134
|
+
const message = typeof json === "object" && json !== null ? json.message : undefined;
|
|
135
|
+
return typeof message === "string" && /\bexceeded quota\b/.test(message);
|
|
136
|
+
}
|
|
95
137
|
function restoreFailureIsTransient(cls) {
|
|
96
138
|
switch (cls) {
|
|
97
139
|
case "timeout":
|
|
@@ -174,6 +216,42 @@ export function boundedStoreCall(op, bound) {
|
|
|
174
216
|
});
|
|
175
217
|
});
|
|
176
218
|
}
|
|
219
|
+
function snapshotOpOf(req) {
|
|
220
|
+
if (req.method === "LIST")
|
|
221
|
+
return req.lane === "space" ? "k8s-space/prefix:LIST" : "k8s-park/prefix:LIST";
|
|
222
|
+
if ("object" in req)
|
|
223
|
+
return req.lane === "space" ? "k8s-space/object:DELETE" : "k8s-park/object:DELETE";
|
|
224
|
+
if ("pointer" in req) {
|
|
225
|
+
switch (req.method) {
|
|
226
|
+
case "GET":
|
|
227
|
+
return "k8s-space/latest:GET";
|
|
228
|
+
case "PUT":
|
|
229
|
+
return "k8s-space/latest:PUT";
|
|
230
|
+
case "DELETE":
|
|
231
|
+
return "k8s-space/latest:DELETE";
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (req.lane === "park") {
|
|
235
|
+
switch (req.method) {
|
|
236
|
+
case "GET":
|
|
237
|
+
return "k8s-park/archive:GET";
|
|
238
|
+
case "PUT":
|
|
239
|
+
return "k8s-park/archive:PUT";
|
|
240
|
+
case "HEAD":
|
|
241
|
+
return "k8s-park/archive:HEAD";
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
switch (req.method) {
|
|
245
|
+
case "GET":
|
|
246
|
+
return "k8s-space/archive:GET";
|
|
247
|
+
case "PUT":
|
|
248
|
+
return "k8s-space/archive:PUT";
|
|
249
|
+
case "DELETE":
|
|
250
|
+
return "k8s-space/archive:DELETE";
|
|
251
|
+
case "HEAD":
|
|
252
|
+
return "k8s-space/archive:HEAD";
|
|
253
|
+
}
|
|
254
|
+
}
|
|
177
255
|
import { execSocketTlsOptions, exitCodeFromStatus } from "./k8s-exec-protocol.js";
|
|
178
256
|
export { execSocketTlsOptions } from "./k8s-exec-protocol.js";
|
|
179
257
|
export function errorMessageOf(e) {
|
|
@@ -222,7 +300,18 @@ export class RemoteK8sExecutionEnv {
|
|
|
222
300
|
idleWaiters = [];
|
|
223
301
|
connectInFlight;
|
|
224
302
|
resumeInFlight;
|
|
225
|
-
|
|
303
|
+
seat = createConnectSeat({
|
|
304
|
+
live: () => (this.podName !== undefined && this.connectInFlight === undefined && !this.destroyed ? this.workspaceHandle() : undefined),
|
|
305
|
+
inFlight: () => this.connectInFlight,
|
|
306
|
+
establish: (config) => {
|
|
307
|
+
const walk = this.establish(config).finally(() => {
|
|
308
|
+
if (this.connectInFlight === walk)
|
|
309
|
+
this.connectInFlight = undefined;
|
|
310
|
+
});
|
|
311
|
+
this.connectInFlight = walk;
|
|
312
|
+
return walk;
|
|
313
|
+
},
|
|
314
|
+
});
|
|
226
315
|
get homeDir() {
|
|
227
316
|
return this.homeSeat.home;
|
|
228
317
|
}
|
|
@@ -307,29 +396,32 @@ export class RemoteK8sExecutionEnv {
|
|
|
307
396
|
return { sandboxId: this.podName ?? "(unconnected)", provider: PROVIDER, mountPath: this.cwd, ...(this.handleSnapshotId ? { snapshotId: this.handleSnapshotId } : {}) };
|
|
308
397
|
}
|
|
309
398
|
creds() {
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
399
|
+
const access = resolveK8sApiAccess(this.cfg, this.deps.inCluster?.());
|
|
400
|
+
if (!access.ok)
|
|
401
|
+
throw new RemoteExecutionError(access.code, describeMissingK8sCredential(access.fact));
|
|
402
|
+
return { apiUrl: access.apiUrl.replace(/\/+$/, ""), token: access.token, ca: access.ca };
|
|
403
|
+
}
|
|
404
|
+
missingApiCredential() {
|
|
405
|
+
const access = resolveK8sApiAccess(this.cfg, this.deps.inCluster?.());
|
|
406
|
+
return access.ok ? undefined : access.fact;
|
|
407
|
+
}
|
|
408
|
+
async apiCredentialReading() {
|
|
409
|
+
const fact = this.missingApiCredential();
|
|
410
|
+
if (fact !== undefined)
|
|
411
|
+
return { state: "missing", fact };
|
|
412
|
+
try {
|
|
413
|
+
const r = await this.request("POST", "/apis/authorization.k8s.io/v1/selfsubjectaccessreviews", {
|
|
414
|
+
apiVersion: "authorization.k8s.io/v1",
|
|
415
|
+
kind: "SelfSubjectAccessReview",
|
|
416
|
+
spec: { resourceAttributes: { namespace: this.cfg.namespace, verb: "create", resource: "pods" } },
|
|
417
|
+
});
|
|
418
|
+
if (r.status === 401)
|
|
419
|
+
return { state: "rejected" };
|
|
420
|
+
return r.status >= 200 && r.status < 300 ? { state: "accepted" } : { state: "unproven", detail: `HTTP ${r.status}` };
|
|
323
421
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
ca = readFileSync(`${SA_DIR}/ca.crt`, "utf8");
|
|
327
|
-
}
|
|
328
|
-
catch {
|
|
329
|
-
throw new RemoteExecutionError("auth_failed", "no k8s CA: set K8S_CA_CERT_B64, K8S_INSECURE_TLS=true (lab), or run in-cluster");
|
|
330
|
-
}
|
|
422
|
+
catch (e) {
|
|
423
|
+
return { state: "unproven", detail: errorMessageOf(e) };
|
|
331
424
|
}
|
|
332
|
-
return { apiUrl: apiUrl.replace(/\/+$/, ""), token, ca };
|
|
333
425
|
}
|
|
334
426
|
async request(method, apiPath, body, opts) {
|
|
335
427
|
if (this.deps.request)
|
|
@@ -386,18 +478,12 @@ export class RemoteK8sExecutionEnv {
|
|
|
386
478
|
});
|
|
387
479
|
}
|
|
388
480
|
connect(config) {
|
|
389
|
-
|
|
390
|
-
return this.connectInFlight;
|
|
391
|
-
const walk = this.establish(config).finally(() => {
|
|
392
|
-
if (this.connectInFlight === walk)
|
|
393
|
-
this.connectInFlight = undefined;
|
|
394
|
-
});
|
|
395
|
-
this.connectInFlight = walk;
|
|
396
|
-
return walk;
|
|
481
|
+
return this.seat.connect(config);
|
|
397
482
|
}
|
|
398
483
|
async establish(config) {
|
|
399
|
-
|
|
400
|
-
|
|
484
|
+
const held = this.seat.held;
|
|
485
|
+
if (held)
|
|
486
|
+
return held;
|
|
401
487
|
const signal = config?.abortSignal;
|
|
402
488
|
const lane = this.spaceLane;
|
|
403
489
|
switch (lane.state) {
|
|
@@ -434,7 +520,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
434
520
|
const filled = await fill.fill(this.fillChannel(), this.cwd, c.origin);
|
|
435
521
|
if (!filled.ok) {
|
|
436
522
|
await this.releasePod();
|
|
437
|
-
return
|
|
523
|
+
return this.seat.answer(filled);
|
|
438
524
|
}
|
|
439
525
|
}
|
|
440
526
|
if (this.destroyed) {
|
|
@@ -488,10 +574,6 @@ export class RemoteK8sExecutionEnv {
|
|
|
488
574
|
effect: "WORKSPACE_PERSIST=space, but the session store has no occupant (incarnation) for this run's session — its /workspace is neither restored nor saved (it is never keyed by the session id instead)",
|
|
489
575
|
});
|
|
490
576
|
}
|
|
491
|
-
holdRefusal(error) {
|
|
492
|
-
this.connectRefusal = { ok: false, error };
|
|
493
|
-
return this.connectRefusal;
|
|
494
|
-
}
|
|
495
577
|
refusePod(pod, phase, reason, message) {
|
|
496
578
|
this.logger?.warn("sandbox_pod_refused", {
|
|
497
579
|
pod,
|
|
@@ -501,19 +583,24 @@ export class RemoteK8sExecutionEnv {
|
|
|
501
583
|
...(this.cfg.sessionId ? { sessionId: this.cfg.sessionId } : {}),
|
|
502
584
|
effect: "the cluster created this run's sandbox pod and it ended before it ran — this run's operations answer the same refusal without creating another pod; a retry of the run builds a fresh sandbox",
|
|
503
585
|
});
|
|
504
|
-
return this.
|
|
586
|
+
return this.seat.answer(connectRefusal("pod_admission_refused", `pod entered ${phase} before Running (${reason ?? "?"}) — the cluster refused this run's sandbox pod; the refusal stands for the run (no pod is created again), a retry of the run asks the cluster afresh`));
|
|
505
587
|
}
|
|
506
588
|
refuseUnreadableOccupant(code) {
|
|
507
589
|
const ways = [...(this.spaceLane.state === "unreadable" ? ["WORKSPACE_PERSIST=off"] : []), ...(this.cacheLane.state === "unreadable" ? ["WORKSPACE_CACHE=off"] : [])].join(" and ");
|
|
590
|
+
const missing = code === SESSION_INCARNATION_MISSING;
|
|
508
591
|
if (!this.unreadableOccupantSaid) {
|
|
509
592
|
this.unreadableOccupantSaid = true;
|
|
510
593
|
this.logger?.warn("workspace_space_unreadable_occupant", {
|
|
511
594
|
sessionId: this.cfg.sessionId,
|
|
512
595
|
code,
|
|
513
|
-
effect:
|
|
596
|
+
effect: missing
|
|
597
|
+
? `the session row for this run carries no occupant (incarnation) token — this run is refused rather than started on a workspace that is neither restored nor saved; ${ways} runs without it`
|
|
598
|
+
: `the session store did not answer for this run's session occupant (incarnation) — this run is refused rather than started on a workspace that is neither restored nor saved; ${ways} runs without it`,
|
|
514
599
|
});
|
|
515
600
|
}
|
|
516
|
-
return
|
|
601
|
+
return missing
|
|
602
|
+
? this.seat.answer(connectRefusal("occupant_missing", `workspace space occupant read failed (${code}) — the session row carries no occupant token, so this run is not started on a workspace that could be neither restored nor saved; give the row its token or delete the session, or set ${ways}`))
|
|
603
|
+
: connectRefusal("occupant_unreadable", `workspace space occupant read failed (${code}) — refusing to start this run on a workspace that could be neither restored nor saved; retry the run once the session store answers, or set ${ways}`);
|
|
517
604
|
}
|
|
518
605
|
spaceLine(event, space, fields) {
|
|
519
606
|
this.snapshotLine(event, { space: incarnationLogPrefix(space.incarnation), ...fields });
|
|
@@ -524,8 +611,9 @@ export class RemoteK8sExecutionEnv {
|
|
|
524
611
|
provision(signal) {
|
|
525
612
|
const space = this.spaceLane;
|
|
526
613
|
const cache = this.cacheLane;
|
|
527
|
-
|
|
528
|
-
|
|
614
|
+
const held = this.seat.held;
|
|
615
|
+
if (held)
|
|
616
|
+
return Promise.resolve(held);
|
|
529
617
|
if (space.state === "unreadable")
|
|
530
618
|
return Promise.resolve(this.refuseUnreadableOccupant(space.code));
|
|
531
619
|
if (cache.state === "unreadable")
|
|
@@ -540,7 +628,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
540
628
|
const halt = signal ? AbortSignal.any([signal, refused.signal]) : refused.signal;
|
|
541
629
|
return withRetry(async () => {
|
|
542
630
|
const r = await once(signal);
|
|
543
|
-
if (!r.ok && this.
|
|
631
|
+
if (!r.ok && this.seat.held)
|
|
544
632
|
refused.abort();
|
|
545
633
|
return r;
|
|
546
634
|
}, policy, { signal: halt });
|
|
@@ -716,7 +804,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
716
804
|
const leaseName = broker !== undefined ? `${SANDBOX_LEASE_NAME_PREFIX}${randomUUID()}` : undefined;
|
|
717
805
|
const placeholder = broker !== undefined ? buildSandboxLeaseFile(broker.origins, placeholderLeaseEntries(broker.origins)) : undefined;
|
|
718
806
|
if (placeholder !== undefined && !placeholder.ok) {
|
|
719
|
-
return this.
|
|
807
|
+
return this.seat.answer(connectRefusal("credential_broker_refused", `the member-credential broker cannot be set up for this pod: ${placeholder.problem}`));
|
|
720
808
|
}
|
|
721
809
|
const layered = { ...(cache ? workspaceCacheEnv(cache.mount) : {}), ...(this.cfg.podEnv ?? {}) };
|
|
722
810
|
const envEntries = [
|
|
@@ -770,7 +858,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
770
858
|
applyPodSpecPatch(pod, this.cfg.podSpecPatch, { broker: true });
|
|
771
859
|
}
|
|
772
860
|
catch (e) {
|
|
773
|
-
return this.
|
|
861
|
+
return this.seat.answer(connectRefusal("credential_broker_refused", `${errorMessageOf(e)} — no pod is created (the member-credential broker never shares a pod with a patch that could reach it)`));
|
|
774
862
|
}
|
|
775
863
|
}
|
|
776
864
|
else if (this.cfg.podSpecPatch)
|
|
@@ -783,7 +871,8 @@ export class RemoteK8sExecutionEnv {
|
|
|
783
871
|
return { ok: false, error: new RemoteExecutionError("connect_failed", `pod create RPC failed: ${e instanceof Error ? e.message : String(e)}`, e instanceof Error ? e : undefined) };
|
|
784
872
|
}
|
|
785
873
|
if (created.status === 401 || created.status === 403) {
|
|
786
|
-
|
|
874
|
+
const denied = `pod create denied (${created.status}): ${JSON.stringify(created.json).slice(0, 200)}`;
|
|
875
|
+
return created.status === 403 && isQuotaExceeded(created.json) ? connectRefusal("pod_quota_exceeded", denied) : { ok: false, error: new RemoteExecutionError("auth_failed", denied) };
|
|
787
876
|
}
|
|
788
877
|
if (created.status >= 300) {
|
|
789
878
|
return { ok: false, error: new RemoteExecutionError("connect_failed", `pod create failed (${created.status}): ${JSON.stringify(created.json).slice(0, 300)}`) };
|
|
@@ -876,8 +965,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
876
965
|
if (verdict !== undefined) {
|
|
877
966
|
await this.deletePod(name).catch(() => { });
|
|
878
967
|
this.podName = undefined;
|
|
879
|
-
|
|
880
|
-
return verdict.answered ? this.holdRefusal(error) : { ok: false, error };
|
|
968
|
+
return verdict.answered ? this.seat.answer(connectRefusal("home_unconfirmed", verdict.refusal)) : { ok: false, error: new RemoteExecutionError("connect_failed", verdict.refusal) };
|
|
881
969
|
}
|
|
882
970
|
}
|
|
883
971
|
if (cache?.fresh)
|
|
@@ -990,12 +1078,13 @@ export class RemoteK8sExecutionEnv {
|
|
|
990
1078
|
if (snapshotKeyPrefixProblem(this.snapshotKeyPrefix()) !== undefined)
|
|
991
1079
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "unsafe snapshot key segment (keyPrefix): refusing to build a traversing object key") };
|
|
992
1080
|
const common = {
|
|
1081
|
+
op: snapshotOpOf(req),
|
|
993
1082
|
endpoint: s3.endpoint,
|
|
994
1083
|
bucket: s3.bucket,
|
|
995
1084
|
accessKey: s3.accessKey,
|
|
996
1085
|
secretKey: s3.secretKey,
|
|
997
1086
|
...(s3.region ? { region: s3.region } : {}),
|
|
998
|
-
expiresSec:
|
|
1087
|
+
...(s3.presignTtlSec !== undefined ? { expiresSec: s3.presignTtlSec } : {}),
|
|
999
1088
|
};
|
|
1000
1089
|
const base = this.snapshotBase(req);
|
|
1001
1090
|
if (req.method === "LIST")
|
|
@@ -1004,7 +1093,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
1004
1093
|
return { ok: true, value: presignS3Url({ ...common, key: `${base}${object}`, method: req.method }) };
|
|
1005
1094
|
}
|
|
1006
1095
|
snapshotKeyPrefix() {
|
|
1007
|
-
return this.cfg.s3Snapshot
|
|
1096
|
+
return workspaceSnapshotPrefixOf(this.cfg.s3Snapshot);
|
|
1008
1097
|
}
|
|
1009
1098
|
snapshotBase(req) {
|
|
1010
1099
|
const prefix = this.snapshotKeyPrefix();
|
|
@@ -1129,7 +1218,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
1129
1218
|
const detail = ` (${SNAPSHOT_BUCKET_MISSING}): the workspace snapshot bucket "${bucket}" (WORKSPACE_SNAPSHOT_BUCKET; default ${WORKSPACE_SNAPSHOT_BUCKET_DEFAULT}) does not exist in the object store — ` +
|
|
1130
1219
|
`refusing to start this run on a workspace that could be neither restored nor saved. Ways out: create the bucket, or set WORKSPACE_SNAPSHOT_BUCKET to one that exists, ` +
|
|
1131
1220
|
"or set WORKSPACE_PERSIST=off for a deployment that keeps no workspace between runs";
|
|
1132
|
-
return this.
|
|
1221
|
+
return this.seat.answer(connectRefusal("snapshot_bucket_missing", read === "pointer" ? `workspace space pointer read failed${detail}` : `workspace snapshot archive read failed${detail}`));
|
|
1133
1222
|
}
|
|
1134
1223
|
async readLatest(space, signal) {
|
|
1135
1224
|
const r = await this.readPointer(space, "latest", signal);
|
|
@@ -1391,7 +1480,7 @@ export class RemoteK8sExecutionEnv {
|
|
|
1391
1480
|
case "space": {
|
|
1392
1481
|
const tries = attempt === 1 ? "1 attempt" : `${attempt} attempts`;
|
|
1393
1482
|
this.spaceLine("workspace_restore_failed", target.space, { snapshotId, class: failure.cls, attempts: attempt, boundMs: this.cfg.dataTimeoutMs, error: failure.detail });
|
|
1394
|
-
return this.
|
|
1483
|
+
return this.seat.answer(connectRefusal("archive_unrecoverable", `${failure.detail} — the workspace's latest snapshot (${snapshotId}) is in the store but did not come back (${failure.cls}, ${tries}, bound ${this.cfg.dataTimeoutMs}ms each), ` +
|
|
1395
1484
|
"so this run does not start on an empty /workspace. Ways out: raise WORKSPACE_SNAPSHOT_TIMEOUT_MS if the archive is large, " +
|
|
1396
1485
|
"or set WORKSPACE_PERSIST=off for one run (it starts from an empty /workspace and deletes no snapshot)", failure.cause));
|
|
1397
1486
|
}
|
|
@@ -2263,6 +2352,14 @@ export class RemoteK8sExecutionEnv {
|
|
|
2263
2352
|
run: (cmd, abortSignal) => this.fsExec(cmd, abortSignal),
|
|
2264
2353
|
resolve: (p) => this.resolve(p),
|
|
2265
2354
|
tempDir: () => this.cwd,
|
|
2355
|
+
boundLane: {
|
|
2356
|
+
run: async (cmd, _cap, abortSignal) => {
|
|
2357
|
+
const r = await this.execData(cmd, abortSignal);
|
|
2358
|
+
return r.ok ? { ok: true, value: { stdout: Buffer.from(r.value.stdout, "utf8"), stderr: r.value.stderr, exitCode: r.value.exitCode } } : r;
|
|
2359
|
+
},
|
|
2360
|
+
payload: "base64",
|
|
2361
|
+
boundSec: this.cfg.dataTimeoutMs / 1000,
|
|
2362
|
+
},
|
|
2266
2363
|
}));
|
|
2267
2364
|
}
|
|
2268
2365
|
async fileInfo(p, abortSignal) {
|
|
@@ -2277,6 +2374,9 @@ export class RemoteK8sExecutionEnv {
|
|
|
2277
2374
|
async canonicalChain(p, abortSignal) {
|
|
2278
2375
|
return this.posixFs.canonicalChain(p, abortSignal);
|
|
2279
2376
|
}
|
|
2377
|
+
async openBound(p, abortSignal) {
|
|
2378
|
+
return this.posixFs.openBound(p, abortSignal);
|
|
2379
|
+
}
|
|
2280
2380
|
async canonicalPath(p, abortSignal) {
|
|
2281
2381
|
return this.posixFs.canonicalPath(p, abortSignal);
|
|
2282
2382
|
}
|
|
@@ -2403,6 +2503,12 @@ export function createSpaceReclaimer(config, deps) {
|
|
|
2403
2503
|
export async function checkSandboxEgressPolicy(config, deps) {
|
|
2404
2504
|
return new RemoteK8sExecutionEnv(config, deps).egressPolicyGaps();
|
|
2405
2505
|
}
|
|
2506
|
+
export function sandboxApiCredentialFact(config, deps) {
|
|
2507
|
+
return new RemoteK8sExecutionEnv(config, deps).missingApiCredential();
|
|
2508
|
+
}
|
|
2509
|
+
export async function readSandboxApiCredentials(config, deps) {
|
|
2510
|
+
return new RemoteK8sExecutionEnv(config, deps).apiCredentialReading();
|
|
2511
|
+
}
|
|
2406
2512
|
export async function readSandboxSecretSeat(config, seat, deps) {
|
|
2407
2513
|
return new RemoteK8sExecutionEnv(config, deps).secretSeatReading(seat);
|
|
2408
2514
|
}
|
|
@@ -2,7 +2,7 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { type LaneHomeConfig } from "../lane-home-probe.js";
|
|
3
3
|
import { type LaneLogger } from "./remote-shell.js";
|
|
4
4
|
import { type CustodyMember } from "./workspace-custody.js";
|
|
5
|
-
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, type ExecutionEnvCapabilities } from "@sema-agent/core";
|
|
5
|
+
import { FileError, ExecutionError, RemoteExecutionError, type ExecutionEnv, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type SymlinkChain, type BoundFileObject, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type VmLifecycleOptions, type ExecutionEnvFactory, type ExecutionEnvCapabilities } from "@sema-agent/core";
|
|
6
6
|
import { type SandboxReadFloorKnob } from "../execution-lane-caps.js";
|
|
7
7
|
import { type SandboxReadFloor } from "./sandbox-read-floor.js";
|
|
8
8
|
import type { WorkspaceFill, WorkspaceFillOf } from "./workspace-fill.js";
|
|
@@ -140,9 +140,12 @@ export declare class RemoteLocalDockerExecutionEnv implements CustodyMember<Loca
|
|
|
140
140
|
private destroyed;
|
|
141
141
|
/** In-flight connect, memoized so concurrent lazy first-use starts exactly one container (no double-run). */
|
|
142
142
|
private connecting?;
|
|
143
|
-
/**
|
|
144
|
-
*
|
|
145
|
-
|
|
143
|
+
/**
|
|
144
|
+
* 建连座(`remote-env-connect-seat.ts`):`connect` 的唯一次序(记住的拒 ⇒ 原样再答 · 起容器在飞 ⇒ 等那一次 · 已连 ⇒ 当下的把手 · 否则起或附着一只),并持有这只环境记住的拒 ——
|
|
145
|
+
* 记一次、此后每次连接原样回它(同一镜像同一答案:不再起容器、不再问)。两件立定的事实写它:家目录(环境答了而与声明不一致;`env.home_unconfirmed`)
|
|
146
|
+
* 与恢复点的填充(换一只容器也是同一个答的拒:种子不是项目包、摘要不符、镜像没有 `tar`、镜像预置撞名 —— `FillOutcome.standing`;`env.sandbox_refused`)。
|
|
147
|
+
*/
|
|
148
|
+
private readonly seat;
|
|
146
149
|
/** 家目录的座(声明在场 ⇒ 开环境那一拍对证 · 否则开容器那一拍实测 · 实测缺席 ⇒ 缺席 + 一行 warn)。与其余读得出家目录的车道同一只判官、同一句拒。 */
|
|
147
150
|
private readonly homeSeat;
|
|
148
151
|
/** 本环境的生命期信号:{@link destroy} 先断它 —— 在帽前等空位的那一次起动立刻收场(不拖满预算)。 */
|
|
@@ -171,7 +174,7 @@ export declare class RemoteLocalDockerExecutionEnv implements CustodyMember<Loca
|
|
|
171
174
|
ok: false;
|
|
172
175
|
error: RemoteExecutionError;
|
|
173
176
|
}>;
|
|
174
|
-
/** 一只在飞的连接(并发的首用调用方 / 附着都 join 它 —— 只起一只容器、只附着一次)
|
|
177
|
+
/** 一只在飞的连接(并发的首用调用方 / 附着都 join 它 —— 只起一只容器、只附着一次);落定即清(按身份):连上 = `containerId`,失败 ⇒ 下一次重来。 */
|
|
175
178
|
private connectOnce;
|
|
176
179
|
/**
|
|
177
180
|
* 先问 daemon 这只身份的容器({@link sightContainer}),再按它的样子(状态闭集,穷举):
|
|
@@ -214,8 +217,8 @@ export declare class RemoteLocalDockerExecutionEnv implements CustodyMember<Loca
|
|
|
214
217
|
private fillChannel;
|
|
215
218
|
/**
|
|
216
219
|
* 家目录:座要问({@link LaneHomeSeat.asks}:声明在场 ⇒ 对证;没声明 ⇒ 实测)⇒ 在本容器里问一次 `$HOME`(与命令同一条 `docker exec` 通道、同一份 `-e` env),读数交座。
|
|
217
|
-
* 声明在场:环境答了而不一致 / 不是绝对路径 ⇒
|
|
218
|
-
*
|
|
220
|
+
* 声明在场:环境答了而不一致 / 不是绝对路径 ⇒ 立定的拒(`env.home_unconfirmed`,建连座记住它:同一镜像同一答案,此后每次连接原样回它,不再起容器、不再问);
|
|
221
|
+
* 没答上(exec 失败 / 超时 / 非零退出)⇒ 这一次同样不开(`connect_failed`),但不记(与任何一次起容器失败同:下一次连接重问)。没声明:座收下绝对路径;答不上 / 不是绝对路径 ⇒ 座缺席 + 一行 warn,环境照开(没声明就没有声明可拒)。
|
|
219
222
|
* 调用方中止 ⇒ `aborted`、不记、不交座。容器由调用方收。
|
|
220
223
|
*/
|
|
221
224
|
private homeVerdict;
|
|
@@ -306,7 +309,7 @@ export declare class RemoteLocalDockerExecutionEnv implements CustodyMember<Loca
|
|
|
306
309
|
private get posixFs();
|
|
307
310
|
/** 文件面的一次容器内 shell 往返(基座、暂存写的准备 / 上传 / 提交 / 清理共用)。承 fsReady 契约(其余三腿走公有 exec、守卫天然在;本腿直用私有
|
|
308
311
|
* docker,必须自带):destroyed 守卫 + 懒连接,fail closed 不抛 —— 消息保留 "destroyed" 字样(测试钉的就是它)。`input` 在场 ⇒ 同一只 argv 多一个
|
|
309
|
-
* `-i`、载荷走 stdin({@link pipeIn})
|
|
312
|
+
* `-i`、载荷走 stdin({@link pipeIn});身份与工作目录与不带载荷的往返逐字相同。`binary` ⇒ stdout 逐字节收(`stdoutBytes`,绑定读的载荷;与 readBinaryFile 同一收集器)。 */
|
|
310
313
|
private fsExec;
|
|
311
314
|
fileInfo(p: string, abortSignal?: AbortSignal): Promise<Result<FileInfo, FileError>>;
|
|
312
315
|
listDir(p: string, abortSignal?: AbortSignal): Promise<Result<FileInfo[], FileError>>;
|
|
@@ -315,6 +318,8 @@ export declare class RemoteLocalDockerExecutionEnv implements CustodyMember<Loca
|
|
|
315
318
|
* 循环(上限 64、只锚不折、遇环即止),脚本与读法的单一属主在 `remote-shell.ts`,四条 shell 腿共用同一份。
|
|
316
319
|
* 缺席读法用不上(本腿在场);`ok:false` 由 core 读作「这一次没有跳」,永不是拒绝。 */
|
|
317
320
|
canonicalChain(p: string, abortSignal?: AbortSignal): Promise<Result<SymlinkChain, FileError>>;
|
|
321
|
+
/** 绑定读(逐答重绑,Linux 读法;脚本与读法的单一属主在 `remote-shell.ts`,四条 shell 腿共用同一份)。 */
|
|
322
|
+
openBound(p: string, abortSignal?: AbortSignal): Promise<Result<BoundFileObject, FileError>>;
|
|
318
323
|
canonicalPath(p: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
|
|
319
324
|
exists(p: string, abortSignal?: AbortSignal): Promise<Result<boolean, FileError>>;
|
|
320
325
|
createDir(p: string, options?: {
|
|
@@ -13,6 +13,7 @@ import { FileError, ExecutionError, RemoteExecutionError, RollingTailBuffer, mar
|
|
|
13
13
|
import { capabilitiesFor } from "../execution-lane-caps.js";
|
|
14
14
|
import { ADAPTER_START, BOOTSTRAP_START, createSandboxReadFloor, dockerIdentityFlags, engineStart, floorArgv, } from "./sandbox-read-floor.js";
|
|
15
15
|
import { fileErrorFromExec, classifyFsStderr } from "./remote-env-file-error.js";
|
|
16
|
+
import { connectRefusal, createConnectSeat, withdrawOnAbort } from "./remote-env-connect-seat.js";
|
|
16
17
|
import { createPosixShellFs } from "./posix-shell-fs.js";
|
|
17
18
|
const PROVIDER = "local-docker";
|
|
18
19
|
const DEFAULT_MOUNT_PATH = "/workspace";
|
|
@@ -49,7 +50,11 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
49
50
|
handle;
|
|
50
51
|
destroyed = false;
|
|
51
52
|
connecting;
|
|
52
|
-
|
|
53
|
+
seat = createConnectSeat({
|
|
54
|
+
live: () => (this.containerId !== undefined ? this.workspaceHandle() : undefined),
|
|
55
|
+
inFlight: () => this.connecting,
|
|
56
|
+
establish: (config) => this.connectOnce(config, "start-or-attach"),
|
|
57
|
+
});
|
|
53
58
|
homeSeat;
|
|
54
59
|
lifecycle = new AbortController();
|
|
55
60
|
capacityDeadline;
|
|
@@ -100,20 +105,15 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
100
105
|
return unsupported("connect(snapshotId)");
|
|
101
106
|
if (this.destroyed)
|
|
102
107
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env already destroyed") };
|
|
103
|
-
|
|
104
|
-
return { ok: false, error: this.connectRefusal };
|
|
105
|
-
if (config?.abortSignal?.aborted)
|
|
106
|
-
return { ok: false, error: new RemoteExecutionError("aborted", "connect aborted") };
|
|
107
|
-
if (this.containerId)
|
|
108
|
-
return ok(this.workspaceHandle());
|
|
109
|
-
return this.connectOnce(config, "start-or-attach");
|
|
108
|
+
return this.seat.connect(config);
|
|
110
109
|
}
|
|
111
110
|
async connectOnce(config, mode) {
|
|
112
111
|
if (this.connecting)
|
|
113
112
|
return this.connecting;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
const mine = this.doConnect(config, mode);
|
|
114
|
+
this.connecting = mine;
|
|
115
|
+
const r = await mine;
|
|
116
|
+
if (this.connecting === mine)
|
|
117
117
|
this.connecting = undefined;
|
|
118
118
|
return r;
|
|
119
119
|
}
|
|
@@ -230,11 +230,8 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
230
230
|
if (this.destroyed)
|
|
231
231
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during connect") };
|
|
232
232
|
const filled = await this.fillWorkspace("restored");
|
|
233
|
-
if (!filled.ok)
|
|
234
|
-
|
|
235
|
-
this.connectRefusal = filled.error;
|
|
236
|
-
return { ok: false, error: filled.error };
|
|
237
|
-
}
|
|
233
|
+
if (!filled.ok)
|
|
234
|
+
return this.seat.answer(filled);
|
|
238
235
|
if (this.destroyed)
|
|
239
236
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during connect") };
|
|
240
237
|
this.containerId = id;
|
|
@@ -299,9 +296,7 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
299
296
|
const filled = await this.fillWorkspace("minted");
|
|
300
297
|
if (!filled.ok || this.destroyed) {
|
|
301
298
|
await this.removeInstance(id);
|
|
302
|
-
|
|
303
|
-
this.connectRefusal = filled.error;
|
|
304
|
-
return { ok: false, error: filled.ok ? new RemoteExecutionError("connect_failed", "execution env destroyed during connect") : filled.error };
|
|
299
|
+
return filled.ok ? { ok: false, error: new RemoteExecutionError("connect_failed", "execution env destroyed during connect") } : this.seat.answer(filled);
|
|
305
300
|
}
|
|
306
301
|
this.containerId = id;
|
|
307
302
|
this.handle = { sandboxId: this.containerName, provider: PROVIDER, mountPath: this.cfg.mountPath, sessionToken: this.containerName };
|
|
@@ -356,10 +351,7 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
356
351
|
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 });
|
|
357
352
|
if (verdict === undefined)
|
|
358
353
|
return undefined;
|
|
359
|
-
|
|
360
|
-
if (verdict.answered)
|
|
361
|
-
this.connectRefusal = error;
|
|
362
|
-
return error;
|
|
354
|
+
return verdict.answered ? this.seat.answer(connectRefusal("home_unconfirmed", verdict.refusal)).error : new RemoteExecutionError("connect_failed", verdict.refusal);
|
|
363
355
|
}
|
|
364
356
|
async suspendVM(_options) {
|
|
365
357
|
return unsupported("suspendVM");
|
|
@@ -373,8 +365,9 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
373
365
|
async reconnect(sessionToken) {
|
|
374
366
|
if (this.destroyed)
|
|
375
367
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "execution env already destroyed") };
|
|
376
|
-
|
|
377
|
-
|
|
368
|
+
const held = this.seat.held;
|
|
369
|
+
if (held)
|
|
370
|
+
return held;
|
|
378
371
|
if (sessionToken && sessionToken !== this.containerName) {
|
|
379
372
|
return { ok: false, error: new RemoteExecutionError("connect_failed", `reconnect token '${String(sessionToken)}' does not match this env's container '${this.containerName}'`) };
|
|
380
373
|
}
|
|
@@ -666,7 +659,7 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
666
659
|
return appendFileStaged(this.stagedLane(content), abs, abortSignal, readyUpload((dest, signal) => this.pipeIn(content, dest, signal, ">>")));
|
|
667
660
|
}
|
|
668
661
|
async pipeIn(content, dest, abortSignal, redirect = ">") {
|
|
669
|
-
const r = await this.fsExec(`cat ${redirect} ${shellQuote(dest)}`, abortSignal, typeof content === "string" ? Buffer.from(content, "utf8") : content);
|
|
662
|
+
const r = await this.fsExec(`cat ${redirect} ${shellQuote(dest)}`, abortSignal, { input: typeof content === "string" ? Buffer.from(content, "utf8") : content });
|
|
670
663
|
if (!r.ok)
|
|
671
664
|
return { ok: false, error: fileErrorFromExec(r.error, dest) };
|
|
672
665
|
if (r.value.exitCode !== 0)
|
|
@@ -679,9 +672,18 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
679
672
|
run: (cmd, abortSignal) => this.fsExec(cmd, abortSignal),
|
|
680
673
|
resolve: (p) => this.resolve(p),
|
|
681
674
|
tempDir: () => this.cwd,
|
|
675
|
+
boundLane: {
|
|
676
|
+
run: async (cmd, _cap, abortSignal) => {
|
|
677
|
+
const r = await this.fsExec(cmd, abortSignal, { binary: true });
|
|
678
|
+
return r.ok ? { ok: true, value: { stdout: r.value.stdoutBytes ?? new Uint8Array(), stderr: r.value.stderr, exitCode: r.value.exitCode } } : r;
|
|
679
|
+
},
|
|
680
|
+
payload: "raw",
|
|
681
|
+
boundSec: this.cfg.commandTimeoutMs / 1000,
|
|
682
|
+
},
|
|
682
683
|
}));
|
|
683
684
|
}
|
|
684
|
-
async fsExec(cmd, abortSignal,
|
|
685
|
+
async fsExec(cmd, abortSignal, o = {}) {
|
|
686
|
+
const input = o.input;
|
|
685
687
|
if (this.destroyed)
|
|
686
688
|
return { ok: false, error: new ExecutionError("shell_unavailable", "execution env already destroyed") };
|
|
687
689
|
if (!this.containerId) {
|
|
@@ -694,7 +696,7 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
694
696
|
const argv = this.startArgv(ADAPTER_START, cmd, { stdin: input !== undefined });
|
|
695
697
|
if (!argv.ok)
|
|
696
698
|
return argv;
|
|
697
|
-
return this.docker(argv.value, { signal: abortSignal, timeoutMs: this.cfg.commandTimeoutMs, ...(input !== undefined ? { input } : {}) });
|
|
699
|
+
return this.docker(argv.value, { signal: abortSignal, timeoutMs: this.cfg.commandTimeoutMs, ...(input !== undefined ? { input } : {}), ...(o.binary === true ? { binary: true } : {}) });
|
|
698
700
|
}
|
|
699
701
|
async fileInfo(p, abortSignal) {
|
|
700
702
|
return this.posixFs.statFileInfo(p, abortSignal);
|
|
@@ -708,6 +710,9 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
708
710
|
async canonicalChain(p, abortSignal) {
|
|
709
711
|
return this.posixFs.canonicalChain(p, abortSignal);
|
|
710
712
|
}
|
|
713
|
+
async openBound(p, abortSignal) {
|
|
714
|
+
return this.posixFs.openBound(p, abortSignal);
|
|
715
|
+
}
|
|
711
716
|
async canonicalPath(p, abortSignal) {
|
|
712
717
|
return this.posixFs.canonicalPath(p, abortSignal);
|
|
713
718
|
}
|
|
@@ -882,19 +887,7 @@ export class RemoteLocalDockerExecutionEnv {
|
|
|
882
887
|
});
|
|
883
888
|
}
|
|
884
889
|
joinConnect(signal) {
|
|
885
|
-
|
|
886
|
-
if (signal === undefined)
|
|
887
|
-
return shared;
|
|
888
|
-
if (signal.aborted)
|
|
889
|
-
return Promise.resolve({ ok: false, error: new RemoteExecutionError("aborted", "aborted while connecting") });
|
|
890
|
-
return new Promise((resolve) => {
|
|
891
|
-
const onAbort = () => resolve({ ok: false, error: new RemoteExecutionError("aborted", "aborted while connecting") });
|
|
892
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
893
|
-
void shared.then((r) => {
|
|
894
|
-
signal.removeEventListener("abort", onAbort);
|
|
895
|
-
resolve(r);
|
|
896
|
-
});
|
|
897
|
-
});
|
|
890
|
+
return withdrawOnAbort(this.connect(), signal);
|
|
898
891
|
}
|
|
899
892
|
containerShell = "/bin/sh";
|
|
900
893
|
containerShellReady;
|