@north-light/cli 0.3.561 → 0.3.562
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/dist/api/client.d.ts +27 -4
- package/dist/api/client.js +3 -3
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/bash-jobs.d.ts +5 -1
- package/dist/api/dto/broker-ops.d.ts +25 -1
- package/dist/api/dto/charges.d.ts +9 -2
- package/dist/api/dto/delivery.d.ts +26 -2
- package/dist/api/dto/execution-start.d.ts +57 -0
- package/dist/api/dto/execution-start.js +0 -0
- package/dist/api/dto/modelauth.d.ts +5 -0
- package/dist/api/dto/node-records.d.ts +16 -0
- package/dist/api/dto/objects.d.ts +1 -1
- package/dist/api/dto/reports.d.ts +0 -3
- package/dist/api/dto/run-events.d.ts +7 -1
- package/dist/api/dto/settings.d.ts +55 -0
- package/dist/api/dto/settings.js +0 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +1 -1
- package/dist/api/routes.d.ts +11 -0
- package/dist/api/routes.js +1 -1
- package/dist/builtin-memory/crouter-sdk/release-notes.md +4 -0
- package/dist/cli.js +7 -7
- package/dist/clients/attach/chrome/bash-jobs.d.ts +11 -1
- package/dist/clients/attach/chrome/bash-jobs.js +1 -1
- package/dist/clients/attach/chrome/canvas-panels.d.ts +1 -1
- package/dist/clients/attach/chrome/roster.js +6 -4
- package/dist/clients/attach/overlays/auth.js +2 -2
- package/dist/clients/attach/render/chat-view.js +1 -1
- package/dist/clients/attach/viewer.js +550 -567
- package/dist/commands/canvas-config.js +2 -2
- package/dist/commands/canvas-use.js +1 -1
- package/dist/commands/human.js +2 -2
- package/dist/commands/node/bash.js +3 -3
- package/dist/commands/node/create.js +2 -2
- package/dist/commands/person-settings.d.ts +1 -0
- package/dist/commands/person-settings.js +1 -0
- package/dist/commands/pkg/market-manage.d.ts +2 -2
- package/dist/commands/pkg/market-manage.js +1 -1
- package/dist/commands/pkg/plugin-manage.js +13 -13
- package/dist/commands/pkg/shared.js +1 -1
- package/dist/commands/profile/default.js +1 -1
- package/dist/commands/push.js +2 -3
- package/dist/commands/sys/config.js +1 -1
- package/dist/commands/sys/connect.js +1 -1
- package/dist/commands/sys/context/sysprompt.js +2 -2
- package/dist/commands/sys/doctor.js +1 -1
- package/dist/commands/sys/panels/broker-limits-panel.js +1 -1
- package/dist/commands/sys/panels/keybindings-panel.js +1 -1
- package/dist/commands/sys/panels/models-panel.d.ts +8 -2
- package/dist/commands/sys/panels/models-panel.js +1 -1
- package/dist/commands/sys/panels/prefs-panel.d.ts +1 -0
- package/dist/commands/sys/panels/prefs-panel.js +1 -1
- package/dist/commands/sys/panels/profiles-panel.js +1 -1
- package/dist/commands/sys/panels/provider-panel.d.ts +4 -0
- package/dist/commands/sys/panels/provider-panel.js +1 -1
- package/dist/commands/sys/provider-login.js +5 -5
- package/dist/commands/sys/setup-core.js +3 -3
- package/dist/commands/sys/setup-settings-runner.js +1 -1
- package/dist/commands/sys/spend.js +3 -3
- package/dist/commands/sys/update.js +1 -1
- package/dist/core/auth-file.d.ts +11 -19
- package/dist/core/auth-file.js +1 -2
- package/dist/core/auto-update.d.ts +1 -1
- package/dist/core/auto-update.js +4 -4
- package/dist/core/bash-jobs.d.ts +29 -71
- package/dist/core/bash-jobs.js +9 -10
- package/dist/core/blobs/directory.d.ts +3 -0
- package/dist/core/blobs/directory.js +1 -0
- package/dist/core/blobs/fault.d.ts +3 -0
- package/dist/core/blobs/fault.js +1 -0
- package/dist/core/blobs/index.d.ts +21 -0
- package/dist/core/blobs/index.js +1 -0
- package/dist/core/blobs/r2.d.ts +9 -0
- package/dist/core/blobs/r2.js +4 -0
- package/dist/core/bootstrap.d.ts +1 -1
- package/dist/core/bootstrap.js +2 -2
- package/dist/core/canvas/canvas.d.ts +9 -7
- package/dist/core/canvas/canvas.js +8 -8
- package/dist/core/canvas/crons.d.ts +3 -2
- package/dist/core/canvas/crons.js +3 -3
- package/dist/core/canvas/daemon-owner.d.ts +5 -0
- package/dist/core/canvas/daemon-owner.js +1 -1
- package/dist/core/canvas/db.d.ts +10 -9
- package/dist/core/canvas/db.js +4 -4
- package/dist/core/canvas/executions.d.ts +100 -4
- package/dist/core/canvas/executions.js +1 -1
- package/dist/core/canvas/export-sqlite.js +1 -1
- package/dist/core/canvas/focuses.d.ts +4 -0
- package/dist/core/canvas/focuses.js +1 -1
- package/dist/core/canvas/history.js +9 -9
- package/dist/core/canvas/managed-worktree-sweep-candidates.d.ts +2 -1
- package/dist/core/canvas/managed-worktree-sweep-candidates.js +3 -2
- package/dist/core/canvas/node-tokens.d.ts +1 -4
- package/dist/core/canvas/node-tokens.js +3 -3
- package/dist/core/canvas/paths.d.ts +0 -1
- package/dist/core/canvas/paths.js +1 -1
- package/dist/core/canvas/person-state.d.ts +26 -0
- package/dist/core/canvas/person-state.js +1 -0
- package/dist/core/canvas/person.d.ts +3 -10
- package/dist/core/canvas/person.js +7 -7
- package/dist/core/canvas/reconciler-leases.d.ts +12 -0
- package/dist/core/canvas/reconciler-leases.js +8 -0
- package/dist/core/canvas/recovery.d.ts +4 -0
- package/dist/core/canvas/recovery.js +1 -1
- package/dist/core/canvas/schema-pg/003-fleet-removals.sql +1 -1
- package/dist/core/canvas/schema-pg/005-fleet-blobs.sql +13 -0
- package/dist/core/canvas/schema-pg/006-job-rows.sql +20 -0
- package/dist/core/canvas/schema-pg/007-ledger-check.sql +117 -0
- package/dist/core/canvas/schema-version.d.ts +1 -1
- package/dist/core/canvas/schema-version.js +1 -1
- package/dist/core/canvas/sessions.d.ts +8 -11
- package/dist/core/canvas/sessions.js +1 -4
- package/dist/core/canvas/tree.d.ts +4 -2
- package/dist/core/canvas/tree.js +6 -6
- package/dist/core/canvas/types.d.ts +7 -0
- package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
- package/dist/core/command-plugins/bundle.d.ts +1 -1
- package/dist/core/command-plugins/bundle.js +1 -1
- package/dist/core/command-plugins/compose.d.ts +1 -1
- package/dist/core/command-plugins/discovery.d.ts +0 -1
- package/dist/core/command-plugins/discovery.js +1 -1
- package/dist/core/command-plugins/help-addenda.js +1 -1
- package/dist/core/command-plugins/presence.d.ts +2 -0
- package/dist/core/command-plugins/presence.js +1 -1
- package/dist/core/config.d.ts +16 -15
- package/dist/core/config.js +1 -1
- package/dist/core/conversation-store/client-worker.js +1 -1
- package/dist/core/conversation-store/client.js +2 -2
- package/dist/core/conversation-store/index.d.ts +9 -11
- package/dist/core/conversation-store/index.js +1 -1
- package/dist/core/conversation-store/patch.js +1 -1
- package/dist/core/conversation-store/row-store.d.ts +14 -0
- package/dist/core/conversation-store/row-store.js +13 -0
- package/dist/core/directory/join.js +1 -1
- package/dist/core/env-name.d.ts +1 -0
- package/dist/core/env-name.js +1 -1
- package/dist/core/environment-recipe.d.ts +15 -0
- package/dist/core/environment-recipe.js +1 -0
- package/dist/core/environments.js +1 -1
- package/dist/core/events/emit.js +2 -2
- package/dist/core/events/run-event-chunks.d.ts +25 -0
- package/dist/core/events/run-event-chunks.js +5 -0
- package/dist/core/feed/messages.js +5 -5
- package/dist/core/grants/mirror.d.ts +15 -0
- package/dist/core/grants/mirror.js +15 -3
- package/dist/core/grants/on-sync.d.ts +9 -5
- package/dist/core/grants/on-sync.js +1 -1
- package/dist/core/grants/remove.d.ts +1 -6
- package/dist/core/grants/remove.js +1 -1
- package/dist/core/grants/sync.js +1 -1
- package/dist/core/grants/watch.d.ts +15 -9
- package/dist/core/grants/watch.js +1 -1
- package/dist/core/graph/custom.js +8 -8
- package/dist/core/graph/jobs.d.ts +83 -5
- package/dist/core/graph/jobs.js +11 -2
- package/dist/core/graph/kinds/job.js +2 -2
- package/dist/core/graph/names.js +7 -7
- package/dist/core/graph/objects.d.ts +5 -1
- package/dist/core/graph/objects.js +11 -11
- package/dist/core/graph/reader.d.ts +3 -0
- package/dist/core/graph/reader.js +3 -3
- package/dist/core/graph/repo-sync/identity.d.ts +3 -1
- package/dist/core/graph/repo-sync/identity.js +1 -1
- package/dist/core/graph/repo-sync/repos.d.ts +1 -1
- package/dist/core/graph/repo-sync/repos.js +2 -2
- package/dist/core/graph/repo-sync/sync.js +2 -2
- package/dist/core/installed-plugins.js +1 -1
- package/dist/core/keybindings/persistence.d.ts +1 -1
- package/dist/core/keybindings/persistence.js +1 -1
- package/dist/core/layout-migrate/loose-keys.d.ts +1 -1
- package/dist/core/layout-migrate/loose-keys.js +1 -1
- package/dist/core/ledger/account.d.ts +12 -0
- package/dist/core/ledger/account.js +2 -0
- package/dist/core/ledger/charges.d.ts +2 -2
- package/dist/core/ledger/charges.js +1 -1
- package/dist/core/ledger/check.d.ts +5 -1
- package/dist/core/ledger/check.js +1 -7
- package/dist/core/ledger/chunks.d.ts +8 -0
- package/dist/core/ledger/chunks.js +2 -0
- package/dist/core/ledger/index.d.ts +2 -1
- package/dist/core/ledger/index.js +1 -1
- package/dist/core/ledger/infra-allowance.d.ts +9 -0
- package/dist/core/ledger/infra-allowance.js +1 -0
- package/dist/core/ledger/limits.js +3 -3
- package/dist/core/ledger/payer.d.ts +1 -1
- package/dist/core/ledger/payer.js +1 -1
- package/dist/core/ledger/read.d.ts +14 -4
- package/dist/core/ledger/read.js +2 -3
- package/dist/core/ledger/totals.d.ts +5 -16
- package/dist/core/ledger/totals.js +4 -4
- package/dist/core/ledger/types.d.ts +12 -3
- package/dist/core/llm/run.js +2 -2
- package/dist/core/managed-providers.d.ts +72 -0
- package/dist/core/managed-providers.js +1 -0
- package/dist/core/model-auth/api-credential-store.d.ts +10 -0
- package/dist/core/model-auth/api-credential-store.js +1 -0
- package/dist/core/model-auth/daemon-login.d.ts +1 -1
- package/dist/core/model-auth/daemon-login.js +1 -1
- package/dist/core/model-auth/flows.d.ts +5 -4
- package/dist/core/model-auth/flows.js +1 -1
- package/dist/core/model-auth/handoff-jti.d.ts +3 -4
- package/dist/core/model-auth/handoff-jti.js +1 -1
- package/dist/core/model-auth/readiness.js +1 -1
- package/dist/core/model-config.d.ts +1 -1
- package/dist/core/model-config.js +1 -1
- package/dist/core/model-routes-pool.d.ts +14 -0
- package/dist/core/model-routes-pool.js +1 -0
- package/dist/core/model-routes.d.ts +11 -16
- package/dist/core/model-routes.js +1 -1
- package/dist/core/peer/ingest.d.ts +2 -0
- package/dist/core/peer/ingest.js +1 -1
- package/dist/core/peer/stubs.d.ts +8 -0
- package/dist/core/peer/stubs.js +1 -1
- package/dist/core/permissions/evaluator.d.ts +7 -2
- package/dist/core/permissions/evaluator.js +2 -2
- package/dist/core/plugin-env.js +1 -1
- package/dist/core/pool-credential-store.d.ts +2 -5
- package/dist/core/pool-credential-store.js +1 -1
- package/dist/core/profiles/app-env-store.d.ts +5 -5
- package/dist/core/profiles/app-env-store.js +1 -2
- package/dist/core/profiles/default-binding.d.ts +5 -5
- package/dist/core/profiles/default-binding.js +1 -1
- package/dist/core/profiles/env-store.d.ts +10 -21
- package/dist/core/profiles/env-store.js +1 -2
- package/dist/core/profiles/manifest.d.ts +14 -18
- package/dist/core/profiles/manifest.js +1 -1
- package/dist/core/profiles/relocate.js +1 -1
- package/dist/core/profiles/select.js +21 -21
- package/dist/core/provider-credential.d.ts +1 -1
- package/dist/core/provider-credential.js +1 -1
- package/dist/core/provider-management.d.ts +3 -4
- package/dist/core/provider-management.js +1 -1
- package/dist/core/providers/bundles.js +2 -2
- package/dist/core/providers/call.d.ts +3 -34
- package/dist/core/providers/description.d.ts +34 -0
- package/dist/core/providers/description.js +0 -0
- package/dist/core/providers/token-cache.d.ts +14 -14
- package/dist/core/providers/token-cache.js +1 -1
- package/dist/core/review/companion.js +1 -1
- package/dist/core/runs/activity.d.ts +1 -1
- package/dist/core/runs/activity.js +1 -1
- package/dist/core/runs/events.d.ts +7 -5
- package/dist/core/runs/events.js +2 -6
- package/dist/core/runs/operations.d.ts +1 -1
- package/dist/core/runs/operations.js +6 -6
- package/dist/core/runtime/bearings.js +1 -1
- package/dist/core/runtime/broker/attachments-fetch.d.ts +5 -0
- package/dist/core/runtime/broker/attachments-fetch.js +1 -0
- package/dist/core/runtime/broker/bash-job-launch.d.ts +4 -2
- package/dist/core/runtime/broker/bash-job-launch.js +1 -1
- package/dist/core/runtime/broker/boot-state.d.ts +9 -0
- package/dist/core/runtime/broker/boot-state.js +1 -0
- package/dist/core/runtime/broker/cli-relay.d.ts +2 -1
- package/dist/core/runtime/broker/cli-relay.js +1 -1
- package/dist/core/runtime/broker/client-registry.d.ts +3 -3
- package/dist/core/runtime/broker/daemon-ops.d.ts +10 -1
- package/dist/core/runtime/broker/daemon-ops.js +1 -1
- package/dist/core/runtime/broker/fault-retry.d.ts +2 -0
- package/dist/core/runtime/broker/fault-retry.js +1 -1
- package/dist/core/runtime/broker/frame-engine-control.js +1 -1
- package/dist/core/runtime/broker/held-deferred-inbox.d.ts +3 -0
- package/dist/core/runtime/broker/held-deferred-inbox.js +1 -1
- package/dist/core/runtime/broker/job-reporter.d.ts +18 -0
- package/dist/core/runtime/broker/job-reporter.js +2 -0
- package/dist/core/runtime/broker/model-adapter.d.ts +3 -0
- package/dist/core/runtime/broker/model-adapter.js +3 -2
- package/dist/core/runtime/broker/signal-stream.js +1 -1
- package/dist/core/runtime/broker/spilled-body.d.ts +5 -0
- package/dist/core/runtime/broker/spilled-body.js +1 -0
- package/dist/core/runtime/broker/summaries-post.d.ts +5 -0
- package/dist/core/runtime/broker/summaries-post.js +1 -0
- package/dist/core/runtime/broker/tool-groups.d.ts +3 -0
- package/dist/core/runtime/broker/tool-groups.js +1 -1
- package/dist/core/runtime/broker/turn-replies.d.ts +1 -0
- package/dist/core/runtime/broker/turn-replies.js +1 -1
- package/dist/core/runtime/broker-persona-guidance.js +2 -2
- package/dist/core/runtime/broker.js +1 -1
- package/dist/core/runtime/deliver-live.js +1 -1
- package/dist/core/runtime/first-boot-rows.d.ts +8 -0
- package/dist/core/runtime/first-boot-rows.js +2 -0
- package/dist/core/runtime/fleet.d.ts +13 -12
- package/dist/core/runtime/front-door-login.js +1 -1
- package/dist/core/runtime/front-door.js +6 -6
- package/dist/core/runtime/headless-pi.js +1 -1
- package/dist/core/runtime/host.d.ts +14 -3
- package/dist/core/runtime/host.js +3 -3
- package/dist/core/runtime/invocation.d.ts +6 -0
- package/dist/core/runtime/kickoff.d.ts +2 -14
- package/dist/core/runtime/kickoff.js +17 -19
- package/dist/core/runtime/launch-config-worker.js +1 -1
- package/dist/core/runtime/launch.js +2 -2
- package/dist/core/runtime/model-registry.js +1 -1
- package/dist/core/runtime/node-read.d.ts +4 -6
- package/dist/core/runtime/node-read.js +3 -3
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/core/runtime/outcome-document.d.ts +0 -1
- package/dist/core/runtime/outcome-document.js +1 -1
- package/dist/core/runtime/output-result.d.ts +15 -0
- package/dist/core/runtime/output-result.js +5 -0
- package/dist/core/runtime/placement.d.ts +17 -1
- package/dist/core/runtime/placement.js +1 -1
- package/dist/core/runtime/provider-credential-gate.d.ts +6 -2
- package/dist/core/runtime/provider-credential-gate.js +2 -2
- package/dist/core/runtime/recovery-hold.d.ts +21 -2
- package/dist/core/runtime/recovery-hold.js +2 -1
- package/dist/core/runtime/recycle.js +1 -1
- package/dist/core/runtime/reset.js +1 -1
- package/dist/core/runtime/revive.d.ts +2 -2
- package/dist/core/runtime/revive.js +2 -2
- package/dist/core/runtime/runner/blaxel/client.d.ts +81 -0
- package/dist/core/runtime/runner/blaxel/client.js +1 -0
- package/dist/core/runtime/runner/blaxel/image-build.d.ts +74 -0
- package/dist/core/runtime/runner/blaxel/image-build.js +5 -0
- package/dist/core/runtime/runner/blaxel/runner.d.ts +41 -0
- package/dist/core/runtime/runner/blaxel/runner.js +3 -0
- package/dist/core/runtime/runner/index.d.ts +8 -0
- package/dist/core/runtime/runner/index.js +1 -0
- package/dist/core/runtime/runner/process.d.ts +11 -0
- package/dist/core/runtime/runner/process.js +1 -0
- package/dist/core/runtime/runner/types.d.ts +95 -0
- package/dist/core/runtime/runner/types.js +0 -0
- package/dist/core/runtime/situational-context.d.ts +3 -6
- package/dist/core/runtime/situational-context.js +2 -2
- package/dist/core/runtime/situational-live.js +1 -1
- package/dist/core/runtime/spawn-env-rows.d.ts +5 -0
- package/dist/core/runtime/spawn-env-rows.js +1 -0
- package/dist/core/runtime/spawn-env.d.ts +4 -18
- package/dist/core/runtime/spawn-env.js +1 -1
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/core/runtime/stop-guard.d.ts +1 -1
- package/dist/core/runtime/stop-guard.js +2 -8
- package/dist/core/runtime/structured-output.d.ts +0 -67
- package/dist/core/runtime/structured-output.js +3 -8
- package/dist/core/runtime/tmux-driver.d.ts +8 -0
- package/dist/core/runtime/tmux-driver.js +6 -6
- package/dist/core/runtime/view-socket.d.ts +20 -0
- package/dist/core/runtime/view-socket.js +3 -1
- package/dist/core/runtime/warm-pool.d.ts +13 -1
- package/dist/core/runtime/warm-pool.js +1 -1
- package/dist/core/scoped-state/legacy-profiles.d.ts +11 -0
- package/dist/core/scoped-state/legacy-profiles.js +1 -0
- package/dist/core/scoped-state/materialized-plugins.d.ts +18 -0
- package/dist/core/scoped-state/materialized-plugins.js +1 -0
- package/dist/core/scoped-state/migrate.d.ts +8 -1
- package/dist/core/scoped-state/migrate.js +3 -3
- package/dist/core/scoped-state/person-rows.d.ts +10 -0
- package/dist/core/scoped-state/person-rows.js +6 -0
- package/dist/core/scoped-state/person-store.d.ts +72 -0
- package/dist/core/scoped-state/person-store.js +1 -0
- package/dist/core/secrets/blaxel-launch.d.ts +24 -0
- package/dist/core/secrets/blaxel-launch.js +4 -0
- package/dist/core/secrets/blaxel-register.d.ts +2 -0
- package/dist/core/secrets/blaxel-register.js +1 -0
- package/dist/core/secrets/env-rows.d.ts +17 -0
- package/dist/core/secrets/env-rows.js +4 -0
- package/dist/core/secrets/environment-owner.d.ts +8 -0
- package/dist/core/secrets/environment-owner.js +1 -0
- package/dist/core/secrets/environment-secrets.d.ts +14 -0
- package/dist/core/secrets/environment-secrets.js +1 -0
- package/dist/core/secrets/index.d.ts +2 -0
- package/dist/core/secrets/index.js +1 -0
- package/dist/core/secrets/key.d.ts +3 -0
- package/dist/core/secrets/key.js +2 -0
- package/dist/core/secrets/seal.d.ts +18 -0
- package/dist/core/secrets/seal.js +1 -0
- package/dist/core/spaces/mounts.d.ts +1 -1
- package/dist/core/spaces/mounts.js +1 -1
- package/dist/core/spaces/process.d.ts +1 -1
- package/dist/core/spaces/stop.d.ts +7 -5
- package/dist/core/spaces/stop.js +2 -2
- package/dist/core/spaces/users.d.ts +2 -1
- package/dist/core/spaces/users.js +1 -1
- package/dist/core/storage/attachments.d.ts +11 -8
- package/dist/core/storage/attachments.js +1 -1
- package/dist/core/storage/tables.d.ts +4 -0
- package/dist/core/storage/tables.js +3 -3
- package/dist/core/subscription-state.d.ts +34 -72
- package/dist/core/subscription-state.js +1 -4
- package/dist/core/substrate/delivery/plan.js +1 -1
- package/dist/core/user-settings.js +1 -1
- package/dist/daemon/api/app-listener.js +10 -10
- package/dist/daemon/api/auth/person-bearer.d.ts +14 -0
- package/dist/daemon/api/auth/person-bearer.js +1 -0
- package/dist/daemon/api/bridge.js +4 -4
- package/dist/daemon/api/document-listener.js +3 -3
- package/dist/daemon/api/environment-of.d.ts +18 -0
- package/dist/daemon/api/environment-of.js +5 -0
- package/dist/daemon/api/handlers/analytics.js +1 -1
- package/dist/daemon/api/handlers/app-profiles.d.ts +2 -2
- package/dist/daemon/api/handlers/app-profiles.js +1 -1
- package/dist/daemon/api/handlers/bash-jobs.js +1 -1
- package/dist/daemon/api/handlers/bash.js +1 -1
- package/dist/daemon/api/handlers/broker-ops.d.ts +3 -0
- package/dist/daemon/api/handlers/broker-ops.js +1 -1
- package/dist/daemon/api/handlers/broker-recovery.js +1 -1
- package/dist/daemon/api/handlers/broker-signals.d.ts +0 -3
- package/dist/daemon/api/handlers/broker-signals.js +2 -2
- package/dist/daemon/api/handlers/canvas.js +4 -4
- package/dist/daemon/api/handlers/charges.d.ts +1 -1
- package/dist/daemon/api/handlers/charges.js +1 -1
- package/dist/daemon/api/handlers/conversations.d.ts +2 -0
- package/dist/daemon/api/handlers/conversations.js +3 -0
- package/dist/daemon/api/handlers/crons.js +1 -1
- package/dist/daemon/api/handlers/daemon.js +1 -1
- package/dist/daemon/api/handlers/delivery.d.ts +1 -1
- package/dist/daemon/api/handlers/delivery.js +1 -1
- package/dist/daemon/api/handlers/docs.js +1 -1
- package/dist/daemon/api/handlers/exec.js +1 -1
- package/dist/daemon/api/handlers/execution-start.d.ts +2 -0
- package/dist/daemon/api/handlers/execution-start.js +2 -0
- package/dist/daemon/api/handlers/files.js +1 -1
- package/dist/daemon/api/handlers/git-credential.d.ts +11 -0
- package/dist/daemon/api/handlers/git-credential.js +1 -0
- package/dist/daemon/api/handlers/hook-exec.d.ts +1 -1
- package/dist/daemon/api/handlers/hook-exec.js +1 -1
- package/dist/daemon/api/handlers/human-requests.js +1 -1
- package/dist/daemon/api/handlers/inbox.js +1 -1
- package/dist/daemon/api/handlers/messages.js +1 -1
- package/dist/daemon/api/handlers/model-config.js +1 -1
- package/dist/daemon/api/handlers/modelauth.d.ts +1 -1
- package/dist/daemon/api/handlers/modelauth.js +1 -1
- package/dist/daemon/api/handlers/node-events.d.ts +6 -0
- package/dist/daemon/api/handlers/node-events.js +3 -3
- package/dist/daemon/api/handlers/node-outcomes.js +1 -1
- package/dist/daemon/api/handlers/node-records.js +3 -2
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/objects.js +3 -3
- package/dist/daemon/api/handlers/profiles.js +1 -1
- package/dist/daemon/api/handlers/providers.js +1 -1
- package/dist/daemon/api/handlers/reports.js +9 -13
- package/dist/daemon/api/handlers/reviews.js +1 -1
- package/dist/daemon/api/handlers/runs.js +1 -1
- package/dist/daemon/api/handlers/settings.d.ts +2 -0
- package/dist/daemon/api/handlers/settings.js +1 -0
- package/dist/daemon/api/handlers/structured-requests.js +1 -1
- package/dist/daemon/api/handlers/vendor-status.d.ts +1 -1
- package/dist/daemon/api/handlers/vendor-status.js +1 -1
- package/dist/daemon/api/handlers/worktree.js +1 -1
- package/dist/daemon/api/map.d.ts +2 -2
- package/dist/daemon/api/map.js +2 -2
- package/dist/daemon/api/operations.js +1 -1
- package/dist/daemon/api/reader.d.ts +8 -1
- package/dist/daemon/api/reader.js +1 -1
- package/dist/daemon/api/router.d.ts +4 -2
- package/dist/daemon/api/router.js +1 -1
- package/dist/daemon/api/server.d.ts +15 -3
- package/dist/daemon/api/server.js +1 -1
- package/dist/daemon/api/vendor-signin.d.ts +2 -1
- package/dist/daemon/api/vendor-signin.js +19 -19
- package/dist/daemon/api/viewer-presence.d.ts +20 -6
- package/dist/daemon/api/viewer-presence.js +2 -1
- package/dist/daemon/broker-signals/bus.d.ts +48 -11
- package/dist/daemon/broker-signals/bus.js +1 -1
- package/dist/daemon/cron/armed-context.js +1 -1
- package/dist/daemon/cron/lease-recovery.js +1 -1
- package/dist/daemon/cron/live-runs.d.ts +6 -0
- package/dist/daemon/cron/live-runs.js +1 -1
- package/dist/daemon/cron/run-socket.js +1 -1
- package/dist/daemon/cron-run.js +2 -2
- package/dist/daemon/crtrd-cli.js +1 -1
- package/dist/daemon/crtrd.d.ts +10 -0
- package/dist/daemon/crtrd.js +18 -17
- package/dist/daemon/delivery/run-delivery.d.ts +1 -1
- package/dist/daemon/delivery/run-delivery.js +1 -1
- package/dist/daemon/due-sources.d.ts +1 -1
- package/dist/daemon/due-sources.js +1 -1
- package/dist/daemon/due.js +7 -6
- package/dist/daemon/fleet.d.ts +6 -6
- package/dist/daemon/fleet.js +9 -9
- package/dist/daemon/park-activity.d.ts +2 -1
- package/dist/daemon/park-activity.js +1 -1
- package/dist/daemon/park-pending.d.ts +20 -13
- package/dist/daemon/park-pending.js +3 -1
- package/dist/daemon/profile-delete.js +1 -1
- package/dist/daemon/reconcilers/bash-deadline.d.ts +15 -10
- package/dist/daemon/reconcilers/bash-deadline.js +1 -3
- package/dist/daemon/reconcilers/broker-supervision.d.ts +13 -3
- package/dist/daemon/reconcilers/broker-supervision.js +4 -4
- package/dist/daemon/reconcilers/cron-lane.d.ts +0 -1
- package/dist/daemon/reconcilers/cron-lane.js +1 -1
- package/dist/daemon/reconcilers/fault-retry-backstop.d.ts +2 -9
- package/dist/daemon/reconcilers/fault-retry-backstop.js +1 -1
- package/dist/daemon/reconcilers/grant-effects.d.ts +8 -0
- package/dist/daemon/reconcilers/grant-effects.js +1 -0
- package/dist/daemon/reconcilers/grove-instance-sweep.d.ts +1 -3
- package/dist/daemon/reconcilers/grove-instance-sweep.js +1 -1
- package/dist/daemon/reconcilers/ledger-r2.d.ts +27 -0
- package/dist/daemon/reconcilers/ledger-r2.js +7 -0
- package/dist/daemon/reconcilers/ledger-sandbox.d.ts +55 -0
- package/dist/daemon/reconcilers/ledger-sandbox.js +9 -0
- package/dist/daemon/reconcilers/ledger-storage.d.ts +22 -0
- package/dist/daemon/reconcilers/ledger-storage.js +5 -0
- package/dist/daemon/reconcilers/live-obligation.d.ts +3 -2
- package/dist/daemon/reconcilers/live-obligation.js +1 -1
- package/dist/daemon/reconcilers/managed-worktree-sweep.d.ts +0 -5
- package/dist/daemon/reconcilers/managed-worktree-sweep.js +1 -1
- package/dist/daemon/reconcilers/node-deadline.d.ts +2 -1
- package/dist/daemon/reconcilers/node-deadline.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -2
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/remote-wake.d.ts +31 -0
- package/dist/daemon/reconcilers/node-lifecycle/remote-wake.js +1 -0
- package/dist/daemon/reconcilers/node-lifecycle/requested-stops.d.ts +5 -0
- package/dist/daemon/reconcilers/node-lifecycle/requested-stops.js +2 -0
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
- package/dist/daemon/reconcilers/pending-review-submit.js +1 -1
- package/dist/daemon/reconcilers/recipe-image.d.ts +49 -0
- package/dist/daemon/reconcilers/recipe-image.js +7 -0
- package/dist/daemon/reconcilers/row-claim.d.ts +19 -0
- package/dist/daemon/reconcilers/row-claim.js +2 -0
- package/dist/daemon/reconcilers/storage-due-work.d.ts +18 -3
- package/dist/daemon/reconcilers/storage-due-work.js +2 -1
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +5 -13
- package/dist/daemon/reconcilers/storage-maintenance.js +1 -1
- package/dist/daemon/reconcilers/structured-request-lane.js +1 -1
- package/dist/daemon/reconcilers/throttled-lane.d.ts +11 -0
- package/dist/daemon/reconcilers/throttled-lane.js +1 -0
- package/dist/daemon/review/finish.js +1 -1
- package/dist/daemon/run-notices.d.ts +3 -0
- package/dist/daemon/run-notices.js +1 -1
- package/dist/daemon/runs/append-section.d.ts +4 -1
- package/dist/daemon/runs/append-section.js +2 -2
- package/dist/daemon/runs/observer.d.ts +3 -2
- package/dist/daemon/runs/observer.js +3 -2
- package/dist/daemon/runs/view-transport.d.ts +19 -0
- package/dist/daemon/runs/view-transport.js +1 -0
- package/dist/daemon/structured-requests/boot.d.ts +2 -1
- package/dist/daemon/structured-requests/boot.js +1 -1
- package/dist/daemon/structured-requests/effects.d.ts +4 -3
- package/dist/daemon/structured-requests/effects.js +1 -1
- package/dist/daemon/structured-requests/notifier.d.ts +2 -0
- package/dist/daemon/structured-requests/notifier.js +1 -1
- package/dist/daemon/structured-requests/sidecar.d.ts +4 -3
- package/dist/daemon/structured-requests/sidecar.js +1 -1
- package/dist/launcher/validate.js +1 -1
- package/dist/migrations/004-canvas-documents/index.js +2 -2
- package/dist/pi-extensions/broker-local.d.ts +3 -3
- package/dist/pi-extensions/broker-local.js +1 -2
- package/dist/pi-extensions/canvas-bash-valve.js +6 -6
- package/dist/pi-extensions/canvas-context-intro.js +2 -2
- package/dist/pi-extensions/canvas-elapsed.js +2 -2
- package/dist/pi-extensions/canvas-goal-capture.js +1 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +2 -2
- package/dist/pi-extensions/canvas-review-boundary.d.ts +11 -1
- package/dist/pi-extensions/canvas-review-boundary.js +3 -3
- package/dist/pi-extensions/canvas-stophook.js +1 -1
- package/dist/pi-extensions/canvas-structured-output.d.ts +5 -3
- package/dist/pi-extensions/canvas-structured-output.js +6 -11
- package/dist/pi-extensions/canvas-tool-guide.d.ts +9 -2
- package/dist/pi-extensions/canvas-tool-guide.js +6 -6
- package/dist/shared/inbox-entry-body.js +7 -7
- package/dist/types.d.ts +12 -0
- package/docs/sdk/release-notes.md +4 -0
- package/package.json +7 -4
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -13
- package/scripts/git-credential-crtr +33 -0
- package/scripts/sandbox-bootstrap.sh +54 -0
- package/scripts/sandbox-start.mjs +320 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +0 -78
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +0 -1179
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +0 -1406
- package/dist/core/conversation-store/file-store.d.ts +0 -37
- package/dist/core/conversation-store/file-store.js +0 -9
- package/dist/core/conversation-store/listener.d.ts +0 -4
- package/dist/core/conversation-store/listener.js +0 -8
- package/dist/core/scoped-state/profiles.d.ts +0 -27
- package/dist/core/scoped-state/profiles.js +0 -1
- package/dist/core/scoped-state/providers.d.ts +0 -24
- package/dist/core/scoped-state/providers.js +0 -1
- package/dist/core/scoped-state/settings.d.ts +0 -28
- package/dist/core/scoped-state/settings.js +0 -1
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
import { type FocusRow } from '../canvas/index.js';
|
|
2
2
|
export type { FocusRow };
|
|
3
|
-
export { splitWindow, breakPane, selectLayout, selectPane, focusWindow, selectWindow, switchClient, openNodeWindow, ensureSession, paneLocation, paneExists, paneRunning, paneCurrentPath, currentTmux, inTmux, paneOfNode, setPaneOption, getPaneOption, piCommand, shellQuote, respawnPaneSync, closePane, displayPopup, windowOfPane, renameWindow, paneOfWindow, windowAlive, listLivePanes, listLivePanesAsync, } from './tmux-driver.js';
|
|
3
|
+
export { splitWindow, breakPane, selectLayout, selectPane, focusWindow, selectWindow, switchClient, openNodeWindow, ensureSession, paneLocation, paneExists, paneRunning, paneCurrentPath, currentTmux, inTmux, paneOfNode, setPaneOption, getPaneOption, piCommand, shellQuote, respawnPaneSync, closePane, displayPopup, windowOfPane, renameWindow, paneOfWindow, windowAlive, listLivePanes, listLivePanesAsync, paneStateAsync, } from './tmux-driver.js';
|
|
4
4
|
export type { RespawnPaneOpts } from './tmux-driver.js';
|
|
5
5
|
export { installTmuxBindings } from './tmux-bindings.js';
|
|
6
6
|
export type { TmuxInstalledPair, TmuxInstallDiagnostic, TmuxInstallResult } from './tmux-bindings.js';
|
|
7
7
|
/** The viewer a node has on screen, or null. UNIQUE(node_id) ⇒ at most one. */
|
|
8
8
|
export declare function focusOf(nodeId: string): Promise<FocusRow | null>;
|
|
9
|
+
/** A node's viewer, probed ahead of a canvas write: `live` is the row whose pane tmux answered for (or did not answer for in time),
|
|
10
|
+
* `stale` the row whose pane tmux reported gone; both null means the node had no row. The probe is a snapshot taken outside the
|
|
11
|
+
* write, so the write passes it through {@link confirmViewer} before deciding from it. */
|
|
12
|
+
export interface ViewerProbe {
|
|
13
|
+
nodeId: string;
|
|
14
|
+
live: FocusRow | null;
|
|
15
|
+
stale: FocusRow | null;
|
|
16
|
+
}
|
|
17
|
+
/** Read a node's viewer row and probe its pane with a bounded, non-blocking tmux call. Call it BEFORE `withCanvasWrite`: the
|
|
18
|
+
* probe holds no connection, and a hung tmux costs one timeout instead of an open transaction. A timed-out probe counts as live. */
|
|
19
|
+
export declare function probeViewer(nodeId: string): Promise<ViewerProbe>;
|
|
20
|
+
/** Inside the write: re-read the node's viewer row under its lock and compare it with the probe. A row that matches the probe
|
|
21
|
+
* (same focus and pane) keeps the probe's verdict, and a stale one is deleted here, only while it is still on the probed pane.
|
|
22
|
+
* A row that differs from the probe — re-pointed to another pane, or created after an empty probe — was never probed, so it
|
|
23
|
+
* counts as a live viewer and nothing is deleted; the next settle probes it. No tmux runs here. */
|
|
24
|
+
export declare function confirmViewer(probe: ViewerProbe): Promise<ViewerProbe>;
|
|
9
25
|
/** Does this node have a live viewer on screen? */
|
|
10
26
|
export declare function isFocused(nodeId: string): Promise<boolean>;
|
|
11
27
|
/** The viewer realized by a given pane (`%id`), or null. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var b=Object.defineProperty;var i=(e,n)=>b(e,"name",{value:n,configurable:!0});import{envNodeId as H}from"../../shared/env.js";import{getNode as p,fullName as M,deleteNode as R,listNodes as U,openFocusRow as z,closeFocusRow as c,closeFocusRowOnPane as D,getFocusByNodeForUpdate as J,getFocusByNode as _,getFocusByPane as x,getFocusById as Q,listFocuses as X}from"../canvas/index.js";import{nodeHasAssistantMessage as j}from"../canvas/render-source.js";import{headlessBrokerHost as S}from"./host.js";import{publishNotice as q}from"./close.js";import{paneExists as m,paneStateAsync as T,listLivePanesAsync as G,paneLocation as g,closePane as P,currentTmux as K,switchClient as Y,selectWindow as Z,selectLayout as I,selectPane as k,getPaneOption as ee,setPaneOption as ne,respawnPaneSync as ae,windowOfPane as te,renameWindow as ie}from"./tmux-driver.js";import{openViewerPane as se,viewerSplitEnv as B,waitForBrokerViewSocket as oe}from"./placement-tmux.js";import{newJobId as le}from"./nodes.js";import{isPidAlive as h}from"../canvas/pid.js";import{splitWindow as Be,breakPane as We,selectLayout as Ee,selectPane as Le,focusWindow as Ce,selectWindow as Ve,switchClient as $e,openNodeWindow as be,ensureSession as He,paneLocation as Me,paneExists as Ue,paneRunning as ze,paneCurrentPath as De,currentTmux as Je,inTmux as Qe,paneOfNode as Xe,setPaneOption as je,getPaneOption as qe,piCommand as Ge,shellQuote as Ke,respawnPaneSync as Ye,closePane as Ze,displayPopup as Ie,windowOfPane as en,renameWindow as nn,paneOfWindow as an,windowAlive as tn,listLivePanes as sn,listLivePanesAsync as on,paneStateAsync as ln}from"./tmux-driver.js";import{installTmuxBindings as un}from"./tmux-bindings.js";async function N(e,n=null){return e===null?null:e.pane!==null&&!(n!==null?n.has(e.pane):await T(e.pane)!=="gone")?(await c(e.focus_id),null):e}i(N,"liveOrPrune");async function w(e){return await N(await _(e))}i(w,"focusOf");async function he(e){const n=await _(e);return n===null?{nodeId:e,live:null,stale:null}:n.pane===null||await T(n.pane)!=="gone"?{nodeId:e,live:n,stale:null}:{nodeId:e,live:null,stale:n}}i(he,"probeViewer");async function Ne(e){const n=await J(e.nodeId),a=e.live??e.stale;return n===null?{nodeId:e.nodeId,live:null,stale:null}:a===null||a.focus_id!==n.focus_id||a.pane!==n.pane?{nodeId:e.nodeId,live:n,stale:null}:e.stale!==null?(await D(n.focus_id,n.pane),{nodeId:e.nodeId,live:null,stale:null}):{nodeId:e.nodeId,live:n,stale:null}}i(Ne,"confirmViewer");async function Fe(e){return await w(e)!==null}i(Fe,"isFocused");async function re(e){return await N(await x(e))}i(re,"focusByPane");async function Oe(){return new Set((await ue()).map(e=>e.node_id))}i(Oe,"focusedNodes");async function ue(){const e=[],n=await X(),a=n.some(t=>t.pane!==null)?await G():null;for(const t of n)await N(t,a)!==null&&e.push(t);return e}i(ue,"listFocuses");function ce(){return`f-${le()}`}i(ce,"newFocusId");async function W(e,n,a,t){const r=await x(n);if(r!==null)return r;const o=await _(e);if(o!==null)return o;const l=ce();return await z(l,n,a,e),await Q(l)}i(W,"registerViewerFocus");async function E(e,n,a={}){const t=se(e,n,a);return t===null?null:await W(e,t.pane,t.session,t.window)}i(E,"openViewerWindow");function L(e){const n=g(e)?.window??null;n!==null&&I(n,"even-horizontal"),k(e)}i(L,"surfaceNewPane");async function Ae(e,n){const a=await p(e);if(a===null)return{focused:!1,session:null,inPlace:!1,revived:!1};const t=n.pane??process.env.TMUX_PANE??K()?.pane;if(t===void 0||t==="")return{focused:!1,session:null,inPlace:!1,revived:!1};const r=h(a.pi_pid??null),o=n.revive(e),l=!r;if(!await oe(e,o?.launch?.exited))return{focused:!1,session:null,inPlace:!1,revived:l};const y=g(t)?.session??null,F=y??"";if(n.inPlace===!0){const s=await w(e);s!==null&&(s.pane!==null&&s.pane!==t&&m(s.pane)&&P(s.pane),await c(s.focus_id));const u=await x(t);u!==null&&u.node_id!==e&&await c(u.focus_id);try{ne(t,"@crtr_node","")}catch{}const v=te(t),O=u?.node_id,$=O===void 0?B():{...B(),CRTR_ATTACH_ROSTER:O},A=ae({pane:t,cwd:a.cwd,env:$,command:`crtr surface attach to ${e}`});return A&&(v!==null&&ie(v,M(a)),await W(e,t,y,v)),{focused:A,session:y,inPlace:!0,revived:l}}if(n.newPane===!0){const s=await w(e);s!==null&&(s.pane!==null&&m(s.pane)&&P(s.pane),await c(s.focus_id));const u=await E(e,F,{cwd:a.cwd,besidePane:t});return u===null?{focused:!1,session:null,inPlace:!1,revived:l}:(u.pane!==null&&L(u.pane),{focused:!0,session:u.session,inPlace:!1,revived:l})}const f=await w(e);if(f!==null&&f.pane!==null)if(ee(f.pane,"@crtr_node")===e){const s=g(f.pane);if(s!==null)return Y(s.session),Z(s.session,s.window),k(f.pane),{focused:!0,session:s.session,inPlace:!0,revived:l};await c(f.focus_id)}else await c(f.focus_id);const d=await E(e,F,{cwd:a.cwd,besidePane:t});return d===null?{focused:!1,session:null,inPlace:!1,revived:l}:(d.pane!==null&&L(d.pane),{focused:!0,session:d.session,inPlace:!1,revived:l})}i(Ae,"focus");async function C(e,n){const a=await w(e);a!==null&&(a.pane!==null&&a.pane!==n&&m(a.pane)&&P(a.pane),await c(a.focus_id))}i(C,"tearDownNode");async function Re(e,n){const a=n??(await w(e))?.pane??null;if(a===null||!m(a))return!1;const t=await re(a);t!==null&&await c(t.focus_id);const r=P(a);return await fe(e),r}i(Re,"detachToBackground");async function V(e){const n=await p(e);return n===null||n.streaming===!0&&h(n.pi_pid)?!1:!await j(n.pi_session_file)}i(V,"isEmptyNode");async function fe(e,n,a=!0){return(await p(e))?.managed_worktree?.state==="open"||!await V(e)?!1:(a&&S.teardown(e),await C(e,n),(await R(e)).deleted)}i(fe,"reapIfEmpty");async function Se(e={}){const n=e.dryRun??!1,a=H()??"",t=[];for(const r of await U()){const o=r.node_id,l=await p(o);o===a||r.status==="dead"||h(r.pi_pid)||l?.managed_worktree?.state==="open"||!await V(o)||!n&&(await q(o,"notice.close",`Child closed \u2014 ${l?.name??o} (${o}) was closed from the canvas and is no longer running.`,{reason:"child-closed",child:o}),S.teardown(o),await C(o),!(await R(o)).deleted)||t.push(o)}return t}i(Se,"reapEmptyNodes");export{We as breakPane,Ze as closePane,Ne as confirmViewer,Je as currentTmux,Re as detachToBackground,Ie as displayPopup,He as ensureSession,Ae as focus,re as focusByPane,w as focusOf,Ce as focusWindow,Oe as focusedNodes,qe as getPaneOption,Qe as inTmux,un as installTmuxBindings,Fe as isFocused,ue as listFocuses,sn as listLivePanes,on as listLivePanesAsync,be as openNodeWindow,E as openViewerWindow,De as paneCurrentPath,Ue as paneExists,Me as paneLocation,Xe as paneOfNode,an as paneOfWindow,ze as paneRunning,ln as paneStateAsync,Ge as piCommand,he as probeViewer,Se as reapEmptyNodes,fe as reapIfEmpty,W as registerViewerFocus,nn as renameWindow,Ye as respawnPaneSync,Ee as selectLayout,Le as selectPane,Ve as selectWindow,je as setPaneOption,Ke as shellQuote,Be as splitWindow,$e as switchClient,C as tearDownNode,tn as windowAlive,en as windowOfPane};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import type { CredentialStore } from '@earendil-works/pi-ai';
|
|
2
|
+
/** The daemon, which owns the rows, registers its row-backed store; every other process asks the daemon over /v1/model-auth. */
|
|
3
|
+
export declare function registerGateCredentialStore(store: CredentialStore): void;
|
|
1
4
|
export declare const NO_PROVIDER_CREDENTIAL_MESSAGE = "crtr: no provider credential; run `crtr sys setup` to log in.";
|
|
2
|
-
/** Check the setup catalog before a path creates a broker-backed node.
|
|
3
|
-
|
|
5
|
+
/** Check the setup catalog before a path creates a broker-backed node. `profileEnvNames` are the names stored on the
|
|
6
|
+
* launching profile (values are never needed: a stored value is never empty). */
|
|
7
|
+
export declare function hasConfiguredProviderCredential(profileEnvNames: readonly string[]): Promise<boolean>;
|
|
4
8
|
export declare function exitForMissingProviderCredential(): never;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var m=Object.defineProperty;var
|
|
2
|
-
`),process.exit(1)}
|
|
1
|
+
var m=Object.defineProperty;var t=(r,o)=>m(r,"name",{value:o,configurable:!0});import{ModelRegistry as a,ModelRuntime as d}from"@earendil-works/pi-coding-agent";import{join as p}from"node:path";import{ApiCredentialStore as c}from"../model-auth/api-credential-store.js";import{cliClient as l}from"../../commands/api-client.js";import{hasProviderCredential as f}from"../provider-credential.js";import{piAgentDir as u}from"./package-health.js";import{PROVIDER_ENV_KEYS as E}from"./spawn-env.js";let n;function S(r){n=r}t(S,"registerGateCredentialStore");const C="crtr: no provider credential; run `crtr sys setup` to log in.";async function _(r){const o=Object.fromEntries(r.map(e=>[e,"stored"]));if(Object.values(E).some(e=>(o[e]??process.env[e])?.trim()))return!0;const s=u(),i=await d.create({credentials:n??new c(()=>l()),modelsPath:p(s,"models.json")});return await f(i,new a(i))}t(_,"hasConfiguredProviderCredential");function j(){process.stderr.write(`${C}
|
|
2
|
+
`),process.exit(1)}t(j,"exitForMissingProviderCredential");export{C as NO_PROVIDER_CREDENTIAL_MESSAGE,j as exitForMissingProviderCredential,_ as hasConfiguredProviderCredential,S as registerGateCredentialStore};
|
|
@@ -1,2 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/** A stop in progress on a node, held on the node's row (`recovery_held_until`, `recovery_held_by`).
|
|
2
|
+
* Dead-row recovery leaves a held node alone, so the broker's exit cannot be read as a crash and
|
|
3
|
+
* resumed before the caller that is stopping it on purpose (a grant-sync revocation stop) decides the
|
|
4
|
+
* row's next state. The same hold is the single-flight of a node's stop across processes: one
|
|
5
|
+
* holder at a time, and a holder that died frees the node when the hold expires. */
|
|
6
|
+
export declare const RECOVERY_HOLD_MS: number;
|
|
7
|
+
/** A stop's claim on a node. It renews itself every third of the hold's length while the stop runs, so a stop longer than
|
|
8
|
+
* the hold never lets recovery restart the node; `renew` is also the fence a stop checks before each step it must not
|
|
9
|
+
* repeat after losing the hold. */
|
|
10
|
+
export interface RecoveryHold {
|
|
11
|
+
/** Extends the hold; false when it lapsed and another stop took it (or its expiry passed). */
|
|
12
|
+
renew(): Promise<boolean>;
|
|
13
|
+
release(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
/** Claims the hold for a fresh owner token, or null when another stop holds the node. A holder that overran its expiry
|
|
16
|
+
* cannot renew or release a successor's hold: both match the owner token. */
|
|
17
|
+
export declare function holdRecovery(nodeId: string): Promise<RecoveryHold | null>;
|
|
18
|
+
export declare function isRecoveryHeld(nodeId: string): Promise<boolean>;
|
|
19
|
+
/** Waits until no stop holds the node. `lapsed` means the last holder never released (it died or stalled past expiry), so
|
|
20
|
+
* the stop it was running did not finish; `released` means it finished and cleared the hold itself. */
|
|
21
|
+
export declare function waitForRecoveryHold(nodeId: string): Promise<'released' | 'lapsed'>;
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var l=Object.defineProperty;var t=(e,r)=>l(e,"name",{value:r,configurable:!0});import{randomUUID as _}from"node:crypto";import{openDb as n}from"../canvas/db.js";const a=5*6e4;async function v(e){const r=_(),o=new Date;if((await(await n()).prepare(`UPDATE nodes SET recovery_held_until = ?, recovery_held_by = ?
|
|
2
|
+
WHERE node_id = ? AND (recovery_held_until IS NULL OR recovery_held_until <= ?)`).run(new Date(o.getTime()+a).toISOString(),r,e,o.toISOString())).changes!==1)return null;const i=t(async()=>{const d=new Date;return(await(await n()).prepare("UPDATE nodes SET recovery_held_until = ? WHERE node_id = ? AND recovery_held_by = ? AND recovery_held_until > ?").run(new Date(d.getTime()+a).toISOString(),e,r,d.toISOString())).changes===1},"renew"),c=setInterval(()=>{i().catch(()=>{})},a/3);return c.unref(),{renew:i,release:t(async()=>{clearInterval(c),await(await n()).prepare("UPDATE nodes SET recovery_held_until = NULL, recovery_held_by = NULL WHERE node_id = ? AND recovery_held_by = ?").run(e,r)},"release")}}t(v,"holdRecovery");async function s(e){return await(await n()).prepare("SELECT 1 AS held FROM nodes WHERE node_id = ? AND recovery_held_until > ?").get(e,new Date().toISOString())!==void 0}t(s,"isRecoveryHeld");async function p(e){for(;await s(e);)await new Promise(o=>setTimeout(o,250));return(await(await n()).prepare("SELECT recovery_held_by FROM nodes WHERE node_id = ?").get(e))?.recovery_held_by==null?"released":"lapsed"}t(p,"waitForRecoveryHold");export{a as RECOVERY_HOLD_MS,v as holdRecovery,s as isRecoveryHeld,p as waitForRecoveryHold};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var p=Object.defineProperty;var
|
|
1
|
+
var p=Object.defineProperty;var r=(e,t)=>p(e,"name",{value:t,configurable:!0});import{abortExecution as y,beginExecution as _,getNode as s,setPresence as h,setFocusOccupant as v,fullName as R,recordExecutionPid as b,recordLaunch as k}from"../canvas/index.js";import{pushFinal as E}from"../feed/feed.js";import{newestReportBody as g}from"../feed/reports.js";import{spawnNode as S,rootOfSpine as x}from"./nodes.js";import{buildLaunchSpecAsync as T,buildPiArgv as B}from"./launch.js";import{focusOf as C,respawnPaneSync as N,setPaneOption as O}from"./placement.js";import{waitForBrokerViewSocket as P,viewerSplitEnv as D}from"./placement-tmux.js";import{headlessBrokerHost as u}from"./host.js";import{boundFleet as F,brokerThresholdsForDaemon as z}from"./fleet.js";import{transition as A}from"./lifecycle.js";import{ensureDaemon as L}from"../../daemon/manage.js";import{invokeBirthLifecycleHooks as U}from"./spawn.js";import{checkStart as H}from"./start-check.js";async function ne(e,t){const a=await s(e);if(a===null)return{recycled:!1,finalized:!1,newRoot:null,delivered:[]};const o=t??process.env.TMUX_PANE;if(o===void 0||o==="")return{recycled:!1,finalized:!1,newRoot:null,delivered:[]};await H(a);const w=await C(e);try{L()}catch{}const{launch:f}=await T("general","base",{lifecycle:"resident",hasManager:!1,cwd:a.cwd,profileId:a.profile_id}),m=await g(e)||`Closed via recycle \u2014 no final summary was authored by ${a.name}.`;let c=[],d=!1;const n=await S({kind:"general",mode:"base",lifecycle:"resident",cwd:a.cwd,name:"general",parent:null,replaces:e,profile_id:a.profile_id,launch:f,beforeCreate:r(async()=>{try{c=(await E(e,m)).deliveredTo,d=!0}catch{}},"beforeCreate")}),i=await s(n.node_id);await U(i);const l=B(i);if(l.env={...l.env,CRTR_SUBTREE:await x(n.node_id)},!await M(i,l))return{recycled:!1,finalized:d,newRoot:n.node_id,delivered:c};try{u.teardown(e)}catch{}try{await h(e,{pane:null,window:null,tmux_session:null})}catch{}if(w!==null)try{await v(w.focus_id,n.node_id)}catch{}return{recycled:X(i,o),finalized:d,newRoot:n.node_id,delivered:c}}r(ne,"recycleNode");async function M(e,t){const a=await _(e.node_id,{daemonEpoch:F().epoch(),cap:z().automaticReviveCap});t.env={...t.env,CRTR_EXECUTION_ID:a};let o;try{if(o=await u.launch(e.node_id,t,{cwd:e.cwd,name:R(e),resuming:!1}),o.pid===null)throw new Error("broker host returned no pid");if(await k(e.node_id,new Date().toISOString()),await b(a,e.node_id,o.pid)==="shutdown")throw new Error("broker execution was superseded");if(await P(e.node_id,o.exited))return!0}catch{await y(a,{reason:"launch_failed"})}try{await V(e.node_id)}catch{}try{u.teardown(e.node_id)}catch{}return!1}r(M,"launchRecycledBroker");async function V(e){const t=await s(e);(t?.status==="active"||t?.status==="idle")&&await A(e,"crash")}r(V,"transitionReplacementToDead");function X(e,t){try{O(t,"@crtr_node","")}catch{}return N({pane:t,cwd:e.cwd,env:D(),command:`crtr surface attach to ${e.node_id}`})}r(X,"respawnRecycledViewer");export{ne as recycleNode};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var S=Object.defineProperty;var s=(e,a)=>S(e,"name",{value:a,configurable:!0});import{getNode as f,beginExecution as
|
|
1
|
+
var S=Object.defineProperty;var s=(e,a)=>S(e,"name",{value:a,configurable:!0});import{getNode as f,beginExecution as b,recordExecutionPid as B,abortExecution as v,bindSession as F,recordLaunch as N,fullName as x,liveExecutionForNode as R,closeFocusRow as g,view as C}from"../canvas/index.js";import{transition as r}from"./lifecycle.js";import{headlessBrokerHost as y,requestBrokerTeardown as D}from"./host.js";import{boundFleet as O,brokerThresholdsForDaemon as T}from"./fleet.js";import{tearDownNode as V,focusOf as P,registerViewerFocus as I,respawnPaneSync as L,windowOfPane as q,renameWindow as A}from"./placement.js";import{viewerSplitEnv as H,waitForBrokerViewSocket as M}from"./placement-tmux.js";import{buildLaunchSpecAsync as U,buildPiArgv as j}from"./launch.js";import{newNodeId as W,spawnNode as X,rootOfSpine as $}from"./nodes.js";import{appSpace as z}from"../layout.js";import{join as G}from"node:path";import{invokeBirthLifecycleHooks as J}from"./spawn.js";import{checkStart as K}from"./start-check.js";async function Q(e){const a=[];for(const i of await C(e))try{await r(i,"cancel",{reason:"closed"}),D(i),await V(i),a.push(i)}catch{}return a}s(Q,"reapDescendants");async function we(e,a={}){const i=a.launchBroker??y.launch,l=a.waitForViewSocket??M,p=a.respawnViewer??L,c=a.teardownBroker??y.teardown,n=await f(e);if(n===null||n.parent!=null||n.status==="done")return null;await K(n);const d=await P(e),h=n.isolated?await W():void 0,_=h?G(z(n.grantee??"app:terminal").nodes,h):n.cwd,{launch:E}=await U(n.kind,"base",{lifecycle:"resident",hasManager:!1,model:n.model_override??void 0,modelIntent:n.launch?.modelIntent,modelExact:n.launch?.modelExact,cwd:_,profileId:n.profile_id}),t=await X({nodeId:h,kind:n.kind,mode:"base",lifecycle:"resident",cwd:_,name:n.kind,parent:null,replaces:e,profile_id:n.profile_id,launch:E,modelOverride:n.model_override??void 0});await J(t);const u=j(t,{});u.env={...u.env,CRTR_SUBTREE:await $(t.node_id)};const w=await b(t.node_id,{daemonEpoch:O().epoch(),cap:T().automaticReviveCap});u.env={...u.env,CRTR_EXECUTION_ID:w};let m;try{m=await i(t.node_id,u,{cwd:_,name:x(t),resuming:!1})}catch(o){throw await v(w,{reason:"launch_failed"}),await r(t.node_id,"crash"),o}if(m.pid==null)return await v(w,{reason:"launch_failed"}),await r(t.node_id,"crash"),null;if(await N(t.node_id,new Date().toISOString()),await B(w,t.node_id,m.pid)==="shutdown"){await v(w,{reason:"superseded"});try{c(t.node_id)}catch{}return await r(t.node_id,"crash"),null}let k=!1;try{k=await l(t.node_id,m.exited)}catch{}if(!k){const o=await f(t.node_id);(o?.status==="active"||o?.status==="idle")&&await r(t.node_id,"crash");try{c(t.node_id)}catch{}return null}if(await Q(e),await r(e,"finish"),d?.pane!=null){await g(d.focus_id),p({pane:d.pane,cwd:n.cwd,env:H(),command:`crtr surface attach to ${t.node_id}`});const o=q(d.pane);o!==null&&A(o,x(t)),await I(t.node_id,d.pane,d.session,o)}return c(e),{newNodeId:t.node_id}}s(we,"relaunchRoot");async function Y(e,a,i){const l=await f(e),p={reaped:[],detached:[],reset:!1};if(l===null||l.parent==null)return p;if(a!==void 0){const c=await R(e);c!==null&&await F(e,{executionId:c.executionId,sessionId:a,transcriptPath:i??null})}return p}s(Y,"resetRoot");async function fe(e,a,i){return await f(e)===null?{path:"noop"}:(await Y(e,a,i),{path:"reset-child"})}s(fe,"handleNewSession");async function pe(e,a){if(a!=="quit")return!1;const i=await f(e);return i===null||i.status!=="active"&&i.status!=="idle"||i.intent!=null?!1:(await r(e,"finish"),!0)}s(pe,"markCleanExitDone");export{fe as handleNewSession,pe as markCleanExitDone,Q as reapDescendants,we as relaunchRoot,Y as resetRoot};
|
|
@@ -4,7 +4,7 @@ import type { WakeOrigin } from './bearings.js';
|
|
|
4
4
|
* abort is the one exception: continue the persisted transcript with a factual
|
|
5
5
|
* warning rather than creating a fresh cycle. */
|
|
6
6
|
export type ReviveWakeReason = WakeOrigin | 'runtime-restart-abort';
|
|
7
|
-
import {
|
|
7
|
+
import { processRunner } from './runner/process.js';
|
|
8
8
|
/** Pick the `--session` source for a revive. Both resume=true (a true resume)
|
|
9
9
|
* and resume=false (a refresh-yield) resume by the absolute session-file path
|
|
10
10
|
* (immune to cwd; pi opens it directly) — but ONLY when that file actually
|
|
@@ -45,7 +45,7 @@ export interface ReviveResult {
|
|
|
45
45
|
resumed: boolean;
|
|
46
46
|
/** Launch handle for the detached broker, so callers can fail fast on its real
|
|
47
47
|
* exit before the socket appears. */
|
|
48
|
-
launch?: Awaited<ReturnType<typeof
|
|
48
|
+
launch?: Awaited<ReturnType<typeof processRunner.start>>;
|
|
49
49
|
/** Reads a fatal launch fault recorded by THIS revive attempt, scoped via
|
|
50
50
|
* `beginBootFaultAttempt` at the exact clear-then-launch boundary below.
|
|
51
51
|
* Present only when a fresh launch actually happened (absent on the
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var q=Object.defineProperty;var s=(e,r)=>q(e,"name",{value:r,configurable:!0});import{assertGranteeRunsHere as Q}from"./unsandboxed.js";import{existsSync as B}from"node:fs";import{conversationIdFromPath as h,conversationStore as d,ConversationNotFoundError as D}from"../conversation-store/index.js";import{isAbsolute as Z}from"node:path";import{findNodeBySessionFile as I,getNode as R,updateNode as E,beginExecution as ee,recordExecutionPid as re,abortExecution as S,endLiveExecution as ie,unbindSession as O,recordLaunch as te,setFrozen as ne,clearFrozen as oe,fullName as T}from"../canvas/index.js";import{emitEvent as ae}from"../events/emit.js";import{consumeDeadlineOnWake as se}from"../feed/messages.js";import{isParked as z,transition as x}from"./lifecycle.js";import{publishNotice as le}from"./close.js";import{InputError as $}from"../io.js";import{buildPiArgv as p}from"./launch.js";import{buildReviveKickoff as ce,drainBearings as ue,hasRetainedReports as fe,readGoal as k,readYieldMessage as we,RUNTIME_RESTART_CONTINUATION as de}from"./kickoff.js";import{readRoadmap as H}from"./roadmap.js";import{encodeKickoffOrigin as he,KICKOFF_ORIGIN_ENV as pe}from"./stamp/protocol.js";import{headlessBrokerHost as M}from"./host.js";import{appMemoryFull as ve,appMemoryTooSmall as me,boundFleet as U,brokerCapReached as _e,brokerThresholdsForDaemon as K}from"./fleet.js";import{admitBrokerMemory as ye}from"./memory-admission.js";import{beginBootFaultAttempt as ke,clearFault as ge,hasAdmittedTurn as be}from"../canvas/recovery.js";import{clearNodeLedger as G,forkNodeLedger as Re,noticeChangedWhileDone as Ee}from"./ledger.js";import{forkSourceNode as Se,rootOfSpine as xe}from"./nodes.js";import{checkStart as $e}from"./start-check.js";import{isReviewCompanionBound as Ce}from"../review/companion.js";import{assertProfileActive as Ne}from"../profiles/manifest.js";import{isPidAlive as Ae}from"../canvas/pid.js";import{crtrHome as Fe,jobDir as Pe}from"../canvas/paths.js";import{contextDir as Be,ensureNodeDirs as De,nodeAgentDir as Oe}from"../canvas/node-agent-paths.js";import{discoverLifecycleHookRegistry as Te}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as ze}from"../command-hooks/transport/exec-lifecycle.js";async function He(e,r){const i=e.pi_session_file,t=i?h(i):null;if(t===null)return{};try{const n=await d().header(t);return r?{resumeSessionPath:n.path}:{resumeSessionPath:n.path,newCycle:!0}}catch(n){if(n instanceof D)return{};throw n}}s(He,"resumeArgs");async function L(e){const r=h(e);if(r===null)return!1;try{return await d().header(r),!0}catch(i){if(i instanceof D)return!1;throw i}}s(L,"conversationExists");async function Me(e){const r=h(e);return r===null?!0:(await d().read(r)).entries.some(i=>i.type==="message")}s(Me,"sessionHasConversation");async function Ue(e){const r=h(e);if(r===null)return!0;const i=(await d().header(r)).header.cwd;return typeof i!="string"||B(i)}s(Ue,"sessionCwdExists");async function Ke(e,r,i){const t=r.pi_session_file;if(!t||!await L(t))return{};const n=await I(t);return n!==null&&n.node_id!==e&&Ae(n.pi_pid)?{}:await Ue(t)?await He(r,i):{}}s(Ke,"resumableSessionArgs");async function Ge(e){return await H(e)===null&&await we(e)===null&&!await fe(e)}s(Ge,"isUnstartedBirth");async function kr(e){const r=await k(e);if(r!==null&&r.trim()!=="")return!0;const i=await H(e);return i!==null&&i.trim()!==""}s(kr,"hasFreshGroundState");async function gr(e,r){const i=await j(e,r,!0);if(i.parked)throw new Error(`reviveNode: internal parked decision for activating revive ${e}`);return i.result}s(gr,"reviveNode");async function br(e,r,i){return j(e,{...r,viewerAttach:!0},i)}s(br,"decideAttachRevive");async function j(e,r,i){let t=await R(e);if(t===null)throw new Error(`reviveNode: unknown node ${e}`);if(t=await R(e)??t,t.run_id&&(await R(t.run_id))?.deleting_at)throw new Error("run is deleting");if(t.final_report!==null)throw new Error(`reviveNode: refusing to revive ${e} \u2014 its finalization latch is set (final_report=${t.final_report}). A final landed between the caller's reopen-gate check and this revive; re-run with --reopen if this retask is still wanted.`);Ne(t.profile_id),Q(t.grantee);const n=U();if(!n.has(e)&&!n.isClaimed(e)&&r.wakeReason!=="runtime-restart-abort"&&r.viewerAttach!==!0&&!(!i&&t.lifecycle==="resident"&&z(t))&&await $e(t),n.has(e))return await x(e,t.intent==="refresh"?"refresh-launch":"revive"),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(n.isClaimed(e))return{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(!i&&t.lifecycle==="resident"&&z(t))return{parked:!0};const l=n.reserveSlot(e);let a=null;if(l){try{a=await ye(e)}catch(u){throw n.releaseReservation(e),u}a.verdict!=="admitted"&&n.releaseReservation(e)}if(a?.verdict==="too_small")throw me(a);if(!l||a?.verdict==="denied"){if(r.capacity==="refuse")throw a?.verdict==="denied"?ve(a):_e(K().automaticReviveCap,n.size());return t.frozen_at==null&&(await ne(e,new Date().toISOString()),await ie(e,{reason:"frozen"}),ae({level:"info",event:"broker.frozen",node_id:e,fields:a?.verdict==="denied"?{reason:"app_memory",free_bytes:a.free_bytes,needed_bytes:a.needed_bytes}:{reason:"broker_cap",live_count:n.size(),hard_cap:K().automaticReviveCap}})),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}try{return{parked:!1,result:await Le(e,t,r)}}finally{n.releaseReservation(e)}}s(j,"decideRevive");async function Le(e,r,i){if(!B(r.cwd)){const v=r.fork_from!=null?`Restore ${r.cwd}, then revive the fork normally with \`crtr node lifecycle revive ${e}\`.`:r.managed_worktree?.state==="open"?"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon recovery.":`Recreate ${r.cwd}, or repair it with \`crtr node config --cwd <path> --node ${e}\`; durable node work resumes in a fresh conversation. Then retry \`crtr node lifecycle revive ${e}\`.`;throw new $({error:"cwd_missing",message:`${e} cannot be revived \u2014 its recorded cwd no longer exists: ${r.cwd}`,next:v})}r.host_kind!=="broker"&&(await E(e,{host_kind:"broker"}),r.host_kind="broker"),r.review_binding!=null&&!await Ce(e)&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await O(e),r.pi_session_id=null,r.pi_session_file=null);const n=r.fork_from!=null&&r.pi_session_id==null,l=r.fork_source_file;if(n&&(typeof l!="string"||!Z(l)))throw new $({error:"fork_source_invalid",message:`${e} cannot be revived \u2014 its resolved fork source file is missing or invalid.`,next:`Restore the node's fork source metadata, then retry \`crtr node lifecycle revive ${e}\`.`});const a=n&&typeof l=="string";if(a&&!await L(l))throw new $({error:"fork_from_missing",message:`${e} cannot be revived \u2014 its fork source no longer exists: ${l}`,next:`Restore ${l}, or update the node's fork source, then retry \`crtr node lifecycle revive ${e}\`.`});const u=await ee(e,{daemonEpoch:U().epoch()});try{r.cycles=(r.cycles??0)+1,await E(e,{cycles:r.cycles});const W=r.intent==="refresh"||r.cycle_pending===!0?!1:i.resume,w=a?{}:await Ke(e,r,W),m=w.resumeSessionPath!==void 0,C=m&&w.newCycle===!0,_=m&&!C,N=!m&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&await Ge(e),g=_&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&!await be(e)&&!await Me(w.resumeSessionPath)?(await k(e))?.trim():void 0,A=g!==void 0&&g!=="",J=a||N||A,F=r.cycle_pending===!0||C;await E(e,{cycle_pending:F}),r.cycle_pending=F,!a&&!m&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await O(e),r.pi_session_id=null,r.pi_session_file=null);let c,f=null;const b=s(()=>({type:"runtime",kind:"kickoff",...r.spawned_by!=null&&r.spawned_by!==""?{spawnedBy:r.spawned_by}:{}}),"birthOrigin");if(a){const o=await k(e),P=h(l);if(P===null)throw new Error(`invalid fork source ${l}`);const Y=(await d().header(await d().fork(P,e))).path;c=p(r,{resumeSessionPath:Y,...o!=null&&o!==""?{prompt:o}:{}}),o!=null&&o!==""&&(f=b()),await Re(e,(await Se(l))?.node_id??null)}else if(A)c=p(r,{...w,prompt:g}),f=b();else if(_)c=p(r,{...w,...i.wakeReason==="runtime-restart-abort"?{prompt:de}:{}}),i.wakeReason==="runtime-restart-abort"&&(f={type:"runtime",kind:"restart-continuation"});else if(N){const o=(await k(e))?.trim();c=p(r,o!==void 0&&o!==""?{prompt:o}:{}),o!==void 0&&o!==""&&(f=b()),await G(e)}else{const o=await ue(r,u);c=p(r,{...w,prompt:await ce(r,o,i.wakeReason==="runtime-restart-abort"?void 0:i.wakeReason)}),r.run_id&&o.unreadMessageIds?.length&&(c.env.CRTR_KICKOFF_MESSAGE_IDS=JSON.stringify(o.unreadMessageIds)),f=i.wakeReason!==void 0&&i.wakeReason!=="runtime-restart-abort"?{type:"runtime",kind:"wake",wake:i.wakeReason}:{type:"runtime",kind:"revive",cycle:r.cycles??0},await G(e)}c.env={...c.env,CRTR_SUBTREE:await xe(e)},f!==null&&(c.env[pe]=he(f)),r.status==="done"&&r.last_settled_at!=null&&await Ee(e,r.last_settled_at),await x(e,r.intent==="refresh"?"refresh-launch":"revive"),await ge(e,{preserveEpisode:!0});const V=await ke(e);i.recovery!==!0&&i.viewerAttach!==!0&&await se(e),await De(e,r.grantee);const X=Te(r.cwd,r.profile_id).plans.get("node:start")??[];await ze(X,{node:{id:e,name:r.name,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle,cwd:r.cwd,nodeDir:await Oe(e),contextDir:await Be(e),jobDir:Pe(e)},runtime:{isBirth:J,canvasHome:Fe(),profile:r.profile_id??null}}),c.env={...c.env,CRTR_EXECUTION_ID:u};let y;try{if(y=await M.launch(e,c,{cwd:r.cwd,name:T(r),resuming:_}),y.pid===null)throw new Error(`broker host returned no pid for ${e}`)}catch(o){try{await x(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:o instanceof Error?o.message:String(o)}}}),await le(e,"notice.crash",`Child crashed \u2014 ${T(r)} (${e}) failed to relaunch and is now dead: ${o.message}
|
|
1
|
+
var re=Object.defineProperty;var l=(e,r)=>re(e,"name",{value:r,configurable:!0});import{assertGranteeRunsHere as ie}from"./unsandboxed.js";import{existsSync as L}from"node:fs";import{conversationIdFromPath as v,conversationStore as p,ConversationNotFoundError as H}from"../conversation-store/index.js";import{isAbsolute as te}from"node:path";import{findNodeBySessionFile as ne,getNode as E,updateNode as S,beginExecution as ae,ExecutionAlreadyLive as oe,recordExecutionPid as se,abortExecution as $,endLiveExecution as le,unbindSession as M,recordLaunch as ce,setFrozen as ue,clearFrozen as U,fullName as fe}from"../canvas/index.js";import{emitEvent as we}from"../events/emit.js";import{consumeDeadlineOnWake as de}from"../feed/messages.js";import{isParked as z,transition as N}from"./lifecycle.js";import{publishNotice as he}from"./close.js";import{InputError as C}from"../io.js";import{buildPiArgv as _}from"./launch.js";import{buildReviveKickoff as pe,drainBearings as me,hasRetainedReports as ve,readGoal as g,readYieldMessage as _e,RUNTIME_RESTART_CONTINUATION as ye}from"./kickoff.js";import{readRoadmap as K}from"./roadmap.js";import{encodeKickoffOrigin as ke,KICKOFF_ORIGIN_ENV as ge}from"./stamp/protocol.js";import{headlessBrokerHost as be,brokerLaunchJson as Re}from"./host.js";import{processRunner as xe}from"./runner/process.js";import{runnerForEnvironment as Ee}from"./runner/index.js";import{acceptedRelease as Se,blaxelEnvironmentOf as G,checkBilledWake as $e,EnvironmentImagePending as Ne,imageForWake as Ce}from"../../daemon/reconcilers/node-lifecycle/remote-wake.js";import{ExecutionCapReached as Fe,liveExecutionForNode as Ae,setExecutionLaunchJson as Pe}from"../canvas/executions.js";import{appMemoryFull as Be,appMemoryTooSmall as Oe,boundFleet as J,brokerCapReached as W,brokerThresholdsForDaemon as F}from"./fleet.js";import{admitBrokerMemory as De}from"./memory-admission.js";import{beginBootFaultAttempt as Te,clearFault as Le,hasAdmittedTurn as He}from"../canvas/recovery.js";import{clearNodeLedger as j,forkNodeLedger as Me,noticeChangedWhileDone as Ue}from"./ledger.js";import{forkSourceNode as ze,rootOfSpine as Ke}from"./nodes.js";import{checkStart as Ge}from"./start-check.js";import{isReviewCompanionBound as Je}from"../review/companion.js";import{assertProfileActive as We}from"../profiles/manifest.js";import{isPidAlive as je}from"../canvas/pid.js";import{crtrHome as Ve,jobDir as Xe}from"../canvas/paths.js";import{contextDir as Ye,ensureNodeDirs as qe,nodeAgentDir as Qe}from"../canvas/node-agent-paths.js";import{discoverLifecycleHookRegistry as Ze}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as Ie}from"../command-hooks/transport/exec-lifecycle.js";async function er(e,r){const i=e.pi_session_file,t=i?v(i):null;if(t===null)return{};try{const a=await p().header(t);return r?{resumeSessionPath:a.path}:{resumeSessionPath:a.path,newCycle:!0}}catch(a){if(a instanceof H)return{};throw a}}l(er,"resumeArgs");async function V(e){const r=v(e);if(r===null)return!1;try{return await p().header(r),!0}catch(i){if(i instanceof H)return!1;throw i}}l(V,"conversationExists");async function rr(e){const r=v(e);return r===null?!0:(await p().read(r)).entries.some(i=>i.type==="message")}l(rr,"sessionHasConversation");async function ir(e){const r=v(e);if(r===null)return!0;const i=(await p().header(r)).header.cwd;return typeof i!="string"||L(i)}l(ir,"sessionCwdExists");async function tr(e,r,i,t){const a=r.pi_session_file;if(!a||!await V(a))return{};const u=await ne(a);return u!==null&&u.node_id!==e&&je(u.pi_pid)?{}:t&&!await ir(a)?{}:await er(r,i)}l(tr,"resumableSessionArgs");async function nr(e){return await K(e)===null&&await _e(e)===null&&!await ve(e)}l(nr,"isUnstartedBirth");async function Ur(e){const r=await g(e);if(r!==null&&r.trim()!=="")return!0;const i=await K(e);return i!==null&&i.trim()!==""}l(Ur,"hasFreshGroundState");async function zr(e,r){const i=await X(e,r,!0);if(i.parked)throw new Error(`reviveNode: internal parked decision for activating revive ${e}`);return i.result}l(zr,"reviveNode");async function Kr(e,r,i){return X(e,{...r,viewerAttach:!0},i)}l(Kr,"decideAttachRevive");async function X(e,r,i){let t=await E(e);if(t===null)throw new Error(`reviveNode: unknown node ${e}`);if(t=await E(e)??t,t.run_id&&(await E(t.run_id))?.deleting_at)throw new Error("run is deleting");if(t.final_report!==null)throw new Error(`reviveNode: refusing to revive ${e} \u2014 its finalization latch is set (final_report=${t.final_report}). A final landed between the caller's reopen-gate check and this revive; re-run with --reopen if this retask is still wanted.`);We(t.profile_id),ie(t.grantee);const a=J();if(!await a.has(e)&&!await a.isClaimed(e)&&r.wakeReason!=="runtime-restart-abort"&&r.viewerAttach!==!0&&!(!i&&t.lifecycle==="resident"&&z(t))&&(await Ge(t),await G(t.profile_id??null)!==null&&await $e(t)),await a.has(e))return await N(e,t.intent==="refresh"?"refresh-launch":"revive"),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(await a.isClaimed(e))return{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(!i&&t.lifecycle==="resident"&&z(t))return{parked:!0};const u=await a.reserveSlot(e);let o=null;if(u){try{o=await De(e)}catch(w){throw a.releaseReservation(e),w}o.verdict!=="admitted"&&a.releaseReservation(e)}if(o?.verdict==="too_small")throw Oe(o);if(!u||o?.verdict==="denied"){if(r.capacity==="refuse")throw o?.verdict==="denied"?Be(o):W(F().automaticReviveCap,await a.occupancy());return t.frozen_at==null&&(await ue(e,new Date().toISOString()),await le(e,{reason:"frozen"}),we({level:"info",event:"broker.frozen",node_id:e,fields:o?.verdict==="denied"?{reason:"app_memory",free_bytes:o.free_bytes,needed_bytes:o.needed_bytes}:{reason:"broker_cap",live_count:await a.occupancy(),hard_cap:F().automaticReviveCap}})),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}try{return{parked:!1,result:await ar(e,t,r)}}finally{a.releaseReservation(e)}}l(X,"decideRevive");async function ar(e,r,i){const t=await G(r.profile_id??null);if(t===null&&!L(r.cwd)){const s=r.fork_from!=null?`Restore ${r.cwd}, then revive the fork normally with \`crtr node lifecycle revive ${e}\`.`:r.managed_worktree?.state==="open"?"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon recovery.":`Recreate ${r.cwd}, or repair it with \`crtr node config --cwd <path> --node ${e}\`; durable node work resumes in a fresh conversation. Then retry \`crtr node lifecycle revive ${e}\`.`;throw new C({error:"cwd_missing",message:`${e} cannot be revived \u2014 its recorded cwd no longer exists: ${r.cwd}`,next:s})}r.host_kind!=="broker"&&(await S(e,{host_kind:"broker"}),r.host_kind="broker"),r.review_binding!=null&&!await Je(e)&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await M(e),r.pi_session_id=null,r.pi_session_file=null);const u=r.fork_from!=null&&r.pi_session_id==null,o=r.fork_source_file;if(u&&(typeof o!="string"||!te(o)))throw new C({error:"fork_source_invalid",message:`${e} cannot be revived \u2014 its resolved fork source file is missing or invalid.`,next:`Restore the node's fork source metadata, then retry \`crtr node lifecycle revive ${e}\`.`});const w=u&&typeof o=="string";if(w&&!await V(o))throw new C({error:"fork_from_missing",message:`${e} cannot be revived \u2014 its fork source no longer exists: ${o}`,next:`Restore ${o}, or update the node's fork source, then retry \`crtr node lifecycle revive ${e}\`.`});const{automaticReviveCap:Y}=F();if(t!==null){const s=await Ce(t);if(s.state==="pending")throw new Ne(t,s.error)}const q=t===null?xe:Ee("blaxel");let f;try{f=await ae(e,{daemonEpoch:J().epoch(),cap:Y,...t===null?{}:{runner:"blaxel",release:Se()}})}catch(s){if(s instanceof Fe)throw W(s.cap,s.live);if(s instanceof oe)return{window:null,session:r.tmux_session??null,resumed:!1,outcome:"already-live"};throw s}try{r.cycles=(r.cycles??0)+1,await S(e,{cycles:r.cycles});const Q=r.intent==="refresh"||r.cycle_pending===!0?!1:i.resume,h=w?{}:await tr(e,r,Q,t===null),y=h.resumeSessionPath!==void 0,A=y&&h.newCycle===!0,m=y&&!A,P=!y&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&await nr(e),b=m&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&!await He(e)&&!await rr(h.resumeSessionPath)?(await g(e))?.trim():void 0,B=b!==void 0&&b!=="",Z=w||P||B,O=r.cycle_pending===!0||A;await S(e,{cycle_pending:O}),r.cycle_pending=O,!w&&!y&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await M(e),r.pi_session_id=null,r.pi_session_file=null);let c,d=null;const R=l(()=>({type:"runtime",kind:"kickoff",...r.spawned_by!=null&&r.spawned_by!==""?{spawnedBy:r.spawned_by}:{}}),"birthOrigin");if(w){const n=await g(e),x=v(o);if(x===null)throw new Error(`invalid fork source ${o}`);const ee=(await p().header(await p().fork(x,e))).path;c=_(r,{resumeSessionPath:ee,...n!=null&&n!==""?{prompt:n}:{}}),n!=null&&n!==""&&(d=R()),await Me(e,(await ze(o))?.node_id??null)}else if(B)c=_(r,{...h,prompt:b}),d=R();else if(m)c=_(r,{...h,...i.wakeReason==="runtime-restart-abort"?{prompt:ye}:{}}),i.wakeReason==="runtime-restart-abort"&&(d={type:"runtime",kind:"restart-continuation"});else if(P){const n=(await g(e))?.trim();c=_(r,n!==void 0&&n!==""?{prompt:n}:{}),n!==void 0&&n!==""&&(d=R()),await j(e)}else{const n=await me(r,f);c=_(r,{...h,prompt:await pe(r,n,i.wakeReason==="runtime-restart-abort"?void 0:i.wakeReason)}),r.run_id&&n.unreadMessageIds?.length&&(c.env.CRTR_KICKOFF_MESSAGE_IDS=JSON.stringify(n.unreadMessageIds)),d=i.wakeReason!==void 0&&i.wakeReason!=="runtime-restart-abort"?{type:"runtime",kind:"wake",wake:i.wakeReason}:{type:"runtime",kind:"revive",cycle:r.cycles??0},await j(e)}c.env={...c.env,CRTR_SUBTREE:await Ke(e)},d!==null&&(c.env[ge]=ke(d)),r.status==="done"&&r.last_settled_at!=null&&await Ue(e,r.last_settled_at),await N(e,r.intent==="refresh"?"refresh-launch":"revive"),await Le(e,{preserveEpisode:!0});const D=await Te(e);i.recovery!==!0&&i.viewerAttach!==!0&&await de(e),await qe(e,r.grantee);const I=Ze(r.cwd,r.profile_id).plans.get("node:start")??[];await Ie(I,{node:{id:e,name:r.name,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle,cwd:r.cwd,nodeDir:await Qe(e),contextDir:await Ye(e),jobDir:Xe(e)},runtime:{isBirth:Z,canvasHome:Ve(),profile:r.profile_id??null}}),c.env={...c.env,CRTR_EXECUTION_ID:f};const T=await Re(e,c,r.cwd);await Pe(f,T);let k;try{const n=await Ae(e);if(k=await q.start({executionId:f,nodeId:e,attempt:n?.attempt??1,sandboxName:n?.sandboxName??null,release:n?.release??"",launchJson:T,cwd:r.cwd,resuming:m}),t===null&&k.pid===null)throw new Error(`broker host returned no pid for ${e}`)}catch(n){try{await N(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:n instanceof Error?n.message:String(n)}}}),await he(e,"notice.crash",`Child crashed \u2014 ${fe(r)} (${e}) failed to relaunch and is now dead: ${n.message}
|
|
2
2
|
|
|
3
|
-
It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,{reason:"child-crashed",child:e})}catch{}throw await
|
|
3
|
+
It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,{reason:"child-crashed",child:e})}catch{}throw await $(f,{reason:"launch_failed"}),new Error(`[broker] refusing to revive ${e}: ${n.message}`)}if(await ce(e,new Date().toISOString()),t!==null)return await U(e),{window:null,session:r.tmux_session??null,resumed:m,faultExplanation:D.explanation,outcome:"launched"};if(await se(f,e,k.pid)==="shutdown")throw await $(f,{reason:"superseded"}),be.teardown(e),new Error(`[broker] refusing to revive ${e}: execution was superseded during launch`);return await U(e),{window:null,session:r.tmux_session??null,resumed:m,launch:k,faultExplanation:D.explanation,outcome:"launched"}}catch(s){throw await $(f,{reason:"launch_failed"}),s}}l(ar,"launchRevive");export{Kr as decideAttachRevive,Ur as hasFreshGroundState,er as resumeArgs,zr as reviveNode};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export interface BlaxelConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
workspace: string;
|
|
4
|
+
region: string;
|
|
5
|
+
/** Defaults to `https://api.blaxel.ai/v0`. */
|
|
6
|
+
controlUrl?: string;
|
|
7
|
+
fetch?: typeof fetch;
|
|
8
|
+
}
|
|
9
|
+
/** `BLAXEL_API_KEY`, `BLAXEL_WORKSPACE`, `BLAXEL_REGION` (H-1 names). Throws when one is missing. */
|
|
10
|
+
export declare function blaxelConfigFromEnv(env?: NodeJS.ProcessEnv): BlaxelConfig;
|
|
11
|
+
export declare class BlaxelApiError extends Error {
|
|
12
|
+
readonly status: number;
|
|
13
|
+
readonly code: string | null;
|
|
14
|
+
constructor(status: number, code: string | null, message: string);
|
|
15
|
+
}
|
|
16
|
+
export interface SandboxSpec {
|
|
17
|
+
name: string;
|
|
18
|
+
image: string;
|
|
19
|
+
memoryMb: number;
|
|
20
|
+
/** Extra ports beyond the sandbox API (8080), e.g. the broker's view port. */
|
|
21
|
+
ports?: Array<{
|
|
22
|
+
name: string;
|
|
23
|
+
target: number;
|
|
24
|
+
}>;
|
|
25
|
+
}
|
|
26
|
+
export interface SandboxInfo {
|
|
27
|
+
name: string;
|
|
28
|
+
/** Base URL of the sandbox API. */
|
|
29
|
+
url: string;
|
|
30
|
+
/** `RUNNING`, `STANDBY` (frozen), ...; reading it does not wake the sandbox. */
|
|
31
|
+
state: string | null;
|
|
32
|
+
status: string | null;
|
|
33
|
+
}
|
|
34
|
+
export type ProcessStatus = 'running' | 'completed' | 'failed' | 'killed' | 'stopped';
|
|
35
|
+
export interface SandboxProcess {
|
|
36
|
+
name: string;
|
|
37
|
+
pid: string;
|
|
38
|
+
status: ProcessStatus;
|
|
39
|
+
exitCode: number;
|
|
40
|
+
command: string;
|
|
41
|
+
stdout: string;
|
|
42
|
+
stderr: string;
|
|
43
|
+
logs: string;
|
|
44
|
+
}
|
|
45
|
+
export interface StartProcessInput {
|
|
46
|
+
name: string;
|
|
47
|
+
command: string;
|
|
48
|
+
env?: Record<string, string>;
|
|
49
|
+
workingDir?: string;
|
|
50
|
+
waitForCompletion?: boolean;
|
|
51
|
+
/** Seconds, with `waitForCompletion`. */
|
|
52
|
+
timeout?: number;
|
|
53
|
+
}
|
|
54
|
+
export interface PreviewToken {
|
|
55
|
+
token: string;
|
|
56
|
+
expiresAt: string;
|
|
57
|
+
}
|
|
58
|
+
export interface BlaxelClient {
|
|
59
|
+
readonly config: BlaxelConfig;
|
|
60
|
+
/** Creates the sandbox; an existing one with that name is adopted (`created: false`). */
|
|
61
|
+
createSandbox(spec: SandboxSpec): Promise<SandboxInfo & {
|
|
62
|
+
created: boolean;
|
|
63
|
+
}>;
|
|
64
|
+
/** Null when the sandbox does not exist. */
|
|
65
|
+
getSandbox(name: string): Promise<SandboxInfo | null>;
|
|
66
|
+
/** Deleting an absent sandbox is not an error. */
|
|
67
|
+
deleteSandbox(name: string): Promise<void>;
|
|
68
|
+
startProcess(sandbox: SandboxInfo, input: StartProcessInput): Promise<SandboxProcess>;
|
|
69
|
+
/** Null when the sandbox API answers 404 for that process. */
|
|
70
|
+
getProcess(sandbox: SandboxInfo, name: string): Promise<SandboxProcess | null>;
|
|
71
|
+
/** SIGTERM. Stopping a stopped process is not an error. */
|
|
72
|
+
stopProcess(sandbox: SandboxInfo, name: string): Promise<void>;
|
|
73
|
+
killProcess(sandbox: SandboxInfo, name: string): Promise<void>;
|
|
74
|
+
/** Run a command to completion in the sandbox. */
|
|
75
|
+
exec(sandbox: SandboxInfo, name: string, command: string, timeoutS: number, env?: Record<string, string>): Promise<SandboxProcess>;
|
|
76
|
+
putFile(sandbox: SandboxInfo, path: string, content: string, permissions?: string): Promise<void>;
|
|
77
|
+
/** Creates (or adopts) a private preview on `port` and returns its URL. */
|
|
78
|
+
ensurePreview(sandboxName: string, previewName: string, port: number): Promise<string>;
|
|
79
|
+
createPreviewToken(sandboxName: string, previewName: string, expiresAt: Date): Promise<PreviewToken>;
|
|
80
|
+
}
|
|
81
|
+
export declare function createBlaxelClient(config: BlaxelConfig): BlaxelClient;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var w=Object.defineProperty;var p=(n,o)=>w(n,"name",{value:o,configurable:!0});function h(n=process.env){const o=p(i=>{const $=n[i];if(!$)throw new Error(`${i} is required for the Blaxel runner`);return $},"need");return{apiKey:o("BLAXEL_API_KEY"),workspace:o("BLAXEL_WORKSPACE"),region:o("BLAXEL_REGION")}}p(h,"blaxelConfigFromEnv");class E extends Error{static{p(this,"BlaxelApiError")}status;code;constructor(o,i,$){super($),this.status=o,this.code=i,this.name="BlaxelApiError"}}function f(n){const o=n.metadata.url;if(!o)throw new Error(`Blaxel sandbox ${n.metadata.name} has no url`);return{name:n.metadata.name,url:o,state:n.state??null,status:n.status??null}}p(f,"toInfo");function b(n){const o=n.fetch??fetch,i=n.controlUrl??"https://api.blaxel.ai/v0",$=p(()=>({authorization:`Bearer ${n.apiKey}`,"x-blaxel-workspace":n.workspace,"content-type":"application/json"}),"headers");async function c(e,t,s,r=[]){const a=await o(e,{method:t,headers:$(),...s===void 0?{}:{body:JSON.stringify(s)}}),l=await a.text();let x=null;if(l!=="")try{x=JSON.parse(l)}catch{x={raw:l}}if(!a.ok&&!r.includes(a.status)){const d=x??{},m=typeof d.message=="string"?d.message:typeof d.error=="string"?d.error:l.slice(0,300);throw new E(a.status,typeof d.code=="string"?d.code:null,`Blaxel ${t} ${e} failed (${a.status}): ${m}`)}return{status:a.status,json:x}}p(c,"call");const u=encodeURIComponent;return{config:n,async createSandbox(e){const t=[...e.ports??[]].map(l=>({name:l.name,target:l.target,protocol:"HTTP"})),s={metadata:{name:e.name},spec:{runtime:{image:e.image,memory:e.memoryMb,...t.length>0?{ports:t}:{}},region:n.region}},{status:r,json:a}=await c(`${i}/sandboxes`,"POST",s,[409]);if(r===409){const l=await this.getSandbox(e.name);if(l===null)throw new Error(`Blaxel sandbox ${e.name} reported as existing but cannot be read`);return{...l,created:!1}}return{...f(a),created:!0}},async getSandbox(e){const{status:t,json:s}=await c(`${i}/sandboxes/${u(e)}`,"GET",void 0,[404]);return t===404?null:f(s)},async deleteSandbox(e){await c(`${i}/sandboxes/${u(e)}`,"DELETE",void 0,[404])},async startProcess(e,t){const{json:s}=await c(`${e.url}/process`,"POST",t);return s},async getProcess(e,t){const{status:s,json:r}=await c(`${e.url}/process/${u(t)}`,"GET",void 0,[404]);return s===404?null:r},async stopProcess(e,t){await c(`${e.url}/process/${u(t)}`,"DELETE",void 0,[404])},async killProcess(e,t){await c(`${e.url}/process/${u(t)}/kill`,"DELETE",void 0,[404])},async exec(e,t,s,r,a){return await this.startProcess(e,{name:t,command:s,waitForCompletion:!0,timeout:r,...a?{env:a}:{}})},async putFile(e,t,s,r="0644"){await c(`${e.url}/filesystem/${t.replace(/^\/+/,"").split("/").map(u).join("/")}`,"PUT",{content:s,permissions:r})},async ensurePreview(e,t,s){const{json:r}=await c(`${i}/sandboxes/${u(e)}/previews`,"POST",{metadata:{name:t},spec:{port:s,public:!1}},[409]),a=r?.spec?.url;if(a)return a;const x=(await c(`${i}/sandboxes/${u(e)}/previews`,"GET")).json.find(d=>d.metadata.name===t);if(!x)throw new Error(`Blaxel preview ${t} of ${e} not found`);return x.spec.url},async createPreviewToken(e,t,s){const{json:r}=await c(`${i}/sandboxes/${u(e)}/previews/${u(t)}/tokens`,"POST",{spec:{expiresAt:s.toISOString()}}),a=r.spec;return{token:a.token,expiresAt:a.expiresAt}}}}p(b,"createBlaxelClient");export{E as BlaxelApiError,h as blaxelConfigFromEnv,b as createBlaxelClient};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { type BlaxelConfig } from './client.js';
|
|
2
|
+
export interface RecipeRepository {
|
|
3
|
+
name: string;
|
|
4
|
+
github_full_name: string;
|
|
5
|
+
default_branch: string;
|
|
6
|
+
}
|
|
7
|
+
export interface Recipe {
|
|
8
|
+
repositories: RecipeRepository[];
|
|
9
|
+
setup_script: string | null;
|
|
10
|
+
/** pi package sources, one per line (the `environments.pi_packages` text). */
|
|
11
|
+
pi_packages: string | null;
|
|
12
|
+
}
|
|
13
|
+
export declare const NODE_BASE_IMAGE = "public.ecr.aws/docker/library/node:24-alpine";
|
|
14
|
+
/** Where the image installs the recipe's pi packages: one pi agent dir of its own, not any app's. The start script (`sandbox-start.mjs`) links its
|
|
15
|
+
* `npm`/`git` trees into, and merges its `packages` setting with, the agent dir of whichever app the node runs in. Keep the two in step. */
|
|
16
|
+
export declare const RECIPE_PI_AGENT_DIR = "/var/lib/crtr/recipe-pi-agent";
|
|
17
|
+
export declare const SETUP_SCRIPT_FILE = "recipe-setup.sh";
|
|
18
|
+
export declare const REPOS_DIR = "repos";
|
|
19
|
+
/** The Dockerfile for a recipe revision. Pure. It clones and fetches nothing: the repositories arrive by `COPY`, so a token cannot appear here. */
|
|
20
|
+
export declare function recipeDockerfile(recipe: Recipe, revision: number): string;
|
|
21
|
+
export type GitRunner = (args: string[], env: Record<string, string>, cwd: string) => Promise<void>;
|
|
22
|
+
export interface PrepareBuildDirInput {
|
|
23
|
+
recipe: Recipe;
|
|
24
|
+
revision: number;
|
|
25
|
+
/** A GitHub installation token limited to the recipe's repositories, or null for a source that needs none. */
|
|
26
|
+
token: string | null;
|
|
27
|
+
/** An empty directory. */
|
|
28
|
+
dir: string;
|
|
29
|
+
git?: GitRunner;
|
|
30
|
+
/** The clone URL of a repository; the default is `https://github.com/<full name>.git`. */
|
|
31
|
+
cloneUrl?: (githubFullName: string) => string;
|
|
32
|
+
}
|
|
33
|
+
/** Clones each repository into `<dir>/repos/<name>` and writes the Dockerfile and the setup script beside it. */
|
|
34
|
+
export declare function prepareBuildDir(input: PrepareBuildDirInput): Promise<void>;
|
|
35
|
+
/** A zip of every file under `dir` (deflate, unix modes kept so scripts stay executable). Empty directories are not carried. */
|
|
36
|
+
export declare function zipDirectory(dir: string): Buffer;
|
|
37
|
+
export interface BuiltImage {
|
|
38
|
+
/** `sandbox/<name>:<tag>`, the value of `environments.image_ref` and of a sandbox's `runtime.image`. */
|
|
39
|
+
ref: string;
|
|
40
|
+
/** Milliseconds from the upload request to `BUILT`. */
|
|
41
|
+
buildMs: number;
|
|
42
|
+
}
|
|
43
|
+
export interface BuildImageOptions {
|
|
44
|
+
pollMs?: number;
|
|
45
|
+
/** Give up after this long in a non-terminal state. Default 20 minutes. */
|
|
46
|
+
timeoutMs?: number;
|
|
47
|
+
sleep?: (ms: number) => Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
interface ImageDoc {
|
|
50
|
+
metadata?: {
|
|
51
|
+
status?: string;
|
|
52
|
+
events?: Array<{
|
|
53
|
+
message?: string;
|
|
54
|
+
status?: string;
|
|
55
|
+
}>;
|
|
56
|
+
};
|
|
57
|
+
spec?: {
|
|
58
|
+
tags?: Array<{
|
|
59
|
+
name?: string;
|
|
60
|
+
createdAt?: string;
|
|
61
|
+
updatedAt?: string;
|
|
62
|
+
}>;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export declare function getImage(config: BlaxelConfig, name: string): Promise<ImageDoc | null>;
|
|
66
|
+
/** Deleting an absent image is not an error; an image a sandbox still uses is refused by Blaxel. */
|
|
67
|
+
export declare function deleteImage(config: BlaxelConfig, name: string): Promise<void>;
|
|
68
|
+
/** Uploads `dir` (Dockerfile and context) as a build of sandbox image `name` and waits for it. A failed build throws with Blaxel's last event message. */
|
|
69
|
+
export declare function buildImage(config: BlaxelConfig, name: string, dir: string, options?: BuildImageOptions): Promise<BuiltImage>;
|
|
70
|
+
/** The image name of an environment: every revision is a new tag of it. */
|
|
71
|
+
export declare const environmentImageName: (environmentId: string) => string;
|
|
72
|
+
/** Removes a build directory. */
|
|
73
|
+
export declare function removeBuildDir(dir: string): void;
|
|
74
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
var T=Object.defineProperty;var p=(t,e)=>T(t,"name",{value:e,configurable:!0});import{spawn as O}from"node:child_process";import{constants as L,lstatSync as v,mkdirSync as B,readFileSync as D,readdirSync as A,readlinkSync as P,rmSync as C,writeFileSync as R}from"node:fs";import{join as I,relative as G}from"node:path";import{crc32 as M,deflateRawSync as F}from"node:zlib";import{BlaxelApiError as j}from"./client.js";const Y="public.ecr.aws/docker/library/node:24-alpine",z="ghcr.io/blaxel-ai/sandbox:latest",E="crtr",y="/var/lib/crtr/recipe-pi-agent",K="1.1.0",U="recipe-setup.sh",$="repos",J=p(t=>`'${t.replace(/'/g,"'\\''")}'`,"shellQuote"),H=p(t=>(t??"").split(`
|
|
2
|
+
`).map(e=>e.trim()).filter(e=>e!==""),"lines");function V(t,e){const s=H(t.pi_packages),n=[`FROM ${Y}`,"RUN apk add --no-cache bash git curl ripgrep",`COPY --from=${z} /sandbox-api /usr/local/bin/sandbox-api`,`RUN adduser -D -h /home/${E} -s /bin/sh ${E} && mkdir -p /work/.crtr ${y} && chown -R ${E} /work /var/lib/crtr`];t.repositories.length>0&&n.push(`COPY --chown=${E} ${$}/ /work/`),s.length>0&&n.push(`RUN npm install -g @earendil-works/pi-coding-agent@${K}`),t.setup_script!==null&&t.setup_script.trim()!==""&&n.push(`COPY ${U} /tmp/${U}`),n.push(`USER ${E}`,"WORKDIR /work");for(const r of s)n.push(`RUN HOME=/var/lib/crtr PI_CODING_AGENT_DIR=${y} pi install ${J(r)}`);return t.setup_script!==null&&t.setup_script.trim()!==""&&n.push(`RUN bash /tmp/${U}`),n.push(`RUN echo ${Math.trunc(e)} > /work/.crtr/recipe-revision`,"USER root",'ENTRYPOINT ["/usr/local/bin/sandbox-api"]',""),n.join(`
|
|
3
|
+
`)}p(V,"recipeDockerfile");const W=p((t,e,s)=>new Promise((n,r)=>{const i=O("git",t,{cwd:s,env:{...process.env,...e,GIT_TERMINAL_PROMPT:"0"},stdio:["ignore","ignore","pipe"]});let o="";i.stderr.on("data",a=>{o+=a.toString()}),i.on("error",r),i.on("close",a=>{a===0?n():r(new Error(`git ${t[0]} failed (${a}): ${o.slice(0,300)}`))})}),"runGit");async function ot(t){const e=t.git??W,s=t.cloneUrl??(r=>`https://github.com/${r}.git`);B(I(t.dir,$),{recursive:!0});const n=t.token===null?{}:{GIT_CONFIG_COUNT:"1",GIT_CONFIG_KEY_0:"http.https://github.com/.extraheader",GIT_CONFIG_VALUE_0:`AUTHORIZATION: basic ${Buffer.from(`x-access-token:${t.token}`).toString("base64")}`};for(const r of t.recipe.repositories){if(!/^[A-Za-z0-9._-]+$/.test(r.name)||r.name==="."||r.name==="..")throw new Error(`repository name ${JSON.stringify(r.name)} is not a plain directory name`);await e(["clone","--quiet","--branch",r.default_branch,s(r.github_full_name),I($,r.name)],n,t.dir)}R(I(t.dir,"Dockerfile"),V(t.recipe,t.revision)),t.recipe.setup_script!==null&&t.recipe.setup_script.trim()!==""&&R(I(t.dir,U),t.recipe.setup_script.endsWith(`
|
|
4
|
+
`)?t.recipe.setup_script:`${t.recipe.setup_script}
|
|
5
|
+
`)}p(ot,"prepareBuildDir");function N(t,e,s){for(const n of A(e).sort()){const r=I(e,n),i=v(r),o=G(t,r).split("\\").join("/");i.isDirectory()?N(t,r,s):i.isSymbolicLink()?s.push({name:o,data:Buffer.from(P(r)),mode:L.S_IFLNK|511}):i.isFile()&&s.push({name:o,data:D(r),mode:L.S_IFREG|i.mode&511})}}p(N,"walk");function Z(t){const e=[];N(t,t,e);const s=[],n=[];let r=0;for(const a of e){const d=Buffer.from(a.name),h=F(a.data),w=M(a.data),c=Buffer.alloc(30);c.writeUInt32LE(67324752,0),c.writeUInt16LE(20,4),c.writeUInt16LE(2048,6),c.writeUInt16LE(8,8),c.writeUInt32LE(33,12),c.writeUInt32LE(w,14),c.writeUInt32LE(h.length,18),c.writeUInt32LE(a.data.length,22),c.writeUInt16LE(d.length,26),s.push(c,d,h);const l=Buffer.alloc(46);l.writeUInt32LE(33639248,0),l.writeUInt16LE(788,4),l.writeUInt16LE(20,6),l.writeUInt16LE(2048,8),l.writeUInt16LE(8,10),l.writeUInt32LE(33,14),l.writeUInt32LE(w,16),l.writeUInt32LE(h.length,20),l.writeUInt32LE(a.data.length,24),l.writeUInt16LE(d.length,28),l.writeUInt32LE(a.mode<<16>>>0,38),l.writeUInt32LE(r,42),n.push(l,d),r+=c.length+d.length+h.length}const i=Buffer.concat(n),o=Buffer.alloc(22);return o.writeUInt32LE(101010256,0),o.writeUInt16LE(e.length,8),o.writeUInt16LE(e.length,10),o.writeUInt32LE(i.length,12),o.writeUInt32LE(r,16),Buffer.concat([...s,i,o])}p(Z,"zipDirectory");async function x(t,e,s,n,r=[]){const i=`${t.controlUrl??"https://api.blaxel.ai/v0"}${s}`,o=await(t.fetch??fetch)(i,{method:e,headers:{authorization:`Bearer ${t.apiKey}`,"x-blaxel-workspace":t.workspace,"content-type":"application/json"},...n===void 0?{}:{body:JSON.stringify(n)}}),a=await o.text();let d=null;if(a!=="")try{d=JSON.parse(a)}catch{d={raw:a}}if(!o.ok&&!r.includes(o.status))throw new j(o.status,null,`Blaxel ${e} ${i} failed (${o.status}): ${a.slice(0,300)}`);return{status:o.status,headers:o.headers,json:d}}p(x,"api");async function S(t,e){const{status:s,json:n}=await x(t,"GET",`/images/sandbox/${encodeURIComponent(e)}`,void 0,[404]);return s===404?null:n}p(S,"getImage");async function st(t,e){await x(t,"DELETE",`/images/sandbox/${encodeURIComponent(e)}`,void 0,[404])}p(st,"deleteImage");async function at(t,e,s,n={}){const r=n.sleep??(u=>new Promise(f=>setTimeout(f,u))),i=Date.now(),o=await S(t,e),a=new Set((o?.spec?.tags??[]).map(u=>u.name)),d=o?.metadata?.events?.length??0,w=(await x(t,"POST","/images",{resourceType:"sandbox",name:e})).headers.get("x-blaxel-upload-url");if(w===null)throw new Error(`Blaxel gave no upload URL for image ${e}`);const c=await(t.fetch??fetch)(w,{method:"PUT",headers:{"content-type":"application/zip"},body:new Uint8Array(Z(s))});if(!c.ok)throw new Error(`uploading the build context of image ${e} failed (${c.status}): ${(await c.text()).slice(0,300)}`);const l=i+(n.timeoutMs??20*6e4);for(;;){const u=await S(t,e),f=u?.metadata?.status;if(f==="BUILT"&&(u?.metadata?.events?.length??0)>=d+2){const m=(u?.spec?.tags??[]).filter(g=>g.name!==void 0),_=m.filter(g=>!a.has(g.name)),b=(_.length>0?_:m).sort((g,k)=>(k.updatedAt??"").localeCompare(g.updatedAt??""))[0]?.name;if(b===void 0)throw new Error(`Blaxel built image ${e} but no new tag appeared`);return{ref:`sandbox/${e}:${b}`,buildMs:Date.now()-i}}if(f==="FAILED"||f==="TERMINATED"){const m=u?.metadata?.events??[];throw new Error(`building image ${e} ${f.toLowerCase()}: ${m[m.length-1]?.message??"no message"}`)}if(Date.now()>l)throw new Error(`building image ${e} did not finish within ${n.timeoutMs??20*6e4} ms (last status ${f??"none"})`);await r(n.pollMs??3e3)}}p(at,"buildImage");const it=p(t=>`env-${t}`,"environmentImageName");function ct(t){C(t,{recursive:!0,force:!0})}p(ct,"removeBuildDir");export{Y as NODE_BASE_IMAGE,y as RECIPE_PI_AGENT_DIR,$ as REPOS_DIR,U as SETUP_SCRIPT_FILE,at as buildImage,st as deleteImage,it as environmentImageName,S as getImage,ot as prepareBuildDir,V as recipeDockerfile,ct as removeBuildDir,Z as zipDirectory};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Runner, RunnerExecution, RunnerStartInput } from '../types.js';
|
|
2
|
+
import { BlaxelApiError, type BlaxelClient } from './client.js';
|
|
3
|
+
/** The broker listens here inside the sandbox; the private preview forwards it (`wss://<preview>/view`). */
|
|
4
|
+
export declare const BROKER_VIEW_PORT = 4180;
|
|
5
|
+
/** Where the bootstrap keeps the newest release it installed; the wake script is run from here. */
|
|
6
|
+
export declare const WAKE_COMMAND = "node /opt/crtr/current/scripts/sandbox-start.mjs --wake";
|
|
7
|
+
/** `crtr-sandbox-start --wake` exits with this when no broker of the execution runs. */
|
|
8
|
+
export declare const EXIT_NO_BROKER = 3;
|
|
9
|
+
/** A failing start script prints a last line `crtr-sandbox-start: failed <reason>`; `status` reports the reason. */
|
|
10
|
+
export declare const FAILURE_LINE: RegExp;
|
|
11
|
+
export declare const brokerProcessName: (executionId: string) => string;
|
|
12
|
+
export declare const sandboxNameFor: (execution: RunnerExecution) => string;
|
|
13
|
+
/** What `start` needs from the control plane beyond the execution: the environment's image and size, the release object, the secrets. */
|
|
14
|
+
export interface BlaxelLaunchContext {
|
|
15
|
+
/** `environments.image_ref` for a recipe environment, else `blaxel/base-image:latest`. */
|
|
16
|
+
image: string;
|
|
17
|
+
memoryMb: number;
|
|
18
|
+
/** `CRTR_API_URL` the broker reaches `/v1` at. */
|
|
19
|
+
apiUrl: string;
|
|
20
|
+
/** Signed GET of `releases/<version>/runtime.tar.gz` (15 min) and its sha256. */
|
|
21
|
+
releaseUrl: string;
|
|
22
|
+
releaseSha256: string;
|
|
23
|
+
/** The environment's secrets, opened at this call (Environment secrets resolution). Never `CRTR_*` or `HOME`. */
|
|
24
|
+
secrets: Record<string, string>;
|
|
25
|
+
}
|
|
26
|
+
export interface BlaxelRunnerDeps {
|
|
27
|
+
client: BlaxelClient;
|
|
28
|
+
launchContext(input: RunnerStartInput): Promise<BlaxelLaunchContext>;
|
|
29
|
+
/** Mints the execution's node token (the execution must be `launching` and have none). Default: `mintNodeToken`. */
|
|
30
|
+
mintToken?(input: RunnerStartInput): Promise<string>;
|
|
31
|
+
/** The bootstrap script text passed as the process command (`scripts/sandbox-bootstrap.sh`). */
|
|
32
|
+
bootstrap(): string;
|
|
33
|
+
/** Sandbox names that belong to a node, for `delete`. Default: the node's executions' `sandbox_name`. */
|
|
34
|
+
sandboxNamesForNode?(nodeId: string): Promise<string[]>;
|
|
35
|
+
/** Seconds `stop` waits after SIGTERM before the kill. */
|
|
36
|
+
stopGraceS?: number;
|
|
37
|
+
}
|
|
38
|
+
export declare function createBlaxelRunner(deps: BlaxelRunnerDeps): Runner & {
|
|
39
|
+
sandboxState(execution: RunnerExecution): Promise<string | null>;
|
|
40
|
+
};
|
|
41
|
+
export { BlaxelApiError };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var _=Object.defineProperty;var o=(t,a)=>_(t,"name",{value:a,configurable:!0});import{withCanvasWrite as R,openDb as g}from"../../../canvas/db.js";import{mintNodeToken as I}from"../../../canvas/node-tokens.js";import{BlaxelApiError as k}from"./client.js";const x=4180,l="view",T="node /opt/crtr/current/scripts/sandbox-start.mjs --wake",S=3,C=/^crtr-sandbox-start: failed (\S+)/m,m=o(t=>`broker-${t}`,"brokerProcessName"),f=o(t=>t.sandboxName??`${t.nodeId}-${t.attempt}`,"sandboxNameFor"),N=o(async t=>await R(a=>I(a,t.executionId,t.nodeId,new Date().toISOString())),"defaultMint");async function y(t){return(await(await g()).prepare("SELECT DISTINCT sandbox_name FROM executions WHERE node_id = ? AND sandbox_name IS NOT NULL").all(t)).map(u=>u.sandbox_name)}o(y,"defaultSandboxNames");function P(t){const a=`${t.logs}
|
|
2
|
+
${t.stderr}
|
|
3
|
+
${t.stdout}`;return{state:"failed",reason:C.exec(a)?.[1]??"start_failed",code:t.exitCode}}o(P,"failureOf");function v(t){const{client:a}=t,u=(t.stopGraceS??10)*1e3,E=new Map;async function d(n){return await a.getSandbox(f(n))}return o(d,"sandboxOf"),{kind:"blaxel",async start(n){const r=await t.launchContext(n),e=f(n),s=await a.createSandbox({name:e,image:r.image,memoryMb:r.memoryMb,ports:[{name:l,target:x}]}),i=m(n.executionId);if((await a.getProcess(s,i))?.status==="running")return{pid:null,exited:null};await a.ensurePreview(e,l,x);const w=await(t.mintToken??N)(n),p={...r.secrets,CRTR_API_URL:r.apiUrl,CRTR_EXECUTION_ID:n.executionId,CRTR_NODE_TOKEN:w,CRTR_RELEASE:n.release,CRTR_RELEASE_URL:r.releaseUrl,CRTR_RELEASE_SHA256:r.releaseSha256};return await a.startProcess(s,{name:i,command:t.bootstrap(),env:p,waitForCompletion:!1}),{pid:null,exited:null}},async wake(n){const r=await d(n);if(r===null)return"no_broker";const e=await a.exec(r,`wake-${n.executionId}-${Date.now()}`,`${T} ${n.executionId}`,30);if(e.exitCode===0)return"signalled";if(e.exitCode===S)return"no_broker";throw new Error(`wake of ${n.executionId} failed (exit ${e.exitCode}): ${(e.stderr||e.logs).slice(0,300)}`)},async stop(n,r){try{const e=await d(n);if(e===null)return{confirmed:!0};const s=m(n.executionId),i=o(async()=>(await a.getProcess(e,s))?.status==="running","running");if(!await i())return{confirmed:!0};await a.stopProcess(e,s);const c=Date.now()+u;for(;Date.now()<c;){if(!await i())return{confirmed:!0};await new Promise(w=>setTimeout(w,250))}return await a.killProcess(e,s),{confirmed:!await i()}}catch(e){return{confirmed:!1,error:e instanceof Error?e:new Error(String(e))}}},async status(n){try{const r=await d(n);if(r===null)return{state:"gone"};const e=await a.getProcess(r,m(n.executionId));return e===null?{state:"gone"}:e.status==="running"?{state:"running",pid:null}:e.status==="failed"||e.status==="completed"&&e.exitCode!==0?P(e):{state:"gone"}}catch(r){return{state:"unknown",error:r instanceof Error?r.message:String(r)}}},async delete(n){for(const r of await(t.sandboxNamesForNode??y)(n))await a.deleteSandbox(r)},async viewerAddress(n){const r=f(n),e=E.get(r);if(e&&e.expiresAt-Date.now()>5*6e4)return b(e.url,e.token);const s=await a.ensurePreview(r,l,x),i=new Date(Date.now()+60*6e4),{token:c}=await a.createPreviewToken(r,l,i);return E.set(r,{url:s,token:c,expiresAt:i.getTime()}),b(s,c)},async sandboxState(n){return(await d(n))?.state??null}}}o(v,"createBlaxelRunner");function b(t,a){return{kind:"wss",url:`${t.replace(/^https:/,"wss:")}/view`,headers:{"x-blaxel-preview-token":a}}}o(b,"viewer");export{x as BROKER_VIEW_PORT,k as BlaxelApiError,S as EXIT_NO_BROKER,C as FAILURE_LINE,T as WAKE_COMMAND,m as brokerProcessName,v as createBlaxelRunner,f as sandboxNameFor};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Runner, RunnerKind } from './types.js';
|
|
2
|
+
/** The Blaxel implementation is installed by the cloud runner module. */
|
|
3
|
+
export declare function registerBlaxelRunner(runner: Runner): void;
|
|
4
|
+
export declare function runnerKindForEnvironment(kind: 'machine' | 'blaxel'): RunnerKind;
|
|
5
|
+
export declare function runnerForEnvironment(kind: 'machine' | 'blaxel'): Runner;
|
|
6
|
+
export declare function runnerForEnvironmentId(environmentId: string): Promise<Runner>;
|
|
7
|
+
/** The runner that holds an execution row, by the row's `runner` column. */
|
|
8
|
+
export declare function runnerForExecution(runner: RunnerKind): Runner;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var i=Object.defineProperty;var r=(n,e)=>i(n,"name",{value:e,configurable:!0});import{openDb as u}from"../../canvas/db.js";import{processRunner as l}from"./process.js";let o=null;function x(n){if(n.kind!=="blaxel")throw new Error("expected a Blaxel runner");o=n}r(x,"registerBlaxelRunner");function f(n){return n==="machine"?"process":"blaxel"}r(f,"runnerKindForEnvironment");function t(n){if(n==="machine")return l;if(o===null)throw new Error("Blaxel runner is not registered");return o}r(t,"runnerForEnvironment");async function m(n){const e=await(await u()).prepare("SELECT kind FROM environments WHERE object = ?").get(n);if(!e)throw new Error(`environment ${n} not found`);return t(e.kind)}r(m,"runnerForEnvironmentId");function s(n){return t(n==="process"?"machine":"blaxel")}r(s,"runnerForExecution");export{x as registerBlaxelRunner,t as runnerForEnvironment,m as runnerForEnvironmentId,s as runnerForExecution,f as runnerKindForEnvironment};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Runner, RunnerExit, RunnerStartInput } from './types.js';
|
|
2
|
+
/** The local runner delegates process ownership to the existing detached broker host. */
|
|
3
|
+
/** `start` narrows `exited` to non-null: the process runner always observes its child. */
|
|
4
|
+
export declare const processRunner: Omit<Runner, 'start'> & {
|
|
5
|
+
start(input: RunnerStartInput): Promise<{
|
|
6
|
+
pid: number | null;
|
|
7
|
+
exited: Promise<RunnerExit>;
|
|
8
|
+
}>;
|
|
9
|
+
} & {
|
|
10
|
+
kind: 'process';
|
|
11
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var l=Object.defineProperty;var i=(e,r)=>l(e,"name",{value:r,configurable:!0});import{existsSync as w,mkdirSync as m}from"node:fs";import{join as u}from"node:path";import{InputError as f}from"../../io.js";import{getNode as c}from"../../canvas/index.js";import{liveExecutionForNode as p}from"../../canvas/executions.js";import{nodeRunDir as s,viewSocketPath as I}from"../../canvas/paths.js";import{capturePidIdentities as h,identitiesMatch as y,isPidAlive as g}from"../../canvas/pid.js";import{writeFileBeneath as v}from"../../spaces/open-beneath.js";import{headlessBrokerHost as a}from"../host.js";async function t(e){const r=await p(e.nodeId);if(r?.executionId!==e.executionId||r.pid===null||!g(r.pid))return null;const o=h([r.pid])?.get(r.pid);return r.processIdentity&&o&&y(o,r.processIdentity)?r.pid:null}i(t,"pidFor");const F={kind:"process",async start(e){if(!w(e.cwd))throw new f({error:"cwd_missing",message:`${e.nodeId} cannot be revived \u2014 its recorded cwd no longer exists: ${e.cwd}`,next:`Recreate ${e.cwd}, or repair it with \`crtr node config --cwd <path> --node ${e.nodeId}\`; then retry \`crtr node lifecycle revive ${e.nodeId}\`.`});const r=s(e.nodeId);m(r,{recursive:!0}),v(r,u(r,"broker-launch.json"),e.launchJson,{atomic:!0});const o=JSON.parse(e.launchJson),n=await c(e.nodeId);if(!n)throw new Error(`node ${e.nodeId} not found`);const d=await a.launch(e.nodeId,o,{cwd:e.cwd,name:n.name??e.nodeId,resuming:e.resuming,launchJson:e.launchJson});return{pid:d.pid,exited:d.exited}},async wake(e){const r=await t(e);if(r===null)return"no_broker";try{return process.kill(r,"SIGUSR1"),"signalled"}catch(o){if(o.code==="ESRCH")return"no_broker";throw o}},async stop(e,r){const o=await t(e);if(o===null)return{confirmed:!0};if((await c(e.nodeId))?.pi_pid!==o)throw new Error(`node ${e.nodeId} no longer points at execution ${e.executionId}`);return a.teardown(e.nodeId,{excludePid:r.excludePid})},async status(e){const r=await t(e);return r!==null?{state:"running",pid:r}:{state:"gone"}},async delete(e){const{rm:r}=await import("node:fs/promises");await r(s(e),{recursive:!0,force:!0})},async viewerAddress(e){return{kind:"unix",path:I(e.nodeId)}}};export{F as processRunner};
|