@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
|
|
2
|
-
`).withLockAsync(async(
|
|
3
|
-
`),{result:void 0}))}
|
|
1
|
+
var K=Object.defineProperty;var p=(e,t)=>K(e,"name",{value:t,configurable:!0});import{prepared as E}from"../sqlite-statements.js";import{randomUUID as Y}from"node:crypto";import{chmodSync as R,copyFileSync as G,existsSync as y,mkdirSync as g,readFileSync as S,readdirSync as b,statSync as I}from"node:fs";import{basename as B,dirname as j,join as m,relative as X}from"node:path";import q from"proper-lockfile";import{CONFIG_FILE as F,PROFILE_DIR as z,STATE_FILE as k}from"../../types.js";import{LockedJsonFile as Q}from"../locked-file.js";import{assertScopedStoreReady as Z,createScopedStore as C,openScopedStore as $,discardIncompleteScopedStore as ee,legacyScopedStorePaths as D,PROFILE_ID_SHAPE as te,scopedStoreExists as v,withProjectStateLock as re,writeOwnerRoot as oe}from"./db.js";import{canonicalRoot as ae,providerStore as h,projectStore as ie,userStore as ne}from"./paths.js";import{profileSpace as P,appSpace as se}from"../layout.js";import{createScopedSchema as x}from"./schema.js";import{openDb as ce,withCanvasWrite as le}from"../canvas/db.js";import{loadSecretsKey as fe,seal as de}from"../secrets/index.js";import{putEnvRowIfAbsent as pe}from"../secrets/env-rows.js";import{DEPLOYMENT_ID as ue}from"../secrets/environment-secrets.js";import{isReservedEnvName as V,validateEnvVarName as me}from"../env-name.js";import{insertAccount as _e,upsertModelCooldown as ye}from"../subscription-state.js";import{userScopeRoot as Ee}from"../scope.js";import{secretsDir as U}from"../layout.js";import{readLegacyUserSnapshot as we}from"./legacy-profiles.js";import{revisionOf as ve}from"./person-store.js";import{loadPersonSettings as Se,applyOpsToRows as he,readSnapshotFromRows as ge}from"./person-rows.js";function w(e){return JSON.parse(S(e,"utf8"))}p(w,"json");function W(e){return e.some(y)}p(W,"existsLegacy");function O(e,t){const o=m(e,".legacy-scoped-state");try{g(o,{mode:448})}catch(a){if(a.code!=="EEXIST"||!I(o).isDirectory())throw a}R(o,448);for(const a of t)if(y(a)&&I(a).isFile()){const i=X(e,a);if(i===""||i.startsWith(".."))throw new Error(`legacy state is outside its owning root: ${a}`);const r=m(o,i);j(r)!==o&&g(j(r),{recursive:!0,mode:448}),G(a,r),R(r,384)}}p(O,"preserve");function Ie(e){const t=e.kind==="user"?ne(e.root):e.kind==="project"?ie(e.root):h(e.root);if(e.kind!=="project"&&v(t))return;if(e.kind==="provider")throw new Error("provider conversion requires convertLegacyProviderStore() under coordinated shared-agent-dir activation");const o=D(t),a=p(()=>{e.kind==="project"&&ee(t),!v(t)&&(e.kind==="project"&&W(o)&&O(t.root,o),C(t,i=>{x(i,e.kind);const r=e.kind==="user"?"user":"project";oe(i,r,t.root),e.kind==="user"?Ae(i,t.root):N(i,r,m(t.root,k))}),e.kind==="user"&&W(o)&&O(t.root,o))},"convert");e.kind==="project"?re(t.root,()=>{a(),Z(t)}):a()}p(Ie,"convertLegacyScopedStore");function ke(e){if(!y(e))return[];const t=JSON.parse(S(e,"utf8"));if(!Array.isArray(t))throw new Error(`legacy subscription pool is malformed: ${e}`);const o=new Set;return t.map((a,i)=>{if(a===null||typeof a!="object"||Array.isArray(a))throw new Error(`legacy subscription pool entry ${i+1} is malformed: ${e}`);const r=a,l=typeof r.label=="string"?r.label.trim():"",d=typeof r.refresh=="string"?r.refresh.trim():"",n=typeof r.access=="string"?r.access.trim():"",s=Number(r.expires);if(!l||!d||!n||!Number.isFinite(s))throw new Error(`legacy subscription pool entry ${i+1} is incomplete: ${e}`);const c=l.toLowerCase();if(o.has(c))throw new Error(`legacy subscription pool has duplicate label "${l}": ${e}`);o.add(c);const f=p(u=>Number.isFinite(Number(r[u]))?Number(r[u]):0,"timing"),_=typeof r.accountId=="string"&&r.accountId.trim()!==""?r.accountId.trim():void 0;return{label:l,refresh:d,access:n,expires:s,rateLimitedUntil:f("rateLimitedUntil"),lastAttemptAt:f("lastAttemptAt"),lastRateLimitedAt:f("lastRateLimitedAt"),...r.authFailure==="invalid_grant"?{authFailure:"invalid_grant"}:{},..._?{accountId:_}:{}}})}p(ke,"parseLegacyProviderPool");function Oe(e){if(!y(e))return{};const t=JSON.parse(S(e,"utf8"));if(t===null||typeof t!="object"||Array.isArray(t))throw new Error(`legacy provider rotation settings are malformed: ${e}`);const o=t;return{...o.defaultFallbackStrength==="ultra"||o.defaultFallbackStrength==="strong"||o.defaultFallbackStrength==="medium"||o.defaultFallbackStrength==="light"?{defaultFallbackStrength:o.defaultFallbackStrength}:{},...typeof o.revertWhenAvailable=="boolean"?{revertWhenAvailable:o.revertWhenAvailable}:{}}}p(Oe,"parseLegacyRotation");async function Ne(e,t){const o=[];try{for(const a of e)y(a)&&o.push(await q.lock(a,{realpath:!1,retries:0,stale:3e4,update:1e4}));return await t()}finally{await Promise.allSettled(o.reverse().map(a=>a()))}}p(Ne,"withLegacyProviderLocks");async function rt(e){const t=h(e);if(v(t))return;const o=D(t);await Ne(o,async()=>{if(v(t))return;const a=new Map(o.slice(0,2).map((r,l)=>[l===0?"anthropic":"openai-codex",ke(r)])),i=Oe(o[2]);g(t.root,{recursive:!0,mode:448}),O(t.root,o);for(const[r,l]of a){const d=Object.fromEntries(l.map(s=>[Y(),{refresh:s.refresh,access:s.access,expires:s.expires,...s.accountId?{accountId:s.accountId}:{}}]));await new Q(m(t.root,`${r}-credentials.json`),!0,`{"version":1,"accounts":{}}
|
|
2
|
+
`).withLockAsync(async(s,c,f)=>(f(`${JSON.stringify({version:1,accounts:d})}
|
|
3
|
+
`),{result:void 0}))}C(t,r=>{x(r,"provider");for(const[l,d]of a){const n=JSON.parse(S(m(t.root,`${l}-credentials.json`),"utf8")),s=Object.keys(n.accounts),c=E(r,"INSERT INTO managed_accounts(provider_id,id,label,label_key,position,last_attempt_at,last_rate_limited_at,rate_limited_until,auth_failure) VALUES(?,?,?,?,?,?,?,?,?)");d.forEach((f,_)=>c.run(l,s[_],f.label,f.label.toLowerCase(),_,f.lastAttemptAt,f.lastRateLimitedAt,f.rateLimitedUntil,f.authFailure??null))}(i.defaultFallbackStrength!==void 0||i.revertWhenAvailable!==void 0)&&E(r,"INSERT INTO rotation_settings(singleton,default_fallback_strength,revert_when_available) VALUES(1,?,?)").run(i.defaultFallbackStrength??null,i.revertWhenAvailable===void 0?null:i.revertWhenAvailable?1:0)})})}p(rt,"convertLegacyProviderStore");function M(e,t,o){if(!y(o))return;const a=w(o);if(a===null||typeof a!="object"||Array.isArray(a))throw new Error(`legacy config is malformed: ${o}`);E(e,"INSERT INTO scope_settings(owner_key,raw_json) VALUES(?,?)").run(t,JSON.stringify(a))}p(M,"importSettings");function N(e,t,o){if(!y(o))return;const a=w(o);if(a===null||typeof a!="object"||Array.isArray(a))throw new Error(`legacy state is malformed: ${o}`);const i=a;E(e,"INSERT INTO scope_bookkeeping(owner_key,last_self_check,active_canvas) VALUES(?,?,?)").run(t,i.last_self_check??null,i.activeCanvas??null);const r=E(e,"INSERT INTO scope_marketplaces(owner_key,name,last_updated) VALUES(?,?,?)");for(const[d,n]of Object.entries(i.marketplaces??{}))r.run(t,d,n.last_updated??null);const l=E(e,"INSERT INTO scope_plugins(owner_key,name,last_updated,etag,checked_at) VALUES(?,?,?,?,?)");for(const[d,n]of Object.entries(i.plugins??{}))l.run(t,d,n.last_updated??null,n.etag??null,n.checked_at??null)}p(N,"importState");function Ae(e,t){M(e,"user",m(t,F)),N(e,"user",m(t,k));const o=m(t,z);if(y(o))for(const i of b(o,{withFileTypes:!0})){if(!i.isDirectory()||!te.test(i.name))continue;const r=i.name,l=m(o,r),d=m(l,"profile.json");if(!y(d))throw new Error(`legacy profile manifest is missing: ${d}`);const n=w(d);if(!n||typeof n!="object"||!Array.isArray(n.projects)||typeof n.name!="string"||typeof n.created_at!="string")throw new Error(`legacy profile manifest is malformed: ${d}`);E(e,"INSERT INTO profiles(id,name,created_at,last_used_at,paused_at,default_kind,grantee,metadata_json) VALUES(?,?,?,?,?,?,?,?)").run(r,n.name,n.created_at,n.last_used_at??null,n.paused_at??null,n.default_kind??null,n.grantee??null,JSON.stringify(n.metadata??{})),E(e,"INSERT INTO scope_owners(owner_key,kind,root,profile_id) VALUES(?,?,?,?)").run(`profile:${r}`,"profile",ae(P(n.grantee??"app:terminal",r).dir),r);const s=E(e,"INSERT INTO profile_projects(profile_id,path,position) VALUES(?,?,?)"),c=E(e,"INSERT INTO legacy_project_caps(profile_id,path,memory) VALUES(?,?,?)");n.projects.forEach((f,_)=>{s.run(r,f.path,_),f.memory!==void 0&&f.memory!=="content"&&c.run(r,f.path,f.memory)}),M(e,`profile:${r}`,m(l,F)),N(e,`profile:${r}`,m(l,k))}const a=m(t,"profile-defaults.json");if(y(a)){const i=w(a);if(i===null||typeof i!="object"||Array.isArray(i))throw new Error(`legacy profile defaults are malformed: ${a}`);const r=E(e,"INSERT INTO profile_defaults(directory,profile_id) VALUES(?,?)");for(const[l,d]of Object.entries(i)){if(typeof d!="string")throw new Error(`legacy profile default is malformed: ${a}`);r.run(l,d)}}}p(Ae,"importUser");const A="person_stores_copied",L={anthropic:"anthropic-credentials.json","openai-codex":"openai-codex-credentials.json",openai:"openai-credentials.json"};async function Le(){return await(await ce()).prepare("SELECT value FROM canvas_meta WHERE key = ?").get(A)!==void 0}p(Le,"personStoresCopied");function Te(e){const t=h(e);if(!v(t))return[];const o=$(t),a=[];for(const i of Object.keys(L)){const r=m(e,L[i]);if(!y(r))continue;const l=w(r),d=E(o,"SELECT account_id,family,rate_limited_until,last_rate_limited_at FROM managed_account_model_cooldowns WHERE provider_id=?").all(i);for(const n of E(o,"SELECT id,label,label_key,position,last_attempt_at,last_rate_limited_at,rate_limited_until,auth_failure FROM managed_accounts WHERE provider_id=? ORDER BY position").all(i)){const s=l.accounts?.[n.id];s!==void 0&&a.push({provider:i,id:n.id,row:{providerId:i,id:n.id,label:n.label,labelKey:n.label_key,position:n.position,lastAttemptAt:n.last_attempt_at,lastRateLimitedAt:n.last_rate_limited_at,rateLimitedUntil:n.rate_limited_until,...n.auth_failure?{authFailure:n.auth_failure}:{}},tokens:{refresh:s.refresh,access:s.access,expires:s.expires,...s.accountId?{accountId:s.accountId}:{},...s.clientId?{clientId:s.clientId}:{}},cooldowns:d.filter(c=>c.account_id===n.id).map(c=>({family:c.family,until:c.rate_limited_until,at:c.last_rate_limited_at}))})}}return a}p(Te,"readLegacyAccounts");function T(e,t){if(!y(e)||!I(e).isFile())return{};let o;try{o=w(e)}catch{return{}}const a={};if(o===null||typeof o!="object"||o.vars===null||typeof o.vars!="object"||Array.isArray(o.vars))return a;for(const[i,r]of Object.entries(o.vars))me(i).isValid&&t(i)&&typeof r=="string"&&!r.includes("\0")&&(a[i]=r);return a}p(T,"readLegacyEnvFile");const Re=new Set(["CRTR_FEEDBACK_ENDPOINT","CRTR_FEEDBACK_TOKEN"]);async function be(e,t,o){const a=m(U(),"env");if(!y(a))return;const i=p(async(r,l)=>{for(const[d,n]of Object.entries(l))await pe(e,r,d,n)},"put");for(const r of o)await i({person:t,kind:"profile",id:r.profileId},T(P(r.manifest.grantee??"app:terminal",r.profileId).env,l=>!V(l)));for(const r of b(a,{withFileTypes:!0})){if(!r.isDirectory())continue;const l=`app:${r.name}`;B(se(l).root)===r.name&&await i({person:t,kind:"app",id:l},T(m(a,r.name,"_app"),d=>!V(d)))}await i({person:null,kind:"deployment",id:ue},T(m(a,"_deployment"),r=>Re.has(r)))}p(be,"copyLegacyEnvFiles");async function je(e,t,o){const a=Te(o),i=(()=>{const s=h(o);if(v(s))return E($(s),"SELECT default_fallback_strength,revert_when_available FROM rotation_settings WHERE singleton=1").get()})(),r=m(o,"openai-device-id"),l=y(r)?S(r,"utf8").trim():"",d=m(o,"auth.json"),n=y(d)?Object.entries(w(d)).filter(([s])=>!(s in L)):[];await le(async s=>{if(await s.prepare("SELECT 1 FROM canvas_meta WHERE key = ?").get(A)===void 0){if(t!==null){const c=await ge(s,e),f=[],_=new Set(c.profiles.map(u=>u.profileId));for(const u of t.profiles)_.has(u.profileId)||f.push({op:"profile.insert",profile:u});for(const u of Object.keys(t.settings))c.settings[u]===void 0&&f.push({op:"settings.replace",owner:u,raw:t.settings[u],ifRevision:ve(void 0)});for(const u of Object.keys(t.state)){const H=t.state[u];c.state[u]===void 0&&(u==="user"||_.has(u.replace(/^profile:/,""))||t.profiles.some(J=>`profile:${J.profileId}`===u))&&f.push({op:"state.write",owner:u,state:H})}Object.keys(c.defaults).length===0&&Object.keys(t.defaults).length>0&&f.push({op:"defaults.replace",defaults:t.defaults}),f.length>0&&await he(s,e,f)}for(const c of a)if(await s.prepare("SELECT 1 FROM model_accounts WHERE person=? AND provider_id=? AND (id=? OR label_key=?)").get(e,c.provider,c.id,c.row.labelKey)===void 0){await _e(s,e,c.provider,c.row,c.tokens);for(const _ of c.cooldowns)await ye(s,e,c.provider,c.id,_.family,_.until,_.at)}i!==void 0&&await s.prepare("INSERT INTO model_settings(person,default_fallback_strength,revert_when_available) VALUES(?,?,?) ON CONFLICT(person) DO NOTHING").run(e,i.default_fallback_strength,i.revert_when_available),/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(l)&&await s.prepare("INSERT INTO model_settings(person,openai_device_id) VALUES(?,?) ON CONFLICT(person) DO UPDATE SET openai_device_id=COALESCE(model_settings.openai_device_id,EXCLUDED.openai_device_id)").run(e,l.toLowerCase());for(const[c,f]of n){const{sealed:_,keyId:u}=de(JSON.stringify(f),fe(),`model_api_keys|${e}|${c}`);await s.prepare("INSERT INTO model_api_keys(person,provider_id,credential_sealed,key_id,updated_at) VALUES(?,?,?,?,?) ON CONFLICT(person,provider_id) DO NOTHING").run(e,c,_,u,new Date().toISOString())}await be(s,e,t?.profiles??[]),await s.prepare("INSERT INTO canvas_meta(key,value) VALUES(?,?)").run(A,new Date().toISOString())}})}p(je,"copyPersonStoresToRows");async function ot(e){if(!await Le()){const t=Ee();Ie({kind:"user",root:t}),await je(e,we(t),U())}await Se(e)}p(ot,"adoptInstallPerson");export{ot as adoptInstallPerson,rt as convertLegacyProviderStore,Ie as convertLegacyScopedStore,je as copyPersonStoresToRows,Le as personStoresCopied};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type CanvasDb } from '../canvas/db.js';
|
|
2
|
+
import { type PersonSnapshot, type SettingsOp, type SettingsTransport } from './person-store.js';
|
|
3
|
+
export declare function readSnapshotFromRows(db: CanvasDb, person: string): Promise<PersonSnapshot>;
|
|
4
|
+
/** Load (or reload) one person's snapshot from the rows into this process. */
|
|
5
|
+
export declare function loadPersonSettings(person: string): Promise<PersonSnapshot>;
|
|
6
|
+
/** Apply ops to the rows inside the caller's transaction. Bumps `person_settings.plugins_revision` when a plugin or marketplace
|
|
7
|
+
* block changed, and signals `settings:<person>` in the same transaction so other processes holding the person reload. */
|
|
8
|
+
export declare function applyOpsToRows(db: CanvasDb, person: string, ops: readonly SettingsOp[]): Promise<void>;
|
|
9
|
+
/** The process holds the database: write the rows in one transaction, then reload the person from the committed rows. */
|
|
10
|
+
export declare const rowsTransport: SettingsTransport;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
var O=Object.defineProperty;var _=(a,n)=>O(a,"name",{value:n,configurable:!0});import{openDb as S,withCanvasWrite as N}from"../canvas/db.js";import{isCloudRole as R}from"../canvas/person-state.js";import{materializePlugins as T}from"./materialized-plugins.js";import{revisionOf as y,setPersonSnapshot as D,setSettingsReloader as v,setSettingsTransport as L,SettingsRevisionConflictError as C}from"./person-store.js";const s=_(a=>typeof a=="string"?a:void 0,"s");async function w(a,n){const o=await a.prepare("SELECT * FROM profiles WHERE person = ? AND deleting_since IS NULL ORDER BY created_at, id").all(n),f=await a.prepare("SELECT p.profile_id, p.path FROM profile_projects p JOIN profiles f ON f.id = p.profile_id WHERE f.person = ? ORDER BY p.profile_id, p.position").all(n),r=new Map;for(const e of f)(r.get(e.profile_id)??r.set(e.profile_id,[]).get(e.profile_id)).push({path:e.path});const t=o.map(e=>{const l=JSON.parse(String(e.metadata_json)),p=JSON.parse(String(e.delivery_limits_json));return{profileId:String(e.id),manifest:{schema_version:1,name:String(e.name),projects:r.get(String(e.id))??[],paused_at:s(e.paused_at)??null,...s(e.default_kind)===void 0?{}:{default_kind:s(e.default_kind)},...s(e.grantee)===void 0?{}:{grantee:s(e.grantee)},...s(e.environment_id)===void 0?{}:{environment_id:s(e.environment_id)},...Object.keys(p).length===0?{}:{delivery_limits:p},...Object.keys(l).length===0?{}:{metadata:l},created_at:String(e.created_at),last_used_at:s(e.last_used_at)??null}}}),i=Object.fromEntries((await a.prepare("SELECT directory, profile_id FROM profile_defaults WHERE person = ?").all(n)).map(e=>[e.directory,e.profile_id])),u={};for(const e of await a.prepare("SELECT owner_key, raw_json FROM scope_settings WHERE person = ?").all(n))u[e.owner_key]=JSON.parse(e.raw_json);const m={},E=_(e=>m[e]??={marketplaces:{},plugins:{},activeCanvas:null},"stateOf");for(const e of await a.prepare("SELECT owner_key, last_self_check, active_canvas FROM scope_bookkeeping WHERE person = ?").all(n)){const l=E(e.owner_key);e.last_self_check!==null&&(l.last_self_check=e.last_self_check),l.activeCanvas=e.active_canvas}for(const e of await a.prepare("SELECT * FROM scope_marketplaces WHERE person = ? ORDER BY owner_key, name").all(n)){const l=String(e.owner_key),p=String(e.name);if(E(l).marketplaces[p]=s(e.last_updated)===void 0?{}:{last_updated:s(e.last_updated)},s(e.url)!==void 0){const d=u[l]??={},c=d.marketplaces??={};c[p]={url:s(e.url),ref:s(e.ref)??"",installed_at:s(e.installed_at)??""}}}for(const e of await a.prepare("SELECT * FROM scope_plugins WHERE person = ? ORDER BY owner_key, name").all(n)){const l=String(e.owner_key),p=String(e.name);E(l).plugins[p]={...s(e.last_updated)===void 0?{}:{last_updated:s(e.last_updated)},...s(e.etag)===void 0?{}:{etag:s(e.etag)},...s(e.checked_at)===void 0?{}:{checked_at:s(e.checked_at)}};const d=u[l]??={},c=d.plugins??={};c[p]={enabled:Number(e.enabled)===1,...s(e.source_marketplace)===void 0?{}:{source_marketplace:s(e.source_marketplace)},...s(e.version)===void 0?{}:{version:s(e.version)}}}return{profiles:t,defaults:i,settings:u,state:m}}_(w,"readSnapshotFromRows");async function g(a){const n=await S(),o=await w(n,a);return R()&&await I(n,a),D(a,o),o}_(g,"loadPersonSettings");async function I(a,n){const o=await a.prepare(`SELECT p.name, p.version, p.source_path, p.source_marketplace, m.url, m.ref FROM scope_plugins p
|
|
2
|
+
LEFT JOIN scope_marketplaces m ON m.person = p.person AND m.owner_key = p.owner_key AND m.name = p.source_marketplace
|
|
3
|
+
WHERE p.person = ? AND p.owner_key = 'user' AND p.enabled = 1 ORDER BY p.name`).all(n),f=await a.prepare("SELECT plugins_revision FROM person_settings WHERE person = ?").get(n),r=o.map(t=>({name:String(t.name),version:s(t.version)??null,sourcePath:s(t.source_path)??null,marketplace:s(t.source_marketplace)===void 0?null:{name:s(t.source_marketplace),url:s(t.url)??null,ref:s(t.ref)??null}}));await T(n,f===void 0?0:Number(f.plugins_revision),r)}_(I,"materializePersonPlugins");async function h(a,n,o){return(await w(a,n)).settings[o]}_(h,"currentRaw");async function j(a,n,o){let f=!1;for(const r of o)if(r.op==="settings.replace"){const t=await h(a,n,r.owner);if(r.ifRevision!==y(t))throw new C;const{plugins:i,marketplaces:u,...m}=r.raw,E=JSON.stringify(m);await a.prepare("INSERT INTO scope_settings (person, owner_key, raw_json) VALUES (?, ?, ?) ON CONFLICT (person, owner_key) DO UPDATE SET raw_json = EXCLUDED.raw_json").run(n,r.owner,E);const e=i??{},l=u??{},p=JSON.stringify([t?.plugins,t?.marketplaces]);p!==JSON.stringify([i,u])&&!(p==="[null,null]"&&i===void 0&&u===void 0)&&(f=!0),await a.prepare("DELETE FROM scope_plugins WHERE person = ? AND owner_key = ? AND NOT (name IN (SELECT jsonb_array_elements_text(?::jsonb)))").run(n,r.owner,JSON.stringify(Object.keys(e)));for(const[d,c]of Object.entries(e))await a.prepare(`INSERT INTO scope_plugins (person, owner_key, name, enabled, source_marketplace, version) VALUES (?, ?, ?, ?, ?, ?)
|
|
4
|
+
ON CONFLICT (person, owner_key, name) DO UPDATE SET enabled = EXCLUDED.enabled, source_marketplace = EXCLUDED.source_marketplace, version = EXCLUDED.version`).run(n,r.owner,d,c.enabled===!1?0:1,c.source_marketplace??null,c.version??null);await a.prepare("DELETE FROM scope_marketplaces WHERE person = ? AND owner_key = ? AND NOT (name IN (SELECT jsonb_array_elements_text(?::jsonb)))").run(n,r.owner,JSON.stringify(Object.keys(l)));for(const[d,c]of Object.entries(l))await a.prepare(`INSERT INTO scope_marketplaces (person, owner_key, name, url, ref, installed_at) VALUES (?, ?, ?, ?, ?, ?)
|
|
5
|
+
ON CONFLICT (person, owner_key, name) DO UPDATE SET url = EXCLUDED.url, ref = EXCLUDED.ref, installed_at = EXCLUDED.installed_at`).run(n,r.owner,d,c.url??null,c.ref??null,c.installed_at??null)}else if(r.op==="state.write"){await a.prepare(`INSERT INTO scope_bookkeeping (person, owner_key, last_self_check, active_canvas) VALUES (?, ?, ?, ?)
|
|
6
|
+
ON CONFLICT (person, owner_key) DO UPDATE SET last_self_check = EXCLUDED.last_self_check, active_canvas = EXCLUDED.active_canvas`).run(n,r.owner,r.state.last_self_check??null,r.state.activeCanvas??null);for(const[t,i]of Object.entries(r.state.marketplaces))await a.prepare("UPDATE scope_marketplaces SET last_updated = ? WHERE person = ? AND owner_key = ? AND name = ?").run(i.last_updated??null,n,r.owner,t);for(const[t,i]of Object.entries(r.state.plugins))await a.prepare("UPDATE scope_plugins SET last_updated = ?, etag = ?, checked_at = ? WHERE person = ? AND owner_key = ? AND name = ?").run(i.last_updated??null,i.etag??null,i.checked_at??null,n,r.owner,t)}else if(r.op==="profile.insert"){const t=r.profile.manifest;await a.prepare("INSERT INTO profiles (id, person, name, created_at, last_used_at, paused_at, default_kind, grantee, metadata_json, delivery_limits_json, environment_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(r.profile.profileId,n,t.name,t.created_at,t.last_used_at,t.paused_at,t.default_kind??null,t.grantee??null,JSON.stringify(t.metadata??{}),JSON.stringify(t.delivery_limits??{}),t.environment_id??null),await k(a,r.profile)}else if(r.op==="profile.update"){const t=r.profile.manifest;if((await a.prepare("UPDATE profiles SET name = ?, last_used_at = ?, paused_at = ?, default_kind = ?, grantee = ?, metadata_json = ?, delivery_limits_json = ?, environment_id = ? WHERE id = ? AND person = ?").run(t.name,t.last_used_at,t.paused_at,t.default_kind??null,t.grantee??null,JSON.stringify(t.metadata??{}),JSON.stringify(t.delivery_limits??{}),t.environment_id??null,r.profile.profileId,n)).changes!==1)throw new Error(`no stored profile ${r.profile.profileId}`);await k(a,r.profile)}else if(r.op==="profile.delete"){const t=`profile:${r.profileId}`;for(const i of["scope_settings","scope_bookkeeping","scope_marketplaces","scope_plugins"])await a.prepare(`DELETE FROM ${i} WHERE person = ? AND owner_key = ?`).run(n,t);await a.prepare("DELETE FROM profiles WHERE id = ? AND person = ?").run(r.profileId,n)}else{await a.prepare("DELETE FROM profile_defaults WHERE person = ?").run(n);for(const[t,i]of Object.entries(r.defaults))await a.prepare("INSERT INTO profile_defaults (person, directory, profile_id) VALUES (?, ?, ?)").run(n,t,i)}f&&await a.prepare("INSERT INTO person_settings (person, plugins_revision) VALUES (?, 1) ON CONFLICT (person) DO UPDATE SET plugins_revision = person_settings.plugins_revision + 1").run(n),await a.prepare("SELECT pg_notify('crtr_signal', ?)").get(`settings:${n}`)}_(j,"applyOpsToRows");async function k(a,n){await a.prepare("DELETE FROM profile_projects WHERE profile_id = ?").run(n.profileId);let o=0;for(const f of n.manifest.projects)await a.prepare("INSERT INTO profile_projects (profile_id, path, position) VALUES (?, ?, ?)").run(n.profileId,f.path,o++)}_(k,"replaceProjects");const A=_(async(a,n)=>(await N(o=>j(o,a,n)),await g(a)),"rowsTransport");L(A),v(g);export{j as applyOpsToRows,g as loadPersonSettings,w as readSnapshotFromRows,A as rowsTransport};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { ProfileManifest, ScopeState } from '../../types.js';
|
|
2
|
+
export type StoredProfile = {
|
|
3
|
+
profileId: string;
|
|
4
|
+
manifest: ProfileManifest;
|
|
5
|
+
};
|
|
6
|
+
/** Everything one person's rows hold, in the shape the synchronous readers want. `settings` is keyed by owner (`user`,
|
|
7
|
+
* `profile:<id>`) and carries the rebuilt `plugins` and `marketplaces` blocks; `state` carries the bookkeeping. */
|
|
8
|
+
export interface PersonSnapshot {
|
|
9
|
+
profiles: StoredProfile[];
|
|
10
|
+
defaults: Record<string, string>;
|
|
11
|
+
settings: Record<string, Record<string, unknown>>;
|
|
12
|
+
state: Record<string, ScopeState>;
|
|
13
|
+
}
|
|
14
|
+
export type SettingsOp = {
|
|
15
|
+
op: 'settings.replace';
|
|
16
|
+
owner: string;
|
|
17
|
+
raw: Record<string, unknown>;
|
|
18
|
+
ifRevision: string;
|
|
19
|
+
} | {
|
|
20
|
+
op: 'state.write';
|
|
21
|
+
owner: string;
|
|
22
|
+
state: ScopeState;
|
|
23
|
+
} | {
|
|
24
|
+
op: 'profile.insert';
|
|
25
|
+
profile: StoredProfile;
|
|
26
|
+
} | {
|
|
27
|
+
op: 'profile.update';
|
|
28
|
+
profile: StoredProfile;
|
|
29
|
+
} | {
|
|
30
|
+
op: 'profile.delete';
|
|
31
|
+
profileId: string;
|
|
32
|
+
} | {
|
|
33
|
+
op: 'defaults.replace';
|
|
34
|
+
defaults: Record<string, string>;
|
|
35
|
+
};
|
|
36
|
+
export declare class SettingsRevisionConflictError extends Error {
|
|
37
|
+
constructor();
|
|
38
|
+
}
|
|
39
|
+
export declare class PersonSettingsNotLoadedError extends Error {
|
|
40
|
+
constructor(person: string);
|
|
41
|
+
}
|
|
42
|
+
declare const BLOCKS: readonly ["plugins", "marketplaces"];
|
|
43
|
+
export declare function revisionOf(raw: Record<string, unknown> | undefined): string;
|
|
44
|
+
export declare function installPersonSnapshot(person: string, snapshot: PersonSnapshot): void;
|
|
45
|
+
export declare function heldPersons(): string[];
|
|
46
|
+
export declare function dropPersonSnapshots(): void;
|
|
47
|
+
/** Before the install's person is resolved (a Mac's first boot reads its config to resolve it), reads answer from this snapshot of
|
|
48
|
+
* the old local store; `loadPersonSettings` replaces it once the person is known. */
|
|
49
|
+
export declare function installPreludeSnapshot(snapshot: PersonSnapshot | undefined): void;
|
|
50
|
+
/** The current person's snapshot. A miss is an error: a person whose rows exist never reads as defaults. A cloud role outside a
|
|
51
|
+
* request has no person and no install settings: it reads defaults. */
|
|
52
|
+
export declare function currentSnapshot(): PersonSnapshot;
|
|
53
|
+
export declare function personHasSnapshot(): boolean;
|
|
54
|
+
export type SettingsTransport = (person: string, ops: SettingsOp[]) => Promise<PersonSnapshot>;
|
|
55
|
+
export declare function setSettingsTransport(next: SettingsTransport): void;
|
|
56
|
+
/** Compute ops from the cached snapshot and send them; on a revision conflict reload (the transport returned or the rows hold a newer
|
|
57
|
+
* snapshot) and compute again, up to three times. A failed write throws and leaves the cache as it was. */
|
|
58
|
+
export declare function writeSettings(compute: (snapshot: PersonSnapshot) => SettingsOp[]): Promise<PersonSnapshot>;
|
|
59
|
+
export declare function setPersonSnapshot(person: string, snapshot: PersonSnapshot): void;
|
|
60
|
+
export declare function setSettingsReloader(next: (person: string) => Promise<PersonSnapshot>): void;
|
|
61
|
+
export declare function ownerKeyOf(profileId?: string): string;
|
|
62
|
+
export declare function readCachedSettings(owner: string): {
|
|
63
|
+
settings: Record<string, unknown> | null;
|
|
64
|
+
revision: string;
|
|
65
|
+
};
|
|
66
|
+
export declare function readCachedState(owner: string): ScopeState;
|
|
67
|
+
export { BLOCKS as SETTINGS_ROW_BLOCKS };
|
|
68
|
+
export declare function listCachedProfiles(): StoredProfile[];
|
|
69
|
+
export declare function getCachedProfile(profileId: string): StoredProfile | null;
|
|
70
|
+
export declare function cachedProfilePaused(profileId: string): boolean;
|
|
71
|
+
export declare function cachedPausedProfileIds(): Set<string>;
|
|
72
|
+
export declare function cachedDefaults(): Record<string, string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var l=Object.defineProperty;var n=(e,t)=>l(e,"name",{value:t,configurable:!0});import{createHash as h}from"node:crypto";import{PersonOutsideRequestError as x,PersonUnresolvedError as g,personId as u}from"../canvas/person-state.js";class S extends Error{static{n(this,"SettingsRevisionConflictError")}constructor(){super("settings changed since the supplied revision"),this.name="SettingsRevisionConflictError"}}class w extends Error{static{n(this,"PersonSettingsNotLoadedError")}constructor(t){super(`settings for ${t} are not loaded in this process`),this.name="PersonSettingsNotLoadedError"}}const P=["plugins","marketplaces"],s=new Map;function m(e){return e===void 0?"absent":h("sha256").update(JSON.stringify(e)).digest("hex")}n(m,"revisionOf");function O(e,t){s.set(e,t)}n(O,"installPersonSnapshot");function I(){return[...s.keys()]}n(I,"heldPersons");function R(){s.clear()}n(R,"dropPersonSnapshots");const f=n(()=>({profiles:[],defaults:{},settings:{},state:{}}),"emptySnapshot");let a;function L(e){a=e}n(L,"installPreludeSnapshot");function r(){let e;try{e=u()}catch(o){if(o instanceof x)return f();if(o instanceof g)return a??f();throw o}const t=s.get(e);if(t!==void 0)return t;if(a!==void 0)return a;throw new w(e)}n(r,"currentSnapshot");function N(){try{return s.has(u())}catch{return!1}}n(N,"personHasSnapshot");let d=n(async()=>{throw new Error("no settings transport installed in this process")},"transport");function T(e){d=e}n(T,"setSettingsTransport");async function _(e){const t=u();for(let o=0;;o++){const c=e(r());if(c.length===0)return r();try{const i=await d(t,c);return s.set(t,i),i}catch(i){if(!(i instanceof S)||o>=2)throw i;await C(t)}}}n(_,"writeSettings");function k(e,t){s.set(e,t),a=void 0}n(k,"setPersonSnapshot");let p;function K(e){p=e}n(K,"setSettingsReloader");async function C(e){s.set(e,await(p??(async()=>{throw new Error("no settings reloader installed in this process")}))(e))}n(C,"reloadViaTransport");function B(e){return e===void 0?"user":`profile:${e}`}n(B,"ownerKeyOf");function H(e){const t=r().settings[e];return{settings:t===void 0?null:structuredClone(t),revision:m(t)}}n(H,"readCachedSettings");function $(e){const t=r().state[e];return t===void 0?{marketplaces:{},plugins:{},activeCanvas:null}:structuredClone(t)}n($,"readCachedState");function b(){return structuredClone(r().profiles)}n(b,"listCachedProfiles");function q(e){const t=r().profiles.find(o=>o.profileId===e);return t===void 0?null:structuredClone(t)}n(q,"getCachedProfile");function D(e){return r().profiles.find(t=>t.profileId===e)?.manifest.paused_at!=null}n(D,"cachedProfilePaused");function G(){return new Set(r().profiles.filter(e=>e.manifest.paused_at!==null).map(e=>e.profileId))}n(G,"cachedPausedProfileIds");function J(){return{...r().defaults}}n(J,"cachedDefaults");export{w as PersonSettingsNotLoadedError,P as SETTINGS_ROW_BLOCKS,S as SettingsRevisionConflictError,J as cachedDefaults,G as cachedPausedProfileIds,D as cachedProfilePaused,r as currentSnapshot,R as dropPersonSnapshots,q as getCachedProfile,I as heldPersons,O as installPersonSnapshot,L as installPreludeSnapshot,b as listCachedProfiles,B as ownerKeyOf,N as personHasSnapshot,H as readCachedSettings,$ as readCachedState,m as revisionOf,k as setPersonSnapshot,K as setSettingsReloader,T as setSettingsTransport,_ as writeSettings};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { BlaxelLaunchContext } from '../runtime/runner/blaxel/runner.js';
|
|
2
|
+
import type { RunnerStartInput } from '../runtime/runner/types.js';
|
|
3
|
+
export declare const BASE_IMAGE = "blaxel/base-image:latest";
|
|
4
|
+
/** How long the signed release URL stays valid. */
|
|
5
|
+
export declare const RELEASE_URL_TTL_S: number;
|
|
6
|
+
export interface ReleaseSigner {
|
|
7
|
+
bucket: string;
|
|
8
|
+
endpoint: string;
|
|
9
|
+
accessKeyId: string;
|
|
10
|
+
secretAccessKey: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function releaseSignerFromEnv(env?: NodeJS.ProcessEnv): ReleaseSigner;
|
|
13
|
+
/** A SigV4 query-signed GET (path style, region `auto`) of `key`, valid `ttlS` seconds from `now`. */
|
|
14
|
+
export declare function presignGet(signer: ReleaseSigner, key: string, ttlS: number, now?: Date): string;
|
|
15
|
+
export interface BlaxelLaunchDeps {
|
|
16
|
+
apiUrl: string;
|
|
17
|
+
signer: ReleaseSigner;
|
|
18
|
+
/** The sha256 text of `releases/<version>/runtime.tar.gz.sha256`; default: the blob store. */
|
|
19
|
+
releaseSha?: (version: string) => Promise<string | null>;
|
|
20
|
+
now?: () => Date;
|
|
21
|
+
}
|
|
22
|
+
/** Reads the control plane's settings from the environment: `CRTR_PUBLIC_API_URL` (where a sandbox reaches `/v1`) and the four `CRTR_R2_*` variables. */
|
|
23
|
+
export declare function blaxelLaunchDepsFromEnv(env?: NodeJS.ProcessEnv): BlaxelLaunchDeps;
|
|
24
|
+
export declare function createBlaxelLaunchContext(deps: BlaxelLaunchDeps): (input: RunnerStartInput) => Promise<BlaxelLaunchContext>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
var S=Object.defineProperty;var t=(r,e)=>S(r,"name",{value:e,configurable:!0});import{createHash as A,createHmac as E}from"node:crypto";import{openDb as C}from"../canvas/db.js";import{blobStore as $}from"../blobs/index.js";import{environmentOfNode as I}from"../../daemon/api/environment-of.js";import{EnvironmentImagePending as b}from"../../daemon/reconcilers/node-lifecycle/remote-wake.js";import{resolveEnvironmentImage as L}from"../../daemon/reconcilers/recipe-image.js";import{environmentSecrets as U}from"./environment-secrets.js";import{environmentOwnerProfile as x,profileInApp as y}from"./environment-owner.js";const T="blaxel/base-image:latest",v=900;function z(r=process.env){const e=t(o=>{const n=r[o];if(!n)throw new Error(`${o} is required to sign release URLs`);return n},"need");return{bucket:e("CRTR_R2_BUCKET"),endpoint:e("CRTR_R2_ENDPOINT"),accessKeyId:e("CRTR_R2_ACCESS_KEY_ID"),secretAccessKey:e("CRTR_R2_SECRET_ACCESS_KEY")}}t(z,"releaseSignerFromEnv");const D=t(r=>A("sha256").update(r).digest("hex"),"sha256hex"),f=t((r,e)=>E("sha256",r).update(e).digest(),"hmac"),h=t(r=>encodeURIComponent(r).replace(/[!'()*]/g,e=>`%${e.charCodeAt(0).toString(16).toUpperCase()}`),"encode");function H(r,e,o,n=new Date){const c=new URL(r.endpoint),i=n.toISOString().replace(/[:-]|\.\d{3}/g,""),s=i.slice(0,8),a=`${s}/auto/s3/aws4_request`,p=`/${h(r.bucket)}/${e.split("/").map(h).join("/")}`,m=[["X-Amz-Algorithm","AWS4-HMAC-SHA256"],["X-Amz-Credential",`${r.accessKeyId}/${a}`],["X-Amz-Date",i],["X-Amz-Expires",String(o)],["X-Amz-SignedHeaders","host"]].sort(([u],[w])=>u<w?-1:1).map(([u,w])=>`${h(u)}=${h(w)}`).join("&"),d=["GET",p,m,`host:${c.host}
|
|
2
|
+
`,"host","UNSIGNED-PAYLOAD"].join(`
|
|
3
|
+
`),g=["AWS4-HMAC-SHA256",i,a,D(d)].join(`
|
|
4
|
+
`),_=f(f(f(f(`AWS4${r.secretAccessKey}`,s),"auto"),"s3"),"aws4_request"),R=E("sha256",_).update(g).digest("hex");return`${c.origin}${p}?${m}&X-Amz-Signature=${R}`}t(H,"presignGet");function F(r=process.env){const e=r.CRTR_PUBLIC_API_URL;if(!e||!/^https?:\/\//.test(e))throw new Error("CRTR_PUBLIC_API_URL must be an http(s) URL for the Blaxel runner");return{apiUrl:e,signer:z(r)}}t(F,"blaxelLaunchDepsFromEnv");async function P(r){const e=await(await $()).get(`releases/${r}/runtime.tar.gz.sha256`);return e===null?null:e.toString("utf8")}t(P,"defaultReleaseSha");function G(r){return async e=>{const o=await C(),n=await o.prepare("SELECT profile_id, grantee FROM node_rows WHERE node_id = ?").get(e.nodeId);if(n===void 0)throw new Error(`no node ${e.nodeId}`);if(n.profile_id===null)throw new Error(`node ${e.nodeId} has no profile, so it has no person`);const c=await o.prepare("SELECT person FROM profiles WHERE id = ?").get(n.profile_id);if(c===void 0)throw new Error(`profile ${n.profile_id} has no row`);const i=n.grantee??"app:terminal",s=await I(n.profile_id),a=await L(s);if(a.state==="pending")throw new b(s,a.error);const p=await o.prepare("SELECT memory_mb FROM environments WHERE object = ?").get(s);if(p===void 0)throw new Error(`no environment ${s}`);const l=await x(s),m=l!==null&&await y(l,i),d=(await(r.releaseSha??P)(e.release)??"").trim().split(/\s+/)[0]??"";if(!/^[0-9a-f]{64}$/.test(d))throw new Error(`release ${e.release} has no sha256 object (releases/${e.release}/runtime.tar.gz.sha256)`);return{image:a.state==="image"?a.ref:T,memoryMb:Number(p.memory_mb),apiUrl:r.apiUrl,releaseUrl:H(r.signer,`releases/${e.release}/runtime.tar.gz`,v,r.now?.()),releaseSha256:d,secrets:await U({person:c.person,app:i,ownerProfile:l,ownerProfileInApp:m,includeDeployment:!1})}}}t(G,"createBlaxelLaunchContext");export{T as BASE_IMAGE,v as RELEASE_URL_TTL_S,F as blaxelLaunchDepsFromEnv,G as createBlaxelLaunchContext,H as presignGet,z as releaseSignerFromEnv};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var t=Object.defineProperty;var o=(r,e)=>t(r,"name",{value:e,configurable:!0});import{readFileSync as n}from"node:fs";import{join as l}from"node:path";import{emitEvent as a}from"../events/emit.js";import{assetRoot as i}from"../asset-root.js";import{createBlaxelClient as m,blaxelConfigFromEnv as s}from"../runtime/runner/blaxel/client.js";import{registerBlaxelRunner as p}from"../runtime/runner/index.js";import{createBlaxelRunner as f}from"../runtime/runner/blaxel/runner.js";import{blaxelLaunchDepsFromEnv as u,createBlaxelLaunchContext as c}from"./blaxel-launch.js";function C(r=process.env){if(!r.BLAXEL_API_KEY)return!1;const e=n(l(i(),"..","scripts","sandbox-bootstrap.sh"),"utf8");return p(f({client:m(s(r)),launchContext:c(u(r)),bootstrap:o(()=>e,"bootstrap")})),a({level:"info",event:"daemon.blaxel_runner.registered",fields:{workspace:r.BLAXEL_WORKSPACE??null,region:r.BLAXEL_REGION??null}}),!0}o(C,"registerBlaxelRunnerFromEnv");export{C as registerBlaxelRunnerFromEnv};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type CanvasDb } from '../canvas/db.js';
|
|
2
|
+
import { type SecretsKey } from './index.js';
|
|
3
|
+
export type EnvOwnerKind = 'profile' | 'app' | 'deployment';
|
|
4
|
+
export interface EnvOwner {
|
|
5
|
+
person: string | null;
|
|
6
|
+
kind: EnvOwnerKind;
|
|
7
|
+
id: string;
|
|
8
|
+
}
|
|
9
|
+
/** Insert or replace one value. Returns true when the name was new. */
|
|
10
|
+
export declare function putEnvRow(owner: EnvOwner, name: string, value: string, key?: SecretsKey): Promise<boolean>;
|
|
11
|
+
/** Seal one value into an open transaction, keeping a row that already holds the name. Used by the one-time boot copy. */
|
|
12
|
+
export declare function putEnvRowIfAbsent(db: CanvasDb, owner: EnvOwner, name: string, value: string, key?: SecretsKey): Promise<void>;
|
|
13
|
+
export declare function removeEnvRow(owner: EnvOwner, name: string): Promise<boolean>;
|
|
14
|
+
/** Names only: no value is opened. */
|
|
15
|
+
export declare function listEnvRowNames(owner: EnvOwner): Promise<string[]>;
|
|
16
|
+
/** Every value of one owner, opened. Throws `SecretsError` when any row fails to open: a wrong key never yields an empty or partial map. */
|
|
17
|
+
export declare function readEnvRows(owner: EnvOwner, key?: SecretsKey): Promise<Record<string, string>>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
var u=Object.defineProperty;var t=(e,n)=>u(e,"name",{value:n,configurable:!0});import{openDb as o}from"../canvas/db.js";import{loadSecretsKey as i,open as l,seal as c}from"./index.js";const E=t((e,n)=>`env_vars|${e.person??""}|${e.kind}|${e.id}|${n}`,"aadOf"),p=t(e=>e.person??"","personKey");async function D(e,n,a,d=i()){const{sealed:r,keyId:s}=c(a,d,E(e,n));return(await(await o()).prepare(`INSERT INTO env_vars (person, owner_kind, owner_id, name, value_sealed, key_id, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
2
|
+
ON CONFLICT (COALESCE(person, ''), owner_kind, owner_id, name) DO UPDATE SET value_sealed = EXCLUDED.value_sealed, key_id = EXCLUDED.key_id, updated_at = EXCLUDED.updated_at
|
|
3
|
+
RETURNING (xmax = 0) AS created`).get(e.person,e.kind,e.id,n,r,s,new Date().toISOString())).created}t(D,"putEnvRow");async function N(e,n,a,d,r=i()){const{sealed:s,keyId:_}=c(d,r,E(n,a));await e.prepare(`INSERT INTO env_vars (person, owner_kind, owner_id, name, value_sealed, key_id, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
4
|
+
ON CONFLICT (COALESCE(person, ''), owner_kind, owner_id, name) DO NOTHING`).run(n.person,n.kind,n.id,a,s,_,new Date().toISOString())}t(N,"putEnvRowIfAbsent");async function C(e,n){return(await(await o()).prepare("DELETE FROM env_vars WHERE COALESCE(person, '') = ? AND owner_kind = ? AND owner_id = ? AND name = ?").run(p(e),e.kind,e.id,n)).changes>0}t(C,"removeEnvRow");async function S(e){return(await(await o()).prepare("SELECT name FROM env_vars WHERE COALESCE(person, '') = ? AND owner_kind = ? AND owner_id = ? ORDER BY name").all(p(e),e.kind,e.id)).map(a=>a.name)}t(S,"listEnvRowNames");async function m(e,n=i()){const a=await(await o()).prepare("SELECT name, value_sealed, key_id FROM env_vars WHERE COALESCE(person, '') = ? AND owner_kind = ? AND owner_id = ?").all(p(e),e.kind,e.id),d=Object.create(null);for(const r of a)d[r.name]=l(r.value_sealed,r.key_id,n,E(e,r.name));return d}t(m,"readEnvRows");export{S as listEnvRowNames,D as putEnvRow,N as putEnvRowIfAbsent,m as readEnvRows,C as removeEnvRow};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** The profile that owns `environmentId` (an environment object whose owner carries a `profile` identity), or null when an app owns it. */
|
|
2
|
+
export declare function environmentOwnerProfile(environmentId: string): Promise<string | null>;
|
|
3
|
+
/** Whether profile `profileId` belongs to `app`; a profile of another app adds no secrets. */
|
|
4
|
+
export declare function profileInApp(profileId: string, app: string): Promise<boolean>;
|
|
5
|
+
/** The secrets a local process, bash command or cron of `app` under `profileId` receives: the app's rows, then the rows of the profile that owns the
|
|
6
|
+
* profile's environment (a profile pointing at another profile's environment gets that profile's, not its own), plus the deployment rows.
|
|
7
|
+
* A profile on the machine environment (owned by the app, not a profile) is its own owner. */
|
|
8
|
+
export declare function localEnvironmentSecrets(profileId: string | null, app: string): Promise<Record<string, string>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var p=Object.defineProperty;var t=(e,n)=>p(e,"name",{value:n,configurable:!0});import{openDb as o}from"../canvas/db.js";import{personIdAsync as l}from"../canvas/person.js";import{environmentSecrets as c}from"./environment-secrets.js";async function m(e){return(await(await o()).prepare("SELECT i.external_id AS profile FROM objects o JOIN identities i ON i.object = o.owner AND i.scheme = 'profile' WHERE o.id = ?").get(e))?.profile??null}t(m,"environmentOwnerProfile");async function s(e,n){return((await(await o()).prepare("SELECT grantee FROM profiles WHERE id = ?").get(e))?.grantee??"app:terminal")===n}t(s,"profileInApp");async function v(e,n){let a=await l(),i=null;if(e!==null&&e!==""){const r=await(await o()).prepare("SELECT person, environment_id FROM profiles WHERE id = ?").get(e);r!==void 0&&(a=r.person),i=r?.environment_id==null||(await(await o()).prepare("SELECT kind FROM environments WHERE object = ?").get(r.environment_id))?.kind==="machine"?e:await m(r.environment_id)}return c({person:a,app:n,ownerProfile:i,ownerProfileInApp:i!==null&&await s(i,n),includeDeployment:!0})}t(v,"localEnvironmentSecrets");export{m as environmentOwnerProfile,v as localEnvironmentSecrets,s as profileInApp};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SecretsKey } from './index.js';
|
|
2
|
+
/** `owner_id` of every deployment row. */
|
|
3
|
+
export declare const DEPLOYMENT_ID = "_deployment";
|
|
4
|
+
export interface EnvironmentSecretsInput {
|
|
5
|
+
person: string;
|
|
6
|
+
app: string;
|
|
7
|
+
/** The environment's owning profile, or null when the owner is the app. */
|
|
8
|
+
ownerProfile: string | null;
|
|
9
|
+
/** Whether that profile's grantee is `app`; a profile of another app adds nothing. */
|
|
10
|
+
ownerProfileInApp: boolean;
|
|
11
|
+
includeDeployment: boolean;
|
|
12
|
+
key?: SecretsKey;
|
|
13
|
+
}
|
|
14
|
+
export declare function environmentSecrets(input: EnvironmentSecretsInput): Promise<Record<string, string>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var p=Object.defineProperty;var i=(e,n)=>p(e,"name",{value:n,configurable:!0});import{readEnvRows as r}from"./env-rows.js";const t="_deployment";async function s(e){const{person:n,app:l,key:o}=e;return{...await r({person:n,kind:"app",id:l},o),...e.includeDeployment?await r({person:null,kind:"deployment",id:t},o):{},...e.ownerProfile!==null&&e.ownerProfileInApp?await r({person:n,kind:"profile",id:e.ownerProfile},o):{}}}i(s,"environmentSecrets");export{t as DEPLOYMENT_ID,s as environmentSecrets};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{SecretsError as o,keyIdOf as s,open as t,parseSecretsKey as c,seal as p}from"./seal.js";import{loadSecretsKey as a,secretsKeyFile as f}from"./key.js";export{o as SecretsError,s as keyIdOf,a as loadSecretsKey,t as open,c as parseSecretsKey,p as seal,f as secretsKeyFile};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var i=Object.defineProperty;var s=(r,e)=>i(r,"name",{value:e,configurable:!0});import{chmodSync as f,existsSync as m,readFileSync as p,writeFileSync as y}from"node:fs";import{randomBytes as u}from"node:crypto";import{join as t}from"node:path";import{secretsDir as l}from"../layout.js";import{ensureDir as S}from"../fs-utils.js";import{parseSecretsKey as c,SecretsError as a}from"./seal.js";const n="CRTR_SECRETS_KEY",d=s(()=>t(l(),"secrets.key"),"secretsKeyFile"),E=s(()=>(process.env.CRTR_DATABASE_URL??"")!=="","isCloudProcess");let o;function x(){const r=process.env[n];if(r!==void 0&&r!=="")return o?.source!==`env:${r}`&&(o={source:`env:${r}`,key:c(r)}),o.key;if(E())throw new a("secrets_key_missing",`${n} is not set; a cloud process cannot seal or open secrets without it`);const e=d();return o?.source!==`file:${e}`&&(m(e)||(S(t(e,"..")),y(e,`${u(32).toString("hex")}
|
|
2
|
+
`,{mode:384,flag:"wx"})),f(e,384),o={source:`file:${e}`,key:c(p(e,"utf8"))}),o.key}s(x,"loadSecretsKey");export{x as loadSecretsKey,d as secretsKeyFile};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare class SecretsError extends Error {
|
|
2
|
+
readonly code: 'secrets_key_missing' | 'secrets_key_invalid' | 'secrets_open_failed';
|
|
3
|
+
constructor(code: SecretsError['code'], message: string);
|
|
4
|
+
}
|
|
5
|
+
export interface SecretsKey {
|
|
6
|
+
id: string;
|
|
7
|
+
key: Buffer;
|
|
8
|
+
}
|
|
9
|
+
export interface Sealed {
|
|
10
|
+
sealed: Buffer;
|
|
11
|
+
keyId: string;
|
|
12
|
+
}
|
|
13
|
+
/** The id a key is known by in `key_id` columns: a prefix of its SHA-256, never reversible to the key. */
|
|
14
|
+
export declare function keyIdOf(key: Buffer): string;
|
|
15
|
+
/** Parse a 32-byte key written as 64 hex characters or as base64. */
|
|
16
|
+
export declare function parseSecretsKey(text: string): SecretsKey;
|
|
17
|
+
export declare function seal(plaintext: string, key: SecretsKey, aad: string): Sealed;
|
|
18
|
+
export declare function open(sealed: Buffer | Uint8Array, keyId: string, key: SecretsKey, aad: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var u=Object.defineProperty;var a=(r,e)=>u(r,"name",{value:e,configurable:!0});import{createCipheriv as d,createDecipheriv as h,createHash as l,randomBytes as p}from"node:crypto";const n=12,i=16;class f extends Error{static{a(this,"SecretsError")}code;constructor(e,t){super(t),this.name="SecretsError",this.code=e}}function y(r){return l("sha256").update(r).digest("hex").slice(0,16)}a(y,"keyIdOf");function B(r){const e=r.trim(),t=/^[0-9a-fA-F]{64}$/.test(e)?Buffer.from(e,"hex"):Buffer.from(e,"base64");if(t.length!==32)throw new f("secrets_key_invalid","the secrets key must be 32 bytes (64 hex characters or base64)");return{id:y(t),key:t}}a(B,"parseSecretsKey");function b(r,e,t){const c=p(n),s=d("aes-256-gcm",e.key,c);s.setAAD(Buffer.from(t,"utf8"));const o=Buffer.concat([s.update(r,"utf8"),s.final()]);return{sealed:Buffer.concat([c,s.getAuthTag(),o]),keyId:e.id}}a(b,"seal");function g(r,e,t,c){if(e!==t.id)throw new f("secrets_open_failed",`sealed value was written under key ${e}, this process holds key ${t.id}`);const s=Buffer.from(r);if(s.length<n+i)throw new f("secrets_open_failed","sealed value is truncated");try{const o=h("aes-256-gcm",t.key,s.subarray(0,n));return o.setAAD(Buffer.from(c,"utf8")),o.setAuthTag(s.subarray(n,n+i)),Buffer.concat([o.update(s.subarray(n+i)),o.final()]).toString("utf8")}catch{throw new f("secrets_open_failed","sealed value failed authentication (wrong key, altered bytes or another row)")}}a(g,"open");export{f as SecretsError,y as keyIdOf,g as open,B as parseSecretsKey,b as seal};
|
|
@@ -16,7 +16,7 @@ export interface LaunchNode {
|
|
|
16
16
|
folder?: string;
|
|
17
17
|
cwd?: string;
|
|
18
18
|
/** A cron execution (launch id `cron-<execution_id>`): its only daemon path is `cli.sock` in its own run folder
|
|
19
|
-
* `nodeRunDir(nodeId)`, so
|
|
19
|
+
* `nodeRunDir(nodeId)`, so `api.sock` is not mounted. `anchorDir` is an anchored cron's anchor agent folder. */
|
|
20
20
|
cron?: {
|
|
21
21
|
anchorDir?: string;
|
|
22
22
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var F=Object.defineProperty;var a=(t,o)=>F(t,"name",{value:o,configurable:!0});import{lstatSync as W}from"node:fs";import{join as
|
|
1
|
+
var F=Object.defineProperty;var a=(t,o)=>F(t,"name",{value:o,configurable:!0});import{lstatSync as W}from"node:fs";import{join as p,relative as f,sep as u}from"node:path";import{appSpace as d,appsRoot as S,runtimeRoot as h,socketDir as b,userFilesRoot as R}from"../layout.js";import{nodeAgentDir as I,nodeRunDir as k}from"../canvas/paths.js";import{uidForApp as A}from"./users.js";import{permissionsForRun as E}from"./permissions.js";function x(t){const o=[];for(const e of t.otherFiles){const s=e.holder==="user"?R():d(e.holder).files;o.push({source:e.path==="."?s:p(s,e.path),writable:e.writable})}for(const e of t.otherNodes)o.push({source:d(e).nodes,writable:!1});return o}a(x,"grantedMounts");function w(t,o){const e=f(t,o);return e===""||e!==".."&&!e.startsWith(`..${u}`)&&!e.startsWith(u)}a(w,"beneath");function M(t,o){return w(R(),o)||w(S(),o)&&!w(d(t).root,o)}a(M,"isGrantedSource");function j(t,o){return o.some(e=>w(e.source,t.source)&&(e.writable||!t.writable))}a(j,"mountAllowed");async function z(t,o){try{const e=x(await E(t.app,t.sub,t.grantId,t.scopes));return o.mounts.every(s=>!M(t.app,s.source)||j(s,e))}catch{return!1}}a(z,"launchStillGranted");async function B(t){const o=d(t.app),e=await E(t.app,t.sub,t.grantId,t.scopes);if(t.isolated&&t.withoutNode&&t.folder===void 0)throw new Error("isolated launch requires a node");const s=t.folder??(t.isolated?I(t.nodeId,t.app):void 0);if(s&&t.cwd!==void 0&&!w(s,t.cwd))throw new Error("isolated cwd must be inside the node folder");const c=new Map,i=a((r,n,l=!1,v=!1)=>{if(l)try{W(r)}catch(g){if(g.code!=="ENOENT")throw g;v&&t.auditMissing(r);return}c.set(r,n||(c.get(r)??!1))},"add");for(const r of["/usr","/bin","/lib","/lib64","/opt/crouter","/etc/passwd","/etc/group","/etc/resolv.conf","/etc/hosts","/etc/ssl","/etc/ca-certificates"])i(r,!1,!0);t.withoutNode||i(I(t.nodeId,t.app),!0),t.folder!==void 0&&i(t.folder,!0),t.cron?.anchorDir!==void 0&&i(t.cron.anchorDir,!0),t.isolated||i(o.home,!0),t.isolated||i(o.files,!0),i(o.cache,!0,!0),(!t.withoutNode||t.cron!==void 0)&&i(k(t.nodeId),!0),t.cron===void 0&&i(p(b(),"api.sock"),!0);for(const r of x(e))i(r.source,r.writable,!0,!0);if(t.pluginRoot!==void 0){const r=a(l=>t.pluginRoot===l||f(l,t.pluginRoot)!==".."&&!f(l,t.pluginRoot).startsWith(`..${u}`),"within"),n=p(h(),"plugins");if([...c].some(([l])=>r(l))){if(c.get(t.pluginRoot)===!0)throw new Error("hook root cannot also be writable");i(t.pluginRoot,!1)}else if(r(n)&&t.pluginRoot!==n)i(t.pluginRoot,!1);else if(r("/opt/crouter"))i(t.pluginRoot,!1);else throw new Error("hook root is not readable with this app\u2019s mounts")}const y=t.cwd??s??o.files,m=[...c].sort(([r],[n])=>r.split(u).length-n.split(u).length||r.localeCompare(n)),D=p(h(),"nodes",t.nodeId,"job","broker.log"),N=process.platform!=="linux"?[k(t.nodeId),p(b(),"api.sock")]:[];if(m.some(([r])=>r!==t.pluginRoot&&!N.includes(r)&&(r===h()||!f(h(),r).startsWith("..")&&!f(h(),r).startsWith(u))))throw new Error("runtime records cannot be mounted");return{nodeId:t.nodeId,uid:await A(t.app),mounts:m.map(([r,n])=>({source:r,writable:n})),cwd:y,env:t.env,command:t.command,log:D,...t.isolated?{network:"none"}:{}}}a(B,"compileLaunch");export{B as compileLaunch,x as grantedMounts,M as isGrantedSource,z as launchStillGranted,j as mountAllowed};
|
|
@@ -17,7 +17,7 @@ export interface AppProcessOptions {
|
|
|
17
17
|
grantId: string | null;
|
|
18
18
|
scopes: string[] | null;
|
|
19
19
|
};
|
|
20
|
-
/** A cron execution: launch id `cron-<executionId>`, no node, and no `api.sock
|
|
20
|
+
/** A cron execution: launch id `cron-<executionId>`, no node, and no `api.sock` — its only API path is
|
|
21
21
|
* its own execution folder's `cli.sock`. `anchorDir` is an anchored cron's anchor agent folder (rw). Needs `principal`. */
|
|
22
22
|
cron?: {
|
|
23
23
|
executionId: string;
|
|
@@ -9,14 +9,16 @@ export declare function killBashJobObject(jobId: string, killedBy: (db: CanvasDb
|
|
|
9
9
|
* daemon adopting a job the broker backgrounded while exiting. Daemon-only. */
|
|
10
10
|
export declare function recordBashJobObject(nodeId: string, jobId: string, spec: {
|
|
11
11
|
command: string;
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
purpose?: string | null;
|
|
13
|
+
deadlineAtMs?: number | null;
|
|
14
14
|
}): Promise<ObjectRow>;
|
|
15
|
-
|
|
16
|
-
export declare function stopNodeSandboxes(nodeId: string, reason: string, options?: {
|
|
15
|
+
type StopOptions = {
|
|
17
16
|
excludePid?: number;
|
|
18
17
|
startAfter?: Promise<unknown>;
|
|
19
18
|
after?: () => Promise<void>;
|
|
20
19
|
deleting?: boolean;
|
|
21
20
|
holdRecovery?: boolean;
|
|
22
|
-
}
|
|
21
|
+
};
|
|
22
|
+
/** Stop the broker first so it cannot start another job during the job scan. */
|
|
23
|
+
export declare function stopNodeSandboxes(nodeId: string, reason: string, options?: StopOptions): Promise<TeardownResult>;
|
|
24
|
+
export {};
|
package/dist/core/spaces/stop.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
2
|
-
AND type IN ('node.turn.started', 'node.turn.completed') ORDER BY sequence_number DESC LIMIT 1`).get(t),"latestTurn"),
|
|
1
|
+
var D=Object.defineProperty;var c=(t,r)=>D(t,"name",{value:r,configurable:!0});import{randomUUID as x}from"node:crypto";import{readJobSupervisorState as J,signalBashJob as k,unfinishedBashJobIds as O}from"../bash-jobs.js";import{contextDir as M}from"../canvas/node-agent-paths.js";import{getNode as P}from"../canvas/index.js";import{withCanvasWrite as R,openDb as h}from"../canvas/db.js";import{finishJob as $,ownerRunsRemotely as A,runningJobs as N,startJob as W}from"../graph/jobs.js";import{getById as S,nodeObject as C}from"../graph/objects.js";import{readLiveSession as H}from"../canvas/sessions.js";import{conversationStore as L}from"../conversation-store/index.js";import{requestBrokerTeardown as _}from"../runtime/host.js";import{holdRecovery as q,waitForRecoveryHold as F}from"../runtime/recovery-hold.js";async function T(t,r,e){return await R(async n=>{const a=await S(n,t);return a===null||a.type!=="job"?!1:(await $(n,a,{killedBy:await r(n),...e===void 0?{}:{reason:e}}),!0)})}c(T,"killBashJobObject");async function nt(t,r,e){return await R(async n=>{const a=await S(n,r);if(a!==null){if(a.type!=="job")throw new Error(`${r} names a ${a.type}`);return a}return await W(n,await C(n,t),{id:r,...e})})}c(nt,"recordBashJobObject");const y=new Map;async function U(t,r,e){return await F(t)==="lapsed"?await Y(t,r,e):await _(t,{excludePid:e.excludePid})}c(U,"stopHeldElsewhere");async function Y(t,r,e={}){const n=y.get(t);if(n)return n;const a=await P(t);if(!a)return Promise.resolve({confirmed:!1,error:new Error(`missing node ${t}`)});const g=(await H(t))?.sessionId,b=c(async()=>await(await h()).prepare(`SELECT type, body_json FROM run_events WHERE node_id = ?
|
|
2
|
+
AND type IN ('node.turn.started', 'node.turn.completed') ORDER BY sequence_number DESC LIMIT 1`).get(t),"latestTurn"),j=a.run_id!==null&&a.pi_pid!==null&&(await b())?.type==="node.turn.started",u=await q(t);if(u===null)return await U(t,r,e);const B=_(t,{excludePid:e.excludePid,...e.startAfter?{startAfter:e.startAfter}:{}}),w=(async()=>{const f=await B;if(!f.confirmed)return f;try{const o=c(()=>({confirmed:!1,error:new Error(`the recovery hold on ${t} lapsed during its stop`)}),"lost");if(!await u.renew())return o();const l=new Map((await N(await h(),t)).map(s=>[s.jobId,s]));if(await A(await h(),t)){if(!e.deleting)for(const s of l.keys())await T(s,async()=>null,r)}else{const s=await M(t);for(const i of new Set([...l.keys(),...O(s)])){const d=J(s,i),m=d.pgid??l.get(i)?.pgid??null,p=d.pgidIdentity??l.get(i)?.pgidIdentity??null;if(m===null||p===null)throw new Error(`bash job ${i} could not be stopped`);await k(m,p,t),!e.deleting&&l.has(i)&&await T(i,async()=>null,r)}}if(!await u.renew())return o();if(j&&g&&!e.deleting){if((await b())?.type!=="node.turn.started")return await u.renew()?(await e.after?.(),f):o();const i=L(),{entries:d}=await i.read(g),m=d.at(-1),p=new Date().toISOString(),v=r==="permission_revoked",E={type:"message",id:x(),parentId:m?.id??null,timestamp:p,message:{role:"assistant",content:[],api:"openai-completions",provider:"crouter",model:"",usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:v?"error":"aborted",errorMessage:r,timestamp:Date.now()}};await i.append(g,[E,{type:"custom",id:x(),parentId:E.id,timestamp:p,customType:"crtr-turn-end",data:v?{stop_reason:"error",error:{code:"model_error",message:r}}:{stop_reason:"aborted"}}])}return await u.renew()?(await e.after?.(),f):o()}catch(o){return{confirmed:!1,error:o instanceof Error?o:new Error(String(o))}}})();return y.set(t,w),w.finally(()=>{u.release().catch(()=>{}),y.get(t)===w&&y.delete(t)}),w}c(Y,"stopNodeSandboxes");export{T as killBashJobObject,nt as recordBashJobObject,Y as stopNodeSandboxes};
|
|
@@ -7,7 +7,8 @@ export interface AppUser {
|
|
|
7
7
|
/** The launcher is absent on macOS; there is no app uid on that host. */
|
|
8
8
|
export declare function uidForApp(app: string): Promise<number>;
|
|
9
9
|
/** An app has at most one active row. A removed app that reconnects gets a new
|
|
10
|
-
* row above every uid ever allocated, so a uid is never reused.
|
|
10
|
+
* row above every uid ever allocated, so a uid is never reused. The lock makes the
|
|
11
|
+
* read-then-insert safe when two first starts for one app, or two apps, race. */
|
|
11
12
|
export declare function allocateAppUser(app: string): Promise<AppUser>;
|
|
12
13
|
export declare function activeAppUsers(): Promise<Array<{
|
|
13
14
|
app: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var o=Object.defineProperty;var e=(t,a)=>o(t,"name",{value:a,configurable:!0});import{existsSync as c}from"node:fs";import{withCanvasWrite as E,openDb as p}from"../canvas/db.js";import{APP_UID_MAX as
|
|
1
|
+
var o=Object.defineProperty;var e=(t,a)=>o(t,"name",{value:a,configurable:!0});import{existsSync as c}from"node:fs";import{withCanvasWrite as E,openDb as p}from"../canvas/db.js";import{APP_UID_MAX as _,APP_UID_MIN as u,LAUNCHER_SOCKET as d}from"../../launcher/spec.js";async function l(t){return process.platform!=="linux"||!c(d)?process.getuid?.()??0:(await w(t)).uid}e(l,"uidForApp");const A=7340002;async function w(t){if(process.platform!=="linux")throw new Error("app OS users exist only on Linux");return await E(async a=>{await a.prepare(`SELECT pg_advisory_xact_lock(${A})`).get();const s=await a.prepare("SELECT app, uid, created, status FROM app_users WHERE app = ? AND status = 'active'").get(t);if(s)return s;const n=(await a.prepare("SELECT MAX(uid) AS uid FROM app_users").get()).uid,r=Math.max(u,(n??u-1)+1);if(r>_)throw new Error("app OS user range exhausted");const i=new Date().toISOString();return await a.prepare("INSERT INTO app_users (app, uid, created, status) VALUES (?, ?, ?, ?)").run(t,r,i,"active"),{app:t,uid:r,created:i,status:"active"}})}e(w,"allocateAppUser");async function v(){return(await(await p()).prepare("SELECT app, uid FROM app_users WHERE status = 'active'").all()).map(a=>({app:a.app.startsWith("app:")?a.app.slice(4):a.app,uid:a.uid}))}e(v,"activeAppUsers");async function O(t){return await(await p()).prepare("SELECT app, uid, created, status FROM app_users WHERE app = ? AND status = 'active'").get(t)??null}e(O,"activeAppUser");async function R(t){await(await p()).prepare("UPDATE app_users SET status = 'removed', removed_at = ? WHERE uid = ? AND status = 'active'").run(new Date().toISOString(),t)}e(R,"markAppUserRemoved");export{O as activeAppUser,v as activeAppUsers,w as allocateAppUser,R as markAppUserRemoved,l as uidForApp};
|
|
@@ -1,33 +1,36 @@
|
|
|
1
|
+
import { type BlobStore } from '../blobs/index.js';
|
|
1
2
|
import { type StorageClient, type StorageConfig } from './client.js';
|
|
2
3
|
import type { CanvasDb } from '../canvas/db.js';
|
|
3
4
|
/** The fetch step of one `run.start` or `run.message` is bounded to 110 s in
|
|
4
5
|
* total (the hosting router waits 120 s for its headers). */
|
|
5
6
|
export declare const ATTACHMENT_FETCH_BUDGET_MS = 110000;
|
|
6
|
-
/** One fetched upload; `url` is the storage URL the text named (for refusals).
|
|
7
|
+
/** One fetched upload; `url` is the storage URL the text named (for refusals). `path` is where the node's broker puts
|
|
8
|
+
* the file; `blob_key` (`attachments/<run root node>/<sha256>`) is where its bytes are in the blob store. */
|
|
7
9
|
export interface AttachmentUse {
|
|
8
10
|
upload_id: string;
|
|
9
11
|
path: string;
|
|
10
12
|
url: string;
|
|
13
|
+
blob_key: string;
|
|
11
14
|
}
|
|
12
15
|
export interface ResolvedAttachments {
|
|
13
16
|
/** The text with each storage URL replaced by its runtime path. */
|
|
14
17
|
text: string;
|
|
15
18
|
uses: AttachmentUse[];
|
|
16
|
-
/** Remove every file (and directory) this call created. Idempotent. */
|
|
17
|
-
cleanup: () => void;
|
|
18
19
|
}
|
|
19
20
|
export interface ResolveOptions {
|
|
20
21
|
config?: () => StorageConfig | null;
|
|
21
22
|
client?: () => StorageClient;
|
|
22
23
|
budgetMs?: number;
|
|
24
|
+
blobs?: () => Promise<BlobStore>;
|
|
25
|
+
/** Paths another call of the same request has already chosen, which no file of this call may take. */
|
|
26
|
+
taken?: readonly string[];
|
|
23
27
|
}
|
|
24
28
|
/** Re-check, inside the accepting write, that every used upload is still this
|
|
25
29
|
* grantee's and not pending delete (the due-work tick or an app removal may
|
|
26
30
|
* have released it while its bytes were fetched). */
|
|
27
31
|
export declare function assertUploadsUsable(grantee: string, uses: readonly AttachmentUse[], db: CanvasDb): Promise<void>;
|
|
28
|
-
/** Fetch every upload a storage URL in `text` names into
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* call wrote is removed before the error propagates. */
|
|
32
|
+
/** Fetch every upload a storage URL in `text` names into the blob store at `attachments/<rootId>/<sha256>` and replace
|
|
33
|
+
* exactly each URL's span with the path the node's broker downloads that file to (`<app space>/nodes/<rootId>/attachments/<name>`).
|
|
34
|
+
* The control plane writes no file there. Without configured storage the text passes through unchanged. A failure leaves
|
|
35
|
+
* at most content-keyed blobs, which are harmless and are deleted with the node (D100). */
|
|
33
36
|
export declare function resolveStorageUrls(grantee: string, rootId: string, text: string, options?: ResolveOptions): Promise<ResolvedAttachments>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var M=Object.defineProperty;var h=(e,t)=>M(e,"name",{value:t,configurable:!0});import{createHash as x}from"node:crypto";import{extname as H,join as v}from"node:path";import{Writable as B}from"node:stream";import{pipeline as O}from"node:stream/promises";import{blobStore as W}from"../blobs/index.js";import{appSpace as Z}from"../layout.js";import{RunError as A}from"../runs/operations.js";import{storageClient as j,storageConfig as q,StorageRefused as D}from"./client.js";import{getUpload as E,runUsesPath as F}from"./tables.js";const G=11e4,m=h((e,t)=>new A(400,"invalid_request",t,void 0,{url:e}),"refused"),b=h(e=>new A(503,"storage_unavailable",e,void 0,void 0,void 0,!0),"unavailable");function T(e,t){return/^[^\s<>"'`)\]]*/.exec(e.slice(t))[0].replace(/[.,;:!?]+$/,"")}h(T,"shownUrl");async function N(e,t,o,r,i){const c=`${t}/`,w=[];let f=0;for(let d=e.indexOf(c,f);d!==-1;d=e.indexOf(c,f)){const a=T(e,d),g=/^([A-Za-z0-9_-]+)\/([A-Za-z0-9_-]+)\//.exec(e.slice(d+c.length));if(!g)throw m(a,`storage URL ${a} does not name an upload`);if(g[1]!==o)throw m(a,`storage URL ${a} names another runtime`);const l=await E(g[2],i);if(!l||l.grantee!==r)throw m(a,`storage URL ${a} names an unknown upload`);if(l.delete_pending_since)throw m(a,`storage URL ${a} names a deleted upload`);const u=d+c.length+g[0].length,p=encodeURIComponent(l.name);if(!e.startsWith(p,u))throw m(a,`storage URL ${a} does not match the upload's name`);w.push({start:d,end:u+p.length,upload:l}),f=u+p.length}return w}h(N,"matchStorageUrls");async function ae(e,t,o){for(const r of t){const i=await E(r.upload_id,o);if(!i||i.grantee!==e||i.delete_pending_since)throw m(r.url,`storage URL ${r.url} names an upload deleted while it was fetched`)}}h(ae,"assertUploadsUsable");function P(e,t){if(t===1)return e;const o=H(e);return o&&o!==e?`${e.slice(0,-o.length)}-${t}${o}`:`${e}-${t}`}h(P,"candidate");async function se(e,t,o,r={}){const i={text:o,uses:[]},c=(r.config??q)();if(!c||!o.includes(`${c.base_url}/`))return i;const w=(r.client??j)(),f=await N(o,c.base_url,w.runtimeId,e);if(!f.length)return i;const d=v(Z(e).nodes,t,"attachments"),a=AbortSignal.timeout(r.budgetMs??G),g=await(r.blobs??W)(),l=new Set(r.taken),u=new Map;for(const{upload:s,start:C}of f){if(u.has(s.upload_id))continue;const _=T(o,C);let y;try{y=await w.fetchUpload(s.upload_id,a)}catch(n){throw n instanceof D?m(_,n.status===409?`storage URL ${_} names an upload that was never finished`:`storage URL ${_} names an unknown upload`):a.aborted?b("attachments could not be fetched within 110 s"):n}const S=[],L=x("sha256");try{await O(y.body,new B({write(n,I,z){L.update(n),S.push(n),z()}}),{signal:a})}catch(n){throw a.aborted?b("attachments could not be fetched within 110 s"):b(`storage stopped sending ${s.name}: ${n instanceof Error?n.message:String(n)}`)}const R=Buffer.concat(S);if(R.length!==s.size)throw b(`storage sent ${R.length} of ${s.size} bytes of ${s.name}`);const k=`attachments/${t}/${L.digest("hex")}`;try{await g.put(k,R)}catch(n){throw b(`the attachment ${s.name} could not be stored: ${n instanceof Error?n.message:String(n)}`)}let $="";for(let n=1;$=v(d,P(s.name,n)),!(!l.has($)&&!await F(t,$));n++);l.add($),u.set(s.upload_id,{upload_id:s.upload_id,path:$,url:_,blob_key:k})}let p="",U=0;for(const s of f)p+=o.slice(U,s.start)+u.get(s.upload.upload_id).path,U=s.end;return p+=o.slice(U),{text:p,uses:[...u.values()]}}h(se,"resolveStorageUrls");export{G as ATTACHMENT_FETCH_BUDGET_MS,ae as assertUploadsUsable,se as resolveStorageUrls};
|
|
@@ -10,10 +10,12 @@ export interface UploadRow {
|
|
|
10
10
|
created_at: string;
|
|
11
11
|
delete_pending_since: string | null;
|
|
12
12
|
}
|
|
13
|
+
/** `blob_key` is where the use's bytes are in the blob store (D98); null for a use recorded before the blob store held them. */
|
|
13
14
|
export interface UploadUseRow {
|
|
14
15
|
upload_id: string;
|
|
15
16
|
run_id: string;
|
|
16
17
|
path: string;
|
|
18
|
+
blob_key?: string | null;
|
|
17
19
|
}
|
|
18
20
|
export interface ShareRow {
|
|
19
21
|
share_id: string;
|
|
@@ -35,6 +37,8 @@ export declare function pendingUploadDeletes(db?: CanvasDb): Promise<UploadRow[]
|
|
|
35
37
|
/** Mark uploads for deletion (idempotent: keeps the first mark). */
|
|
36
38
|
export declare function markUploadsDeletePending(uploadIds: readonly string[], db?: CanvasDb, at?: string): Promise<void>;
|
|
37
39
|
export declare function insertUploadUses(uses: readonly UploadUseRow[], db?: CanvasDb): Promise<void>;
|
|
40
|
+
/** Whether `runId` already has an upload recorded at `path`. */
|
|
41
|
+
export declare function runUsesPath(runId: string, path: string, db?: CanvasDb): Promise<boolean>;
|
|
38
42
|
/** Remove one recorded use (a file result undone after it was recorded). */
|
|
39
43
|
export declare function deleteUploadUse(use: UploadUseRow, db?: CanvasDb): Promise<void>;
|
|
40
44
|
/** Record the size storage actually holds for an upload created with `max_size`. */
|