@north-light/cli 0.3.561 → 0.3.563
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/build-root.d.ts +1 -0
- package/dist/build-root.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/join.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.d.ts +5 -3
- 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/boot-settings.d.ts +3 -0
- package/dist/daemon/boot-settings.js +1 -0
- 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,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};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
export type RunnerKind = 'process' | 'blaxel';
|
|
2
|
+
/** The identity of one execution as the runner is asked about it. Rows already hold these. */
|
|
3
|
+
export interface RunnerExecution {
|
|
4
|
+
executionId: string;
|
|
5
|
+
nodeId: string;
|
|
6
|
+
/** `executions.attempt`, the sandbox name suffix. */
|
|
7
|
+
attempt: number;
|
|
8
|
+
/** `executions.sandbox_name`, null for the process runner. */
|
|
9
|
+
sandboxName: string | null;
|
|
10
|
+
}
|
|
11
|
+
/** What `start` needs beyond the execution: the execution row's `launch_json` is the launch recipe. */
|
|
12
|
+
export interface RunnerStartInput extends RunnerExecution {
|
|
13
|
+
/** The release the wake accepted (`executions.release`). */
|
|
14
|
+
release: string;
|
|
15
|
+
/** `executions.launch_json`: invocation argv and env, config snapshot, system prompt text, scopes. */
|
|
16
|
+
launchJson: string;
|
|
17
|
+
/** The working directory the broker starts in. */
|
|
18
|
+
cwd: string;
|
|
19
|
+
/** True when the broker resumes a saved session. */
|
|
20
|
+
resuming: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface RunnerStarted {
|
|
23
|
+
/** The broker's pid on a Mac; null where the runner cannot see one (Blaxel reports through `broker.started`). */
|
|
24
|
+
pid: number | null;
|
|
25
|
+
/** Resolves when the broker process ends, where the runner observes it (process runner); never for Blaxel. */
|
|
26
|
+
exited: Promise<RunnerExit> | null;
|
|
27
|
+
}
|
|
28
|
+
export interface RunnerExit {
|
|
29
|
+
code: number | null;
|
|
30
|
+
signal: NodeJS.Signals | null;
|
|
31
|
+
oomKilled?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/** Process status of the named execution's broker. A frozen Blaxel broker reads `running`: the sandbox's own status is never the freeze signal. */
|
|
34
|
+
export type RunnerStatus = {
|
|
35
|
+
state: 'running';
|
|
36
|
+
pid: number | null;
|
|
37
|
+
}
|
|
38
|
+
/** No process: the sandbox is absent, or present without the broker or start script. */
|
|
39
|
+
| {
|
|
40
|
+
state: 'gone';
|
|
41
|
+
}
|
|
42
|
+
/** The start script or broker ended non-zero; `reason` is the script's reason (`cwd_missing`, `extension_unavailable`, ...). */
|
|
43
|
+
| {
|
|
44
|
+
state: 'failed';
|
|
45
|
+
reason: string;
|
|
46
|
+
code: number | null;
|
|
47
|
+
}
|
|
48
|
+
/** The runner could not tell (a Blaxel API error). The caller leaves everything as it is and retries on the next claim. */
|
|
49
|
+
| {
|
|
50
|
+
state: 'unknown';
|
|
51
|
+
error: string;
|
|
52
|
+
};
|
|
53
|
+
export type RunnerWakeResult = 'signalled' | 'no_broker';
|
|
54
|
+
export interface RunnerStopOptions {
|
|
55
|
+
/** Why: written to `executions.stop_reason` by the caller; carried here for the runner's diagnostics. */
|
|
56
|
+
reason: string;
|
|
57
|
+
/** A process whose tree is already known to the caller is excluded from the kill (the caller's own relay). */
|
|
58
|
+
excludePid?: number;
|
|
59
|
+
}
|
|
60
|
+
export interface RunnerStopResult {
|
|
61
|
+
/** False when the process could not be confirmed dead; the caller must not clean up what the broker owned. */
|
|
62
|
+
confirmed: boolean;
|
|
63
|
+
error?: Error;
|
|
64
|
+
}
|
|
65
|
+
/** Where a viewer connects. */
|
|
66
|
+
export type RunnerViewerAddress = {
|
|
67
|
+
kind: 'unix';
|
|
68
|
+
path: string;
|
|
69
|
+
} | {
|
|
70
|
+
kind: 'wss';
|
|
71
|
+
url: string;
|
|
72
|
+
headers: Record<string, string>;
|
|
73
|
+
};
|
|
74
|
+
export interface Runner {
|
|
75
|
+
readonly kind: RunnerKind;
|
|
76
|
+
/**
|
|
77
|
+
* Hand the execution to its environment and start the broker. The node token is minted INSIDE this call
|
|
78
|
+
* (`mintNodeToken` returns the raw token; the execution must be `launching` and have no token row) and
|
|
79
|
+
* handed over without being kept: fd 3 / unlinked file (process runner), process env (Blaxel). The process
|
|
80
|
+
* runner writes `broker-launch.json` from `launchJson` into the run dir and checks the cwd exists.
|
|
81
|
+
* Throws on refusal (cap, cwd missing, quota); the caller ends the execution `launch_failed`.
|
|
82
|
+
*/
|
|
83
|
+
start(input: RunnerStartInput): Promise<RunnerStarted>;
|
|
84
|
+
/** Signal the execution's broker to look for mail again. `no_broker` when no process of that execution runs. Carries no token and starts nothing. */
|
|
85
|
+
wake(execution: RunnerExecution): Promise<RunnerWakeResult>;
|
|
86
|
+
/** Stop the execution's broker. Repeating it on a stopped execution confirms. */
|
|
87
|
+
stop(execution: RunnerExecution, options: RunnerStopOptions): Promise<RunnerStopResult>;
|
|
88
|
+
status(execution: RunnerExecution): Promise<RunnerStatus>;
|
|
89
|
+
/** Remove everything the runner holds for the node: the run dir (process) or the sandbox (Blaxel). */
|
|
90
|
+
delete(nodeId: string): Promise<void>;
|
|
91
|
+
/** Where a viewer reaches this execution's broker. */
|
|
92
|
+
viewerAddress(execution: RunnerExecution): Promise<RunnerViewerAddress>;
|
|
93
|
+
}
|
|
94
|
+
/** The runner for an environment kind: `machine` → process, `blaxel` → Blaxel. */
|
|
95
|
+
export type RunnerForKind = (kind: 'machine' | 'blaxel') => Runner;
|
|
File without changes
|
|
@@ -11,9 +11,6 @@ export declare function formatSituationalProse(prose: string): string;
|
|
|
11
11
|
* one sanctioned writer for the sidecar, taking an ALREADY-RENDERED envelope.
|
|
12
12
|
* No-op for blank text, so a caller can pass through an optional/empty value
|
|
13
13
|
* with no guard at the call site. */
|
|
14
|
-
export declare function appendSituationalContext(nodeId: string, text: string): void
|
|
15
|
-
/** The node's
|
|
16
|
-
|
|
17
|
-
* bare prose; that single legacy branch lives here alone and self-clears on
|
|
18
|
-
* the next situation change. */
|
|
19
|
-
export declare function situationalContextEnvelope(nodeId: string): string | null;
|
|
14
|
+
export declare function appendSituationalContext(nodeId: string, text: string): Promise<void>;
|
|
15
|
+
/** The node's latest situational card, never read from the control plane's disk. */
|
|
16
|
+
export declare function situationalContextEnvelope(nodeId: string): Promise<string | null>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
2
|
-
`,
|
|
1
|
+
var i=Object.defineProperty;var a=(t,o)=>i(t,"name",{value:o,configurable:!0});import{openDb as r}from"../canvas/db.js";import{formatCard as e,parseCard as u}from"../../shared/generated-context.js";import{SITUATIONAL_CONTEXT_CUSTOM_TYPE as T}from"../../shared/generated-context.js";function p(t){return t.trim()===""?"":e("situational",{},t)}a(p,"formatSituationalProse");async function l(t,o){const n=o.trim();n!==""&&await(await r()).prepare("UPDATE nodes SET situational_card = ? WHERE node_id = ?").run(n+`
|
|
2
|
+
`,t)}a(l,"appendSituationalContext");async function E(t){const n=(await(await r()).prepare("SELECT situational_card FROM nodes WHERE node_id = ?").get(t))?.situational_card?.trim()??"";return n===""?null:u({content:n})===null?p(n):n}a(E,"situationalContextEnvelope");export{T as SITUATIONAL_CONTEXT_CUSTOM_TYPE,l as appendSituationalContext,p as formatSituationalProse,E as situationalContextEnvelope};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var n=Object.defineProperty;var i=(t,e)=>n(t,"name",{value:e,configurable:!0});import{getNode as a}from"../canvas/index.js";import{deliverCustomMessageLive as r}from"./deliver-live.js";import{appendSituationalContext as l,formatSituationalProse as u,situationalContextEnvelope as s,SITUATIONAL_CONTEXT_CUSTOM_TYPE as m}from"./situational-context.js";async function w(t,e){if(await l(t,u(e)),await a(t)===null)throw new Error(`setSituationalContextLive: unknown node ${t}`);const o=await s(t);o!==null&&await r(t,{customType:m,content:o,deliverAs:"nextTurn"})}i(w,"setSituationalContextLive");export{w as setSituationalContextLive};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PiInvocation } from './invocation.js';
|
|
2
|
+
/** The app process env for a launch: the secrets of the node's environment (the app's rows, the environment owner's profile rows, the deployment rows). */
|
|
3
|
+
export declare function buildAppProcessEnv(targetCwd: string, targetProfileId: string | null, app: string): Promise<NodeJS.ProcessEnv>;
|
|
4
|
+
/** The one authoritative broker child env; every broker launch funnels through `headlessBrokerHost.launch()`, which calls this. */
|
|
5
|
+
export declare function buildBrokerEnv(inv: PiInvocation): Promise<NodeJS.ProcessEnv>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var c=Object.defineProperty;var e=(r,o)=>c(r,"name",{value:o,configurable:!0});import{localEnvironmentSecrets as s}from"../secrets/environment-owner.js";import{composeAppProcessEnv as p,overlayBrokerEnv as a}from"./spawn-env.js";async function E(r,o,n){return p(r,o,n,await s(o,n),{})}e(E,"buildAppProcessEnv");async function m(r){const o=r.env.CRTR_NODE_CWD??process.cwd(),n=r.env.CRTR_PROFILE_ID||null,t=r.env.CRTR_GRANTEE??"app:terminal";return a(r,await E(o,n,t))}e(m,"buildBrokerEnv");export{E as buildAppProcessEnv,m as buildBrokerEnv};
|
|
@@ -34,21 +34,7 @@ export declare function buildOperationalEnvBase(opts: {
|
|
|
34
34
|
* are readable back (`profile show`, ProfileDTO). Read straight off the
|
|
35
35
|
* manifest at every launch; never throws (a bad profile id yields `{}`). */
|
|
36
36
|
export declare function profileMetadataEnv(profileId: string | null): NodeJS.ProcessEnv;
|
|
37
|
-
/** The
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
* daemon's own and belong to an unrelated scope), E — the TARGET profile's
|
|
42
|
-
* own `profile env` store (`readProfileEnvVars`, `core/profiles/env-store.ts`)
|
|
43
|
-
* read directly off disk only when the profile belongs to the launched app, regardless of the host env or any
|
|
44
|
-
* `spawnEnv.allow` entry (setting a value there IS the consent to cross this
|
|
45
|
-
* boundary), F — the TARGET profile's manifest metadata as
|
|
46
|
-
* `CRTR_PROFILE_META_*` (`profileMetadataEnv` above), plus D — the trusted,
|
|
47
|
-
* crtr-constructed `inv.env` overlay and the
|
|
48
|
-
* fork-bomb recursion guard `FRONT_DOOR_ENV=1`. D is layered last so crtr's
|
|
49
|
-
* own constructed env always wins a name collision with a stored profile
|
|
50
|
-
* value. Every broker launch (front-door root, managed child, `--root`,
|
|
51
|
-
* every revive/daemon relaunch) funnels through `headlessBrokerHost.launch()`,
|
|
52
|
-
* which calls this. */
|
|
53
|
-
export declare function buildAppProcessEnv(targetCwd: string, targetProfileId: string | null, app: string): NodeJS.ProcessEnv;
|
|
54
|
-
export declare function buildBrokerEnv(inv: PiInvocation): NodeJS.ProcessEnv;
|
|
37
|
+
/** The app process env: the operational base, the app's and the target profile's stored rows (read by `spawn-env-rows.ts`), and the pins below. */
|
|
38
|
+
export declare function composeAppProcessEnv(targetCwd: string, targetProfileId: string | null, app: string, appVars: Record<string, string>, profileVars: Record<string, string>): NodeJS.ProcessEnv;
|
|
39
|
+
/** A broker's env: the trusted `inv.env` overlay on an app process env, plus the fork-bomb guard. */
|
|
40
|
+
export declare function overlayBrokerEnv(inv: PiInvocation, base: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var E=Object.defineProperty;var
|
|
1
|
+
var E=Object.defineProperty;var a=(e,t)=>E(e,"name",{value:t,configurable:!0});import{statSync as _}from"node:fs";import{SANDBOX_RUNTIME_HOME as p}from"../spaces/runtime-home.js";import{appProcessHome as T,appSpace as d,layoutRoot as R,runtimeRoot as m}from"../layout.js";import{delimiter as O,join as A,resolve as P}from"node:path";import{readMergedLaunchConfig as H}from"../config.js";import{loadProfileManifest as M,metadataEnvName as h,readProfileMetadata as N}from"../profiles/manifest.js";import{binShimDirFor as I}from"./bin-contributions.js";import{FRONT_DOOR_ENV as v}from"./front-door-env.js";const w=new Set(["HOME","PATH","SHELL","USER","LOGNAME","TMPDIR","TERM","TERMINFO","COLORTERM","LANG","LANGUAGE","TZ","NO_PROXY","no_proxy","SSH_AUTH_SOCK","CRTR_BASH_VALVE_MS"]),C=["LC_","XDG_","PI_"],l="CRTR_ADMITTED_HOST_PATH";function S(e,t,o){const r=t.PATH;if(r===void 0||r==="")return null;for(const s of r.split(O)){const c=P(o,s===""?".":s,e);try{const n=_(c);if(n.isFile()&&(n.mode&73)!==0)return c}catch{}}return null}a(S,"resolvePathExecutable");function b(e,t,o){const r=t[l]??t.PATH;if(r===void 0||r==="")throw new Error(`cannot resolve crouter-owned ${e}: the admitted host PATH is empty`);const s=S(e,{PATH:r},o);if(s!==null)return s;throw new Error(`cannot resolve crouter-owned ${e} from the admitted host PATH`)}a(b,"resolveAdmittedHostCommand");const D=["HTTP_PROXY","HTTPS_PROXY","http_proxy","https_proxy"],u={anthropic:"ANTHROPIC_API_KEY",openai:"OPENAI_API_KEY"};function y(e){let t;try{t=new URL(e)}catch{return!1}return!(t.protocol!=="http:"&&t.protocol!=="https:"||t.hostname===""||t.username!==""||t.password!=="")}a(y,"isCredentialFreeProxyValue");function x(e,t){if(!t.includes("*"))return e===t;const o=t.split("*").map(r=>r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join(".*");return new RegExp(`^${o}$`).test(e)}a(x,"matchesAllowPattern");function L(e){const t=e.host??process.env,o={};for(const[n,i]of Object.entries(t))i!==void 0&&(w.has(n)||C.some(f=>n.startsWith(f)))&&(o[n]=i);o.PWD=e.targetCwd;for(const n of D){const i=t[n];i!==void 0&&y(i)&&(o[n]=i)}const r=e.skipSpawnAllow?[]:H(e.targetCwd,e.targetProfileId).spawnEnv.allow;if(r.length>0)for(const[n,i]of Object.entries(t))i!==void 0&&r.some(f=>x(n,f))&&(o[n]=i);const s=t[l]??o.PATH;s!==void 0&&s!==""&&(o[l]=s);const c=I(e.targetCwd,e.targetProfileId);if(c!==null){const n=o.PATH;o.PATH=n===void 0||n===""?c:`${c}:${n}`}return o}a(L,"buildOperationalEnvBase");function G(e){const t={};for(const[o,r]of Object.entries(N(e)))t[h(o)]=r;return t}a(G,"profileMetadataEnv");function B(e,t,o,r,s){const c=t===null?null:M(t).manifest,n=L({targetCwd:e,targetProfileId:t,skipSpawnAllow:o!=="app:terminal"}),i={...n,...r,...c===null?{}:G(t),...s,HOME:T(o),PI_CODING_AGENT_DIR:A(d(o).home,".pi","agent"),[l]:n[l],...process.platform==="linux"?{CRTR_RUNTIME_HOME:p}:{CRTR_HOME:R(),CRTR_RUNTIME_HOME:process.env.CRTR_RUNTIME_HOME??m()}};for(const f of Object.values(u))delete i[f];return i}a(B,"composeAppProcessEnv");function K(e,t){const o={...t,...e.env,HOME:t.HOME,PI_CODING_AGENT_DIR:t.PI_CODING_AGENT_DIR,[l]:t[l],CRTR_RUNTIME_HOME:t.CRTR_RUNTIME_HOME,[v]:"1"};for(const r of Object.values(u))delete o[r];return o}a(K,"overlayBrokerEnv");export{l as ADMITTED_HOST_PATH_ENV,u as PROVIDER_ENV_KEYS,L as buildOperationalEnvBase,B as composeAppProcessEnv,K as overlayBrokerEnv,G as profileMetadataEnv,b as resolveAdmittedHostCommand,S as resolvePathExecutable};
|