@elie-laloum/outpost 2.0.0 → 4.0.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/CHANGELOG.md +42 -0
- package/README.md +3 -1
- package/SECURITY.md +3 -1
- package/dist/adapters/agents/claude-diagnostics.d.ts +1 -0
- package/dist/adapters/agents/claude-diagnostics.js +7 -0
- package/dist/adapters/agents/claude-diagnostics.js.map +1 -0
- package/dist/adapters/agents/cli-diagnostics.constants.d.ts +12 -0
- package/dist/adapters/agents/cli-diagnostics.constants.js +24 -0
- package/dist/adapters/agents/cli-diagnostics.constants.js.map +1 -0
- package/dist/adapters/agents/cli-diagnostics.d.ts +4 -0
- package/dist/adapters/agents/cli-diagnostics.js +14 -0
- package/dist/adapters/agents/cli-diagnostics.js.map +1 -0
- package/dist/adapters/agents/cli-diagnostics.types.d.ts +13 -0
- package/dist/adapters/agents/cli-diagnostics.types.js +2 -0
- package/dist/adapters/agents/cli-diagnostics.types.js.map +1 -0
- package/dist/adapters/agents/codex-diagnostics.d.ts +1 -0
- package/dist/adapters/agents/codex-diagnostics.js +7 -0
- package/dist/adapters/agents/codex-diagnostics.js.map +1 -0
- package/dist/adapters/agents/gemini-adapter.d.ts +3 -0
- package/dist/adapters/agents/gemini-adapter.js +15 -0
- package/dist/adapters/agents/gemini-adapter.js.map +1 -0
- package/dist/adapters/agents/gemini-diagnostics.d.ts +2 -0
- package/dist/adapters/agents/gemini-diagnostics.js +15 -0
- package/dist/adapters/agents/gemini-diagnostics.js.map +1 -0
- package/dist/adapters/agents/gemini-events.d.ts +2 -0
- package/dist/adapters/agents/gemini-events.js +50 -0
- package/dist/adapters/agents/gemini-events.js.map +1 -0
- package/dist/adapters/agents/gemini-request.d.ts +4 -0
- package/dist/adapters/agents/gemini-request.js +21 -0
- package/dist/adapters/agents/gemini-request.js.map +1 -0
- package/dist/adapters/agents/gemini.types.d.ts +6 -0
- package/dist/adapters/agents/gemini.types.js +2 -0
- package/dist/adapters/agents/gemini.types.js.map +1 -0
- package/dist/adapters/agents/protocol-fixtures.constants.d.ts +2 -0
- package/dist/adapters/agents/protocol-fixtures.constants.js +105 -0
- package/dist/adapters/agents/protocol-fixtures.constants.js.map +1 -0
- package/dist/adapters/agents/protocol-fixtures.types.d.ts +6 -0
- package/dist/adapters/agents/protocol-fixtures.types.js +2 -0
- package/dist/adapters/agents/protocol-fixtures.types.js.map +1 -0
- package/dist/application/agent-bootstrap.constants.d.ts +1 -0
- package/dist/application/agent-bootstrap.constants.js +1 -0
- package/dist/application/agent-bootstrap.constants.js.map +1 -1
- package/dist/application/agent-bootstrap.js +6 -2
- package/dist/application/agent-bootstrap.js.map +1 -1
- package/dist/application/agent-output.js +9 -2
- package/dist/application/agent-output.js.map +1 -1
- package/dist/application/artifact-tasks.d.ts +5 -0
- package/dist/application/artifact-tasks.js +31 -0
- package/dist/application/artifact-tasks.js.map +1 -0
- package/dist/application/artifact-tasks.types.d.ts +8 -0
- package/dist/application/artifact-tasks.types.js +2 -0
- package/dist/application/artifact-tasks.types.js.map +1 -0
- package/dist/application/diagnostic-probe.d.ts +3 -0
- package/dist/application/diagnostic-probe.js +55 -0
- package/dist/application/diagnostic-probe.js.map +1 -0
- package/dist/application/dispatch-validation.js +2 -0
- package/dist/application/dispatch-validation.js.map +1 -1
- package/dist/application/doctor-agent.constants.d.ts +11 -0
- package/dist/application/doctor-agent.constants.js +10 -0
- package/dist/application/doctor-agent.constants.js.map +1 -0
- package/dist/application/doctor-agent.d.ts +3 -0
- package/dist/application/doctor-agent.js +53 -0
- package/dist/application/doctor-agent.js.map +1 -0
- package/dist/application/doctor-image.d.ts +3 -0
- package/dist/application/doctor-image.js +133 -0
- package/dist/application/doctor-image.js.map +1 -0
- package/dist/application/doctor-protocol.d.ts +3 -0
- package/dist/application/doctor-protocol.js +30 -0
- package/dist/application/doctor-protocol.js.map +1 -0
- package/dist/application/doctor-protocol.types.d.ts +10 -0
- package/dist/application/doctor-protocol.types.js +2 -0
- package/dist/application/doctor-protocol.types.js.map +1 -0
- package/dist/application/doctor-sandbox.constants.d.ts +5 -0
- package/dist/application/doctor-sandbox.constants.js +6 -0
- package/dist/application/doctor-sandbox.constants.js.map +1 -0
- package/dist/application/doctor-sandbox.d.ts +4 -0
- package/dist/application/doctor-sandbox.js +133 -0
- package/dist/application/doctor-sandbox.js.map +1 -0
- package/dist/application/doctor-sandbox.types.d.ts +23 -0
- package/dist/application/doctor-sandbox.types.js +2 -0
- package/dist/application/doctor-sandbox.types.js.map +1 -0
- package/dist/application/doctor-transfers.constants.d.ts +6 -0
- package/dist/application/doctor-transfers.constants.js +7 -0
- package/dist/application/doctor-transfers.constants.js.map +1 -0
- package/dist/application/doctor-transfers.d.ts +4 -0
- package/dist/application/doctor-transfers.js +88 -0
- package/dist/application/doctor-transfers.js.map +1 -0
- package/dist/application/doctor.constants.d.ts +9 -0
- package/dist/application/doctor.constants.js +15 -0
- package/dist/application/doctor.constants.js.map +1 -0
- package/dist/application/doctor.d.ts +3 -0
- package/dist/application/doctor.js +106 -0
- package/dist/application/doctor.js.map +1 -0
- package/dist/application/doctor.types.d.ts +39 -0
- package/dist/application/doctor.types.js +2 -0
- package/dist/application/doctor.types.js.map +1 -0
- package/dist/application/execution.js +1 -0
- package/dist/application/execution.js.map +1 -1
- package/dist/application/outpost.types.d.ts +4 -0
- package/dist/application/outpost.types.js.map +1 -1
- package/dist/application/queue-worker.d.ts +2 -0
- package/dist/application/queue-worker.js +75 -0
- package/dist/application/queue-worker.js.map +1 -0
- package/dist/application/queue-worker.types.d.ts +15 -0
- package/dist/application/queue-worker.types.js +2 -0
- package/dist/application/queue-worker.types.js.map +1 -0
- package/dist/application/queued-task.d.ts +3 -0
- package/dist/application/queued-task.js +56 -0
- package/dist/application/queued-task.js.map +1 -0
- package/dist/application/queued-task.types.d.ts +11 -0
- package/dist/application/queued-task.types.js +2 -0
- package/dist/application/queued-task.types.js.map +1 -0
- package/dist/application/recovery-checksum-capture.d.ts +2 -0
- package/dist/application/recovery-checksum-capture.js +32 -0
- package/dist/application/recovery-checksum-capture.js.map +1 -0
- package/dist/application/recovery-checksum-paths.d.ts +2 -0
- package/dist/application/recovery-checksum-paths.js +11 -0
- package/dist/application/recovery-checksum-paths.js.map +1 -0
- package/dist/application/recovery-checksums.constants.d.ts +5 -0
- package/dist/application/recovery-checksums.constants.js +6 -0
- package/dist/application/recovery-checksums.constants.js.map +1 -0
- package/dist/application/recovery-checksums.d.ts +3 -0
- package/dist/application/recovery-checksums.js +94 -0
- package/dist/application/recovery-checksums.js.map +1 -0
- package/dist/application/recovery-checksums.types.d.ts +17 -0
- package/dist/application/recovery-checksums.types.js +2 -0
- package/dist/application/recovery-checksums.types.js.map +1 -0
- package/dist/application/recovery-inspection.d.ts +2 -0
- package/dist/application/recovery-inspection.js +32 -0
- package/dist/application/recovery-inspection.js.map +1 -0
- package/dist/application/recovery-inspection.types.d.ts +18 -0
- package/dist/application/recovery-inspection.types.js +2 -0
- package/dist/application/recovery-inspection.types.js.map +1 -0
- package/dist/application/recovery-restorability.d.ts +2 -0
- package/dist/application/recovery-restorability.js +137 -0
- package/dist/application/recovery-restorability.js.map +1 -0
- package/dist/application/recovery-restore-snapshot.d.ts +2 -0
- package/dist/application/recovery-restore-snapshot.js +57 -0
- package/dist/application/recovery-restore-snapshot.js.map +1 -0
- package/dist/application/recovery-restore.d.ts +3 -0
- package/dist/application/recovery-restore.js +161 -0
- package/dist/application/recovery-restore.js.map +1 -0
- package/dist/application/recovery-restore.types.d.ts +28 -0
- package/dist/application/recovery-restore.types.js +2 -0
- package/dist/application/recovery-restore.types.js.map +1 -0
- package/dist/application/recovery-retention-policy.d.ts +2 -0
- package/dist/application/recovery-retention-policy.js +21 -0
- package/dist/application/recovery-retention-policy.js.map +1 -0
- package/dist/application/recovery-retention.constants.d.ts +3 -0
- package/dist/application/recovery-retention.constants.js +2 -0
- package/dist/application/recovery-retention.constants.js.map +1 -0
- package/dist/application/recovery-retention.d.ts +4 -0
- package/dist/application/recovery-retention.js +207 -0
- package/dist/application/recovery-retention.js.map +1 -0
- package/dist/application/recovery-retention.types.d.ts +52 -0
- package/dist/application/recovery-retention.types.js +2 -0
- package/dist/application/recovery-retention.types.js.map +1 -0
- package/dist/application/recovery-verification.constants.d.ts +5 -0
- package/dist/application/recovery-verification.constants.js +10 -0
- package/dist/application/recovery-verification.constants.js.map +1 -0
- package/dist/application/recovery-verification.d.ts +3 -0
- package/dist/application/recovery-verification.js +107 -0
- package/dist/application/recovery-verification.js.map +1 -0
- package/dist/application/recovery-verification.types.d.ts +26 -0
- package/dist/application/recovery-verification.types.js +2 -0
- package/dist/application/recovery-verification.types.js.map +1 -0
- package/dist/application/remote-apply.js +30 -6
- package/dist/application/remote-apply.js.map +1 -1
- package/dist/application/remote-backup.js +6 -2
- package/dist/application/remote-backup.js.map +1 -1
- package/dist/application/remote-download.js +38 -6
- package/dist/application/remote-download.js.map +1 -1
- package/dist/application/remote-history.d.ts +6 -0
- package/dist/application/remote-history.js +114 -0
- package/dist/application/remote-history.js.map +1 -0
- package/dist/application/remote-upload.d.ts +2 -0
- package/dist/application/remote-upload.js +17 -0
- package/dist/application/remote-upload.js.map +1 -0
- package/dist/application/remote-validation.js +39 -28
- package/dist/application/remote-validation.js.map +1 -1
- package/dist/application/remote-workspace.constants.d.ts +3 -0
- package/dist/application/remote-workspace.constants.js +2 -0
- package/dist/application/remote-workspace.constants.js.map +1 -0
- package/dist/application/remote-workspace.js +10 -10
- package/dist/application/remote-workspace.js.map +1 -1
- package/dist/application/remote-workspace.types.d.ts +3 -1
- package/dist/application/remote-workspace.types.js.map +1 -1
- package/dist/application/sandbox-activity.d.ts +3 -0
- package/dist/application/sandbox-activity.js +25 -0
- package/dist/application/sandbox-activity.js.map +1 -0
- package/dist/application/sandbox-provision.js +55 -10
- package/dist/application/sandbox-provision.js.map +1 -1
- package/dist/application/sandbox-session.types.d.ts +2 -0
- package/dist/application/sandbox-session.types.js.map +1 -1
- package/dist/application/sandbox.js +33 -10
- package/dist/application/sandbox.js.map +1 -1
- package/dist/application/speculation-host.d.ts +2 -0
- package/dist/application/speculation-host.js +30 -0
- package/dist/application/speculation-host.js.map +1 -0
- package/dist/application/speculation.constants.d.ts +4 -0
- package/dist/application/speculation.constants.js +2 -0
- package/dist/application/speculation.constants.js.map +1 -0
- package/dist/application/speculation.d.ts +2 -0
- package/dist/application/speculation.js +166 -0
- package/dist/application/speculation.js.map +1 -0
- package/dist/application/speculation.types.d.ts +56 -0
- package/dist/application/speculation.types.js +2 -0
- package/dist/application/speculation.types.js.map +1 -0
- package/dist/application/storage-reservation.d.ts +3 -0
- package/dist/application/storage-reservation.js +10 -0
- package/dist/application/storage-reservation.js.map +1 -0
- package/dist/application/storage-reservation.types.d.ts +4 -0
- package/dist/application/storage-reservation.types.js +2 -0
- package/dist/application/storage-reservation.types.js.map +1 -0
- package/dist/application/task-usage.d.ts +4 -0
- package/dist/application/task-usage.js +41 -0
- package/dist/application/task-usage.js.map +1 -0
- package/dist/application/task-usage.types.d.ts +5 -0
- package/dist/application/task-usage.types.js +2 -0
- package/dist/application/task-usage.types.js.map +1 -0
- package/dist/application/tasks.js +23 -2
- package/dist/application/tasks.js.map +1 -1
- package/dist/application/tasks.types.d.ts +4 -3
- package/dist/application/tasks.types.js.map +1 -1
- package/dist/application/workspace-allocation.d.ts +3 -0
- package/dist/application/workspace-allocation.js +34 -0
- package/dist/application/workspace-allocation.js.map +1 -0
- package/dist/application/workspace.js +2 -2
- package/dist/application/workspace.js.map +1 -1
- package/dist/cli/commands.js +4 -0
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/doctor-command.d.ts +3 -0
- package/dist/cli/doctor-command.js +38 -0
- package/dist/cli/doctor-command.js.map +1 -0
- package/dist/cli/main.constants.d.ts +38 -2
- package/dist/cli/main.constants.js +21 -2
- package/dist/cli/main.constants.js.map +1 -1
- package/dist/cli/recovery-command.d.ts +2 -0
- package/dist/cli/recovery-command.js +93 -0
- package/dist/cli/recovery-command.js.map +1 -0
- package/dist/cli/recovery-prune-command.d.ts +2 -0
- package/dist/cli/recovery-prune-command.js +34 -0
- package/dist/cli/recovery-prune-command.js.map +1 -0
- package/dist/cli/recovery-restore-command.d.ts +2 -0
- package/dist/cli/recovery-restore-command.js +34 -0
- package/dist/cli/recovery-restore-command.js.map +1 -0
- package/dist/cli/recovery-verify-command.d.ts +2 -0
- package/dist/cli/recovery-verify-command.js +43 -0
- package/dist/cli/recovery-verify-command.js.map +1 -0
- package/dist/cli/scaffold-files.js +2 -2
- package/dist/cli/scaffold-files.js.map +1 -1
- package/dist/cli/scaffold-validation.js +1 -1
- package/dist/cli/scaffold-validation.js.map +1 -1
- package/dist/cli/scaffold.constants.d.ts +5 -0
- package/dist/cli/scaffold.constants.js +7 -2
- package/dist/cli/scaffold.constants.js.map +1 -1
- package/dist/cli/scaffold.types.d.ts +1 -1
- package/dist/cli/scaffold.types.js.map +1 -1
- package/dist/domain/agent.types.d.ts +2 -0
- package/dist/domain/agent.types.js.map +1 -1
- package/dist/domain/artifact-reference.d.ts +4 -0
- package/dist/domain/artifact-reference.js +90 -0
- package/dist/domain/artifact-reference.js.map +1 -0
- package/dist/domain/artifact.constants.d.ts +2 -0
- package/dist/domain/artifact.constants.js +3 -0
- package/dist/domain/artifact.constants.js.map +1 -0
- package/dist/domain/artifact.d.ts +7 -0
- package/dist/domain/artifact.js +104 -0
- package/dist/domain/artifact.js.map +1 -0
- package/dist/domain/artifact.types.d.ts +44 -0
- package/dist/domain/artifact.types.js +2 -0
- package/dist/domain/artifact.types.js.map +1 -0
- package/dist/domain/egress.constants.d.ts +1 -0
- package/dist/domain/egress.constants.js +7 -0
- package/dist/domain/egress.constants.js.map +1 -0
- package/dist/domain/egress.d.ts +2 -0
- package/dist/domain/egress.js +48 -0
- package/dist/domain/egress.js.map +1 -0
- package/dist/domain/egress.types.d.ts +8 -0
- package/dist/domain/egress.types.js +2 -0
- package/dist/domain/egress.types.js.map +1 -0
- package/dist/domain/ports.d.ts +1 -1
- package/dist/domain/ports.js.map +1 -1
- package/dist/domain/sandbox.types.d.ts +13 -0
- package/dist/domain/sandbox.types.js.map +1 -1
- package/dist/domain/task-queue.constants.d.ts +8 -0
- package/dist/domain/task-queue.constants.js +9 -0
- package/dist/domain/task-queue.constants.js.map +1 -0
- package/dist/domain/task-queue.d.ts +11 -0
- package/dist/domain/task-queue.js +105 -0
- package/dist/domain/task-queue.js.map +1 -0
- package/dist/domain/task-queue.types.d.ts +41 -0
- package/dist/domain/task-queue.types.js +2 -0
- package/dist/domain/task-queue.types.js.map +1 -0
- package/dist/domain/workflow/budget.constants.d.ts +1 -0
- package/dist/domain/workflow/budget.constants.js +7 -0
- package/dist/domain/workflow/budget.constants.js.map +1 -0
- package/dist/domain/workflow/budget.d.ts +9 -0
- package/dist/domain/workflow/budget.js +69 -0
- package/dist/domain/workflow/budget.js.map +1 -0
- package/dist/domain/workflow/budget.types.d.ts +15 -0
- package/dist/domain/workflow/budget.types.js +2 -0
- package/dist/domain/workflow/budget.types.js.map +1 -0
- package/dist/domain/workflow/checkpoint-validation.d.ts +3 -0
- package/dist/domain/workflow/checkpoint-validation.js +81 -0
- package/dist/domain/workflow/checkpoint-validation.js.map +1 -0
- package/dist/domain/workflow/checkpoint-value.d.ts +2 -0
- package/dist/domain/workflow/checkpoint-value.js +49 -0
- package/dist/domain/workflow/checkpoint-value.js.map +1 -0
- package/dist/domain/workflow/checkpoint.d.ts +3 -0
- package/dist/domain/workflow/checkpoint.js +70 -0
- package/dist/domain/workflow/checkpoint.js.map +1 -0
- package/dist/domain/workflow/checkpoint.types.d.ts +40 -0
- package/dist/domain/workflow/checkpoint.types.js +2 -0
- package/dist/domain/workflow/checkpoint.types.js.map +1 -0
- package/dist/domain/workflow/gate-validation.d.ts +4 -0
- package/dist/domain/workflow/gate-validation.js +71 -0
- package/dist/domain/workflow/gate-validation.js.map +1 -0
- package/dist/domain/workflow/gates.constants.d.ts +4 -0
- package/dist/domain/workflow/gates.constants.js +5 -0
- package/dist/domain/workflow/gates.constants.js.map +1 -0
- package/dist/domain/workflow/gates.d.ts +7 -0
- package/dist/domain/workflow/gates.js +85 -0
- package/dist/domain/workflow/gates.js.map +1 -0
- package/dist/domain/workflow/gates.types.d.ts +27 -0
- package/dist/domain/workflow/gates.types.js +2 -0
- package/dist/domain/workflow/gates.types.js.map +1 -0
- package/dist/domain/workflow/task-runner.js +22 -3
- package/dist/domain/workflow/task-runner.js.map +1 -1
- package/dist/domain/workflow/usage-receipt.constants.d.ts +2 -0
- package/dist/domain/workflow/usage-receipt.constants.js +3 -0
- package/dist/domain/workflow/usage-receipt.constants.js.map +1 -0
- package/dist/domain/workflow/usage-receipt.d.ts +2 -0
- package/dist/domain/workflow/usage-receipt.js +18 -0
- package/dist/domain/workflow/usage-receipt.js.map +1 -0
- package/dist/domain/workflow/validation.js +6 -0
- package/dist/domain/workflow/validation.js.map +1 -1
- package/dist/domain/workflow/workflow-scheduler.js +68 -33
- package/dist/domain/workflow/workflow-scheduler.js.map +1 -1
- package/dist/domain/workflow/workflow-state.d.ts +2 -1
- package/dist/domain/workflow/workflow-state.js +107 -3
- package/dist/domain/workflow/workflow-state.js.map +1 -1
- package/dist/domain/workflow.d.ts +2 -0
- package/dist/domain/workflow.js +1 -0
- package/dist/domain/workflow.js.map +1 -1
- package/dist/domain/workflow.types.d.ts +23 -3
- package/dist/domain/workflow.types.js.map +1 -1
- package/dist/index.d.ts +44 -5
- package/dist/index.js +19 -2
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/artifact-store.constants.d.ts +1 -0
- package/dist/infrastructure/artifact-store.constants.js +2 -0
- package/dist/infrastructure/artifact-store.constants.js.map +1 -0
- package/dist/infrastructure/artifact-store.d.ts +3 -0
- package/dist/infrastructure/artifact-store.js +100 -0
- package/dist/infrastructure/artifact-store.js.map +1 -0
- package/dist/infrastructure/artifact-store.types.d.ts +4 -0
- package/dist/infrastructure/artifact-store.types.js +2 -0
- package/dist/infrastructure/artifact-store.types.js.map +1 -0
- package/dist/infrastructure/file-manifest.d.ts +6 -0
- package/dist/infrastructure/file-manifest.js +92 -0
- package/dist/infrastructure/file-manifest.js.map +1 -0
- package/dist/infrastructure/git/lock-inspection.constants.d.ts +4 -0
- package/dist/infrastructure/git/lock-inspection.constants.js +5 -0
- package/dist/infrastructure/git/lock-inspection.constants.js.map +1 -0
- package/dist/infrastructure/git/lock-inspection.d.ts +3 -0
- package/dist/infrastructure/git/lock-inspection.js +64 -0
- package/dist/infrastructure/git/lock-inspection.js.map +1 -0
- package/dist/infrastructure/git/lock-inspection.types.d.ts +27 -0
- package/dist/infrastructure/git/lock-inspection.types.js +2 -0
- package/dist/infrastructure/git/lock-inspection.types.js.map +1 -0
- package/dist/infrastructure/git/lock.d.ts +1 -0
- package/dist/infrastructure/git/lock.js +70 -29
- package/dist/infrastructure/git/lock.js.map +1 -1
- package/dist/infrastructure/git/process-identity.d.ts +3 -0
- package/dist/infrastructure/git/process-identity.js +73 -0
- package/dist/infrastructure/git/process-identity.js.map +1 -0
- package/dist/infrastructure/git/process-identity.types.d.ts +10 -0
- package/dist/infrastructure/git/process-identity.types.js +2 -0
- package/dist/infrastructure/git/process-identity.types.js.map +1 -0
- package/dist/infrastructure/git/verification-command.d.ts +1 -0
- package/dist/infrastructure/git/verification-command.js +37 -0
- package/dist/infrastructure/git/verification-command.js.map +1 -0
- package/dist/infrastructure/git/workspace-lease.js +1 -0
- package/dist/infrastructure/git/workspace-lease.js.map +1 -1
- package/dist/infrastructure/git/workspace.js +5 -1
- package/dist/infrastructure/git/workspace.js.map +1 -1
- package/dist/infrastructure/git/worktree-inspection.constants.d.ts +5 -0
- package/dist/infrastructure/git/worktree-inspection.constants.js +16 -0
- package/dist/infrastructure/git/worktree-inspection.constants.js.map +1 -0
- package/dist/infrastructure/git/worktree-inspection.d.ts +3 -0
- package/dist/infrastructure/git/worktree-inspection.js +120 -0
- package/dist/infrastructure/git/worktree-inspection.js.map +1 -0
- package/dist/infrastructure/git/worktree-inspection.types.d.ts +19 -0
- package/dist/infrastructure/git/worktree-inspection.types.js +2 -0
- package/dist/infrastructure/git/worktree-inspection.types.js.map +1 -0
- package/dist/infrastructure/inspection-file.constants.d.ts +1 -0
- package/dist/infrastructure/inspection-file.constants.js +5 -0
- package/dist/infrastructure/inspection-file.constants.js.map +1 -0
- package/dist/infrastructure/inspection-file.d.ts +1 -0
- package/dist/infrastructure/inspection-file.js +43 -0
- package/dist/infrastructure/inspection-file.js.map +1 -0
- package/dist/infrastructure/inspection-hash.constants.d.ts +1 -0
- package/dist/infrastructure/inspection-hash.constants.js +2 -0
- package/dist/infrastructure/inspection-hash.constants.js.map +1 -0
- package/dist/infrastructure/inspection-hash.d.ts +2 -0
- package/dist/infrastructure/inspection-hash.js +62 -0
- package/dist/infrastructure/inspection-hash.js.map +1 -0
- package/dist/infrastructure/inspection-hash.types.d.ts +5 -0
- package/dist/infrastructure/inspection-hash.types.js +2 -0
- package/dist/infrastructure/inspection-hash.types.js.map +1 -0
- package/dist/infrastructure/journal-retention.constants.d.ts +4 -0
- package/dist/infrastructure/journal-retention.constants.js +5 -0
- package/dist/infrastructure/journal-retention.constants.js.map +1 -0
- package/dist/infrastructure/journal-retention.d.ts +2 -0
- package/dist/infrastructure/journal-retention.js +51 -0
- package/dist/infrastructure/journal-retention.js.map +1 -0
- package/dist/infrastructure/journal.js +37 -13
- package/dist/infrastructure/journal.js.map +1 -1
- package/dist/infrastructure/opentelemetry.constants.d.ts +10 -0
- package/dist/infrastructure/opentelemetry.constants.js +11 -0
- package/dist/infrastructure/opentelemetry.constants.js.map +1 -0
- package/dist/infrastructure/opentelemetry.d.ts +3 -0
- package/dist/infrastructure/opentelemetry.js +131 -0
- package/dist/infrastructure/opentelemetry.js.map +1 -0
- package/dist/infrastructure/opentelemetry.types.d.ts +21 -0
- package/dist/infrastructure/opentelemetry.types.js +2 -0
- package/dist/infrastructure/opentelemetry.types.js.map +1 -0
- package/dist/infrastructure/resource-activity-inspection.d.ts +2 -0
- package/dist/infrastructure/resource-activity-inspection.js +152 -0
- package/dist/infrastructure/resource-activity-inspection.js.map +1 -0
- package/dist/infrastructure/resource-activity.constants.d.ts +8 -0
- package/dist/infrastructure/resource-activity.constants.js +26 -0
- package/dist/infrastructure/resource-activity.constants.js.map +1 -0
- package/dist/infrastructure/resource-activity.d.ts +2 -0
- package/dist/infrastructure/resource-activity.js +166 -0
- package/dist/infrastructure/resource-activity.js.map +1 -0
- package/dist/infrastructure/resource-activity.types.d.ts +53 -0
- package/dist/infrastructure/resource-activity.types.js +2 -0
- package/dist/infrastructure/resource-activity.types.js.map +1 -0
- package/dist/infrastructure/storage-inventory.constants.d.ts +6 -0
- package/dist/infrastructure/storage-inventory.constants.js +11 -0
- package/dist/infrastructure/storage-inventory.constants.js.map +1 -0
- package/dist/infrastructure/storage-inventory.d.ts +2 -0
- package/dist/infrastructure/storage-inventory.js +123 -0
- package/dist/infrastructure/storage-inventory.js.map +1 -0
- package/dist/infrastructure/storage-inventory.types.d.ts +38 -0
- package/dist/infrastructure/storage-inventory.types.js +2 -0
- package/dist/infrastructure/storage-inventory.types.js.map +1 -0
- package/dist/infrastructure/storage-mutation-lock.constants.d.ts +5 -0
- package/dist/infrastructure/storage-mutation-lock.constants.js +6 -0
- package/dist/infrastructure/storage-mutation-lock.constants.js.map +1 -0
- package/dist/infrastructure/storage-mutation-lock.d.ts +1 -0
- package/dist/infrastructure/storage-mutation-lock.js +21 -0
- package/dist/infrastructure/storage-mutation-lock.js.map +1 -0
- package/dist/infrastructure/storage-reservations.constants.d.ts +4 -0
- package/dist/infrastructure/storage-reservations.constants.js +5 -0
- package/dist/infrastructure/storage-reservations.constants.js.map +1 -0
- package/dist/infrastructure/storage-reservations.d.ts +2 -0
- package/dist/infrastructure/storage-reservations.js +150 -0
- package/dist/infrastructure/storage-reservations.js.map +1 -0
- package/dist/infrastructure/storage-reservations.types.d.ts +21 -0
- package/dist/infrastructure/storage-reservations.types.js +2 -0
- package/dist/infrastructure/storage-reservations.types.js.map +1 -0
- package/dist/infrastructure/task-queue-http.constants.d.ts +2 -0
- package/dist/infrastructure/task-queue-http.constants.js +3 -0
- package/dist/infrastructure/task-queue-http.constants.js.map +1 -0
- package/dist/infrastructure/task-queue-http.d.ts +4 -0
- package/dist/infrastructure/task-queue-http.js +158 -0
- package/dist/infrastructure/task-queue-http.js.map +1 -0
- package/dist/infrastructure/task-queue-http.types.d.ts +16 -0
- package/dist/infrastructure/task-queue-http.types.js +2 -0
- package/dist/infrastructure/task-queue-http.types.js.map +1 -0
- package/dist/infrastructure/task-queue.d.ts +2 -0
- package/dist/infrastructure/task-queue.js +134 -0
- package/dist/infrastructure/task-queue.js.map +1 -0
- package/dist/infrastructure/transfer.js +17 -0
- package/dist/infrastructure/transfer.js.map +1 -1
- package/dist/infrastructure/workflow-checkpoint.constants.d.ts +1 -0
- package/dist/infrastructure/workflow-checkpoint.constants.js +2 -0
- package/dist/infrastructure/workflow-checkpoint.constants.js.map +1 -0
- package/dist/infrastructure/workflow-checkpoint.d.ts +3 -0
- package/dist/infrastructure/workflow-checkpoint.js +77 -0
- package/dist/infrastructure/workflow-checkpoint.js.map +1 -0
- package/dist/infrastructure/workflow-checkpoint.types.d.ts +4 -0
- package/dist/infrastructure/workflow-checkpoint.types.js +2 -0
- package/dist/infrastructure/workflow-checkpoint.types.js.map +1 -0
- package/dist/providers/agents.d.ts +2 -0
- package/dist/providers/agents.js +1 -0
- package/dist/providers/agents.js.map +1 -1
- package/dist/providers/cloud.constants.d.ts +1 -0
- package/dist/providers/cloud.constants.js +1 -0
- package/dist/providers/cloud.constants.js.map +1 -1
- package/dist/providers/container-cache.constants.d.ts +11 -0
- package/dist/providers/container-cache.constants.js +9 -0
- package/dist/providers/container-cache.constants.js.map +1 -0
- package/dist/providers/container-cache.d.ts +4 -0
- package/dist/providers/container-cache.js +48 -0
- package/dist/providers/container-cache.js.map +1 -0
- package/dist/providers/container-cache.types.d.ts +8 -0
- package/dist/providers/container-cache.types.js +2 -0
- package/dist/providers/container-cache.types.js.map +1 -0
- package/dist/providers/container-isolation.d.ts +2 -0
- package/dist/providers/container-isolation.js +29 -0
- package/dist/providers/container-isolation.js.map +1 -0
- package/dist/providers/container-mounts.js +7 -2
- package/dist/providers/container-mounts.js.map +1 -1
- package/dist/providers/container-network.d.ts +2 -0
- package/dist/providers/container-network.js +14 -0
- package/dist/providers/container-network.js.map +1 -0
- package/dist/providers/container-plan.js +6 -2
- package/dist/providers/container-plan.js.map +1 -1
- package/dist/providers/container.constants.d.ts +1 -0
- package/dist/providers/container.constants.js +1 -0
- package/dist/providers/container.constants.js.map +1 -1
- package/dist/providers/container.js +50 -3
- package/dist/providers/container.js.map +1 -1
- package/dist/providers/container.types.d.ts +5 -0
- package/dist/providers/container.types.js.map +1 -1
- package/dist/providers/daytona-command.js +10 -6
- package/dist/providers/daytona-command.js.map +1 -1
- package/dist/providers/daytona-terminal.d.ts +3 -0
- package/dist/providers/daytona-terminal.js +128 -0
- package/dist/providers/daytona-terminal.js.map +1 -0
- package/dist/providers/daytona.js +15 -4
- package/dist/providers/daytona.js.map +1 -1
- package/dist/providers/diagnostic-container.d.ts +4 -0
- package/dist/providers/diagnostic-container.js +15 -0
- package/dist/providers/diagnostic-container.js.map +1 -0
- package/dist/providers/docker.d.ts +2 -0
- package/dist/providers/docker.js.map +1 -1
- package/dist/providers/file-batches.constants.d.ts +10 -0
- package/dist/providers/file-batches.constants.js +57 -0
- package/dist/providers/file-batches.constants.js.map +1 -0
- package/dist/providers/file-batches.d.ts +2 -0
- package/dist/providers/file-batches.js +160 -0
- package/dist/providers/file-batches.js.map +1 -0
- package/dist/providers/file-upload.constants.d.ts +1 -0
- package/dist/providers/file-upload.constants.js +68 -0
- package/dist/providers/file-upload.constants.js.map +1 -0
- package/dist/providers/file-upload.d.ts +2 -0
- package/dist/providers/file-upload.js +146 -0
- package/dist/providers/file-upload.js.map +1 -0
- package/dist/providers/firecracker-command.d.ts +5 -0
- package/dist/providers/firecracker-command.js +114 -0
- package/dist/providers/firecracker-command.js.map +1 -0
- package/dist/providers/firecracker-files.constants.d.ts +1 -0
- package/dist/providers/firecracker-files.constants.js +21 -0
- package/dist/providers/firecracker-files.constants.js.map +1 -0
- package/dist/providers/firecracker-files.d.ts +3 -0
- package/dist/providers/firecracker-files.js +110 -0
- package/dist/providers/firecracker-files.js.map +1 -0
- package/dist/providers/firecracker-machine.d.ts +3 -0
- package/dist/providers/firecracker-machine.js +155 -0
- package/dist/providers/firecracker-machine.js.map +1 -0
- package/dist/providers/firecracker.constants.d.ts +10 -0
- package/dist/providers/firecracker.constants.js +11 -0
- package/dist/providers/firecracker.constants.js.map +1 -0
- package/dist/providers/firecracker.d.ts +4 -0
- package/dist/providers/firecracker.js +103 -0
- package/dist/providers/firecracker.js.map +1 -0
- package/dist/providers/firecracker.types.d.ts +36 -0
- package/dist/providers/firecracker.types.js +2 -0
- package/dist/providers/firecracker.types.js.map +1 -0
- package/dist/providers/local.js +2 -1
- package/dist/providers/local.js.map +1 -1
- package/dist/providers/podman.d.ts +2 -0
- package/dist/providers/podman.js.map +1 -1
- package/dist/providers/terminal-bridge.d.ts +14 -0
- package/dist/providers/terminal-bridge.js +100 -0
- package/dist/providers/terminal-bridge.js.map +1 -0
- package/dist/providers/vercel-directory.d.ts +2 -0
- package/dist/providers/vercel-directory.js +7 -0
- package/dist/providers/vercel-directory.js.map +1 -0
- package/dist/providers/vercel-files.js +3 -2
- package/dist/providers/vercel-files.js.map +1 -1
- package/dist/providers/vercel-network.d.ts +2 -0
- package/dist/providers/vercel-network.js +18 -0
- package/dist/providers/vercel-network.js.map +1 -0
- package/dist/providers/vercel.d.ts +1 -0
- package/dist/providers/vercel.js +8 -2
- package/dist/providers/vercel.js.map +1 -1
- package/dist/providers/vercel.types.d.ts +2 -0
- package/dist/providers/vercel.types.js.map +1 -1
- package/dist/providers/versions.constants.d.ts +1 -0
- package/dist/providers/versions.constants.js +1 -0
- package/dist/providers/versions.constants.js.map +1 -1
- package/package.json +16 -1
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { constants } from "node:fs";
|
|
4
|
+
import { access, chmod, copyFile, mkdir, mkdtemp, rm, writeFile, } from "node:fs/promises";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { isAbsolute, join } from "node:path";
|
|
7
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
8
|
+
import { invariant, OutpostError, positive } from "../domain/errors.js";
|
|
9
|
+
import { registerCleanup } from "../infrastructure/shutdown.js";
|
|
10
|
+
import { firecrackerDefaults } from "./firecracker.constants.js";
|
|
11
|
+
export function validateFirecracker(options) {
|
|
12
|
+
invariant(!("egress" in options) || options.egress === undefined, "Firecracker cannot enforce Outpost egress policies; configure host networking explicitly");
|
|
13
|
+
for (const path of [
|
|
14
|
+
options.binary,
|
|
15
|
+
options.kernel,
|
|
16
|
+
options.rootfs,
|
|
17
|
+
options.home,
|
|
18
|
+
options.root ?? firecrackerDefaults.root,
|
|
19
|
+
options.ssh.identity,
|
|
20
|
+
options.ssh.knownHosts,
|
|
21
|
+
])
|
|
22
|
+
invariant(isAbsolute(path) && !path.includes("\0"), "Firecracker paths must be absolute");
|
|
23
|
+
invariant(/^[a-zA-Z0-9_.-]{1,15}$/.test(options.tap), "Invalid TAP interface");
|
|
24
|
+
invariant(/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/.test(options.guestMac), "Invalid guest MAC address");
|
|
25
|
+
invariant(/^[a-zA-Z0-9_.:-]+$/.test(options.ssh.host) &&
|
|
26
|
+
!options.ssh.host.startsWith("-"), "Invalid SSH host");
|
|
27
|
+
invariant(/^[a-zA-Z0-9_-]+$/.test(options.ssh.user), "Invalid SSH user");
|
|
28
|
+
for (const value of [
|
|
29
|
+
options.cpus ?? firecrackerDefaults.cpus,
|
|
30
|
+
options.memoryMb ?? firecrackerDefaults.memoryMb,
|
|
31
|
+
options.ssh.port ?? 22,
|
|
32
|
+
])
|
|
33
|
+
invariant(Number.isSafeInteger(value) && value > 0, "Firecracker resource limits and SSH port must be positive integers");
|
|
34
|
+
positive(options.bootDeadlineMs ?? firecrackerDefaults.bootDeadlineMs, "bootDeadlineMs");
|
|
35
|
+
}
|
|
36
|
+
export async function firecrackerMachine(options, signal) {
|
|
37
|
+
invariant(process.platform === "linux", "Firecracker requires Linux and KVM");
|
|
38
|
+
signal?.throwIfAborted();
|
|
39
|
+
await access("/dev/kvm", constants.R_OK | constants.W_OK);
|
|
40
|
+
await Promise.all([
|
|
41
|
+
access(options.binary, constants.X_OK),
|
|
42
|
+
access(options.kernel, constants.R_OK),
|
|
43
|
+
access(options.rootfs, constants.R_OK),
|
|
44
|
+
access(options.ssh.identity, constants.R_OK),
|
|
45
|
+
access(options.ssh.knownHosts, constants.R_OK),
|
|
46
|
+
]);
|
|
47
|
+
const lock = join(tmpdir(), `outpost-firecracker-tap-${options.tap}.lock`);
|
|
48
|
+
await mkdir(lock, { mode: 0o700 });
|
|
49
|
+
const endpoint = createHash("sha256")
|
|
50
|
+
.update(`${options.ssh.host}:${options.ssh.port ?? 22}`)
|
|
51
|
+
.digest("hex");
|
|
52
|
+
const transportLock = join(tmpdir(), `outpost-firecracker-ssh-${endpoint}.lock`);
|
|
53
|
+
try {
|
|
54
|
+
await mkdir(transportLock, { mode: 0o700 });
|
|
55
|
+
}
|
|
56
|
+
catch (cause) {
|
|
57
|
+
return failedAllocation([lock], cause);
|
|
58
|
+
}
|
|
59
|
+
let directory;
|
|
60
|
+
try {
|
|
61
|
+
directory = await mkdtemp(join(tmpdir(), "outpost-firecracker-"));
|
|
62
|
+
}
|
|
63
|
+
catch (cause) {
|
|
64
|
+
return failedAllocation([lock, transportLock], cause);
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
await copyFile(options.rootfs, join(directory, "rootfs.ext4"), constants.COPYFILE_FICLONE);
|
|
68
|
+
await chmod(join(directory, "rootfs.ext4"), 0o600);
|
|
69
|
+
signal?.throwIfAborted();
|
|
70
|
+
await writeFile(join(directory, "config.json"), JSON.stringify({
|
|
71
|
+
"boot-source": {
|
|
72
|
+
kernel_image_path: options.kernel,
|
|
73
|
+
boot_args: options.bootArgs,
|
|
74
|
+
},
|
|
75
|
+
drives: [
|
|
76
|
+
{
|
|
77
|
+
drive_id: "rootfs",
|
|
78
|
+
path_on_host: join(directory, "rootfs.ext4"),
|
|
79
|
+
is_root_device: true,
|
|
80
|
+
is_read_only: false,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
"machine-config": {
|
|
84
|
+
vcpu_count: options.cpus ?? firecrackerDefaults.cpus,
|
|
85
|
+
mem_size_mib: options.memoryMb ?? firecrackerDefaults.memoryMb,
|
|
86
|
+
},
|
|
87
|
+
"network-interfaces": [
|
|
88
|
+
{
|
|
89
|
+
iface_id: "net1",
|
|
90
|
+
guest_mac: options.guestMac,
|
|
91
|
+
host_dev_name: options.tap,
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
}), { mode: 0o600 });
|
|
95
|
+
}
|
|
96
|
+
catch (cause) {
|
|
97
|
+
return failedAllocation([directory, lock, transportLock], cause);
|
|
98
|
+
}
|
|
99
|
+
const child = spawn(options.binary, [
|
|
100
|
+
"--api-sock",
|
|
101
|
+
join(directory, "api.sock"),
|
|
102
|
+
"--config-file",
|
|
103
|
+
join(directory, "config.json"),
|
|
104
|
+
], { stdio: "ignore" });
|
|
105
|
+
let exited = false;
|
|
106
|
+
const exit = new Promise((resolve) => {
|
|
107
|
+
child.once("error", () => {
|
|
108
|
+
exited = true;
|
|
109
|
+
resolve();
|
|
110
|
+
});
|
|
111
|
+
child.once("exit", () => {
|
|
112
|
+
exited = true;
|
|
113
|
+
resolve();
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
let releasing;
|
|
117
|
+
let closed = false;
|
|
118
|
+
let unregister = () => { };
|
|
119
|
+
const release = () => (releasing ??= (async () => {
|
|
120
|
+
closed = true;
|
|
121
|
+
if (!exited)
|
|
122
|
+
child.kill("SIGTERM");
|
|
123
|
+
await Promise.race([exit, delay(200, undefined, { ref: false })]);
|
|
124
|
+
if (!exited)
|
|
125
|
+
child.kill("SIGKILL");
|
|
126
|
+
await Promise.race([
|
|
127
|
+
exit,
|
|
128
|
+
delay(firecrackerDefaults.cleanupMs, undefined, { ref: false }),
|
|
129
|
+
]);
|
|
130
|
+
if (!exited)
|
|
131
|
+
throw new OutpostError("provider", `VM termination uncertain; private disk retained at ${directory}`);
|
|
132
|
+
await rm(directory, { recursive: true, force: true });
|
|
133
|
+
await rm(lock, { recursive: true, force: true });
|
|
134
|
+
await rm(transportLock, { recursive: true, force: true });
|
|
135
|
+
unregister();
|
|
136
|
+
})().catch((cause) => {
|
|
137
|
+
releasing = undefined;
|
|
138
|
+
throw cause;
|
|
139
|
+
}));
|
|
140
|
+
unregister = registerCleanup(release, () => {
|
|
141
|
+
if (!exited)
|
|
142
|
+
child.kill("SIGKILL");
|
|
143
|
+
});
|
|
144
|
+
return { directory, isClosed: () => closed || exited, release };
|
|
145
|
+
}
|
|
146
|
+
async function failedAllocation(paths, cause) {
|
|
147
|
+
const results = await Promise.allSettled(paths.map((path) => rm(path, { recursive: true, force: true })));
|
|
148
|
+
const failures = results
|
|
149
|
+
.filter((result) => result.status === "rejected")
|
|
150
|
+
.map((result) => result.reason);
|
|
151
|
+
if (failures.length)
|
|
152
|
+
throw new AggregateError([cause, ...failures], "Firecracker allocation and cleanup failed; inspect retained temporary resources");
|
|
153
|
+
throw cause;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=firecracker-machine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firecracker-machine.js","sourceRoot":"","sources":["../../src/providers/firecracker-machine.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { spawn } from \"node:child_process\";\nimport { constants } from \"node:fs\";\nimport {\n access,\n chmod,\n copyFile,\n mkdir,\n mkdtemp,\n rm,\n writeFile,\n} from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { isAbsolute, join } from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { invariant, OutpostError, positive } from \"../domain/errors.ts\";\nimport { registerCleanup } from \"../infrastructure/shutdown.ts\";\nimport { firecrackerDefaults } from \"./firecracker.constants.ts\";\nimport type {\n FirecrackerMachine,\n FirecrackerOptions,\n} from \"./firecracker.types.ts\";\n\nexport function validateFirecracker(options: FirecrackerOptions): void {\n invariant(\n !(\"egress\" in options) || options.egress === undefined,\n \"Firecracker cannot enforce Outpost egress policies; configure host networking explicitly\",\n );\n for (const path of [\n options.binary,\n options.kernel,\n options.rootfs,\n options.home,\n options.root ?? firecrackerDefaults.root,\n options.ssh.identity,\n options.ssh.knownHosts,\n ])\n invariant(\n isAbsolute(path) && !path.includes(\"\\0\"),\n \"Firecracker paths must be absolute\",\n );\n invariant(\n /^[a-zA-Z0-9_.-]{1,15}$/.test(options.tap),\n \"Invalid TAP interface\",\n );\n invariant(\n /^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/.test(options.guestMac),\n \"Invalid guest MAC address\",\n );\n invariant(\n /^[a-zA-Z0-9_.:-]+$/.test(options.ssh.host) &&\n !options.ssh.host.startsWith(\"-\"),\n \"Invalid SSH host\",\n );\n invariant(/^[a-zA-Z0-9_-]+$/.test(options.ssh.user), \"Invalid SSH user\");\n for (const value of [\n options.cpus ?? firecrackerDefaults.cpus,\n options.memoryMb ?? firecrackerDefaults.memoryMb,\n options.ssh.port ?? 22,\n ])\n invariant(\n Number.isSafeInteger(value) && value > 0,\n \"Firecracker resource limits and SSH port must be positive integers\",\n );\n positive(\n options.bootDeadlineMs ?? firecrackerDefaults.bootDeadlineMs,\n \"bootDeadlineMs\",\n );\n}\n\nexport async function firecrackerMachine(\n options: FirecrackerOptions,\n signal?: AbortSignal,\n): Promise<FirecrackerMachine> {\n invariant(process.platform === \"linux\", \"Firecracker requires Linux and KVM\");\n signal?.throwIfAborted();\n await access(\"/dev/kvm\", constants.R_OK | constants.W_OK);\n await Promise.all([\n access(options.binary, constants.X_OK),\n access(options.kernel, constants.R_OK),\n access(options.rootfs, constants.R_OK),\n access(options.ssh.identity, constants.R_OK),\n access(options.ssh.knownHosts, constants.R_OK),\n ]);\n const lock = join(tmpdir(), `outpost-firecracker-tap-${options.tap}.lock`);\n await mkdir(lock, { mode: 0o700 });\n const endpoint = createHash(\"sha256\")\n .update(`${options.ssh.host}:${options.ssh.port ?? 22}`)\n .digest(\"hex\");\n const transportLock = join(\n tmpdir(),\n `outpost-firecracker-ssh-${endpoint}.lock`,\n );\n try {\n await mkdir(transportLock, { mode: 0o700 });\n } catch (cause) {\n return failedAllocation([lock], cause);\n }\n let directory: string;\n try {\n directory = await mkdtemp(join(tmpdir(), \"outpost-firecracker-\"));\n } catch (cause) {\n return failedAllocation([lock, transportLock], cause);\n }\n try {\n await copyFile(\n options.rootfs,\n join(directory, \"rootfs.ext4\"),\n constants.COPYFILE_FICLONE,\n );\n await chmod(join(directory, \"rootfs.ext4\"), 0o600);\n signal?.throwIfAborted();\n await writeFile(\n join(directory, \"config.json\"),\n JSON.stringify({\n \"boot-source\": {\n kernel_image_path: options.kernel,\n boot_args: options.bootArgs,\n },\n drives: [\n {\n drive_id: \"rootfs\",\n path_on_host: join(directory, \"rootfs.ext4\"),\n is_root_device: true,\n is_read_only: false,\n },\n ],\n \"machine-config\": {\n vcpu_count: options.cpus ?? firecrackerDefaults.cpus,\n mem_size_mib: options.memoryMb ?? firecrackerDefaults.memoryMb,\n },\n \"network-interfaces\": [\n {\n iface_id: \"net1\",\n guest_mac: options.guestMac,\n host_dev_name: options.tap,\n },\n ],\n }),\n { mode: 0o600 },\n );\n } catch (cause) {\n return failedAllocation([directory, lock, transportLock], cause);\n }\n const child = spawn(\n options.binary,\n [\n \"--api-sock\",\n join(directory, \"api.sock\"),\n \"--config-file\",\n join(directory, \"config.json\"),\n ],\n { stdio: \"ignore\" },\n );\n let exited = false;\n const exit = new Promise<void>((resolve) => {\n child.once(\"error\", () => {\n exited = true;\n resolve();\n });\n child.once(\"exit\", () => {\n exited = true;\n resolve();\n });\n });\n let releasing: Promise<void> | undefined;\n let closed = false;\n let unregister = () => {};\n const release = () =>\n (releasing ??= (async () => {\n closed = true;\n if (!exited) child.kill(\"SIGTERM\");\n await Promise.race([exit, delay(200, undefined, { ref: false })]);\n if (!exited) child.kill(\"SIGKILL\");\n await Promise.race([\n exit,\n delay(firecrackerDefaults.cleanupMs, undefined, { ref: false }),\n ]);\n if (!exited)\n throw new OutpostError(\n \"provider\",\n `VM termination uncertain; private disk retained at ${directory}`,\n );\n await rm(directory, { recursive: true, force: true });\n await rm(lock, { recursive: true, force: true });\n await rm(transportLock, { recursive: true, force: true });\n unregister();\n })().catch((cause) => {\n releasing = undefined;\n throw cause;\n }));\n unregister = registerCleanup(release, () => {\n if (!exited) child.kill(\"SIGKILL\");\n });\n return { directory, isClosed: () => closed || exited, release };\n}\n\nasync function failedAllocation(\n paths: readonly string[],\n cause: unknown,\n): Promise<never> {\n const results = await Promise.allSettled(\n paths.map((path) => rm(path, { recursive: true, force: true })),\n );\n const failures = results\n .filter((result) => result.status === \"rejected\")\n .map((result) => result.reason);\n if (failures.length)\n throw new AggregateError(\n [cause, ...failures],\n \"Firecracker allocation and cleanup failed; inspect retained temporary resources\",\n );\n throw cause;\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const firecrackerDefaults: {
|
|
2
|
+
readonly root: "/workspace";
|
|
3
|
+
readonly cpus: 2;
|
|
4
|
+
readonly memoryMb: 2048;
|
|
5
|
+
readonly bootDeadlineMs: 60000;
|
|
6
|
+
readonly commandMs: 600000;
|
|
7
|
+
readonly probeMs: 2000;
|
|
8
|
+
readonly cleanupMs: 5000;
|
|
9
|
+
readonly manifestBytes: number;
|
|
10
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const firecrackerDefaults = {
|
|
2
|
+
root: "/workspace",
|
|
3
|
+
cpus: 2,
|
|
4
|
+
memoryMb: 2048,
|
|
5
|
+
bootDeadlineMs: 60_000,
|
|
6
|
+
commandMs: 600_000,
|
|
7
|
+
probeMs: 2000,
|
|
8
|
+
cleanupMs: 5000,
|
|
9
|
+
manifestBytes: 16 * 1024 * 1024,
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=firecracker.constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firecracker.constants.js","sourceRoot":"","sources":["../../src/providers/firecracker.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,CAAC;IACP,QAAQ,EAAE,IAAI;IACd,cAAc,EAAE,MAAM;IACtB,SAAS,EAAE,OAAO;IAClB,OAAO,EAAE,IAAI;IACb,SAAS,EAAE,IAAI;IACf,aAAa,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;CACvB,CAAC","sourcesContent":["export const firecrackerDefaults = {\n root: \"/workspace\",\n cpus: 2,\n memoryMb: 2048,\n bootDeadlineMs: 60_000,\n commandMs: 600_000,\n probeMs: 2000,\n cleanupMs: 5000,\n manifestBytes: 16 * 1024 * 1024,\n} as const;\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SandboxProvider } from "../domain/sandbox.types.ts";
|
|
2
|
+
import type { FirecrackerOptions } from "./firecracker.types.ts";
|
|
3
|
+
export type { FirecrackerOptions } from "./firecracker.types.ts";
|
|
4
|
+
export declare function firecracker(options: FirecrackerOptions): SandboxProvider;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
2
|
+
import { OutpostError } from "../domain/errors.js";
|
|
3
|
+
import { executeProcess, quote } from "../infrastructure/process.js";
|
|
4
|
+
import { firecrackerCommand, firecrackerSsh } from "./firecracker-command.js";
|
|
5
|
+
import { firecrackerDefaults } from "./firecracker.constants.js";
|
|
6
|
+
import { firecrackerFiles } from "./firecracker-files.js";
|
|
7
|
+
import { firecrackerMachine, validateFirecracker, } from "./firecracker-machine.js";
|
|
8
|
+
export function firecracker(options) {
|
|
9
|
+
validateFirecracker(options);
|
|
10
|
+
let allocated = false;
|
|
11
|
+
return {
|
|
12
|
+
name: "firecracker",
|
|
13
|
+
placement: "remote",
|
|
14
|
+
variables: { ...options.variables },
|
|
15
|
+
async acquire(context) {
|
|
16
|
+
if (allocated)
|
|
17
|
+
throw new OutpostError("provider", "This Firecracker provider already owns its TAP; create separate configurations for concurrent VMs");
|
|
18
|
+
allocated = true;
|
|
19
|
+
let machine;
|
|
20
|
+
try {
|
|
21
|
+
machine = await firecrackerMachine(options, context.signal);
|
|
22
|
+
}
|
|
23
|
+
catch (cause) {
|
|
24
|
+
allocated = false;
|
|
25
|
+
throw cause;
|
|
26
|
+
}
|
|
27
|
+
const root = options.root ?? firecrackerDefaults.root;
|
|
28
|
+
let closed = false;
|
|
29
|
+
const active = new Set();
|
|
30
|
+
const stop = new AbortController();
|
|
31
|
+
const runtime = {
|
|
32
|
+
options,
|
|
33
|
+
root,
|
|
34
|
+
variables: context.variables,
|
|
35
|
+
executor: executeProcess,
|
|
36
|
+
isClosed: () => closed || machine.isClosed(),
|
|
37
|
+
};
|
|
38
|
+
let releasing;
|
|
39
|
+
const release = () => (releasing ??= (async () => {
|
|
40
|
+
closed = true;
|
|
41
|
+
stop.abort(new OutpostError("aborted", "Firecracker sandbox disposed"));
|
|
42
|
+
await Promise.allSettled([...active]);
|
|
43
|
+
await machine.release();
|
|
44
|
+
allocated = false;
|
|
45
|
+
})().catch((cause) => {
|
|
46
|
+
releasing = undefined;
|
|
47
|
+
throw cause;
|
|
48
|
+
}));
|
|
49
|
+
try {
|
|
50
|
+
const deadline = Date.now() +
|
|
51
|
+
(options.bootDeadlineMs ?? firecrackerDefaults.bootDeadlineMs);
|
|
52
|
+
while (true) {
|
|
53
|
+
context.signal?.throwIfAborted();
|
|
54
|
+
if (machine.isClosed())
|
|
55
|
+
throw new OutpostError("provider", "Firecracker exited before guest readiness");
|
|
56
|
+
const result = await executeProcess({
|
|
57
|
+
...firecrackerSsh(options, `test "$HOME" = ${quote(options.home)} && node -e 'if(Number(process.versions.node.split(".")[0])<24)process.exit(1)' && command -v git setsid tar >/dev/null && mkdir -p ${quote(root)}`),
|
|
58
|
+
deadlineMs: Math.max(1, Math.min(firecrackerDefaults.probeMs, deadline - Date.now())),
|
|
59
|
+
...(context.signal ? { signal: context.signal } : {}),
|
|
60
|
+
}).catch((cause) => {
|
|
61
|
+
context.signal?.throwIfAborted();
|
|
62
|
+
return { status: 1, stdout: "", stderr: String(cause) };
|
|
63
|
+
});
|
|
64
|
+
if (machine.isClosed())
|
|
65
|
+
throw new OutpostError("provider", "Firecracker exited during guest readiness");
|
|
66
|
+
if (result.status === 0)
|
|
67
|
+
break;
|
|
68
|
+
if (Date.now() >= deadline)
|
|
69
|
+
throw new OutpostError("timeout", "Firecracker guest SSH/prerequisites did not become ready", { stderr: result.stderr });
|
|
70
|
+
await delay(100, undefined, { signal: context.signal });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (cause) {
|
|
74
|
+
try {
|
|
75
|
+
await release();
|
|
76
|
+
}
|
|
77
|
+
catch (cleanup) {
|
|
78
|
+
throw new AggregateError([cause, cleanup], "Firecracker acquisition and cleanup failed");
|
|
79
|
+
}
|
|
80
|
+
throw cause;
|
|
81
|
+
}
|
|
82
|
+
const invoke = firecrackerCommand(runtime);
|
|
83
|
+
const files = firecrackerFiles(runtime);
|
|
84
|
+
const track = (operation, signal) => {
|
|
85
|
+
if (closed)
|
|
86
|
+
return Promise.reject(new OutpostError("provider", "Firecracker sandbox is closed"));
|
|
87
|
+
const pending = operation(signal ? AbortSignal.any([signal, stop.signal]) : stop.signal);
|
|
88
|
+
active.add(pending);
|
|
89
|
+
void pending.then(() => active.delete(pending), () => active.delete(pending));
|
|
90
|
+
return pending;
|
|
91
|
+
};
|
|
92
|
+
return {
|
|
93
|
+
root,
|
|
94
|
+
home: options.home,
|
|
95
|
+
invoke: (command) => track((signal) => invoke({ ...command, signal }), command.signal),
|
|
96
|
+
upload: (source, destination, options = {}) => track((signal) => files.upload(source, destination, { ...options, signal }), options.signal),
|
|
97
|
+
download: (source, destination, options = {}) => track((signal) => files.download(source, destination, { ...options, signal }), options.signal),
|
|
98
|
+
release,
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=firecracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firecracker.js","sourceRoot":"","sources":["../../src/providers/firecracker.ts"],"names":[],"mappings":"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","sourcesContent":["import { setTimeout as delay } from \"node:timers/promises\";\nimport { OutpostError } from \"../domain/errors.ts\";\nimport type { SandboxProvider } from \"../domain/sandbox.types.ts\";\nimport { executeProcess, quote } from \"../infrastructure/process.ts\";\nimport { firecrackerCommand, firecrackerSsh } from \"./firecracker-command.ts\";\nimport { firecrackerDefaults } from \"./firecracker.constants.ts\";\nimport { firecrackerFiles } from \"./firecracker-files.ts\";\nimport {\n firecrackerMachine,\n validateFirecracker,\n} from \"./firecracker-machine.ts\";\nimport type { FirecrackerOptions } from \"./firecracker.types.ts\";\n\nexport type { FirecrackerOptions } from \"./firecracker.types.ts\";\n\nexport function firecracker(options: FirecrackerOptions): SandboxProvider {\n validateFirecracker(options);\n let allocated = false;\n return {\n name: \"firecracker\",\n placement: \"remote\",\n variables: { ...options.variables },\n async acquire(context) {\n if (allocated)\n throw new OutpostError(\n \"provider\",\n \"This Firecracker provider already owns its TAP; create separate configurations for concurrent VMs\",\n );\n allocated = true;\n let machine;\n try {\n machine = await firecrackerMachine(options, context.signal);\n } catch (cause) {\n allocated = false;\n throw cause;\n }\n const root = options.root ?? firecrackerDefaults.root;\n let closed = false;\n const active = new Set<Promise<unknown>>();\n const stop = new AbortController();\n const runtime = {\n options,\n root,\n variables: context.variables,\n executor: executeProcess,\n isClosed: () => closed || machine.isClosed(),\n };\n let releasing: Promise<void> | undefined;\n const release = () =>\n (releasing ??= (async () => {\n closed = true;\n stop.abort(\n new OutpostError(\"aborted\", \"Firecracker sandbox disposed\"),\n );\n await Promise.allSettled([...active]);\n await machine.release();\n allocated = false;\n })().catch((cause) => {\n releasing = undefined;\n throw cause;\n }));\n try {\n const deadline =\n Date.now() +\n (options.bootDeadlineMs ?? firecrackerDefaults.bootDeadlineMs);\n while (true) {\n context.signal?.throwIfAborted();\n if (machine.isClosed())\n throw new OutpostError(\n \"provider\",\n \"Firecracker exited before guest readiness\",\n );\n const result = await executeProcess({\n ...firecrackerSsh(\n options,\n `test \"$HOME\" = ${quote(options.home)} && node -e 'if(Number(process.versions.node.split(\".\")[0])<24)process.exit(1)' && command -v git setsid tar >/dev/null && mkdir -p ${quote(root)}`,\n ),\n deadlineMs: Math.max(\n 1,\n Math.min(firecrackerDefaults.probeMs, deadline - Date.now()),\n ),\n ...(context.signal ? { signal: context.signal } : {}),\n }).catch((cause) => {\n context.signal?.throwIfAborted();\n return { status: 1, stdout: \"\", stderr: String(cause) };\n });\n if (machine.isClosed())\n throw new OutpostError(\n \"provider\",\n \"Firecracker exited during guest readiness\",\n );\n if (result.status === 0) break;\n if (Date.now() >= deadline)\n throw new OutpostError(\n \"timeout\",\n \"Firecracker guest SSH/prerequisites did not become ready\",\n { stderr: result.stderr },\n );\n await delay(100, undefined, { signal: context.signal });\n }\n } catch (cause) {\n try {\n await release();\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n \"Firecracker acquisition and cleanup failed\",\n );\n }\n throw cause;\n }\n const invoke = firecrackerCommand(runtime);\n const files = firecrackerFiles(runtime);\n const track = <T>(\n operation: (signal: AbortSignal) => Promise<T>,\n signal?: AbortSignal,\n ): Promise<T> => {\n if (closed)\n return Promise.reject(\n new OutpostError(\"provider\", \"Firecracker sandbox is closed\"),\n );\n const pending = operation(\n signal ? AbortSignal.any([signal, stop.signal]) : stop.signal,\n );\n active.add(pending);\n void pending.then(\n () => active.delete(pending),\n () => active.delete(pending),\n );\n return pending;\n };\n return {\n root,\n home: options.home,\n invoke: (command) =>\n track((signal) => invoke({ ...command, signal }), command.signal),\n upload: (source, destination, options = {}) =>\n track(\n (signal) =>\n files.upload(source, destination, { ...options, signal }),\n options.signal,\n ),\n download: (source, destination, options = {}) =>\n track(\n (signal) =>\n files.download(source, destination, { ...options, signal }),\n options.signal,\n ),\n release,\n };\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Variables } from "../domain/command.types.ts";
|
|
2
|
+
import type { Executor } from "../infrastructure/process.types.ts";
|
|
3
|
+
export interface FirecrackerOptions {
|
|
4
|
+
readonly binary: string;
|
|
5
|
+
readonly kernel: string;
|
|
6
|
+
readonly rootfs: string;
|
|
7
|
+
readonly tap: string;
|
|
8
|
+
readonly guestMac: string;
|
|
9
|
+
readonly bootArgs: string;
|
|
10
|
+
readonly ssh: {
|
|
11
|
+
readonly host: string;
|
|
12
|
+
readonly user: string;
|
|
13
|
+
readonly identity: string;
|
|
14
|
+
readonly knownHosts: string;
|
|
15
|
+
readonly port?: number;
|
|
16
|
+
readonly binary?: string;
|
|
17
|
+
};
|
|
18
|
+
readonly root?: string;
|
|
19
|
+
readonly home: string;
|
|
20
|
+
readonly cpus?: number;
|
|
21
|
+
readonly memoryMb?: number;
|
|
22
|
+
readonly bootDeadlineMs?: number;
|
|
23
|
+
readonly variables?: Variables;
|
|
24
|
+
}
|
|
25
|
+
export interface FirecrackerRuntime {
|
|
26
|
+
readonly options: FirecrackerOptions;
|
|
27
|
+
readonly root: string;
|
|
28
|
+
readonly variables: Variables;
|
|
29
|
+
readonly isClosed: () => boolean;
|
|
30
|
+
readonly executor: Executor;
|
|
31
|
+
}
|
|
32
|
+
export interface FirecrackerMachine {
|
|
33
|
+
readonly directory: string;
|
|
34
|
+
readonly isClosed: () => boolean;
|
|
35
|
+
release(): Promise<void>;
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firecracker.types.js","sourceRoot":"","sources":["../../src/providers/firecracker.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Variables } from \"../domain/command.types.ts\";\nimport type { Executor } from \"../infrastructure/process.types.ts\";\n\nexport interface FirecrackerOptions {\n readonly binary: string;\n readonly kernel: string;\n readonly rootfs: string;\n readonly tap: string;\n readonly guestMac: string;\n readonly bootArgs: string;\n readonly ssh: {\n readonly host: string;\n readonly user: string;\n readonly identity: string;\n readonly knownHosts: string;\n readonly port?: number;\n readonly binary?: string;\n };\n readonly root?: string;\n readonly home: string;\n readonly cpus?: number;\n readonly memoryMb?: number;\n readonly bootDeadlineMs?: number;\n readonly variables?: Variables;\n}\n\nexport interface FirecrackerRuntime {\n readonly options: FirecrackerOptions;\n readonly root: string;\n readonly variables: Variables;\n readonly isClosed: () => boolean;\n readonly executor: Executor;\n}\n\nexport interface FirecrackerMachine {\n readonly directory: string;\n readonly isClosed: () => boolean;\n release(): Promise<void>;\n}\n"]}
|
package/dist/providers/local.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { cp, mkdir } from "node:fs/promises";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
|
-
import { OutpostError } from "../domain/errors.js";
|
|
4
|
+
import { invariant, OutpostError } from "../domain/errors.js";
|
|
5
5
|
import { executeProcess } from "../infrastructure/process.js";
|
|
6
6
|
export function local(options = {}) {
|
|
7
|
+
invariant(!("egress" in options) || options.egress === undefined, "Local execution cannot enforce egress policies");
|
|
7
8
|
return {
|
|
8
9
|
name: "local",
|
|
9
10
|
placement: "host",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/providers/local.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/providers/local.ts"],"names":[],"mappings":"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","sourcesContent":["import { cp, mkdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, resolve } from \"node:path\";\nimport type { Command } from \"../domain/command.types.ts\";\nimport { invariant, OutpostError } from \"../domain/errors.ts\";\nimport type {\n SandboxProvider,\n TransferOptions,\n} from \"../domain/sandbox.types.ts\";\nimport { executeProcess } from \"../infrastructure/process.ts\";\nimport type { LocalOptions } from \"./local.types.ts\";\n\nexport function local(options: LocalOptions = {}): SandboxProvider {\n invariant(\n !(\"egress\" in options) || options.egress === undefined,\n \"Local execution cannot enforce egress policies\",\n );\n return {\n name: \"local\",\n placement: \"host\",\n variables: { ...options.variables },\n async acquire(context) {\n context.signal?.throwIfAborted();\n const stop = new AbortController();\n const active = new Set<Promise<unknown>>();\n let disposed = false;\n const copy = async (\n source: string,\n destination: string,\n options: TransferOptions = {},\n ) => {\n options.signal?.throwIfAborted();\n if (disposed)\n throw new OutpostError(\"provider\", \"Local sandbox is closed\");\n if (resolve(source) === resolve(destination)) return;\n await mkdir(dirname(destination), { recursive: true });\n await cp(source, destination, {\n recursive: true,\n force: true,\n filter: () => {\n options.signal?.throwIfAborted();\n return true;\n },\n });\n };\n return {\n root: context.directory,\n home: homedir(),\n invoke(command: Command) {\n if (disposed)\n return Promise.reject(\n new OutpostError(\"provider\", \"Local sandbox is closed\"),\n );\n const signal = command.signal\n ? AbortSignal.any([command.signal, stop.signal])\n : stop.signal;\n const pending = executeProcess({\n ...command,\n directory: command.directory ?? context.directory,\n variables: { ...context.variables, ...command.variables },\n signal,\n });\n active.add(pending);\n void pending.then(\n () => active.delete(pending),\n () => active.delete(pending),\n );\n return pending;\n },\n upload: copy,\n download: copy,\n async release() {\n if (disposed) return;\n disposed = true;\n stop.abort(new OutpostError(\"aborted\", \"Sandbox disposed\"));\n await Promise.allSettled(active);\n },\n };\n },\n };\n}\n"]}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { ContainerOptions } from "./container.types.ts";
|
|
2
2
|
export type { ContainerOptions } from "./container.ts";
|
|
3
3
|
export declare const podman: (options?: ContainerOptions) => import("../index.ts").SandboxProvider;
|
|
4
|
+
export type { DependencyCache } from "./container-cache.types.ts";
|
|
5
|
+
export type { EgressPolicy } from "../domain/egress.types.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"podman.js","sourceRoot":"","sources":["../../src/providers/podman.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAKnD,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,UAA4B,EAAE,EAAE,EAAE,CACvD,iBAAiB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC","sourcesContent":["import { containerProvider } from \"./container.ts\";\nimport type { ContainerOptions } from \"./container.types.ts\";\n\nexport type { ContainerOptions } from \"./container.ts\";\n\nexport const podman = (options: ContainerOptions = {}) =>\n containerProvider(\"podman\", options);\n"]}
|
|
1
|
+
{"version":3,"file":"podman.js","sourceRoot":"","sources":["../../src/providers/podman.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAKnD,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,UAA4B,EAAE,EAAE,EAAE,CACvD,iBAAiB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC","sourcesContent":["import { containerProvider } from \"./container.ts\";\nimport type { ContainerOptions } from \"./container.types.ts\";\n\nexport type { ContainerOptions } from \"./container.ts\";\n\nexport const podman = (options: ContainerOptions = {}) =>\n containerProvider(\"podman\", options);\n\nexport type { DependencyCache } from \"./container-cache.types.ts\";\n\nexport type { EgressPolicy } from \"../domain/egress.types.ts\";\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PtyHandle } from "@daytona/sdk";
|
|
2
|
+
import type { Command } from "../domain/command.types.ts";
|
|
3
|
+
export declare function terminalBridge(command: Command, retain: number): {
|
|
4
|
+
failure: Promise<never>;
|
|
5
|
+
size: () => {
|
|
6
|
+
cols: number;
|
|
7
|
+
rows: number;
|
|
8
|
+
};
|
|
9
|
+
output(data: Uint8Array): void;
|
|
10
|
+
connect(pty: PtyHandle): void;
|
|
11
|
+
flush(): Promise<void>;
|
|
12
|
+
text: () => string;
|
|
13
|
+
close(): void;
|
|
14
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { StringDecoder } from "node:string_decoder";
|
|
2
|
+
import { ReadStream } from "node:tty";
|
|
3
|
+
export function terminalBridge(command, retain) {
|
|
4
|
+
const input = command.terminal?.input ?? process.stdin;
|
|
5
|
+
const output = command.terminal?.output ?? process.stdout;
|
|
6
|
+
const decoder = new StringDecoder("utf8");
|
|
7
|
+
const wasPaused = input.isPaused();
|
|
8
|
+
const raw = input instanceof ReadStream ? input.isRaw : false;
|
|
9
|
+
let captured = "";
|
|
10
|
+
let active = true;
|
|
11
|
+
let pending = Promise.resolve();
|
|
12
|
+
let sending = Promise.resolve();
|
|
13
|
+
let handle;
|
|
14
|
+
let reject = () => { };
|
|
15
|
+
const failure = new Promise((_resolve, fail) => {
|
|
16
|
+
reject = fail;
|
|
17
|
+
});
|
|
18
|
+
void failure.catch(() => undefined);
|
|
19
|
+
const size = () => ({
|
|
20
|
+
cols: "columns" in output && typeof output.columns === "number"
|
|
21
|
+
? output.columns
|
|
22
|
+
: 80,
|
|
23
|
+
rows: "rows" in output && typeof output.rows === "number" ? output.rows : 24,
|
|
24
|
+
});
|
|
25
|
+
const capture = (text) => {
|
|
26
|
+
captured = retain > 0 ? (captured + text).slice(-retain) : "";
|
|
27
|
+
try {
|
|
28
|
+
command.observe?.("stdout", text);
|
|
29
|
+
}
|
|
30
|
+
catch { }
|
|
31
|
+
};
|
|
32
|
+
const send = (data) => {
|
|
33
|
+
input.pause();
|
|
34
|
+
sending = sending.then(async () => {
|
|
35
|
+
if (active)
|
|
36
|
+
await handle?.sendInput(data);
|
|
37
|
+
});
|
|
38
|
+
void sending.then(() => {
|
|
39
|
+
if (active)
|
|
40
|
+
input.resume();
|
|
41
|
+
}, reject);
|
|
42
|
+
};
|
|
43
|
+
const end = () => send(new Uint8Array([4]));
|
|
44
|
+
const resize = () => {
|
|
45
|
+
const { cols, rows } = size();
|
|
46
|
+
void handle?.resize(cols, rows).catch(reject);
|
|
47
|
+
};
|
|
48
|
+
const error = (cause) => reject(cause);
|
|
49
|
+
output.on("error", error);
|
|
50
|
+
return {
|
|
51
|
+
failure,
|
|
52
|
+
size,
|
|
53
|
+
output(data) {
|
|
54
|
+
if (!active)
|
|
55
|
+
return;
|
|
56
|
+
const bytes = Buffer.from(data);
|
|
57
|
+
capture(decoder.write(bytes));
|
|
58
|
+
pending = pending.then(() => new Promise((resolve, rejectWrite) => {
|
|
59
|
+
if (!active) {
|
|
60
|
+
resolve();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
output.write(bytes, (cause) => cause ? rejectWrite(cause) : resolve());
|
|
64
|
+
}));
|
|
65
|
+
void pending.catch(reject);
|
|
66
|
+
},
|
|
67
|
+
connect(pty) {
|
|
68
|
+
handle = pty;
|
|
69
|
+
if (input instanceof ReadStream)
|
|
70
|
+
input.setRawMode(true);
|
|
71
|
+
input.on("data", send);
|
|
72
|
+
input.on("end", end);
|
|
73
|
+
input.on("error", error);
|
|
74
|
+
output.on("resize", resize);
|
|
75
|
+
if (input.readableEnded)
|
|
76
|
+
end();
|
|
77
|
+
input.resume();
|
|
78
|
+
},
|
|
79
|
+
async flush() {
|
|
80
|
+
await Promise.race([pending, failure]);
|
|
81
|
+
capture(decoder.end());
|
|
82
|
+
},
|
|
83
|
+
text: () => captured,
|
|
84
|
+
close() {
|
|
85
|
+
active = false;
|
|
86
|
+
input.removeListener("data", send);
|
|
87
|
+
input.removeListener("end", end);
|
|
88
|
+
input.removeListener("error", error);
|
|
89
|
+
output.removeListener("resize", resize);
|
|
90
|
+
output.removeListener("error", error);
|
|
91
|
+
if (wasPaused || input.listenerCount("data") === 0)
|
|
92
|
+
input.pause();
|
|
93
|
+
if (!wasPaused && input.listenerCount("data") > 0)
|
|
94
|
+
input.resume();
|
|
95
|
+
if (input instanceof ReadStream)
|
|
96
|
+
input.setRawMode(raw);
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=terminal-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-bridge.js","sourceRoot":"","sources":["../../src/providers/terminal-bridge.ts"],"names":[],"mappings":"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","sourcesContent":["import { StringDecoder } from \"node:string_decoder\";\nimport { ReadStream } from \"node:tty\";\nimport type { PtyHandle } from \"@daytona/sdk\";\nimport type { Command } from \"../domain/command.types.ts\";\n\nexport function terminalBridge(command: Command, retain: number) {\n const input = command.terminal?.input ?? process.stdin;\n const output = command.terminal?.output ?? process.stdout;\n const decoder = new StringDecoder(\"utf8\");\n const wasPaused = input.isPaused();\n const raw = input instanceof ReadStream ? input.isRaw : false;\n let captured = \"\";\n let active = true;\n let pending = Promise.resolve();\n let sending = Promise.resolve();\n let handle: PtyHandle | undefined;\n let reject: (cause: unknown) => void = () => {};\n const failure = new Promise<never>((_resolve, fail) => {\n reject = fail;\n });\n void failure.catch(() => undefined);\n const size = () => ({\n cols:\n \"columns\" in output && typeof output.columns === \"number\"\n ? output.columns\n : 80,\n rows:\n \"rows\" in output && typeof output.rows === \"number\" ? output.rows : 24,\n });\n const capture = (text: string) => {\n captured = retain > 0 ? (captured + text).slice(-retain) : \"\";\n try {\n command.observe?.(\"stdout\", text);\n } catch {}\n };\n const send = (data: string | Uint8Array) => {\n input.pause();\n sending = sending.then(async () => {\n if (active) await handle?.sendInput(data);\n });\n void sending.then(() => {\n if (active) input.resume();\n }, reject);\n };\n const end = () => send(new Uint8Array([4]));\n const resize = () => {\n const { cols, rows } = size();\n void handle?.resize(cols, rows).catch(reject);\n };\n const error = (cause: Error) => reject(cause);\n output.on(\"error\", error);\n return {\n failure,\n size,\n output(data: Uint8Array) {\n if (!active) return;\n const bytes = Buffer.from(data);\n capture(decoder.write(bytes));\n pending = pending.then(\n () =>\n new Promise<void>((resolve, rejectWrite) => {\n if (!active) {\n resolve();\n return;\n }\n output.write(bytes, (cause) =>\n cause ? rejectWrite(cause) : resolve(),\n );\n }),\n );\n void pending.catch(reject);\n },\n connect(pty: PtyHandle) {\n handle = pty;\n if (input instanceof ReadStream) input.setRawMode(true);\n input.on(\"data\", send);\n input.on(\"end\", end);\n input.on(\"error\", error);\n output.on(\"resize\", resize);\n if (input.readableEnded) end();\n input.resume();\n },\n async flush() {\n await Promise.race([pending, failure]);\n capture(decoder.end());\n },\n text: () => captured,\n close() {\n active = false;\n input.removeListener(\"data\", send);\n input.removeListener(\"end\", end);\n input.removeListener(\"error\", error);\n output.removeListener(\"resize\", resize);\n output.removeListener(\"error\", error);\n if (wasPaused || input.listenerCount(\"data\") === 0) input.pause();\n if (!wasPaused && input.listenerCount(\"data\") > 0) input.resume();\n if (input instanceof ReadStream) input.setRawMode(raw);\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { OutpostError } from "../domain/errors.js";
|
|
2
|
+
export async function vercelDirectory(sandbox, path) {
|
|
3
|
+
const result = await sandbox.runCommand("mkdir", ["-p", "--", path]);
|
|
4
|
+
if (result.exitCode !== 0)
|
|
5
|
+
throw new OutpostError("provider", `Could not create remote directory ${path}: ${await result.stderr()}`);
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=vercel-directory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vercel-directory.js","sourceRoot":"","sources":["../../src/providers/vercel-directory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAiC,EACjC,IAAY;IAEZ,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IACrE,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC;QACvB,MAAM,IAAI,YAAY,CACpB,UAAU,EACV,qCAAqC,IAAI,KAAK,MAAM,MAAM,CAAC,MAAM,EAAE,EAAE,CACtE,CAAC;AACN,CAAC","sourcesContent":["import { OutpostError } from \"../domain/errors.ts\";\nimport type { VercelRuntime } from \"./vercel.types.ts\";\n\nexport async function vercelDirectory(\n sandbox: VercelRuntime[\"sandbox\"],\n path: string,\n): Promise<void> {\n const result = await sandbox.runCommand(\"mkdir\", [\"-p\", \"--\", path]);\n if (result.exitCode !== 0)\n throw new OutpostError(\n \"provider\",\n `Could not create remote directory ${path}: ${await result.stderr()}`,\n );\n}\n"]}
|
|
@@ -3,12 +3,13 @@ import { OutpostError } from "../domain/errors.js";
|
|
|
3
3
|
import { transfer } from "../infrastructure/transfer.js";
|
|
4
4
|
import { manifestScript } from "./cloud-files.constants.js";
|
|
5
5
|
import { downloadTree, uploadTree } from "./cloud-files.js";
|
|
6
|
+
import { vercelDirectory } from "./vercel-directory.js";
|
|
6
7
|
export function vercelFiles(sandbox) {
|
|
7
8
|
return {
|
|
8
9
|
async upload(source, destination, options = {}) {
|
|
9
10
|
return transfer(options, async (signal) => {
|
|
10
11
|
await uploadTree(source, destination, (path, content) => sandbox.writeFiles([{ path, content }]), async (target, path) => {
|
|
11
|
-
await sandbox
|
|
12
|
+
await vercelDirectory(sandbox, posix.dirname(path));
|
|
12
13
|
const result = await sandbox.runCommand("ln", [
|
|
13
14
|
"-s",
|
|
14
15
|
"--",
|
|
@@ -19,7 +20,7 @@ export function vercelFiles(sandbox) {
|
|
|
19
20
|
throw new OutpostError("provider", "Symlink upload failed");
|
|
20
21
|
}, async (path, directory, mode) => {
|
|
21
22
|
if (directory)
|
|
22
|
-
await sandbox
|
|
23
|
+
await vercelDirectory(sandbox, path);
|
|
23
24
|
const result = await sandbox.runCommand("chmod", [
|
|
24
25
|
mode.toString(8),
|
|
25
26
|
path,
|