@north-light/cli 0.3.560 → 0.3.562
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.d.ts +27 -4
- package/dist/api/client.js +3 -3
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/bash-jobs.d.ts +5 -1
- package/dist/api/dto/broker-ops.d.ts +25 -1
- package/dist/api/dto/charges.d.ts +9 -2
- package/dist/api/dto/delivery.d.ts +26 -2
- package/dist/api/dto/execution-start.d.ts +57 -0
- package/dist/api/dto/execution-start.js +0 -0
- package/dist/api/dto/modelauth.d.ts +5 -0
- package/dist/api/dto/node-records.d.ts +16 -0
- package/dist/api/dto/objects.d.ts +1 -1
- package/dist/api/dto/reports.d.ts +0 -3
- package/dist/api/dto/run-events.d.ts +7 -1
- package/dist/api/dto/settings.d.ts +55 -0
- package/dist/api/dto/settings.js +0 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +1 -1
- package/dist/api/routes.d.ts +11 -0
- package/dist/api/routes.js +1 -1
- package/dist/builtin-memory/crouter-sdk/release-notes.md +4 -0
- package/dist/cli.js +7 -7
- package/dist/clients/attach/chrome/bash-jobs.d.ts +11 -1
- package/dist/clients/attach/chrome/bash-jobs.js +1 -1
- package/dist/clients/attach/chrome/canvas-panels.d.ts +1 -1
- package/dist/clients/attach/chrome/roster.js +6 -4
- package/dist/clients/attach/overlays/auth.js +2 -2
- package/dist/clients/attach/render/chat-view.js +1 -1
- package/dist/clients/attach/viewer.js +550 -567
- package/dist/commands/canvas-config.js +2 -2
- package/dist/commands/canvas-use.js +1 -1
- package/dist/commands/human.js +2 -2
- package/dist/commands/node/bash.js +3 -3
- package/dist/commands/node/create.js +2 -2
- package/dist/commands/person-settings.d.ts +1 -0
- package/dist/commands/person-settings.js +1 -0
- package/dist/commands/pkg/market-manage.d.ts +2 -2
- package/dist/commands/pkg/market-manage.js +1 -1
- package/dist/commands/pkg/plugin-manage.js +13 -13
- package/dist/commands/pkg/shared.js +1 -1
- package/dist/commands/profile/default.js +1 -1
- package/dist/commands/push.js +2 -3
- package/dist/commands/sys/config.js +1 -1
- package/dist/commands/sys/connect.js +1 -1
- package/dist/commands/sys/context/sysprompt.js +2 -2
- package/dist/commands/sys/doctor.js +1 -1
- package/dist/commands/sys/panels/broker-limits-panel.js +1 -1
- package/dist/commands/sys/panels/keybindings-panel.js +1 -1
- package/dist/commands/sys/panels/models-panel.d.ts +8 -2
- package/dist/commands/sys/panels/models-panel.js +1 -1
- package/dist/commands/sys/panels/prefs-panel.d.ts +1 -0
- package/dist/commands/sys/panels/prefs-panel.js +1 -1
- package/dist/commands/sys/panels/profiles-panel.js +1 -1
- package/dist/commands/sys/panels/provider-panel.d.ts +4 -0
- package/dist/commands/sys/panels/provider-panel.js +1 -1
- package/dist/commands/sys/provider-login.js +5 -5
- package/dist/commands/sys/setup-core.js +3 -3
- package/dist/commands/sys/setup-settings-runner.js +1 -1
- package/dist/commands/sys/spend.js +3 -3
- package/dist/commands/sys/update.js +1 -1
- package/dist/core/auth-file.d.ts +11 -19
- package/dist/core/auth-file.js +1 -2
- package/dist/core/auto-update.d.ts +1 -1
- package/dist/core/auto-update.js +4 -4
- package/dist/core/bash-jobs.d.ts +29 -71
- package/dist/core/bash-jobs.js +9 -10
- package/dist/core/blobs/directory.d.ts +3 -0
- package/dist/core/blobs/directory.js +1 -0
- package/dist/core/blobs/fault.d.ts +3 -0
- package/dist/core/blobs/fault.js +1 -0
- package/dist/core/blobs/index.d.ts +21 -0
- package/dist/core/blobs/index.js +1 -0
- package/dist/core/blobs/r2.d.ts +9 -0
- package/dist/core/blobs/r2.js +4 -0
- package/dist/core/bootstrap.d.ts +1 -1
- package/dist/core/bootstrap.js +2 -2
- package/dist/core/canvas/canvas.d.ts +9 -7
- package/dist/core/canvas/canvas.js +8 -8
- package/dist/core/canvas/crons.d.ts +3 -2
- package/dist/core/canvas/crons.js +3 -3
- package/dist/core/canvas/daemon-owner.d.ts +5 -0
- package/dist/core/canvas/daemon-owner.js +1 -1
- package/dist/core/canvas/db.d.ts +10 -9
- package/dist/core/canvas/db.js +4 -4
- package/dist/core/canvas/executions.d.ts +100 -4
- package/dist/core/canvas/executions.js +1 -1
- package/dist/core/canvas/export-sqlite.js +1 -1
- package/dist/core/canvas/focuses.d.ts +4 -0
- package/dist/core/canvas/focuses.js +1 -1
- package/dist/core/canvas/history.js +9 -9
- package/dist/core/canvas/managed-worktree-sweep-candidates.d.ts +2 -1
- package/dist/core/canvas/managed-worktree-sweep-candidates.js +3 -2
- package/dist/core/canvas/node-tokens.d.ts +1 -4
- package/dist/core/canvas/node-tokens.js +3 -3
- package/dist/core/canvas/paths.d.ts +0 -1
- package/dist/core/canvas/paths.js +1 -1
- package/dist/core/canvas/person-state.d.ts +26 -0
- package/dist/core/canvas/person-state.js +1 -0
- package/dist/core/canvas/person.d.ts +3 -10
- package/dist/core/canvas/person.js +7 -7
- package/dist/core/canvas/reconciler-leases.d.ts +12 -0
- package/dist/core/canvas/reconciler-leases.js +8 -0
- package/dist/core/canvas/recovery.d.ts +4 -0
- package/dist/core/canvas/recovery.js +1 -1
- package/dist/core/canvas/schema-pg/003-fleet-removals.sql +1 -1
- package/dist/core/canvas/schema-pg/005-fleet-blobs.sql +13 -0
- package/dist/core/canvas/schema-pg/006-job-rows.sql +20 -0
- package/dist/core/canvas/schema-pg/007-ledger-check.sql +117 -0
- package/dist/core/canvas/schema-version.d.ts +1 -1
- package/dist/core/canvas/schema-version.js +1 -1
- package/dist/core/canvas/sessions.d.ts +8 -11
- package/dist/core/canvas/sessions.js +1 -4
- package/dist/core/canvas/tree.d.ts +4 -2
- package/dist/core/canvas/tree.js +6 -6
- package/dist/core/canvas/types.d.ts +7 -0
- package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
- package/dist/core/command-plugins/bundle.d.ts +1 -1
- package/dist/core/command-plugins/bundle.js +1 -1
- package/dist/core/command-plugins/compose.d.ts +1 -1
- package/dist/core/command-plugins/discovery.d.ts +0 -1
- package/dist/core/command-plugins/discovery.js +1 -1
- package/dist/core/command-plugins/help-addenda.js +1 -1
- package/dist/core/command-plugins/presence.d.ts +2 -0
- package/dist/core/command-plugins/presence.js +1 -1
- package/dist/core/config.d.ts +16 -15
- package/dist/core/config.js +1 -1
- package/dist/core/conversation-store/client-worker.js +1 -1
- package/dist/core/conversation-store/client.js +2 -2
- package/dist/core/conversation-store/index.d.ts +9 -11
- package/dist/core/conversation-store/index.js +1 -1
- package/dist/core/conversation-store/patch.js +1 -1
- package/dist/core/conversation-store/row-store.d.ts +14 -0
- package/dist/core/conversation-store/row-store.js +13 -0
- package/dist/core/directory/join.js +1 -1
- package/dist/core/env-name.d.ts +1 -0
- package/dist/core/env-name.js +1 -1
- package/dist/core/environment-recipe.d.ts +15 -0
- package/dist/core/environment-recipe.js +1 -0
- package/dist/core/environments.js +1 -1
- package/dist/core/events/emit.js +2 -2
- package/dist/core/events/run-event-chunks.d.ts +25 -0
- package/dist/core/events/run-event-chunks.js +5 -0
- package/dist/core/feed/messages.js +5 -5
- package/dist/core/grants/mirror.d.ts +15 -0
- package/dist/core/grants/mirror.js +15 -3
- package/dist/core/grants/on-sync.d.ts +9 -5
- package/dist/core/grants/on-sync.js +1 -1
- package/dist/core/grants/remove.d.ts +1 -6
- package/dist/core/grants/remove.js +1 -1
- package/dist/core/grants/sync.js +1 -1
- package/dist/core/grants/watch.d.ts +15 -9
- package/dist/core/grants/watch.js +1 -1
- package/dist/core/graph/custom.js +8 -8
- package/dist/core/graph/jobs.d.ts +83 -5
- package/dist/core/graph/jobs.js +11 -2
- package/dist/core/graph/kinds/job.js +2 -2
- package/dist/core/graph/names.js +7 -7
- package/dist/core/graph/objects.d.ts +5 -1
- package/dist/core/graph/objects.js +11 -11
- package/dist/core/graph/reader.d.ts +3 -0
- package/dist/core/graph/reader.js +3 -3
- package/dist/core/graph/repo-sync/identity.d.ts +3 -1
- package/dist/core/graph/repo-sync/identity.js +1 -1
- package/dist/core/graph/repo-sync/repos.d.ts +1 -1
- package/dist/core/graph/repo-sync/repos.js +2 -2
- package/dist/core/graph/repo-sync/sync.js +2 -2
- package/dist/core/installed-plugins.js +1 -1
- package/dist/core/keybindings/persistence.d.ts +1 -1
- package/dist/core/keybindings/persistence.js +1 -1
- package/dist/core/layout-migrate/loose-keys.d.ts +1 -1
- package/dist/core/layout-migrate/loose-keys.js +1 -1
- package/dist/core/ledger/account.d.ts +12 -0
- package/dist/core/ledger/account.js +2 -0
- package/dist/core/ledger/charges.d.ts +2 -2
- package/dist/core/ledger/charges.js +1 -1
- package/dist/core/ledger/check.d.ts +5 -1
- package/dist/core/ledger/check.js +1 -7
- package/dist/core/ledger/chunks.d.ts +8 -0
- package/dist/core/ledger/chunks.js +2 -0
- package/dist/core/ledger/index.d.ts +2 -1
- package/dist/core/ledger/index.js +1 -1
- package/dist/core/ledger/infra-allowance.d.ts +9 -0
- package/dist/core/ledger/infra-allowance.js +1 -0
- package/dist/core/ledger/limits.js +3 -3
- package/dist/core/ledger/payer.d.ts +1 -1
- package/dist/core/ledger/payer.js +1 -1
- package/dist/core/ledger/read.d.ts +14 -4
- package/dist/core/ledger/read.js +2 -3
- package/dist/core/ledger/totals.d.ts +5 -16
- package/dist/core/ledger/totals.js +4 -4
- package/dist/core/ledger/types.d.ts +12 -3
- package/dist/core/llm/run.js +2 -2
- package/dist/core/managed-providers.d.ts +72 -0
- package/dist/core/managed-providers.js +1 -0
- package/dist/core/model-auth/api-credential-store.d.ts +10 -0
- package/dist/core/model-auth/api-credential-store.js +1 -0
- package/dist/core/model-auth/daemon-login.d.ts +1 -1
- package/dist/core/model-auth/daemon-login.js +1 -1
- package/dist/core/model-auth/flows.d.ts +5 -4
- package/dist/core/model-auth/flows.js +1 -1
- package/dist/core/model-auth/handoff-jti.d.ts +3 -4
- package/dist/core/model-auth/handoff-jti.js +1 -1
- package/dist/core/model-auth/readiness.js +1 -1
- package/dist/core/model-config.d.ts +1 -1
- package/dist/core/model-config.js +1 -1
- package/dist/core/model-routes-pool.d.ts +14 -0
- package/dist/core/model-routes-pool.js +1 -0
- package/dist/core/model-routes.d.ts +11 -16
- package/dist/core/model-routes.js +1 -1
- package/dist/core/peer/ingest.d.ts +2 -0
- package/dist/core/peer/ingest.js +1 -1
- package/dist/core/peer/stubs.d.ts +8 -0
- package/dist/core/peer/stubs.js +1 -1
- package/dist/core/permissions/evaluator.d.ts +7 -2
- package/dist/core/permissions/evaluator.js +2 -2
- package/dist/core/plugin-env.js +1 -1
- package/dist/core/pool-credential-store.d.ts +2 -5
- package/dist/core/pool-credential-store.js +1 -1
- package/dist/core/profiles/app-env-store.d.ts +5 -5
- package/dist/core/profiles/app-env-store.js +1 -2
- package/dist/core/profiles/default-binding.d.ts +5 -5
- package/dist/core/profiles/default-binding.js +1 -1
- package/dist/core/profiles/env-store.d.ts +10 -21
- package/dist/core/profiles/env-store.js +1 -2
- package/dist/core/profiles/manifest.d.ts +14 -18
- package/dist/core/profiles/manifest.js +1 -1
- package/dist/core/profiles/relocate.js +1 -1
- package/dist/core/profiles/select.js +21 -21
- package/dist/core/provider-credential.d.ts +1 -1
- package/dist/core/provider-credential.js +1 -1
- package/dist/core/provider-management.d.ts +3 -4
- package/dist/core/provider-management.js +1 -1
- package/dist/core/providers/bundles.js +2 -2
- package/dist/core/providers/call.d.ts +3 -34
- package/dist/core/providers/description.d.ts +34 -0
- package/dist/core/providers/description.js +0 -0
- package/dist/core/providers/token-cache.d.ts +14 -14
- package/dist/core/providers/token-cache.js +1 -1
- package/dist/core/review/companion.js +1 -1
- package/dist/core/runs/activity.d.ts +1 -1
- package/dist/core/runs/activity.js +1 -1
- package/dist/core/runs/events.d.ts +7 -5
- package/dist/core/runs/events.js +2 -6
- package/dist/core/runs/operations.d.ts +1 -1
- package/dist/core/runs/operations.js +6 -6
- package/dist/core/runtime/bearings.js +1 -1
- package/dist/core/runtime/broker/attachments-fetch.d.ts +5 -0
- package/dist/core/runtime/broker/attachments-fetch.js +1 -0
- package/dist/core/runtime/broker/bash-job-launch.d.ts +4 -2
- package/dist/core/runtime/broker/bash-job-launch.js +1 -1
- package/dist/core/runtime/broker/boot-state.d.ts +9 -0
- package/dist/core/runtime/broker/boot-state.js +1 -0
- package/dist/core/runtime/broker/cli-relay.d.ts +2 -1
- package/dist/core/runtime/broker/cli-relay.js +1 -1
- package/dist/core/runtime/broker/client-registry.d.ts +3 -3
- package/dist/core/runtime/broker/daemon-ops.d.ts +10 -1
- package/dist/core/runtime/broker/daemon-ops.js +1 -1
- package/dist/core/runtime/broker/fault-retry.d.ts +2 -0
- package/dist/core/runtime/broker/fault-retry.js +1 -1
- package/dist/core/runtime/broker/frame-engine-control.js +1 -1
- package/dist/core/runtime/broker/held-deferred-inbox.d.ts +3 -0
- package/dist/core/runtime/broker/held-deferred-inbox.js +1 -1
- package/dist/core/runtime/broker/job-reporter.d.ts +18 -0
- package/dist/core/runtime/broker/job-reporter.js +2 -0
- package/dist/core/runtime/broker/model-adapter.d.ts +3 -0
- package/dist/core/runtime/broker/model-adapter.js +3 -2
- package/dist/core/runtime/broker/signal-stream.js +1 -1
- package/dist/core/runtime/broker/spilled-body.d.ts +5 -0
- package/dist/core/runtime/broker/spilled-body.js +1 -0
- package/dist/core/runtime/broker/summaries-post.d.ts +5 -0
- package/dist/core/runtime/broker/summaries-post.js +1 -0
- package/dist/core/runtime/broker/tool-groups.d.ts +3 -0
- package/dist/core/runtime/broker/tool-groups.js +1 -1
- package/dist/core/runtime/broker/turn-replies.d.ts +1 -0
- package/dist/core/runtime/broker/turn-replies.js +1 -1
- package/dist/core/runtime/broker-persona-guidance.js +2 -2
- package/dist/core/runtime/broker.js +1 -1
- package/dist/core/runtime/deliver-live.js +1 -1
- package/dist/core/runtime/first-boot-rows.d.ts +8 -0
- package/dist/core/runtime/first-boot-rows.js +2 -0
- package/dist/core/runtime/fleet.d.ts +13 -12
- package/dist/core/runtime/front-door-login.js +1 -1
- package/dist/core/runtime/front-door.js +6 -6
- package/dist/core/runtime/headless-pi.js +1 -1
- package/dist/core/runtime/host.d.ts +14 -3
- package/dist/core/runtime/host.js +3 -3
- package/dist/core/runtime/invocation.d.ts +6 -0
- package/dist/core/runtime/kickoff.d.ts +2 -14
- package/dist/core/runtime/kickoff.js +17 -19
- package/dist/core/runtime/launch-config-worker.js +1 -1
- package/dist/core/runtime/launch.js +2 -2
- package/dist/core/runtime/model-registry.js +1 -1
- package/dist/core/runtime/node-read.d.ts +4 -6
- package/dist/core/runtime/node-read.js +3 -3
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/core/runtime/outcome-document.d.ts +0 -1
- package/dist/core/runtime/outcome-document.js +1 -1
- package/dist/core/runtime/output-result.d.ts +15 -0
- package/dist/core/runtime/output-result.js +5 -0
- package/dist/core/runtime/placement.d.ts +17 -1
- package/dist/core/runtime/placement.js +1 -1
- package/dist/core/runtime/provider-credential-gate.d.ts +6 -2
- package/dist/core/runtime/provider-credential-gate.js +2 -2
- package/dist/core/runtime/recovery-hold.d.ts +21 -2
- package/dist/core/runtime/recovery-hold.js +2 -1
- package/dist/core/runtime/recycle.js +1 -1
- package/dist/core/runtime/reset.js +1 -1
- package/dist/core/runtime/revive.d.ts +2 -2
- package/dist/core/runtime/revive.js +2 -2
- package/dist/core/runtime/runner/blaxel/client.d.ts +81 -0
- package/dist/core/runtime/runner/blaxel/client.js +1 -0
- package/dist/core/runtime/runner/blaxel/image-build.d.ts +74 -0
- package/dist/core/runtime/runner/blaxel/image-build.js +5 -0
- package/dist/core/runtime/runner/blaxel/runner.d.ts +41 -0
- package/dist/core/runtime/runner/blaxel/runner.js +3 -0
- package/dist/core/runtime/runner/index.d.ts +8 -0
- package/dist/core/runtime/runner/index.js +1 -0
- package/dist/core/runtime/runner/process.d.ts +11 -0
- package/dist/core/runtime/runner/process.js +1 -0
- package/dist/core/runtime/runner/types.d.ts +95 -0
- package/dist/core/runtime/runner/types.js +0 -0
- package/dist/core/runtime/situational-context.d.ts +3 -6
- package/dist/core/runtime/situational-context.js +2 -2
- package/dist/core/runtime/situational-live.js +1 -1
- package/dist/core/runtime/spawn-env-rows.d.ts +5 -0
- package/dist/core/runtime/spawn-env-rows.js +1 -0
- package/dist/core/runtime/spawn-env.d.ts +4 -18
- package/dist/core/runtime/spawn-env.js +1 -1
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/core/runtime/stop-guard.d.ts +1 -1
- package/dist/core/runtime/stop-guard.js +2 -8
- package/dist/core/runtime/structured-output.d.ts +0 -67
- package/dist/core/runtime/structured-output.js +3 -8
- package/dist/core/runtime/tmux-driver.d.ts +8 -0
- package/dist/core/runtime/tmux-driver.js +6 -6
- package/dist/core/runtime/view-socket.d.ts +20 -0
- package/dist/core/runtime/view-socket.js +3 -1
- package/dist/core/runtime/warm-pool.d.ts +13 -1
- package/dist/core/runtime/warm-pool.js +1 -1
- package/dist/core/scoped-state/legacy-profiles.d.ts +11 -0
- package/dist/core/scoped-state/legacy-profiles.js +1 -0
- package/dist/core/scoped-state/materialized-plugins.d.ts +18 -0
- package/dist/core/scoped-state/materialized-plugins.js +1 -0
- package/dist/core/scoped-state/migrate.d.ts +8 -1
- package/dist/core/scoped-state/migrate.js +3 -3
- package/dist/core/scoped-state/person-rows.d.ts +10 -0
- package/dist/core/scoped-state/person-rows.js +6 -0
- package/dist/core/scoped-state/person-store.d.ts +72 -0
- package/dist/core/scoped-state/person-store.js +1 -0
- package/dist/core/secrets/blaxel-launch.d.ts +24 -0
- package/dist/core/secrets/blaxel-launch.js +4 -0
- package/dist/core/secrets/blaxel-register.d.ts +2 -0
- package/dist/core/secrets/blaxel-register.js +1 -0
- package/dist/core/secrets/env-rows.d.ts +17 -0
- package/dist/core/secrets/env-rows.js +4 -0
- package/dist/core/secrets/environment-owner.d.ts +8 -0
- package/dist/core/secrets/environment-owner.js +1 -0
- package/dist/core/secrets/environment-secrets.d.ts +14 -0
- package/dist/core/secrets/environment-secrets.js +1 -0
- package/dist/core/secrets/index.d.ts +2 -0
- package/dist/core/secrets/index.js +1 -0
- package/dist/core/secrets/key.d.ts +3 -0
- package/dist/core/secrets/key.js +2 -0
- package/dist/core/secrets/seal.d.ts +18 -0
- package/dist/core/secrets/seal.js +1 -0
- package/dist/core/spaces/mounts.d.ts +1 -1
- package/dist/core/spaces/mounts.js +1 -1
- package/dist/core/spaces/process.d.ts +1 -1
- package/dist/core/spaces/stop.d.ts +7 -5
- package/dist/core/spaces/stop.js +2 -2
- package/dist/core/spaces/users.d.ts +2 -1
- package/dist/core/spaces/users.js +1 -1
- package/dist/core/storage/attachments.d.ts +11 -8
- package/dist/core/storage/attachments.js +1 -1
- package/dist/core/storage/tables.d.ts +4 -0
- package/dist/core/storage/tables.js +3 -3
- package/dist/core/subscription-state.d.ts +34 -72
- package/dist/core/subscription-state.js +1 -4
- package/dist/core/substrate/delivery/plan.js +1 -1
- package/dist/core/user-settings.js +1 -1
- package/dist/daemon/api/app-listener.js +10 -10
- package/dist/daemon/api/auth/person-bearer.d.ts +14 -0
- package/dist/daemon/api/auth/person-bearer.js +1 -0
- package/dist/daemon/api/bridge.js +4 -4
- package/dist/daemon/api/document-listener.js +3 -3
- package/dist/daemon/api/environment-of.d.ts +18 -0
- package/dist/daemon/api/environment-of.js +5 -0
- package/dist/daemon/api/handlers/analytics.js +1 -1
- package/dist/daemon/api/handlers/app-profiles.d.ts +2 -2
- package/dist/daemon/api/handlers/app-profiles.js +1 -1
- package/dist/daemon/api/handlers/bash-jobs.js +1 -1
- package/dist/daemon/api/handlers/bash.js +1 -1
- package/dist/daemon/api/handlers/broker-ops.d.ts +3 -0
- package/dist/daemon/api/handlers/broker-ops.js +1 -1
- package/dist/daemon/api/handlers/broker-recovery.js +1 -1
- package/dist/daemon/api/handlers/broker-signals.d.ts +0 -3
- package/dist/daemon/api/handlers/broker-signals.js +2 -2
- package/dist/daemon/api/handlers/canvas.js +4 -4
- package/dist/daemon/api/handlers/charges.d.ts +1 -1
- package/dist/daemon/api/handlers/charges.js +1 -1
- package/dist/daemon/api/handlers/conversations.d.ts +2 -0
- package/dist/daemon/api/handlers/conversations.js +3 -0
- package/dist/daemon/api/handlers/crons.js +1 -1
- package/dist/daemon/api/handlers/daemon.js +1 -1
- package/dist/daemon/api/handlers/delivery.d.ts +1 -1
- package/dist/daemon/api/handlers/delivery.js +1 -1
- package/dist/daemon/api/handlers/docs.js +1 -1
- package/dist/daemon/api/handlers/exec.js +1 -1
- package/dist/daemon/api/handlers/execution-start.d.ts +2 -0
- package/dist/daemon/api/handlers/execution-start.js +2 -0
- package/dist/daemon/api/handlers/files.js +1 -1
- package/dist/daemon/api/handlers/git-credential.d.ts +11 -0
- package/dist/daemon/api/handlers/git-credential.js +1 -0
- package/dist/daemon/api/handlers/hook-exec.d.ts +1 -1
- package/dist/daemon/api/handlers/hook-exec.js +1 -1
- package/dist/daemon/api/handlers/human-requests.js +1 -1
- package/dist/daemon/api/handlers/inbox.js +1 -1
- package/dist/daemon/api/handlers/messages.js +1 -1
- package/dist/daemon/api/handlers/model-config.js +1 -1
- package/dist/daemon/api/handlers/modelauth.d.ts +1 -1
- package/dist/daemon/api/handlers/modelauth.js +1 -1
- package/dist/daemon/api/handlers/node-events.d.ts +6 -0
- package/dist/daemon/api/handlers/node-events.js +3 -3
- package/dist/daemon/api/handlers/node-outcomes.js +1 -1
- package/dist/daemon/api/handlers/node-records.js +3 -2
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/objects.js +3 -3
- package/dist/daemon/api/handlers/profiles.js +1 -1
- package/dist/daemon/api/handlers/providers.js +1 -1
- package/dist/daemon/api/handlers/reports.js +9 -13
- package/dist/daemon/api/handlers/reviews.js +1 -1
- package/dist/daemon/api/handlers/runs.js +1 -1
- package/dist/daemon/api/handlers/settings.d.ts +2 -0
- package/dist/daemon/api/handlers/settings.js +1 -0
- package/dist/daemon/api/handlers/structured-requests.js +1 -1
- package/dist/daemon/api/handlers/vendor-status.d.ts +1 -1
- package/dist/daemon/api/handlers/vendor-status.js +1 -1
- package/dist/daemon/api/handlers/worktree.js +1 -1
- package/dist/daemon/api/map.d.ts +2 -2
- package/dist/daemon/api/map.js +2 -2
- package/dist/daemon/api/operations.js +1 -1
- package/dist/daemon/api/reader.d.ts +8 -1
- package/dist/daemon/api/reader.js +1 -1
- package/dist/daemon/api/router.d.ts +4 -2
- package/dist/daemon/api/router.js +1 -1
- package/dist/daemon/api/server.d.ts +15 -3
- package/dist/daemon/api/server.js +1 -1
- package/dist/daemon/api/vendor-signin.d.ts +2 -1
- package/dist/daemon/api/vendor-signin.js +20 -20
- package/dist/daemon/api/viewer-presence.d.ts +20 -6
- package/dist/daemon/api/viewer-presence.js +2 -1
- package/dist/daemon/broker-signals/bus.d.ts +48 -11
- package/dist/daemon/broker-signals/bus.js +1 -1
- package/dist/daemon/cron/armed-context.js +1 -1
- package/dist/daemon/cron/lease-recovery.js +1 -1
- package/dist/daemon/cron/live-runs.d.ts +6 -0
- package/dist/daemon/cron/live-runs.js +1 -1
- package/dist/daemon/cron/run-socket.js +1 -1
- package/dist/daemon/cron-run.js +2 -2
- package/dist/daemon/crtrd-cli.js +1 -1
- package/dist/daemon/crtrd.d.ts +10 -0
- package/dist/daemon/crtrd.js +18 -17
- package/dist/daemon/delivery/run-delivery.d.ts +1 -1
- package/dist/daemon/delivery/run-delivery.js +1 -1
- package/dist/daemon/due-sources.d.ts +1 -1
- package/dist/daemon/due-sources.js +1 -1
- package/dist/daemon/due.js +7 -6
- package/dist/daemon/fleet.d.ts +6 -6
- package/dist/daemon/fleet.js +9 -9
- package/dist/daemon/park-activity.d.ts +2 -1
- package/dist/daemon/park-activity.js +1 -1
- package/dist/daemon/park-pending.d.ts +20 -13
- package/dist/daemon/park-pending.js +3 -1
- package/dist/daemon/profile-delete.js +1 -1
- package/dist/daemon/reconcilers/bash-deadline.d.ts +15 -10
- package/dist/daemon/reconcilers/bash-deadline.js +1 -3
- package/dist/daemon/reconcilers/broker-supervision.d.ts +13 -3
- package/dist/daemon/reconcilers/broker-supervision.js +4 -4
- package/dist/daemon/reconcilers/cron-lane.d.ts +0 -1
- package/dist/daemon/reconcilers/cron-lane.js +1 -1
- package/dist/daemon/reconcilers/fault-retry-backstop.d.ts +2 -9
- package/dist/daemon/reconcilers/fault-retry-backstop.js +1 -1
- package/dist/daemon/reconcilers/grant-effects.d.ts +8 -0
- package/dist/daemon/reconcilers/grant-effects.js +1 -0
- package/dist/daemon/reconcilers/grove-instance-sweep.d.ts +1 -3
- package/dist/daemon/reconcilers/grove-instance-sweep.js +1 -1
- package/dist/daemon/reconcilers/ledger-r2.d.ts +27 -0
- package/dist/daemon/reconcilers/ledger-r2.js +7 -0
- package/dist/daemon/reconcilers/ledger-sandbox.d.ts +55 -0
- package/dist/daemon/reconcilers/ledger-sandbox.js +9 -0
- package/dist/daemon/reconcilers/ledger-storage.d.ts +22 -0
- package/dist/daemon/reconcilers/ledger-storage.js +5 -0
- package/dist/daemon/reconcilers/live-obligation.d.ts +3 -2
- package/dist/daemon/reconcilers/live-obligation.js +1 -1
- package/dist/daemon/reconcilers/managed-worktree-sweep.d.ts +0 -5
- package/dist/daemon/reconcilers/managed-worktree-sweep.js +1 -1
- package/dist/daemon/reconcilers/node-deadline.d.ts +2 -1
- package/dist/daemon/reconcilers/node-deadline.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -2
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/remote-wake.d.ts +31 -0
- package/dist/daemon/reconcilers/node-lifecycle/remote-wake.js +1 -0
- package/dist/daemon/reconcilers/node-lifecycle/requested-stops.d.ts +5 -0
- package/dist/daemon/reconcilers/node-lifecycle/requested-stops.js +2 -0
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
- package/dist/daemon/reconcilers/pending-review-submit.js +1 -1
- package/dist/daemon/reconcilers/recipe-image.d.ts +49 -0
- package/dist/daemon/reconcilers/recipe-image.js +7 -0
- package/dist/daemon/reconcilers/row-claim.d.ts +19 -0
- package/dist/daemon/reconcilers/row-claim.js +2 -0
- package/dist/daemon/reconcilers/storage-due-work.d.ts +18 -3
- package/dist/daemon/reconcilers/storage-due-work.js +2 -1
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +5 -13
- package/dist/daemon/reconcilers/storage-maintenance.js +1 -1
- package/dist/daemon/reconcilers/structured-request-lane.js +1 -1
- package/dist/daemon/reconcilers/throttled-lane.d.ts +11 -0
- package/dist/daemon/reconcilers/throttled-lane.js +1 -0
- package/dist/daemon/review/finish.js +1 -1
- package/dist/daemon/run-notices.d.ts +3 -0
- package/dist/daemon/run-notices.js +1 -1
- package/dist/daemon/runs/append-section.d.ts +4 -1
- package/dist/daemon/runs/append-section.js +2 -2
- package/dist/daemon/runs/observer.d.ts +3 -2
- package/dist/daemon/runs/observer.js +3 -2
- package/dist/daemon/runs/view-transport.d.ts +19 -0
- package/dist/daemon/runs/view-transport.js +1 -0
- package/dist/daemon/structured-requests/boot.d.ts +2 -1
- package/dist/daemon/structured-requests/boot.js +1 -1
- package/dist/daemon/structured-requests/effects.d.ts +4 -3
- package/dist/daemon/structured-requests/effects.js +1 -1
- package/dist/daemon/structured-requests/notifier.d.ts +2 -0
- package/dist/daemon/structured-requests/notifier.js +1 -1
- package/dist/daemon/structured-requests/sidecar.d.ts +4 -3
- package/dist/daemon/structured-requests/sidecar.js +1 -1
- package/dist/launcher/validate.js +1 -1
- package/dist/migrations/004-canvas-documents/index.js +2 -2
- package/dist/pi-extensions/broker-local.d.ts +3 -3
- package/dist/pi-extensions/broker-local.js +1 -2
- package/dist/pi-extensions/canvas-bash-valve.js +6 -6
- package/dist/pi-extensions/canvas-context-intro.js +2 -2
- package/dist/pi-extensions/canvas-elapsed.js +2 -2
- package/dist/pi-extensions/canvas-goal-capture.js +1 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +2 -2
- package/dist/pi-extensions/canvas-review-boundary.d.ts +11 -1
- package/dist/pi-extensions/canvas-review-boundary.js +3 -3
- package/dist/pi-extensions/canvas-stophook.js +1 -1
- package/dist/pi-extensions/canvas-structured-output.d.ts +5 -3
- package/dist/pi-extensions/canvas-structured-output.js +6 -11
- package/dist/pi-extensions/canvas-tool-guide.d.ts +9 -2
- package/dist/pi-extensions/canvas-tool-guide.js +6 -6
- package/dist/shared/inbox-entry-body.js +7 -7
- package/dist/types.d.ts +12 -0
- package/docs/sdk/release-notes.md +4 -0
- package/package.json +7 -4
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -13
- package/scripts/git-credential-crtr +33 -0
- package/scripts/sandbox-bootstrap.sh +54 -0
- package/scripts/sandbox-start.mjs +320 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +0 -78
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +0 -1179
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +0 -1406
- package/dist/core/conversation-store/file-store.d.ts +0 -37
- package/dist/core/conversation-store/file-store.js +0 -9
- package/dist/core/conversation-store/listener.d.ts +0 -4
- package/dist/core/conversation-store/listener.js +0 -8
- package/dist/core/scoped-state/profiles.d.ts +0 -27
- package/dist/core/scoped-state/profiles.js +0 -1
- package/dist/core/scoped-state/providers.d.ts +0 -24
- package/dist/core/scoped-state/providers.js +0 -1
- package/dist/core/scoped-state/settings.d.ts +0 -28
- package/dist/core/scoped-state/settings.js +0 -1
package/dist/types.d.ts
CHANGED
|
@@ -405,6 +405,18 @@ export interface ScopeConfig {
|
|
|
405
405
|
/** The money ledger. `take_pct` (0-100, default 0) is Northlight's take on each priced model or tool charge; at 0 no take rows are written. */
|
|
406
406
|
ledger?: {
|
|
407
407
|
take_pct?: number;
|
|
408
|
+
/** USD per GB-hour of Blaxel sandbox awake time; the `ledger-sandbox` lane writes no rows while it is unset. */
|
|
409
|
+
sandbox_usd_per_gb_hour?: number;
|
|
410
|
+
/** Seconds a sandbox stays awake after its broker goes idle or exits (default 30). */
|
|
411
|
+
sandbox_standby_s?: number;
|
|
412
|
+
/** USD per GB-month of R2 storage; the `ledger-storage` lane writes no `r2` rows while it is unset. */
|
|
413
|
+
storage_usd_per_gb_month?: number;
|
|
414
|
+
/** USD per GB-month of Blaxel sandbox disk; the `ledger-storage` lane writes no `blaxel` rows while it is unset. */
|
|
415
|
+
sandbox_disk_usd_per_gb_month?: number;
|
|
416
|
+
/** USD of sandbox and storage a billing account uses free each UTC month (default 50); `billed_usd` on those rows is the part above it. */
|
|
417
|
+
infra_free_usd_per_month?: number;
|
|
418
|
+
/** The `ledger-r2` lane moves closed months into the blob store only while this is true (off until 5b is accepted). */
|
|
419
|
+
r2_move?: boolean;
|
|
408
420
|
};
|
|
409
421
|
/** Conversation store configuration for the daemon. */
|
|
410
422
|
store?: {
|
|
@@ -7,6 +7,10 @@ description: Behavior changes in @north-light/sdk that an app must act on, newes
|
|
|
7
7
|
|
|
8
8
|
Changes to `@north-light/sdk` that can change what an existing app sees. Newest first.
|
|
9
9
|
|
|
10
|
+
## 0.3.562
|
|
11
|
+
|
|
12
|
+
A cloud role's runtime (one with `CRTR_DIRECTORY_URL` and `CRTR_PUBLIC_API_URL` set) accepts a directory person bearer on its TCP listener: the caller acts as that person and reads only the nodes that person may read; schedules, charges, files and provider calls are refused `403 permission_error` to it. Any other listener still refuses a person bearer `401`, now with the code `person_bearer_not_supported` (was `person_bearer_not_supported_on_cloud_role`). A cloud role also answers `GET /v1/runtime/vendor-status` and `POST /v1/runtime/vendor-account-remove` for the person the directory's token names, and refuses a token that names no person `401`.
|
|
13
|
+
|
|
10
14
|
## 0.3.560
|
|
11
15
|
|
|
12
16
|
A read waits through a hosted runtime being created or replaced, instead of failing with `503`. No new option.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.562",
|
|
4
4
|
"description": "crtr — agent runtime with memory, plugins, and marketplaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -70,6 +70,9 @@
|
|
|
70
70
|
"scripts/postinstall.mjs",
|
|
71
71
|
"scripts/patch-pi-tree-root-ordering.mjs",
|
|
72
72
|
"scripts/install-runtime.mjs",
|
|
73
|
+
"scripts/sandbox-start.mjs",
|
|
74
|
+
"scripts/sandbox-bootstrap.sh",
|
|
75
|
+
"scripts/git-credential-crtr",
|
|
73
76
|
"scripts/lib/isolation-env.mjs",
|
|
74
77
|
"scripts/lib/canvas-schema-gate.mjs",
|
|
75
78
|
"scripts/lib/pack-args.mjs",
|
|
@@ -98,7 +101,7 @@
|
|
|
98
101
|
"build:plugin": "tsc -p packages/crouter-plugin/tsconfig.json",
|
|
99
102
|
"typecheck": "tsc --noEmit && tsc -p src/doc-editor/tsconfig.json",
|
|
100
103
|
"typecheck:pi-packages": "npx tsc -p src/builtin-pi-packages/pi-crtr-extensions/tsconfig.json",
|
|
101
|
-
"test:runtime-packaging": "node --test scripts/runtime-smoke.test.mjs scripts/pack-args.test.mjs scripts/ensure-native-linux.test.mjs scripts/release-version.test.mjs",
|
|
104
|
+
"test:runtime-packaging": "node --test scripts/runtime-smoke.test.mjs scripts/pack-args.test.mjs scripts/ensure-native-linux.test.mjs scripts/release-version.test.mjs scripts/sandbox-start.test.mjs",
|
|
102
105
|
"contract:check": "node scripts/contract.mjs check",
|
|
103
106
|
"contract:surface": "node scripts/contract.mjs generate",
|
|
104
107
|
"docs:check-reference": "npm exec --workspace @north-light/docs -- tsx scripts/check-reference.ts",
|
|
@@ -122,7 +125,7 @@
|
|
|
122
125
|
"test:seam": "npm run build && npm run test:seam:built",
|
|
123
126
|
"test:sdk": "npm run build:api && npm run build:identity && node --conditions=crtr-src --import tsx/esm --test --test-timeout=60000 'packages/crouter-sdk/src/__tests__/*.test.ts' 'packages/crouter-sdk/src/__tests__/integration/*.test.ts'",
|
|
124
127
|
"test:sdk:pg": "node -e \"if (!process.env.TEST_DATABASE_URL) { console.error('test:sdk:pg needs TEST_DATABASE_URL (a disposable PostgreSQL), e.g. docker run --rm -d -e POSTGRES_PASSWORD=pw -p 127.0.0.1:55432:5432 postgres:18-alpine; TEST_DATABASE_URL=postgres://postgres:pw@127.0.0.1:55432/postgres'); process.exit(1) }\" && node --conditions=crtr-src --import tsx/esm --test --test-timeout=60000 'packages/crouter-sdk/src/**/__tests__/**/*.pg.test.ts'",
|
|
125
|
-
"test:seam:built": "CRTR_NO_DAEMON_AUTOSTART=1 node scripts/test-lane.mjs -- node --import ./scripts/test-env-scrub.mjs --test --test-concurrency=$(node -p 'Math.min(4, Math.max(2, require(`node:os`).availableParallelism() - 2))') --test-timeout=180000 ${CRTR_TEST_SHARD:+--test-shard=$CRTR_TEST_SHARD} 'dist/**/__tests__/seam/*.test.js'",
|
|
128
|
+
"test:seam:built": "CRTR_NO_DAEMON_AUTOSTART=1 node scripts/test-lane.mjs -- node --import ./scripts/test-env-scrub.mjs --test --test-concurrency=$(node -p 'Math.min(4, Math.max(2, require(`node:os`).availableParallelism() - 2))') --test-timeout=180000 ${CRTR_TEST_SHARD:+--test-shard=$CRTR_TEST_SHARD} 'dist/**/__tests__/seam/*.test.js' scripts/sandbox-bootstrap.test.mjs scripts/sandbox-clone.test.mjs",
|
|
126
129
|
"test:all": "npm test && npm run test:integration && npm run test:seam",
|
|
127
130
|
"test:isolated": "node scripts/test-isolated.mjs",
|
|
128
131
|
"build:identity": "tsc -p packages/crouter-identity/tsconfig.json"
|
|
@@ -141,7 +144,7 @@
|
|
|
141
144
|
},
|
|
142
145
|
"license": "UNLICENSED",
|
|
143
146
|
"dependencies": {
|
|
144
|
-
"@north-light/identity": "0.3.
|
|
147
|
+
"@north-light/identity": "0.3.562",
|
|
145
148
|
"@earendil-works/pi-agent-core": "1.1.0",
|
|
146
149
|
"@earendil-works/pi-ai": "1.1.0",
|
|
147
150
|
"@earendil-works/pi-coding-agent": "1.1.0",
|
package/runtime.lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.562",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@north-light/cli",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.562",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "UNLICENSED",
|
|
12
12
|
"workspaces": [
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@milkdown/preset-gfm": "^7.22.3",
|
|
25
25
|
"@milkdown/prose": "^7.22.3",
|
|
26
26
|
"@milkdown/utils": "^7.22.3",
|
|
27
|
-
"@north-light/identity": "0.3.
|
|
27
|
+
"@north-light/identity": "0.3.562",
|
|
28
28
|
"cron-parser": "^5.6.0",
|
|
29
29
|
"esbuild": "^0.27.7",
|
|
30
30
|
"jose": "^6.2.12",
|
|
@@ -12455,17 +12455,17 @@
|
|
|
12455
12455
|
},
|
|
12456
12456
|
"packages/crouter-api": {
|
|
12457
12457
|
"name": "@north-light/api",
|
|
12458
|
-
"version": "0.3.
|
|
12458
|
+
"version": "0.3.562",
|
|
12459
12459
|
"license": "UNLICENSED"
|
|
12460
12460
|
},
|
|
12461
12461
|
"packages/crouter-env-docker": {
|
|
12462
12462
|
"name": "@north-light/env-docker",
|
|
12463
|
-
"version": "0.3.
|
|
12463
|
+
"version": "0.3.562",
|
|
12464
12464
|
"license": "UNLICENSED"
|
|
12465
12465
|
},
|
|
12466
12466
|
"packages/crouter-identity": {
|
|
12467
12467
|
"name": "@north-light/identity",
|
|
12468
|
-
"version": "0.3.
|
|
12468
|
+
"version": "0.3.562",
|
|
12469
12469
|
"license": "UNLICENSED",
|
|
12470
12470
|
"dependencies": {
|
|
12471
12471
|
"jose": "^6.2.1"
|
|
@@ -12473,21 +12473,21 @@
|
|
|
12473
12473
|
},
|
|
12474
12474
|
"packages/crouter-plugin": {
|
|
12475
12475
|
"name": "@north-light/plugin",
|
|
12476
|
-
"version": "0.3.
|
|
12476
|
+
"version": "0.3.562",
|
|
12477
12477
|
"license": "UNLICENSED",
|
|
12478
12478
|
"dependencies": {
|
|
12479
|
-
"@north-light/api": "0.3.
|
|
12480
|
-
"@north-light/identity": "0.3.
|
|
12479
|
+
"@north-light/api": "0.3.562",
|
|
12480
|
+
"@north-light/identity": "0.3.562"
|
|
12481
12481
|
}
|
|
12482
12482
|
},
|
|
12483
12483
|
"packages/crouter-sdk": {
|
|
12484
12484
|
"name": "@north-light/sdk",
|
|
12485
|
-
"version": "0.3.
|
|
12485
|
+
"version": "0.3.562",
|
|
12486
12486
|
"license": "UNLICENSED",
|
|
12487
12487
|
"dependencies": {
|
|
12488
|
-
"@north-light/api": "0.3.
|
|
12489
|
-
"@north-light/identity": "0.3.
|
|
12490
|
-
"@north-light/plugin": "0.3.
|
|
12488
|
+
"@north-light/api": "0.3.562",
|
|
12489
|
+
"@north-light/identity": "0.3.562",
|
|
12490
|
+
"@north-light/plugin": "0.3.562",
|
|
12491
12491
|
"jose": "^6.2.1"
|
|
12492
12492
|
},
|
|
12493
12493
|
"bin": {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// scripts/git-credential-crtr — git credential helper for github.com (design-fleet, Components: Git credential helper; C-A2).
|
|
3
|
+
// `git-credential-crtr get` reads git's key=value request on stdin and answers username/password from
|
|
4
|
+
// `POST /v1/environments/<id>/git-credential` through the broker's relay socket (`CRTR_API_SOCKET`), which holds the
|
|
5
|
+
// node token; this process never sees it. It caches nothing. `store` and `erase` do nothing.
|
|
6
|
+
import { readFileSync } from 'node:fs';
|
|
7
|
+
import { request } from 'node:http';
|
|
8
|
+
|
|
9
|
+
const [, , action] = process.argv;
|
|
10
|
+
if (action !== 'get') process.exit(0);
|
|
11
|
+
|
|
12
|
+
const fields = Object.fromEntries(readFileSync(0, 'utf8').split('\n').filter((l) => l.includes('=')).map((l) => [l.slice(0, l.indexOf('=')), l.slice(l.indexOf('=') + 1)]));
|
|
13
|
+
if (fields.host !== 'github.com') process.exit(0);
|
|
14
|
+
|
|
15
|
+
const fail = (message) => { process.stderr.write(`git-credential-crtr: ${message}\n`); process.exit(1); };
|
|
16
|
+
const socketPath = process.env.CRTR_API_SOCKET ?? fail('CRTR_API_SOCKET is not set');
|
|
17
|
+
let environmentId = process.env.CRTR_ENVIRONMENT_ID;
|
|
18
|
+
if (!environmentId) {
|
|
19
|
+
try { environmentId = readFileSync(`${process.env.CRTR_HOME ?? '/var/lib/crtr'}/environment-id`, 'utf8').trim(); } catch { fail('the environment id is unknown'); }
|
|
20
|
+
}
|
|
21
|
+
const body = JSON.stringify({ host: fields.host, ...(fields.path ? { path: fields.path } : {}) });
|
|
22
|
+
const req = request({ socketPath, path: `/v1/environments/${environmentId}/git-credential`, method: 'POST', headers: { 'content-type': 'application/json', 'content-length': Buffer.byteLength(body) }, timeout: 30_000 }, (res) => {
|
|
23
|
+
let text = '';
|
|
24
|
+
res.on('data', (c) => { text += c; });
|
|
25
|
+
res.on('end', () => {
|
|
26
|
+
if (res.statusCode !== 200) return fail(`the control plane answered ${res.statusCode}: ${text.slice(0, 300)}`);
|
|
27
|
+
const out = JSON.parse(text);
|
|
28
|
+
process.stdout.write(`username=${out.username}\npassword=${out.password}\npasswordExpiryUtc=${Math.floor(Date.parse(out.expiry) / 1000)}\n`);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
req.on('error', (e) => fail(e.message));
|
|
32
|
+
req.on('timeout', () => { req.destroy(); fail('timed out'); });
|
|
33
|
+
req.end(body);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# scripts/sandbox-bootstrap.sh — the Blaxel runner's process command (design-fleet, Wake call step 5; C-A2).
|
|
3
|
+
#
|
|
4
|
+
# Runs as root in the sandbox's `broker-<execution id>` process. Environment: CRTR_NODE_TOKEN, CRTR_RELEASE,
|
|
5
|
+
# CRTR_RELEASE_URL, CRTR_RELEASE_SHA256 and the rest the runner set. Once per sandbox it creates the `crtr` user
|
|
6
|
+
# (`crtrd` refuses root) and its directories; it installs the release if it is absent (download, sha256 check,
|
|
7
|
+
# unpack into a temp dir, rename into place, keep three), then hands over to `crtr-sandbox-start` as `crtr`.
|
|
8
|
+
# The node token reaches the start script on stdin, never in its environment, so no process of user `crtr` can
|
|
9
|
+
# read it from /proc. A failed download or checksum exits non-zero and prints `crtr-sandbox-start: failed <reason>`
|
|
10
|
+
# as its last line (the runner's `status` reports that reason).
|
|
11
|
+
set -eu
|
|
12
|
+
|
|
13
|
+
fail() { echo "crtr-sandbox-start: failed $1${2:+ ($2)}" >&2; exit "${3:-1}"; }
|
|
14
|
+
|
|
15
|
+
: "${CRTR_RELEASE:?}" "${CRTR_RELEASE_URL:?}" "${CRTR_RELEASE_SHA256:?}" "${CRTR_NODE_TOKEN:?}"
|
|
16
|
+
case "$CRTR_RELEASE" in *[!A-Za-z0-9._-]*|'') fail bad_release "$CRTR_RELEASE" ;; esac
|
|
17
|
+
|
|
18
|
+
ROOT=${CRTR_SANDBOX_ROOT:-/opt/crtr}
|
|
19
|
+
RELEASES="$ROOT/releases"
|
|
20
|
+
RELEASE_DIR="$RELEASES/$CRTR_RELEASE"
|
|
21
|
+
RUN_USER=${CRTR_RUN_USER:-crtr}
|
|
22
|
+
|
|
23
|
+
if ! id "$RUN_USER" >/dev/null 2>&1; then
|
|
24
|
+
adduser -D -h "/home/$RUN_USER" -s /bin/sh "$RUN_USER" || fail user_create
|
|
25
|
+
fi
|
|
26
|
+
mkdir -p /run/crtr /var/lib/crtr /work "$RELEASES"
|
|
27
|
+
chown "$RUN_USER" /run/crtr /var/lib/crtr /work
|
|
28
|
+
# pi's grep tool wants ripgrep; installing it once per sandbox avoids a GitHub download at the first grep.
|
|
29
|
+
if ! command -v rg >/dev/null 2>&1; then apk add --no-cache ripgrep >/dev/null 2>&1 || echo "crtr-sandbox-start: ripgrep not installed" >&2; fi
|
|
30
|
+
|
|
31
|
+
if [ ! -f "$RELEASE_DIR/.complete" ]; then
|
|
32
|
+
tmp=$(mktemp -d "$RELEASES/.tmp.XXXXXX")
|
|
33
|
+
trap 'rm -rf "$tmp"' EXIT
|
|
34
|
+
wget -q -O "$tmp/runtime.tar.gz" "$CRTR_RELEASE_URL" || fail release_download "$CRTR_RELEASE"
|
|
35
|
+
actual=$(sha256sum "$tmp/runtime.tar.gz" | cut -d' ' -f1)
|
|
36
|
+
[ "$actual" = "$CRTR_RELEASE_SHA256" ] || fail release_checksum "expected $CRTR_RELEASE_SHA256, got $actual"
|
|
37
|
+
mkdir "$tmp/unpack"
|
|
38
|
+
tar -xzf "$tmp/runtime.tar.gz" -C "$tmp/unpack" || fail release_unpack
|
|
39
|
+
: > "$tmp/unpack/.complete"
|
|
40
|
+
# A concurrent start installing the same release wins the rename; both leave a complete directory.
|
|
41
|
+
if ! mv "$tmp/unpack" "$RELEASE_DIR" 2>/dev/null; then [ -f "$RELEASE_DIR/.complete" ] || fail release_install; fi
|
|
42
|
+
rm -rf "$tmp"
|
|
43
|
+
trap - EXIT
|
|
44
|
+
fi
|
|
45
|
+
ln -sfn "$RELEASE_DIR" "$ROOT/current.new" && mv -T "$ROOT/current.new" "$ROOT/current"
|
|
46
|
+
# Keep the three newest releases (the current one among them).
|
|
47
|
+
ls -1t "$RELEASES" 2>/dev/null | grep -v '^\.' | tail -n +4 | while read -r old; do
|
|
48
|
+
[ "$old" = "$CRTR_RELEASE" ] || rm -rf "${RELEASES:?}/$old"
|
|
49
|
+
done
|
|
50
|
+
|
|
51
|
+
token=$CRTR_NODE_TOKEN
|
|
52
|
+
unset CRTR_NODE_TOKEN
|
|
53
|
+
# `su -p` keeps the rest of the environment; the start script derives HOME and the layout itself.
|
|
54
|
+
printf '%s' "$token" | exec su -p -s /bin/sh "$RUN_USER" -c "exec node '$RELEASE_DIR/scripts/sandbox-start.mjs'"
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// scripts/sandbox-start.mjs — `crtr-sandbox-start` (design-fleet, Wake call step 5.1–5.9; C-A2).
|
|
3
|
+
//
|
|
4
|
+
// node sandbox-start.mjs start: the node token arrives on stdin (the bootstrap pipes it), the rest in env
|
|
5
|
+
// node sandbox-start.mjs --wake <id> signal the broker of execution <id> with SIGUSR1; exit 3 (no_broker) when none runs
|
|
6
|
+
//
|
|
7
|
+
// Plain node, no imports from dist/. A failing start prints `crtr-sandbox-start: failed <reason>` as its last
|
|
8
|
+
// line (the runner's `status` reads it) and exits non-zero.
|
|
9
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
10
|
+
import { createServer } from 'node:http';
|
|
11
|
+
import { randomBytes } from 'node:crypto';
|
|
12
|
+
import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, readlinkSync, realpathSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
13
|
+
import { tmpdir } from 'node:os';
|
|
14
|
+
import { dirname, join, resolve, sep } from 'node:path';
|
|
15
|
+
import { fileURLToPath } from 'node:url';
|
|
16
|
+
|
|
17
|
+
export const EXIT_NO_BROKER = 3;
|
|
18
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
|
|
20
|
+
class StartFailure extends Error {
|
|
21
|
+
constructor(reason, detail) { super(detail ?? reason); this.reason = reason; }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Broker processes of this sandbox: `{pid, execution}` for each `broker-cli.js ... --epoch <execution> <node>` command line. */
|
|
25
|
+
export function findBrokers(procRoot = '/proc') {
|
|
26
|
+
const out = [];
|
|
27
|
+
for (const name of readdirSync(procRoot)) {
|
|
28
|
+
if (!/^\d+$/.test(name)) continue;
|
|
29
|
+
let argv;
|
|
30
|
+
try { argv = readFileSync(join(procRoot, name, 'cmdline'), 'utf8').split('\0'); } catch { continue; }
|
|
31
|
+
const entry = argv.findIndex((a) => a.endsWith('broker-cli.js'));
|
|
32
|
+
if (entry < 0) continue;
|
|
33
|
+
const epoch = argv.indexOf('--epoch', entry);
|
|
34
|
+
if (epoch < 0 || argv[epoch + 1] === undefined) continue;
|
|
35
|
+
out.push({ pid: Number(name), execution: argv[epoch + 1], node: argv.filter((a) => a !== '').at(-1) });
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
41
|
+
|
|
42
|
+
async function stopBroker(pid) {
|
|
43
|
+
try { process.kill(pid, 'SIGTERM'); } catch { return; }
|
|
44
|
+
for (let i = 0; i < 100; i++) {
|
|
45
|
+
await sleep(100);
|
|
46
|
+
try { process.kill(pid, 0); } catch { return; }
|
|
47
|
+
}
|
|
48
|
+
try { process.kill(pid, 'SIGKILL'); } catch { /* gone */ }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function wake(executionId, brokers = findBrokers()) {
|
|
52
|
+
const found = brokers.find((b) => b.execution === executionId);
|
|
53
|
+
if (!found) return EXIT_NO_BROKER;
|
|
54
|
+
process.kill(found.pid, 'SIGUSR1');
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function readStdin() {
|
|
59
|
+
const chunks = [];
|
|
60
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
61
|
+
return Buffer.concat(chunks).toString('utf8').trim();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function api(baseUrl, token, method, path, body) {
|
|
65
|
+
const response = await fetch(`${baseUrl.replace(/\/$/, '')}${path}`, {
|
|
66
|
+
method, headers: { authorization: `Bearer ${token}`, ...(body ? { 'content-type': 'application/json' } : {}) }, ...(body ? { body: JSON.stringify(body) } : {}),
|
|
67
|
+
signal: AbortSignal.timeout(30_000),
|
|
68
|
+
});
|
|
69
|
+
return response;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function run(command, args, options = {}) {
|
|
73
|
+
return spawnSync(command, args, { encoding: 'utf8', ...options });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Whether `path` lies inside `root` (both resolved). */
|
|
77
|
+
export function within(root, path) {
|
|
78
|
+
const r = resolve(root) + sep;
|
|
79
|
+
return (resolve(path) + sep).startsWith(r);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Step 5.9: a daemon-side extension path under `dist/` maps into the installed release; any other path must already lie in the release or the agent dir. */
|
|
83
|
+
export function mapExtension(path, release, agentDir) {
|
|
84
|
+
const marker = `${sep}dist${sep}`;
|
|
85
|
+
const at = path.lastIndexOf(marker);
|
|
86
|
+
if (at >= 0 && !within(release, path) && !within(agentDir, path)) {
|
|
87
|
+
const mapped = join(release, path.slice(at + 1));
|
|
88
|
+
if (existsSync(mapped)) return mapped;
|
|
89
|
+
}
|
|
90
|
+
if (!within(release, path) && !within(agentDir, path)) throw new StartFailure('extension_unavailable', `extension path ${path} lies outside the release and the agent dir`);
|
|
91
|
+
if (!existsSync(path)) throw new StartFailure('extension_unavailable', `extension ${path} does not exist`);
|
|
92
|
+
return path;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function lstatExists(path) {
|
|
96
|
+
try { lstatSync(path); return true; } catch { return false; }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function gitIn(cwd, args, timeoutMs) {
|
|
100
|
+
return run('git', args, { cwd, timeout: timeoutMs });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** A short-lived credential relay for the start script's own git calls (the broker's relay does not exist until the script ends). It answers
|
|
104
|
+
* only `POST /v1/environments/<id>/git-credential`, forwarding it to the control plane with the node token this process holds; the socket
|
|
105
|
+
* lives in a private directory and the token is neither written to disk nor placed in any child's environment. */
|
|
106
|
+
async function credentialRelay(apiUrl, token, environmentId) {
|
|
107
|
+
const dir = mkdtempSync(join(tmpdir(), 'crtr-credential-'));
|
|
108
|
+
const socketPath = join(dir, 'api.sock');
|
|
109
|
+
const route = `/v1/environments/${environmentId}/git-credential`;
|
|
110
|
+
const server = createServer((req, res) => {
|
|
111
|
+
const chunks = [];
|
|
112
|
+
req.on('data', (c) => chunks.push(c));
|
|
113
|
+
req.on('end', async () => {
|
|
114
|
+
if (req.method !== 'POST' || req.url !== route) return void res.writeHead(404).end();
|
|
115
|
+
try {
|
|
116
|
+
const upstream = await api(apiUrl, token, 'POST', route, JSON.parse(Buffer.concat(chunks).toString('utf8')));
|
|
117
|
+
res.writeHead(upstream.status, { 'content-type': 'application/json' }).end(await upstream.text());
|
|
118
|
+
} catch (error) { res.writeHead(502).end(String(error?.message ?? error)); }
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
await new Promise((resolveListen, rejectListen) => { server.once('error', rejectListen); server.listen(socketPath, resolveListen); });
|
|
122
|
+
return { socketPath, close: async () => { await new Promise((r) => server.close(r)); rmSync(dir, { recursive: true, force: true }); } };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** `git` in `cwd` without blocking the event loop (the credential relay must keep answering while it runs). */
|
|
126
|
+
function gitAsync(cwd, args, timeoutMs, env) {
|
|
127
|
+
return new Promise((resolveGit) => {
|
|
128
|
+
const child = spawn('git', args, { cwd, env, stdio: ['ignore', 'pipe', 'pipe'], timeout: timeoutMs });
|
|
129
|
+
let stderr = '';
|
|
130
|
+
child.stderr.on('data', (c) => { stderr += c; });
|
|
131
|
+
child.stdout.resume();
|
|
132
|
+
child.on('error', (error) => resolveGit({ status: 1, stderr: String(error?.message ?? error) }));
|
|
133
|
+
child.on('close', (status) => resolveGit({ status, stderr }));
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function start(env) {
|
|
138
|
+
const need = (name) => { const v = env[name]; if (!v) throw new StartFailure('bad_environment', `${name} is not set`); return v; };
|
|
139
|
+
const apiUrl = need('CRTR_API_URL');
|
|
140
|
+
const executionId = need('CRTR_EXECUTION_ID');
|
|
141
|
+
const releaseDir = realpathSync(env.CRTR_RELEASE_DIR ?? resolve(here, '..'));
|
|
142
|
+
// 5.1 token first; nothing is started or stopped before the control plane accepts it.
|
|
143
|
+
const token = env.CRTR_NODE_TOKEN ?? await readStdin();
|
|
144
|
+
if (!/^[A-Za-z0-9_-]{43}$/.test(token)) throw new StartFailure('token_missing', 'no node token on stdin');
|
|
145
|
+
let response;
|
|
146
|
+
try { response = await api(apiUrl, token, 'GET', `/v1/executions/${executionId}/start`); }
|
|
147
|
+
catch (error) { throw new StartFailure('bundle_unreachable', String(error?.message ?? error)); }
|
|
148
|
+
if (response.status === 401 || response.status === 403) throw new StartFailure('token_rejected', `the control plane answered ${response.status}`);
|
|
149
|
+
if (!response.ok) throw new StartFailure('bundle_failed', `the control plane answered ${response.status}`);
|
|
150
|
+
const bundle = await response.json();
|
|
151
|
+
|
|
152
|
+
// 5.2 a broker of this execution is signalled; a broker of another execution is stopped.
|
|
153
|
+
const brokers = findBrokers(env.CRTR_PROC_ROOT ?? '/proc').filter((b) => b.node === bundle.node.id);
|
|
154
|
+
if (brokers.some((b) => b.execution === executionId)) { wake(executionId, brokers); return null; }
|
|
155
|
+
for (const b of brokers) await stopBroker(b.pid);
|
|
156
|
+
|
|
157
|
+
const root = env.CRTR_HOME ?? '/var/lib/crtr';
|
|
158
|
+
const home = join(root, 'apps', bundle.node.app.replace(/^app:/, ''), 'home');
|
|
159
|
+
const agentDir = join(home, '.pi', 'agent');
|
|
160
|
+
const work = env.CRTR_WORK_DIR ?? '/work';
|
|
161
|
+
mkdirSync(agentDir, { recursive: true });
|
|
162
|
+
// The recipe image installs its pi packages into one agent dir of its own (RECIPE_PI_AGENT_DIR in image-build.ts); every app's agent dir links to
|
|
163
|
+
// that install, so the packages load whichever app the node runs in.
|
|
164
|
+
const recipeAgent = join(root, 'recipe-pi-agent');
|
|
165
|
+
for (const tree of ['npm', 'git']) {
|
|
166
|
+
const source = join(recipeAgent, tree);
|
|
167
|
+
const target = join(agentDir, tree);
|
|
168
|
+
if (!existsSync(source)) continue;
|
|
169
|
+
if (!lstatExists(target)) symlinkSync(source, target);
|
|
170
|
+
else if (!lstatSync(target).isSymbolicLink() || readlinkSync(target) !== source) throw new StartFailure('recipe_packages_unavailable', `${target} exists and is not the recipe image's ${source}`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// 5.4 git: the credential helper, and the identity only when the bundle carries one.
|
|
174
|
+
const gitEnv = { ...env, HOME: home };
|
|
175
|
+
const gitConfig = (key, value) => run('git', ['config', '--global', key, value], { env: gitEnv });
|
|
176
|
+
gitConfig('credential.https://github.com.helper', join(releaseDir, 'scripts', 'git-credential-crtr'));
|
|
177
|
+
if (bundle.git_identity) { gitConfig('user.name', bundle.git_identity.name); gitConfig('user.email', bundle.git_identity.email); }
|
|
178
|
+
|
|
179
|
+
// 5.5 plugins, once per revision.
|
|
180
|
+
const marker = join(work, '.crtr', 'plugins-revision');
|
|
181
|
+
const have = existsSync(marker) ? readFileSync(marker, 'utf8').trim() : null;
|
|
182
|
+
if (have !== String(bundle.plugins_revision) && bundle.plugins.length > 0) {
|
|
183
|
+
const crtr = join(releaseDir, 'bin', 'crtr');
|
|
184
|
+
const pluginEnv = { ...gitEnv, NPM_CONFIG_PREFIX: join(home, '.npm-global'), CRTR_HOME: root, CRTR_NO_AUTO_INIT: '1' };
|
|
185
|
+
const crtrRun = (args) => run(process.execPath, [crtr, ...args], { env: pluginEnv, timeout: 300_000 });
|
|
186
|
+
const detail = (r) => (r.stderr || r.stdout || '').slice(0, 300);
|
|
187
|
+
// A plugin of a marketplace is installed as `<marketplace name>/<plugin>`; the bundle names only the marketplace's url and ref, so the name is what
|
|
188
|
+
// `pkg market add` reports. Adding re-clones, so a marketplace added once per start is current. A plugin already installed (an earlier revision) is
|
|
189
|
+
// removed first, since install refuses an installed name.
|
|
190
|
+
const marketplaces = new Map();
|
|
191
|
+
for (const plugin of bundle.plugins) {
|
|
192
|
+
if ('path' in plugin.source) throw new StartFailure('plugin_source_unreachable', `${plugin.name}: its source is ${plugin.source.path} on the machine that registered it, which a sandbox cannot read`);
|
|
193
|
+
const { url, ref } = plugin.source.marketplace;
|
|
194
|
+
if (!url) throw new StartFailure('plugin_source_unreachable', `${plugin.name}: its marketplace has no url`);
|
|
195
|
+
const key = `${url}\0${ref ?? ''}`;
|
|
196
|
+
if (!marketplaces.has(key)) {
|
|
197
|
+
const added = crtrRun(['--json', 'pkg', 'market', 'add', url, ...(ref ? ['--ref', ref] : []), '--scope', 'user']);
|
|
198
|
+
let name;
|
|
199
|
+
try { name = JSON.parse(added.stdout).name; } catch { /* reported below */ }
|
|
200
|
+
if (added.status !== 0 || typeof name !== 'string') throw new StartFailure('plugin_install_failed', `${plugin.name}: marketplace ${url}: ${detail(added)}`);
|
|
201
|
+
marketplaces.set(key, name);
|
|
202
|
+
}
|
|
203
|
+
const removed = crtrRun(['pkg', 'plugin', 'remove', plugin.name, '--scope', 'user']);
|
|
204
|
+
if (removed.status !== 0 && !/not found/i.test(removed.stderr + removed.stdout)) throw new StartFailure('plugin_install_failed', `${plugin.name}: remove: ${detail(removed)}`);
|
|
205
|
+
const installed = crtrRun(['pkg', 'plugin', 'install', `${marketplaces.get(key)}/${plugin.name}`, '--scope', 'user']);
|
|
206
|
+
if (installed.status !== 0) throw new StartFailure('plugin_install_failed', `${plugin.name}: ${detail(installed)}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (have !== String(bundle.plugins_revision)) { mkdirSync(dirname(marker), { recursive: true }); writeFileSync(marker, String(bundle.plugins_revision)); }
|
|
210
|
+
|
|
211
|
+
// 5.6 fetch only, never clone and never move a working tree; a failure is recorded and the start continues. The fetch reaches a private
|
|
212
|
+
// repository through the credential helper, over a relay of this process (see credentialRelay) because the broker's does not exist yet.
|
|
213
|
+
const fetchFailures = [];
|
|
214
|
+
const cloned = (bundle.recipe?.repositories ?? []).filter((repo) => existsSync(join(work, repo.name, '.git')));
|
|
215
|
+
if (cloned.length > 0) {
|
|
216
|
+
const environment = bundle.node.environment_id;
|
|
217
|
+
const relay = environment ? await credentialRelay(apiUrl, token, environment) : null;
|
|
218
|
+
const fetchEnv = { ...gitEnv, GIT_TERMINAL_PROMPT: '0', ...(relay ? { CRTR_API_SOCKET: relay.socketPath, CRTR_ENVIRONMENT_ID: environment } : {}) };
|
|
219
|
+
delete fetchEnv.CRTR_NODE_TOKEN;
|
|
220
|
+
try {
|
|
221
|
+
for (const repo of cloned) {
|
|
222
|
+
const r = await gitAsync(join(work, repo.name), ['fetch', '--prune'], 60_000, fetchEnv);
|
|
223
|
+
if (r.status !== 0) fetchFailures.push({ repository: repo.name, error: r.stderr.slice(0, 300) });
|
|
224
|
+
}
|
|
225
|
+
} finally { await relay?.close(); }
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// 5.7 the managed worktree request (D102): the node's branch in the recipe repository's one clone, never a second checkout.
|
|
229
|
+
const worktree = bundle.launch.worktree;
|
|
230
|
+
if (worktree) {
|
|
231
|
+
const dir = join(work, worktree.repository);
|
|
232
|
+
if (!existsSync(join(dir, '.git'))) throw new StartFailure('cwd_missing', `${dir} holds no clone of ${worktree.repository}`);
|
|
233
|
+
const current = gitIn(dir, ['symbolic-ref', '--short', '-q', 'HEAD'], 10_000).stdout?.trim();
|
|
234
|
+
if (current !== worktree.branch) {
|
|
235
|
+
const exists = gitIn(dir, ['rev-parse', '--verify', '-q', `refs/heads/${worktree.branch}`], 10_000).status === 0;
|
|
236
|
+
const r = gitIn(dir, exists ? ['switch', worktree.branch] : ['switch', '-c', worktree.branch, worktree.base], 30_000);
|
|
237
|
+
if (r.status !== 0) throw new StartFailure('worktree_failed', `${worktree.branch}: ${(r.stderr || '').slice(0, 300)}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// 5.7 directories and the cwd.
|
|
242
|
+
const cwd = bundle.node.cwd;
|
|
243
|
+
if (!existsSync(cwd)) {
|
|
244
|
+
const inside = (bundle.recipe?.repositories ?? []).some((repo) => within(join(work, repo.name), cwd));
|
|
245
|
+
if (inside) throw new StartFailure('cwd_missing', `${cwd} lies in a repository that was never cloned`);
|
|
246
|
+
mkdirSync(cwd, { recursive: true });
|
|
247
|
+
}
|
|
248
|
+
const nodeId = bundle.node.id;
|
|
249
|
+
const environmentId = bundle.node.environment_id;
|
|
250
|
+
if (environmentId) writeFileSync(join(root, 'environment-id'), environmentId);
|
|
251
|
+
const appRoot = join(root, 'apps', bundle.node.app.replace(/^app:/, ''));
|
|
252
|
+
const runDir = join(env.CRTR_RUN_ROOT ?? '/run/crtr', 'nodes', nodeId);
|
|
253
|
+
for (const dir of ['context', 'reports', 'attachments', 'worktree'].map((d) => join(appRoot, 'nodes', nodeId, d))
|
|
254
|
+
.concat([join(root, 'runtime', 'nodes', nodeId, 'job'), join(runDir, 'job')])) mkdirSync(dir, { recursive: true });
|
|
255
|
+
|
|
256
|
+
// 5.8 the broker's local inputs.
|
|
257
|
+
const launch = bundle.launch;
|
|
258
|
+
const brokerEntry = join(releaseDir, 'dist', 'core', 'runtime', 'broker-cli.js');
|
|
259
|
+
const argv = [...launch.argv];
|
|
260
|
+
for (let i = 0; i < argv.length; i++) if (argv[i] === '-e') argv[i + 1] = mapExtension(argv[i + 1], releaseDir, agentDir);
|
|
261
|
+
// As host.ts does: the scopes file exists only when the recipe's env names one, holding `scopes ?? []`.
|
|
262
|
+
const scopesFile = launch.env?.CRTR_SCOPES_FILE !== undefined ? join(runDir, 'scopes.json') : null;
|
|
263
|
+
if (scopesFile) writeFileSync(scopesFile, JSON.stringify(launch.scopes ?? []));
|
|
264
|
+
const models = launch.models;
|
|
265
|
+
if (models) writeFileSync(join(agentDir, 'models.json'), `${JSON.stringify(models, null, 2)}\n`);
|
|
266
|
+
writeFileSync(join(runDir, 'broker-launch.json'), JSON.stringify({ ...launch, argv }));
|
|
267
|
+
const settingsPath = join(agentDir, 'settings.json');
|
|
268
|
+
const builtin = join(releaseDir, 'dist', 'builtin-pi-packages', 'pi-crtr-extensions');
|
|
269
|
+
let settings = {};
|
|
270
|
+
if (existsSync(settingsPath)) settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
271
|
+
const packages = Array.isArray(settings.packages) ? settings.packages : [];
|
|
272
|
+
if (!packages.includes(builtin)) packages.push(builtin);
|
|
273
|
+
const recipeSettings = join(recipeAgent, 'settings.json');
|
|
274
|
+
if (existsSync(recipeSettings)) {
|
|
275
|
+
for (const entry of JSON.parse(readFileSync(recipeSettings, 'utf8')).packages ?? []) {
|
|
276
|
+
if (!packages.some((have) => JSON.stringify(have) === JSON.stringify(entry))) packages.push(entry);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
writeFileSync(settingsPath, `${JSON.stringify({ ...settings, packages })}\n`);
|
|
280
|
+
|
|
281
|
+
// 5.9 the broker, with the token on fd 3 and not in its environment.
|
|
282
|
+
const brokerEnv = { ...env, ...launch.env, HOME: home, PI_CODING_AGENT_DIR: agentDir, CRTR_HOME: root, CRTR_RUNTIME_HOME: join(root, 'runtime'),
|
|
283
|
+
CRTR_FRONT_DOOR: '1', CRTR_EXECUTION_ID: executionId, CRTR_API_URL: apiUrl, CRTR_NO_AUTO_INIT: '1',
|
|
284
|
+
CRTR_PLUGINS_REVISION: String(bundle.plugins_revision), ...(environmentId ? { CRTR_ENVIRONMENT_ID: environmentId } : {}), ...(scopesFile ? { CRTR_SCOPES_FILE: scopesFile } : {}),
|
|
285
|
+
PATH: `${join(releaseDir, 'bin')}:${env.PATH ?? '/usr/local/bin:/usr/bin:/bin'}` };
|
|
286
|
+
for (const name of ['CRTR_NODE_TOKEN', 'CRTR_RELEASE_URL', 'CRTR_RELEASE_SHA256']) delete brokerEnv[name];
|
|
287
|
+
const child = spawn(process.execPath, [brokerEntry, '--canvas-home', join(root, 'runtime'), '--epoch', executionId, nodeId],
|
|
288
|
+
{ cwd, env: brokerEnv, stdio: ['ignore', 'inherit', 'inherit', 'pipe'] });
|
|
289
|
+
child.stdio[3].end(token);
|
|
290
|
+
const exited = new Promise((resolveExit) => child.on('exit', (code, signal) => resolveExit(code ?? (signal ? 128 : 1))));
|
|
291
|
+
for (const sig of ['SIGTERM', 'SIGINT']) process.on(sig, () => child.kill(sig));
|
|
292
|
+
// The failure is a node log record (`POST /v1/nodes/:id/records/log`, the route a broker's events use); a refused post goes to the process log (`bl logs`).
|
|
293
|
+
for (const failure of fetchFailures) {
|
|
294
|
+
const record = JSON.stringify({ v: 1, ts: new Date().toISOString(), level: 'warn', event: 'sandbox.fetch.failed', component: 'broker', operation_id: randomBytes(16).toString('hex'), node_id: nodeId, fields: failure });
|
|
295
|
+
try {
|
|
296
|
+
const posted = await api(apiUrl, token, 'POST', `/v1/nodes/${nodeId}/records/log`, { record, expected_execution_id: executionId });
|
|
297
|
+
if (!posted.ok) throw new Error(`the control plane answered ${posted.status}`);
|
|
298
|
+
} catch (error) { console.error(`sandbox.fetch.failed ${record} (not recorded: ${error?.message ?? error})`); }
|
|
299
|
+
}
|
|
300
|
+
return await exited;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
304
|
+
const args = process.argv.slice(2);
|
|
305
|
+
try {
|
|
306
|
+
if (args[0] === '--wake') {
|
|
307
|
+
if (!args[1]) throw new StartFailure('bad_arguments', '--wake needs an execution id');
|
|
308
|
+
const code = wake(args[1], findBrokers(process.env.CRTR_PROC_ROOT ?? '/proc'));
|
|
309
|
+
if (code === EXIT_NO_BROKER) console.error('crtr-sandbox-start: failed no_broker');
|
|
310
|
+
process.exit(code);
|
|
311
|
+
}
|
|
312
|
+
const code = await start(process.env);
|
|
313
|
+
process.exit(code ?? 0);
|
|
314
|
+
} catch (error) {
|
|
315
|
+
const reason = error instanceof StartFailure ? error.reason : 'start_failed';
|
|
316
|
+
console.error(`crtr-sandbox-start: ${error.message}`);
|
|
317
|
+
console.error(`crtr-sandbox-start: failed ${reason}`);
|
|
318
|
+
process.exit(1);
|
|
319
|
+
}
|
|
320
|
+
}
|