@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 +1 @@
|
|
|
1
|
-
var c=Object.defineProperty;var
|
|
1
|
+
var c=Object.defineProperty;var n=(e,r)=>c(e,"name",{value:r,configurable:!0});import{appsRoot as i}from"../layout.js";import{apiSocketPath as p}from"../canvas/paths.js";import{createStoreClient as u}from"./client.js";import{currentNodeToken as f}from"../runtime/broker/node-token.js";class d extends Error{static{n(this,"ConversationNotFoundError")}code="not_found";constructor(r){super(`conversation not found: ${r}`)}}function C(e){return e instanceof d}n(C,"isConversationNotFound");function A(e){return/(?:^|\/)[^/]+_([0-9a-f-]{36})\.jsonl$/i.exec(e)?.[1]??null}n(A,"conversationIdFromPath");function P(){return i()}n(P,"defaultConversationRoot");function l(){return process.env.CRTR_API_URL||p()}n(l,"conversationApiAddress");let t,a;function S(e){t=e}n(S,"installConversationStore");function k(){if(t)return t;const e=s();return{create:n(async(...r)=>e.create(...r),"create"),append:n(async(r,o)=>e.append(r,o),"append"),replace:n(async(...r)=>e.replace(...r),"replace"),read:n(async(...r)=>e.read(...r),"read"),header:n(async(...r)=>e.header(...r),"header"),fork:n(async(...r)=>e.fork(...r),"fork"),list:n(async(...r)=>e.list(...r),"list"),delete:n(async r=>e.delete(r),"delete")}}n(k,"conversationStore");function s(){const e=l();return a?.address!==e&&(a={address:e,store:u(e,f())}),a.store}n(s,"conversationClient");async function R(){t||await s().flush()}n(R,"flushConversation");async function F(e,r){if(t)return t.read(e,r);const o=s();return o.readAsync?o.readAsync(e,r):o.read(e,r)}n(F,"readConversationAsync");import{installSessionManagerStorePatch as E}from"./patch.js";import{findOrphanedParents as O,relinkOrphanedParents as T,repairConversationFile as $}from"./repair.js";export{d as ConversationNotFoundError,l as conversationApiAddress,s as conversationClient,A as conversationIdFromPath,k as conversationStore,P as defaultConversationRoot,O as findOrphanedParents,R as flushConversation,S as installConversationStore,E as installSessionManagerStorePatch,C as isConversationNotFound,F as readConversationAsync,T as relinkOrphanedParents,$ as repairConversationFile};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var x=Object.defineProperty;var d=(p,n)=>x(p,"name",{value:n,configurable:!0});import{dirname as S,resolve as E}from"node:path";import{SessionManager as m}from"@earendil-works/pi-coding-agent";import{conversationClient as B,conversationIdFromPath as P}from"./index.js";import{findOrphanedParents as O}from"./repair.js";import{emitEvent as k}from"../events/emit.js";let N=!1;function z(p,n=B()){if(N)return;const c=m.prototype,a=m;for(const e of["_setSessionFile","_rewriteFile","_persist","createBranchedSession","newSession"])if(typeof c[e]!="function")throw new Error(`pi SessionManager.${e} changed; store patch cannot start`);for(const e of["create","open","continueRecent","forkFrom","findById","list","listAll"])if(typeof a[e]!="function")throw new Error(`pi SessionManager.${e} changed; store patch cannot start`);const D=c.createBranchedSession,w=c.newSession;function M(e,s){const t=O(s);t.length!==0&&k({level:"error",event:"conversation.orphaned_parent",fields:{conversation_id:e,orphan_count:t.length,orphans:t.slice(0,20).map(i=>({entry_id:i.entryId,missing_parent_id:i.missingParentId}))}})}d(M,"reportOrphans");function y(e,s){const{header:t,entries:i,path:o}=n.read(e);M(t.id,i);const r=m.inMemory(s??t.cwd);r.sessionFile=o,r.sessionDir=S(o),r._loadEntries([t,...i]),r.persist=!0,r.flushed=!0;const l=r.fileEntries[0];return l?.type==="session"&&l.version!==t.version&&r._rewriteFile(),r}d(y,"fromStore");function u(e){const[s,...t]=e.fileEntries;if(!s||s.type!=="session")throw new Error("conversation has no session header");n.create(p,s,t),e.sessionFile=n.header(s.id).path,e.sessionDir=S(e.sessionFile),e.flushed=!0}d(u,"persistNew");function b(e,s){n.append(e.sessionId,[s])}d(b,"appendInOrder");function g(e){const s=P(e);if(!s)throw new Error(`invalid conversation path: ${e}`);return s}d(g,"idOf"),c._setSessionFile=function(e){const{header:s,entries:t}=n.read(g(e));this.sessionFile=n.header(s.id).path,this.sessionDir=S(this.sessionFile),M(s.id,t),this._loadEntries([s,...t]),this.flushed=!0},c._rewriteFile=function(){if(!this.persist||!this.sessionFile)return;const[e,...s]=this.fileEntries;if(!e||e.type!=="session")throw new Error("conversation has no session header");n.replace(e.id,e,s)},c._persist=function(e){!this.persist||!this.sessionFile||(this.flushed?b(this,e):u(this))},c.newSession=function(e){if(!this.persist)return w.call(this,e);const s=this.flushed&&this.fileEntries.length===1&&this.sessionFile!==void 0?this.sessionId:void 0;if(s!==void 0&&(e?.id===void 0||e.id===s)){const t=this.sessionFile;w.call(this,{...e,id:s});const i=this.fileEntries[0];if(!i||i.type!=="session")throw new Error("conversation has no session header");return n.replace(s,i,[]),this.sessionFile=t,this.flushed=!0,t}return w.call(this,e),u(this),this.sessionFile},c.createBranchedSession=function(e){if(!this.persist)return D.call(this,e);const s=this.sessionFile;this.persist=!1;try{D.call(this,e)}finally{this.persist=!0}const t=this.fileEntries[0];if(!t||t.type!=="session")throw new Error("branch has no header");return this.fileEntries[0]={...t,parentSession:s},u(this),this.sessionFile},a.create=(e,s,t)=>{const i=m.inMemory(e,t);return i.persist=!0,u(i),i},a.open=(e,s,t)=>y(g(e),t),a.continueRecent=e=>{const s=n.list().find(t=>t.header.cwd===E(e));return s?y(s.conversation_id,e):a.create(e)},a.forkFrom=(e,s)=>y(n.fork(g(e),p,void 0,s)),a.findById=(e,s)=>n.list().find(t=>t.conversation_id===s&&t.header.cwd===E(e))?.path;function I(e){return n.list().filter(s=>e===void 0||s.header.cwd===E(e)).map(s=>{let t,i=0,o="",r;const l=[];for(const f of n.read(s.conversation_id).entries){if(f.type==="session_info"&&(t=f.name?.trim()||void 0),f.type!=="message")continue;i++;const h=f.message;if(h.role!=="user"&&h.role!=="assistant")continue;const A=typeof h.timestamp=="number"?h.timestamp:Date.parse(f.timestamp);Number.isNaN(A)||(r=Math.max(r??0,A));const F=typeof h.content=="string"?h.content:Array.isArray(h.content)?h.content.filter(v=>v.type==="text").map(v=>v.text??"").join(" "):"";F&&(l.push(F),!o&&h.role==="user"&&(o=F))}const _=new Date(s.header.timestamp);return{path:s.path,id:s.conversation_id,cwd:s.header.cwd,...t?{name:t}:{},...s.header.parentSession?{parentSessionPath:s.header.parentSession}:{},created:_,modified:r&&r>0?new Date(r):Number.isNaN(_.getTime())?new Date(s.mtime):_,messageCount:i,firstMessage:o||"(no messages)",allMessagesText:l.join(" ")}})}d(I,"sessionInfos"),a.list=async(e,s,t,i)=>{i?.throwIfAborted();const o=I(e);return t?.(o.length,o.length,o),o},a.listAll=async(...e)=>(e.find(t=>t instanceof AbortSignal)?.throwIfAborted(),I()),N=!0}d(z,"installSessionManagerStorePatch");export{z as installSessionManagerStorePatch};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ConversationStore } from './index.js';
|
|
2
|
+
/** Durable tail rows, with immutable JSONL parts. All broker-visible writes pass through this store. */
|
|
3
|
+
export declare function createRowStore(): ConversationStore & {
|
|
4
|
+
commit(id: string): Promise<number>;
|
|
5
|
+
importLegacy(runId?: string): Promise<void>;
|
|
6
|
+
recover(rows: Array<{
|
|
7
|
+
session_id: string;
|
|
8
|
+
node_id: string;
|
|
9
|
+
transcript_path: string | null;
|
|
10
|
+
}>): void;
|
|
11
|
+
};
|
|
12
|
+
/** Rewrite part 0's header `cwd` under the conversation's row lock, leaving later parts and tail rows untouched.
|
|
13
|
+
* Returns false when the header's cwd is not `oldCwd`. */
|
|
14
|
+
export declare function relocateConversationHeader(id: string, oldCwd: string, newCwd: string): Promise<boolean>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
var H=Object.defineProperty;var f=(o,t)=>H(o,"name",{value:t,configurable:!0});import{randomUUID as g}from"node:crypto";import{existsSync as W,readFileSync as q,rmSync as A}from"node:fs";import{join as B}from"node:path";import{SessionManager as j}from"@earendil-works/pi-coding-agent";import{blobStore as l}from"../blobs/index.js";import{openDb as w,withCanvasWrite as y}from"../canvas/db.js";import{appSpace as J}from"../layout.js";import{appendConversationEvents as T,rootRepromptPending as L}from"../../daemon/runs/append-section.js";import{ConversationNotFoundError as R}from"./index.js";const O="s.unbound_at IS NULL DESC, s.created_at DESC, s.seq DESC",D=f((o,t,n)=>`conversations/${o}/${t}/${n}.jsonl`,"keyFor"),k=f(o=>o.map(t=>JSON.stringify(t)+`
|
|
2
|
+
`).join(""),"encode"),$=f(o=>o.split(`
|
|
3
|
+
`).filter(Boolean).map(t=>JSON.parse(t)),"decode"),h=f(()=>new Date().toISOString(),"at");async function N(o,t,n=!1){const i=await o.prepare(`SELECT s.binding_id, s.node_id, s.transcript_path, s.input_ids_json, s.source_session_id, n.run_id FROM sessions s JOIN nodes n ON n.node_id = s.node_id WHERE s.session_id = ? ORDER BY ${O} LIMIT 1${n?" FOR UPDATE OF s":""}`).get(t);if(!i)throw new R(t);return i}f(N,"binding");async function b(o,t){return await o.prepare("SELECT seq, blob_key, bytes, entries, created FROM conversation_parts WHERE conversation_id = ? ORDER BY seq").all(t)}f(b,"parts");async function Y(o,t){return await o.prepare("SELECT seq, body, bytes, created FROM conversation_entries WHERE conversation_id = ? ORDER BY seq").all(t)}f(Y,"tail");async function I(o,t){const n=await o.prepare(`SELECT 'part' AS kind, seq, blob_key, NULL AS body, bytes, entries, created FROM conversation_parts WHERE conversation_id = ?
|
|
4
|
+
UNION ALL SELECT 'tail', seq, NULL, body, bytes, NULL, created FROM conversation_entries WHERE conversation_id = ? ORDER BY 1, 2`).all(t,t);return{parts:n.filter(i=>i.kind==="part").map(({seq:i,blob_key:s,bytes:a,entries:e,created:r})=>({seq:Number(i),blob_key:s,bytes:Number(a),entries:Number(e),created:r})),tail:n.filter(i=>i.kind==="tail").map(({seq:i,body:s,bytes:a,created:e})=>({seq:Number(i),body:s,bytes:Number(a),created:e}))}}f(I,"snapshot");const C=1024*1024;async function m(o,t,n){const i=[];let s=0;const a=await l();for(const e of o.parts){const r=Math.max(t,s),c=Math.min(n,s+e.bytes);if(r<c){const d=await a.get(e.blob_key,{start:r-s,length:c-r});if(!d)throw new Error(`missing conversation object: ${e.blob_key}`);i.push(d)}s+=e.bytes}for(const e of o.tail){const r=Math.max(t,s),c=Math.min(n,s+e.bytes);r<c&&i.push(Buffer.from(e.body+`
|
|
5
|
+
`).subarray(r-s,c-s)),s+=e.bytes}return Buffer.concat(i)}f(m,"bytesOf");const M=new Map;async function U(o,t,n){const i=await w();if(await i.prepare("SELECT 1 FROM conversation_parts WHERE conversation_id = ? AND seq = 0").get(o)||!W(n))return;let s=q(n);const a=s.lastIndexOf(10);if(a<0)return;s=s.subarray(0,a+1);const e=await i.prepare("SELECT s.binding_id, s.node_id, s.event_offset, s.input_ids_json, s.source_session_id, n.run_id FROM sessions s JOIN nodes n ON n.node_id = s.node_id WHERE s.session_id = ? ORDER BY "+O+" LIMIT 1").get(o);let r=[];if(e?.run_id&&e.event_offset!==null){const p=Number(e.event_offset);if(s.length<p)throw new Error(`conversation shorter than indexed offset: ${o}`);r=$(s.subarray(p).toString("utf8")).filter(u=>u.type!=="session")}const c=e?.run_id?await L(e.run_id,e.node_id,r):!1,d=D(t,o,0);await(await l()).put(d,s),await y(async p=>{if(!await p.prepare("INSERT INTO conversation_parts (conversation_id, seq, blob_key, bytes, entries, created) VALUES (?, 0, ?, ?, ?, ?) ON CONFLICT DO NOTHING RETURNING seq").get(o,d,s.length,Math.max(0,s.toString("utf8").split(`
|
|
6
|
+
`).filter(Boolean).length-1),h())||!e?.run_id||e.event_offset===null)return;const _=e.source_session_id?[]:await T(p,e.run_id,e.node_id,r,JSON.parse(e.input_ids_json),c);await p.prepare("UPDATE sessions SET event_offset = ?, indexed_entry_id = ?, input_ids_json = ? WHERE binding_id = ?").run(s.length,r.at(-1)?.id??null,JSON.stringify(_),e.binding_id)})}f(U,"importOne");async function S(o,t){const n=await t.prepare(`SELECT s.binding_id, s.node_id, s.transcript_path, s.input_ids_json, s.source_session_id, n.run_id FROM sessions s JOIN nodes n ON n.node_id = s.node_id WHERE s.session_id = ? ORDER BY ${O} LIMIT 1`).get(o),i=M.get(o);if(!n&&!i)throw new R(o);let s=(await b(t,o))[0];if(!s){const c=i?.path??n?.transcript_path??void 0;c&&await U(o,i?.node??n.node_id,c),s=(await b(t,o))[0]}if(!s||s.seq!==0)throw new R(o);const a=await(await l()).get(s.blob_key,{start:0,length:Math.min(s.bytes,256*1024)});if(!a)throw new Error(`missing conversation object: ${s.blob_key}`);const e=a.indexOf(10);if(e<0)throw new Error(`invalid conversation header: ${o}`);const r=JSON.parse(a.subarray(0,e).toString("utf8"));if(r.type!=="session"||r.id!==o)throw new Error(`invalid conversation header: ${o}`);return{header:r,path:n?.transcript_path??i?.path??"",binding:n}}f(S,"initial");function et(){const o={async create(t,n,i,s){const e=await(await w()).prepare("SELECT grantee, run_id FROM node_rows WHERE node_id = ?").get(t);if(!e)throw new Error(`missing conversation owner ${t}`);const r=n.id,c=B(J(e.grantee).conversations,t,`${n.timestamp.replace(/[:.]/g,"-")}_${r}.jsonl`),d=k([n,...i]),p=D(t,r,0),u=e.run_id?await L(e.run_id,t,i):!1;return await(await l()).put(p,d),await y(async _=>{if(await _.prepare("SELECT 1 FROM conversation_parts WHERE conversation_id = ?").get(r))throw new Error(`conversation already exists: ${r}`);const E=h(),v=n.parentSession?await _.prepare("SELECT session_id FROM sessions WHERE transcript_path = ? LIMIT 1").get(n.parentSession):void 0;if(await _.prepare("INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at, unbound_at) VALUES (?, ?, ?, ?, ?, NULL, ?, ?, ?)").run(g(),r,t,c,v?v.session_id:null,E,E,E),await _.prepare("INSERT INTO conversation_parts (conversation_id, seq, blob_key, bytes, entries, created) VALUES (?, 0, ?, ?, ?, ?)").run(r,p,Buffer.byteLength(d),i.length,E),e.run_id&&!v){const F=await T(_,e.run_id,t,i,[],u);await _.prepare("UPDATE sessions SET indexed_entry_id = ?, input_ids_json = ? WHERE session_id = ? AND node_id = ?").run(i.at(-1)?.id??null,JSON.stringify(F),r,t)}}),r},async append(t,n){if(!n.length)return;const i=await N(await w(),t),s=i.run_id?await L(i.run_id,i.node_id,n):!1;await y(async a=>{const e=await N(a,t,!0);if(!(await b(a,t)).length)throw new R(t);const r=[];for(const c of n){const d=JSON.stringify(c);await a.prepare("INSERT INTO conversation_entries (conversation_id, entry_id, body, bytes, execution_id, created) VALUES (?, ?, ?, ?, NULL, ?) ON CONFLICT (conversation_id, entry_id) DO NOTHING RETURNING entry_id").get(t,c.id,d,Buffer.byteLength(d)+1,h())&&r.push(c)}if(e.run_id&&r.length){const c=await T(a,e.run_id,e.node_id,r,JSON.parse(e.input_ids_json??"[]"),s);await a.prepare("UPDATE sessions SET indexed_entry_id = ?, input_ids_json = ? WHERE binding_id = ?").run(r.at(-1).id,JSON.stringify(c),e.binding_id)}})},async readLines(t){const n=await w(),{path:i}=await S(t,n),s=await I(n,t),a=s.parts.reduce((r,c)=>r+c.bytes,0)+s.tail.reduce((r,c)=>r+c.bytes,0);async function*e(){let r="";for(let c=0;c<a;c+=C){const d=r+(await m(s,c,Math.min(a,c+C))).toString("latin1"),p=d.lastIndexOf(`
|
|
7
|
+
`);r=d.slice(p+1);for(const u of d.slice(0,p+1).split(`
|
|
8
|
+
`))u&&(yield Buffer.from(u,"latin1").toString("utf8"))}r&&(yield Buffer.from(r,"latin1").toString("utf8"))}return f(e,"lines"),{path:i,lines:e()}},async read(t,n){const i=await w(),{header:s,path:a}=await S(t,i),e=await I(i,t),r=e.parts.reduce((_,E)=>_+E.bytes,0)+e.tail.reduce((_,E)=>_+E.bytes,0),c=f(_=>$(_).filter(E=>E.type!=="session"),"entriesOf");if(!n||r<=n.head+n.tail)return{header:s,entries:c((await m(e,0,r)).toString("utf8")),path:a};const d=(await m(e,0,Math.max(0,n.head))).toString("utf8").split(`
|
|
9
|
+
`);d.pop();const p=Math.max(0,r-n.tail),u=(await m(e,p>0?p-1:0,r)).toString("utf8").split(`
|
|
10
|
+
`);return p>0&&u.shift(),{header:s,entries:c(d.join(`
|
|
11
|
+
`)),tail:c(u.join(`
|
|
12
|
+
`)),path:a}},async header(t){const n=await w(),{header:i,path:s}=await S(t,n),a=await I(n,t);return{header:i,path:s,mtime:Date.parse(a.tail.at(-1)?.created??a.parts.at(-1).created),size:a.parts.reduce((e,r)=>e+r.bytes,0)+a.tail.reduce((e,r)=>e+r.bytes,0)}},async list(t){const i=await(await w()).prepare(`SELECT DISTINCT ON (s.session_id) s.session_id, s.node_id FROM sessions s JOIN conversation_parts p ON p.conversation_id = s.session_id WHERE s.session_id IS NOT NULL ORDER BY s.session_id, ${O}`).all(),s=[];for(const a of i){if(t&&a.node_id!==t)continue;const e=await o.header(a.session_id);s.push({conversation_id:a.session_id,node_id:a.node_id,...e})}return s.sort((a,e)=>e.mtime-a.mtime)},async replace(t,n,i){if(n.id!==t)throw new Error("replacement header id differs from conversation id");const s=await w(),a=await N(s,t);if(a.run_id)throw new Error(`run conversation ${t} is append-only; replace refused`);const e=`conversations/${a.node_id}/${t}/0-${g()}.jsonl`,r=k([n,...i]);await(await l()).put(e,r);const c=await y(async d=>{if((await N(d,t,!0)).run_id)throw new Error(`run conversation ${t} is append-only; replace refused`);const u=await b(d,t);return await d.prepare("DELETE FROM conversation_parts WHERE conversation_id = ?").run(t),await d.prepare("DELETE FROM conversation_entries WHERE conversation_id = ?").run(t),await d.prepare("INSERT INTO conversation_parts (conversation_id, seq, blob_key, bytes, entries, created) VALUES (?, 0, ?, ?, ?, ?)").run(t,e,Buffer.byteLength(r),i.length,h()),u});for(const d of c)await(await l()).delete(d.blob_key)},async fork(t,n,i,s){const a=await o.read(t);let e=a.entries;if(i!==void 0){const r=j.inMemory(a.header.cwd,void 0,[a.header,...e]);r.createBranchedSession(i),e=r.getEntries()}return await o.create(n??(await S(t,await w())).binding?.node_id??M.get(t).node,{...a.header,id:g(),timestamp:h(),cwd:s??a.header.cwd,parentSession:a.path},e)},async delete(t,n){const i=await w(),s=await b(i,t);await y(async a=>{await a.prepare("DELETE FROM conversation_entries WHERE conversation_id = ?").run(t),await a.prepare("DELETE FROM conversation_parts WHERE conversation_id = ?").run(t),await a.prepare("DELETE FROM sessions WHERE session_id = ?").run(t)});for(const a of s)await(await l()).delete(a.blob_key);n&&A(n,{force:!0})},async commit(t){return await y(async n=>{const i=await N(n,t,!0),s=await Y(n,t),a=await b(n,t);if(!s.length)return a.at(-1)?.seq??0;const e=(a.at(-1)?.seq??0)+1,r=D(i.node_id,t,e),c=s.map(d=>d.body+`
|
|
13
|
+
`).join("");return await(await l()).put(r,c),process.env.CRTR_FAULT_CONVERSATION==="commit_exit_after_put"&&process.exit(1),await n.prepare("INSERT INTO conversation_parts (conversation_id, seq, blob_key, bytes, entries, created) VALUES (?, ?, ?, ?, ?, ?)").run(t,e,r,Buffer.byteLength(c),s.length,h()),await n.prepare("DELETE FROM conversation_entries WHERE conversation_id = ? AND seq <= ?").run(t,s.at(-1).seq),e})},async importLegacy(t){const i=await(await w()).prepare(`SELECT DISTINCT ON (s.session_id) s.session_id, s.node_id, s.transcript_path FROM sessions s JOIN nodes n ON n.node_id = s.node_id WHERE s.session_id IS NOT NULL AND s.transcript_path IS NOT NULL ${t?"AND n.run_id = ?":""} ORDER BY s.session_id, ${O}`).all(...t?[t]:[]);for(const s of i)await U(s.session_id,s.node_id,s.transcript_path)},recover(t){for(const n of t)n.transcript_path&&M.set(n.session_id,{node:n.node_id,path:n.transcript_path})}};return o}f(et,"createRowStore");async function nt(o,t,n){const i=await w(),s=await N(i,o),a=(await b(i,o))[0];if(!a||a.seq!==0)return!1;const e=await(await l()).get(a.blob_key);if(!e)throw new Error(`missing conversation object: ${a.blob_key}`);const r=e.indexOf(10);if(r<0)throw new Error(`invalid conversation header: ${o}`);const c=JSON.parse(e.subarray(0,r).toString("utf8"));if(c.type!=="session"||c.id!==o)throw new Error(`invalid conversation header: ${o}`);if(c.cwd!==t)return!1;const d=Buffer.concat([Buffer.from(JSON.stringify({...c,cwd:n})),e.subarray(r)]),p=`conversations/${s.node_id}/${o}/0-${g()}.jsonl`;await(await l()).put(p,d);const u=await y(async _=>await _.prepare("UPDATE conversation_parts SET blob_key = ?, bytes = ? WHERE conversation_id = ? AND seq = 0 AND blob_key = ? RETURNING seq").get(p,d.length,o,a.blob_key)!==void 0);if(await(await l()).delete(u?a.blob_key:p).catch(()=>{}),!u)throw new Error(`conversation header changed during relocation: ${o}`);return!0}f(nt,"relocateConversationHeader");export{et as createRowStore,nt as relocateConversationHeader};
|
|
@@ -40,10 +40,12 @@ export interface JoinDaemonControl {
|
|
|
40
40
|
}
|
|
41
41
|
/** Provider plugin ids installed on this machine (reported for display only). */
|
|
42
42
|
export declare function installedPluginIds(): string[];
|
|
43
|
-
/** The owner a successful join recorded, or null when `crtr sys join` never
|
|
44
|
-
* wrote the client file (no file, or one provisioned without join, which has
|
|
45
|
-
* no `token_sha256`). The daemon's `retireLocalPerson` makes it the install's person at the next start. */
|
|
43
|
+
/** The owner a successful join recorded, or null when `crtr sys join` never wrote the client file. */
|
|
46
44
|
export declare function joinedOwner(): string | null;
|
|
45
|
+
/** The issuer a successful join recorded, or null. */
|
|
46
|
+
export declare function joinedIssuer(): string | null;
|
|
47
|
+
/** The whole registration a successful join recorded, or null; a damaged file throws. */
|
|
48
|
+
export declare function joinedClient(): Registration | null;
|
|
47
49
|
/** Join this runtime to a directory.
|
|
48
50
|
*
|
|
49
51
|
* With `daemon` control, a running daemon is no obstacle: the join holds the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var J=Object.defineProperty;var
|
|
1
|
+
var J=Object.defineProperty;var o=(t,r)=>J(t,"name",{value:r,configurable:!0});import{createHash as I,generateKeyPairSync as N,randomUUID as U}from"node:crypto";import{existsSync as R,mkdirSync as D,readdirSync as L,rmSync as y}from"node:fs";import{hostname as O}from"node:os";import{join as v}from"node:path";import{InputError as l}from"../io.js";import{network as j}from"../errors.js";import{secretsDir as k}from"../layout.js";import{apiSocketPath as C}from"../canvas/paths.js";import{daemonAnswers as K}from"../layout-migrate/index.js";import{atomicWriteJson as _,readJsonIfExists as x}from"../fs-utils.js";import{launcherPresent as T}from"../grants/sandboxes.js";import{crtrVersion as A}from"../../shared/crtr-version.js";import{pluginsDir as W}from"../scope.js";import{withJoinLock as q}from"./join-lock.js";function p(){return v(k(),"runtime-client.json")}o(p,"clientPath");function S(t){if(typeof t!="string")return!1;try{const{protocol:r}=new URL(t);return r==="http:"||r==="https:"}catch{return!1}}o(S,"isUrl");function b(t){const r=t??{},{runtime:c,client_id:e,issuer:a,owner:n,url:s}=r;if(typeof c!="string"||!/^runtime:.+/.test(c)||typeof e!="string"||e===""||!S(a)||typeof n!="string"||!/^user:.+/.test(n)||!S(s))throw j("directory registration answer is missing runtime, client_id, issuer, owner, or url");const{machine_id:i,is_default:u}=r;return{runtime:c,client_id:e,issuer:a,owner:n,url:s,...typeof i=="string"?{machine_id:i}:{},...typeof u=="boolean"?{is_default:u}:{}}}o(b,"registration");function w(){return v(k(),"runtime-client.pending.json")}o(w,"pendingPath");function z(){try{const t=W("user");return!t||!R(t)?[]:L(t,{withFileTypes:!0}).filter(r=>r.isDirectory()&&!r.name.startsWith(".")).map(r=>r.name).sort()}catch{return[]}}o(z,"installedPluginIds");async function B(t,r,c,e){const a=`${t.replace(/\/$/,"")}/v1/runtimes/registration`;let n;try{n=await fetch(a,{method:"PUT",headers:{authorization:`Bearer ${r}`,"content-type":"application/json"},body:JSON.stringify({jwk:c,name:e,platform:`${process.platform}-${process.arch}`,crtr_version:A(),plugins:z(),sandboxed:T()}),signal:AbortSignal.timeout(3e4)})}catch(i){throw j(`directory registration request to ${a} failed: ${i instanceof Error?i.message:String(i)}`)}const s=await n.text();if(!n.ok)throw n.status<500&&y(w(),{force:!0}),new l({error:"join_refused",message:`directory refused the registration: ${n.status} ${s.slice(0,500)}`,next:`Create a new join token at ${t.replace(/\/$/,"")}/account/machines (tokens are single-use and expire after 10 minutes), and run \`crtr sys join\` again.`});try{return b(JSON.parse(s))}catch(i){throw i instanceof SyntaxError?j("directory registration answer is not JSON"):i}}o(B,"register");function $(){const t=x(p());if(t?.token_sha256===void 0)return null;const{owner:r}=t;if(typeof r!="string"||!/^user:.+/.test(r))throw new Error(`${p()} was written by join but has a missing or invalid owner`);return t}o($,"readJoined");function st(){return $()?.owner??null}o(st,"joinedOwner");function at(){return $()?.issuer??null}o(at,"joinedIssuer");function ct(){const t=$();return t===null?null:b(t)}o(ct,"joinedClient");function E(t){return new l({error:"daemon_running",message:`cannot join while a daemon answers on ${t}`,next:"This daemon is managed outside crtr, so join cannot restart it: stop the daemon that owns this volume, then run `crtr sys join` again."})}o(E,"daemonRunningError");async function P(t,r,c,e){const a=x(p());if(a?.token_sha256===e)return{joined:b(a),registered:!1};D(k(),{recursive:!0,mode:448});let n=x(w());if(n?.token_sha256!==e||n.directory!==t||!n.jwk||!n.public_jwk){const{privateKey:h,publicKey:f}=N("ec",{namedCurve:"P-256"}),d=U();n={token_sha256:e,directory:t,jwk:{...h.export({format:"jwk"}),kid:d,alg:"ES256",use:"sig"},public_jwk:{...f.export({format:"jwk"}),kid:d,alg:"ES256",use:"sig"}},_(w(),n,{mode:384})}const{jwk:s,public_jwk:i}=n,u=await B(t,r,i,c);return{joined:u,registered:!0,client:{jwk:s,kid:s.kid,alg:"ES256",...u,token_sha256:e}}}o(P,"obtainRegistration");async function ut(t,r,c=O(),e){if(!S(t))throw new l({error:"invalid_directory",message:"directory must be an http or https URL",received:t,field:"directory",next:"Pass the directory base URL, for example https://directory.example."});if(r==="")throw new l({error:"invalid_token",message:"token is empty",field:"token",next:"Pass the enrollment token provisioning supplied."});const a=C(),n=I("sha256").update(r).digest("hex");if(e===void 0){if(await K(a))throw E(a);const{joined:s,registered:i,client:u}=await P(t,r,c,n);return u&&(_(p(),u,{mode:384}),y(w(),{force:!0})),{...s,registered:i,daemon:"not_running"}}return q(async()=>{const s=o(()=>new l({error:"join_inside_node",message:"a daemon is running and this command is inside a node: stopping the daemon would kill this node's broker and this command with it",next:"Run `crtr sys join` from a plain terminal outside any crtr node. It stops the daemon, joins, and starts it again for you."}),"refuseInsideNode");if(await e.running()&&e.insideNode())throw s();const{joined:i,registered:u,client:h}=await P(t,r,c,n);let f=!1,d;try{if(await e.running()){if(e.insideNode())throw s();if(f=!0,await e.stop(),await e.running())throw E(a)}if(h&&(_(p(),h,{mode:384}),y(w(),{force:!0})),await e.running()){if(e.insideNode())throw s();f=!0,await e.stop()}}catch(m){d=m}let g={daemon:"not_running"};if(d===void 0||f)try{await e.start(),g={daemon:f?"restarted":"started"}}catch(m){g={daemon:"restart_failed",daemon_error:m instanceof Error?m.message:String(m)}}if(d!==void 0)throw d;return g.daemon==="started"&&await e.firstSync?.(),{...i,registered:u,...g}})}o(ut,"joinDirectory");export{z as installedPluginIds,ut as joinDirectory,ct as joinedClient,at as joinedIssuer,st as joinedOwner};
|
package/dist/core/env-name.d.ts
CHANGED
package/dist/core/env-name.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var s=Object.defineProperty;var r=(e,t)=>s(e,"name",{value:t,configurable:!0});function i(e){const t=[];return typeof e!="string"?t.push("env var name must be a string"):/^[A-Za-z_][A-Za-z0-9_]*$/.test(e)||t.push("env var name must start with letter/underscore, followed by alphanumeric/underscore"),{isValid:t.length===0,errors:t}}r(i,"validateEnvVarName");const n="CRTR_",a=new Set(["HOME"]);function o(e){return e.startsWith(n)||a.has(e)}r(o,"isReservedEnvName");export{o as isReservedEnvName,i as validateEnvVarName};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface EnvironmentRecipeInput {
|
|
2
|
+
repositories: Array<{
|
|
3
|
+
name: string;
|
|
4
|
+
github_full_name: string;
|
|
5
|
+
default_branch: string;
|
|
6
|
+
}>;
|
|
7
|
+
setup_script: string | null;
|
|
8
|
+
/** pi package sources, one per line. */
|
|
9
|
+
pi_packages: string | null;
|
|
10
|
+
}
|
|
11
|
+
/** Replaces the recipe of a cloud environment. Returns the recipe revision after the write and whether it changed. */
|
|
12
|
+
export declare function setEnvironmentRecipe(environmentId: string, recipe: EnvironmentRecipeInput): Promise<{
|
|
13
|
+
revision: number;
|
|
14
|
+
changed: boolean;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var c=Object.defineProperty;var p=(r,n)=>c(r,"name",{value:n,configurable:!0});import{withCanvasWrite as u}from"./canvas/db.js";async function h(r,n){const o=new Set;for(const e of n.repositories){if(!/^[A-Za-z0-9._-]+$/.test(e.name)||e.name==="."||e.name==="..")throw new Error(`repository name ${JSON.stringify(e.name)} is not a plain directory name`);if(o.has(e.name))throw new Error(`repository name ${e.name} appears twice in the recipe`);o.add(e.name)}return await u(async e=>{const t=await e.prepare("SELECT kind, recipe_revision, setup_script, pi_packages FROM environments WHERE object = ? FOR UPDATE").get(r);if(t===void 0)throw new Error(`no environment ${r}`);if(t.kind!=="blaxel")throw new Error(`environment ${r} is a ${t.kind} environment; only a cloud (blaxel) environment has a recipe image`);const s=await e.prepare("SELECT name, github_full_name, default_branch FROM environment_repos WHERE environment = ? ORDER BY position").all(r);if(t.setup_script===n.setup_script&&t.pi_packages===n.pi_packages&&s.length===n.repositories.length&&s.every((a,i)=>a.name===n.repositories[i].name&&a.github_full_name===n.repositories[i].github_full_name&&a.default_branch===n.repositories[i].default_branch))return{revision:Number(t.recipe_revision),changed:!1};await e.prepare("DELETE FROM environment_repos WHERE environment = ?").run(r);const m=e.prepare("INSERT INTO environment_repos (environment, position, name, github_full_name, default_branch) VALUES (?, ?, ?, ?, ?)");for(const[a,i]of n.repositories.entries())await m.run(r,a,i.name,i.github_full_name,i.default_branch);const _=await e.prepare("UPDATE environments SET setup_script = ?, pi_packages = ?, recipe_revision = recipe_revision + 1 WHERE object = ? RETURNING recipe_revision").get(n.setup_script,n.pi_packages,r);return{revision:Number(_.recipe_revision),changed:!0}})}p(h,"setEnvironmentRecipe");export{h as setEnvironmentRecipe};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var s=Object.defineProperty;var i=(e,r)=>s(e,"name",{value:r,configurable:!0});import{openDb as p,withCanvasWrite as
|
|
1
|
+
var s=Object.defineProperty;var i=(e,r)=>s(e,"name",{value:r,configurable:!0});import{openDb as p,withCanvasWrite as u}from"./canvas/db.js";import{createObject as w,ownerForGrantee as E}from"./graph/objects.js";import{writeActsFor as d}from"./permissions/facts.js";import{isCloudRole as h,personIdAsync as v}from"./canvas/person.js";let t=null;async function S(e){const r=new Date().toISOString(),o=await u(async n=>{const c=await n.prepare("SELECT object FROM environments WHERE machine_id = ?").get(e);if(c!==void 0)return await n.prepare("UPDATE environments SET last_seen_at = ? WHERE machine_id = ?").run(r,e),{environmentId:c.object,created:!1};const m=await E(n,"app:terminal"),a=await w(n,{type:"environment",kind:"machine",owner:m.id,privacy:"public",name:e,preview:"machine"});return h()||await d(n,a.id,await v()),await n.prepare("INSERT INTO environments (object, kind, machine_id, last_seen_at) VALUES (?, 'machine', ?, ?)").run(a.id,e,r),{environmentId:a.id,created:!0}});return t={environmentId:o.environmentId,machineId:e},o}i(S,"registerMachineEnvironment");async function T(e){t!==null&&await(await p()).prepare("UPDATE environments SET last_seen_at = ? WHERE machine_id = ?").run(e,t.machineId)}i(T,"touchMachineEnvironment");function g(){if(t===null)throw new Error("the machine environment is not registered yet");return t.environmentId}i(g,"machineEnvironmentId");export{g as machineEnvironmentId,S as registerMachineEnvironment,T as touchMachineEnvironment};
|
package/dist/core/events/emit.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var i=Object.defineProperty;var n=(o,e)=>i(o,"name",{value:e,configurable:!0});import{appendBufferedDaemonRecord as s,appendRotatingRecord as f}from"../log.js";import{buildEnvelope as
|
|
1
|
+
var i=Object.defineProperty;var n=(o,e)=>i(o,"name",{value:e,configurable:!0});import{appendBufferedDaemonRecord as s,appendRotatingRecord as f}from"../log.js";import{buildEnvelope as a}from"./envelope.js";import{serializeEventRecord as c}from"./serialize.js";import{eventSource as m}from"./source.js";import{isSandboxedNode as p}from"../../shared/env.js";import{appendBrokerLog as u}from"../runtime/broker/daemon-ops.js";let l,t=Promise.resolve();function E(){return t}n(E,"flushBrokerLog");function _(o,e){t=t.then(async()=>{try{const{appended:r}=await u(o,e);r||process.stderr.write(`[broker] log.jsonl refused record: ${e}
|
|
2
2
|
`)}catch(r){process.stderr.write(`[broker] log.jsonl append failed (${r instanceof Error?r.message:String(r)}): ${e}
|
|
3
|
-
`)}})}n(
|
|
3
|
+
`)}})}n(_,"queueBrokerRecord");function B(o){const e=m();if(e===void 0)return!1;if(e.component==="broker"&&e.node_id!==void 0&&o.node_id!==void 0&&o.node_id!==e.node_id)throw new TypeError(`broker event target node_id must match bound node_id; received ${o.node_id}`);if(o.level==="debug"&&process.env.CRTR_LOG!=="debug")return!1;const r=a({...o,component:e.component,...e.node_id===void 0?{}:{node_id:e.node_id},...e.stream_id===void 0?{}:{stream_id:e.stream_id}}),d=c(r);return e.component==="broker"&&e.node_id!==void 0&&(l??=p())?(_(e.node_id,d),!0):e.component==="daemon"?s(e.path,d):f(e.path,d)}n(B,"emitEvent");export{B as emitEvent,E as flushBrokerLog};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { RunEvent } from '../../api/dto/run-events.js';
|
|
2
|
+
import type { BlobStore } from '../blobs/index.js';
|
|
3
|
+
/** One fixed 128-sequence range of a run's archived events and the immutable objects that hold it. Passes that archive
|
|
4
|
+
* different rows of one range write different objects; the range's events are their union. */
|
|
5
|
+
export interface RunEventChunk {
|
|
6
|
+
first: number;
|
|
7
|
+
last: number;
|
|
8
|
+
keys: string[];
|
|
9
|
+
}
|
|
10
|
+
/** List a run's archived ranges in order, each with the keys of the objects holding it. */
|
|
11
|
+
export declare function listRunEventChunks(store: BlobStore, runId: string): Promise<RunEventChunk[]>;
|
|
12
|
+
/** Read a range's events, each sequence once, ordered by sequence. An event body never changes after it is written,
|
|
13
|
+
* so a sequence held by more than one object (a retried or concurrent pass) has the same body in each. A missing object is an error. */
|
|
14
|
+
export declare function readRunEventChunk(store: BlobStore, chunk: RunEventChunk): Promise<RunEvent[]>;
|
|
15
|
+
/**
|
|
16
|
+
* Archive the same 14-day payload/30-day control events formerly deleted by expireRunEvents.
|
|
17
|
+
* No transaction, connection or lock is held across compression or blob I/O: the rows are read, each range's
|
|
18
|
+
* rows become one immutable object whose key carries a digest of its content, and only then does a short
|
|
19
|
+
* transaction delete the rows. Nothing is ever read back and merged, so there is no object a stale or
|
|
20
|
+
* concurrent archiver could overwrite with fewer rows: it can only write an object with the same content
|
|
21
|
+
* under the same key, or a different one under its own key, and readers take the union by sequence.
|
|
22
|
+
* A crash or failed put leaves the rows (the next pass archives them again); rows are deleted only after
|
|
23
|
+
* their object is durable. Returns the number of rows this pass deleted.
|
|
24
|
+
*/
|
|
25
|
+
export declare function archiveExpiredRunEvents(store: BlobStore, now: number, limit?: number): Promise<number>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
var g=Object.defineProperty;var u=(e,s)=>g(e,"name",{value:s,configurable:!0});import{createHash as v}from"node:crypto";import{promisify as w}from"node:util";import{zstdCompress as k,zstdDecompress as S}from"node:zlib";import{openDb as $,withCanvasWrite as x}from"../canvas/db.js";const D=w(k),N=w(S),l=128,R=16,_=["node.tool_call.completed","node.tool_call.started","node.system_prompt.set","node.thinking.done","node.output_text.done"],h=u(e=>`events/${e}/`,"prefix"),b=u(e=>String(e).padStart(R,"0"),"pad"),I=u(e=>{const s=Math.floor((e-1)/l)*l+1;return{first:s,last:s+l-1}},"range"),q=u((e,s,n,t)=>`${h(e)}${b(s)}-${b(n)}-${t}.jsonl.zst`,"chunkKey");async function z(e,s){const n=new Map;for(const t of await e.list(h(s))){const o=/\/(\d{16})-(\d{16})-[0-9a-f]{32}\.jsonl\.zst$/.exec(t);if(!o)throw new Error(`not a run-event chunk key: ${t}`);const c=Number(o[1]),a=n.get(c);a?a.keys.push(t):n.set(c,{first:c,last:Number(o[2]),keys:[t]})}return[...n.values()].sort((t,o)=>t.first-o.first)}u(z,"listRunEventChunks");async function H(e,s){const n=new Map;for(const t of s.keys){const o=await e.get(t);if(o===null)throw new Error(`run-event chunk missing: ${t}`);const c=(await N(o)).toString("utf8");for(const a of c===""?[]:c.split(`
|
|
2
|
+
`)){const i=JSON.parse(a);n.has(i.sequence_number)||n.set(i.sequence_number,i)}}return[...n.values()].sort((t,o)=>t.sequence_number-o.sequence_number)}u(H,"readRunEventChunk");async function A(e,s,n=128){if(!Number.isSafeInteger(n)||n<0)throw new TypeError("limit must be a nonnegative safe integer");if(n===0)return 0;const t=new Date(s-336*60*6e4).toISOString(),o=new Date(s-720*60*6e4).toISOString(),c=_.map(()=>"?").join(", "),a=await(await $()).prepare(`SELECT run_id, sequence_number, body_json FROM run_events
|
|
3
|
+
WHERE ts < ? AND (ts < ? OR type IN (${c})) ORDER BY ts LIMIT ?`).all(t,o,..._,n),i=new Map;for(const r of a){const{first:p,last:d}=I(Number(r.sequence_number)),f=`${r.run_id}
|
|
4
|
+
${p}`,m=i.get(f);m?m.rows.push(r):i.set(f,{runId:r.run_id,first:p,last:d,rows:[r]})}for(const{runId:r,first:p,last:d,rows:f}of i.values()){const m=f.map(E=>E.body_json).join(`
|
|
5
|
+
`),y=v("sha256").update(m).digest("hex").slice(0,32);await e.put(q(r,p,d,y),await D(Buffer.from(m,"utf8")))}return await x(async r=>{const p=r.prepare("DELETE FROM run_events WHERE run_id = ? AND sequence_number = ?");let d=0;for(const f of a)d+=Number((await p.run(f.run_id,f.sequence_number)).changes);return d})}u(A,"archiveExpiredRunEvents");export{A as archiveExpiredRunEvents,z as listRunEventChunks,H as readRunEventChunk};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var
|
|
1
|
+
var p=Object.defineProperty;var o=(r,e)=>p(r,"name",{value:e,configurable:!0});import{randomBytes as N,randomUUID as E}from"node:crypto";import{join as I}from"node:path";import{cancelCronsOnWake as b}from"../canvas/crons.js";import{withCanvasWrite as c,openDb as v}from"../canvas/db.js";import{getRow as k}from"../canvas/canvas.js";import{messagesDir as h}from"../canvas/paths.js";import{settleDeadControllerWait as R,settleMatchingControllerWait as D}from"../canvas/waits.js";import{generateOperationId as S,operationIdContext as T,validateOperationId as A}from"../events/operation-id.js";import{clipBody as O}from"../../shared/inbox-entry-body.js";function u(){let r;do r=N(16).toString("hex");while(r==="00000000000000000000000000000000");return r}o(u,"newId");function x(r,e){const n=JSON.stringify(r);if(n===void 0)throw new TypeError(`${e} must be JSON-serializable`);return n}o(x,"stringify");async function L(r,e){return e!=="normal"&&e!=="deferred"?e:(await k(r))?.lifecycle==="terminal"?"urgent":e}o(L,"effectiveTier");function C(r,e){return I(h(r),`${e.replace(/[^0-9]/g,"")}-${E().slice(0,6)}.md`)}o(C,"overflowBodyPath");function J(r){if(typeof r!="object"||r===null)return"";const e=r.body;return typeof e=="string"?e.trim():""}o(J,"inlineBody");async function y(r,e){const n=e.messageId??u(),t=Number((await r.prepare("UPDATE message_sequence SET seq = seq + 1 WHERE id = 1 RETURNING seq").get()).seq);return await r.prepare(`INSERT INTO messages
|
|
2
2
|
(message_id, seq, operation_id, created_at, sender_node_id, sender_name, kind, label, body_ref, body_json, disposition,
|
|
3
3
|
event, object_id, level, actor_id, cause_message_id, depth)
|
|
4
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(t,
|
|
4
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(n,t,e.operationId,e.createdAt,e.senderNodeId,e.senderName,e.kind,e.label,e.bodyRef,e.bodyJson===void 0?null:x(e.bodyJson,"message body"),e.disposition,e.event?.event??null,e.event?.objectId??null,e.event?.level??null,e.event?.actorId??null,e.causeMessageId??null,e.depth??0),n}o(y,"insertMessage");async function f(r,e,n,t,a,d,s){const i=u();return await r.prepare(`INSERT INTO deliveries
|
|
5
5
|
(delivery_id, message_id, destination_id, urgency, wake, state, idempotency_key, created_at, updated_at)
|
|
6
|
-
VALUES (?, ?, ?, ?, ?, 'pending', ?, ?, ?)`).run(
|
|
7
|
-
FROM deliveries d JOIN messages m ON m.message_id = d.message_id WHERE d.idempotency_key = ?`).get(e.idempotencyKey);if(
|
|
8
|
-
WHERE w.node_id = ? AND w.kind = 'controller' AND w.target_id = ? AND w.satisfied_at IS NULL`).get(r,e);if(a===void 0||a.controller_status==="active"||a.controller_status==="idle")return null;const d=await
|
|
6
|
+
VALUES (?, ?, ?, ?, ?, 'pending', ?, ?, ?)`).run(i,e,n,t,a,s??null,d,d),i}o(f,"insertNodeDelivery");function w(r,e){const n=new Date().toISOString(),t=r.operationId===void 0?T.current()??S():A(r.operationId);let a=r.bodyRef??null,d=r.bodyJson;if(a===null&&e!==null&&r.senderNodeId!=="human"){const s=J(d),i=O(s);i.clipped&&(a=C(e,n),d={...d,body:i.text,body_full:s})}return{createdAt:n,operationId:t,bodyRef:a,bodyJson:d}}o(w,"finalizeNodeMail");async function U(r,e){const n=w(e,r);return await c(async t=>{const a=await t.prepare("SELECT run_id FROM nodes WHERE node_id = ?").get(r);if(a?.run_id&&(await t.prepare("SELECT deleting_at FROM nodes WHERE node_id = ?").get(a.run_id))?.deleting_at)throw new Error("run is deleting");if(e.idempotencyKey!==void 0){const l=await t.prepare(`SELECT d.delivery_id, d.message_id, d.urgency, m.created_at
|
|
7
|
+
FROM deliveries d JOIN messages m ON m.message_id = d.message_id WHERE d.idempotency_key = ?`).get(e.idempotencyKey);if(l!==void 0)return{messageId:l.message_id,deliveryId:l.delivery_id,urgency:l.urgency,createdAt:l.created_at}}const d=Date.now(),s=await L(r,e.urgency),i=await y(t,{messageId:e.messageId,operationId:n.operationId,createdAt:n.createdAt,senderNodeId:e.senderNodeId??null,senderName:e.senderName??null,kind:e.kind,label:e.label,bodyRef:n.bodyRef,bodyJson:n.bodyJson,disposition:e.disposition??null}),_=await f(t,i,r,s,e.wake,d,e.idempotencyKey);return await D(r,e.senderNodeId??null,d,t),await e.withinEnqueue?.(t,i),e.wake===1&&s!=="deferred"&&await g(r),{messageId:i,deliveryId:_,urgency:s,createdAt:n.createdAt}})}o(U,"enqueueNodeMail");function z(r){switch(r){case"interrupt":return{urgency:"critical",wake:1};case"steer":return{urgency:"urgent",wake:1};case"after-turn":return{urgency:"normal",wake:1};case"next-turn":return{urgency:"deferred",wake:0}}}o(z,"listenDeliveryTier");async function m(r,e,n){const t={kind:"update",label:n.label??"notice",bodyJson:{body:n.body},urgency:n.tier,wake:n.wake},a=w(t,e),d=Date.now(),s=await y(r,{operationId:a.operationId,createdAt:a.createdAt,senderNodeId:null,senderName:null,kind:t.kind,label:t.label,bodyRef:a.bodyRef,bodyJson:a.bodyJson,disposition:null}),i=await f(r,s,e,n.tier,n.wake,d);return{messageId:s,deliveryId:i,urgency:n.tier,createdAt:a.createdAt}}o(m,"insertNodeNotice");async function g(r){await c(async e=>{for(const n of await b(r))await m(e,r,{body:`Your cron ${n.name}, next scheduled for ${n.fire_at}, was canceled by this wake. Re-create it if you still need it.`,label:"cron canceled",tier:"normal",wake:1})})}o(g,"consumeDeadlineOnWake");async function V(r,e,n){const t=await m(r,e,n);return n.wake===1&&n.tier!=="deferred"&&await g(e),t}o(V,"queueNodeNotice");async function G(r,e=Date.now()){return Number((await(await v()).prepare("UPDATE deliveries SET canceled_at = ?, updated_at = ? WHERE delivery_id = ? AND canceled_at IS NULL").run(e,e,r)).changes)===1}o(G,"cancelDelivery");async function Y(r,e={}){return await c(async n=>{const t=["d.destination_id = ?","d.canceled_at IS NULL","d.state IN ('pending', 'handed_off')"],a=[r];e.senderNodeId!==void 0&&(t.push("m.sender_node_id IS NOT DISTINCT FROM ?"),a.push(e.senderNodeId)),e.kind!==void 0&&(t.push("m.kind = ?"),a.push(e.kind));const d=await n.prepareUncached(`SELECT d.delivery_id FROM deliveries d JOIN messages m ON m.message_id = d.message_id WHERE ${t.join(" AND ")}`).all(...a);if(d.length===0)return[];const s=Date.now();return await n.prepareUncached(`UPDATE deliveries SET canceled_at = ?, updated_at = ? WHERE delivery_id IN (${d.map(()=>"?").join(",")})`).run(s,s,...d.map(i=>i.delivery_id)),d.map(i=>i.delivery_id)})}o(Y,"cancelPendingNodeMail");async function Q(r,e){return await c(async n=>{const t=Date.now(),a=await n.prepare(`SELECT target.status AS controller_status FROM waits w LEFT JOIN nodes target ON target.node_id = w.target_id
|
|
8
|
+
WHERE w.node_id = ? AND w.kind = 'controller' AND w.target_id = ? AND w.satisfied_at IS NULL`).get(r,e);if(a===void 0||a.controller_status==="active"||a.controller_status==="idle")return null;const d=await U(r,{kind:"urgent",label:"declared controller is no longer live",bodyJson:{body:`Controller ${e} is no longer live; the declared message wait was cleared.`},urgency:"urgent",wake:1});if(!await R(r,e,t,n))throw new Error(`controller wait changed while notifying ${r}`);return d})}o(Q,"enqueueControllerDeathNotice");export{G as cancelDelivery,Y as cancelPendingNodeMail,g as consumeDeadlineOnWake,L as effectiveTier,Q as enqueueControllerDeathNotice,U as enqueueNodeMail,w as finalizeNodeMail,y as insertMessage,z as listenDeliveryTier,u as newId,V as queueNodeNotice};
|
|
@@ -78,6 +78,21 @@ export declare function grantSyncState(grantId: string): Promise<GrantSyncState
|
|
|
78
78
|
export declare function grantSyncStateFor(grantee: string, sub: string): Promise<GrantSyncState | null>;
|
|
79
79
|
/** The mirrored grant `grantId`, whatever its status, or null when the mirror lacks it or the row is unparsable. */
|
|
80
80
|
export declare function grantRecord(grantId: string): Promise<GrantRecord | null>;
|
|
81
|
+
/** How a grant stands for the effects of a change (`grant-effects`): `inactive` is a missing, revoked, removed or expired grant;
|
|
82
|
+
* `lagging` is an active grant whose computed columns do not yet match its revision (it reads as no grant for requests but
|
|
83
|
+
* stops nothing, because the directory's second write completes it). `sub`, `grantee` and `removal_done_at` come from the row
|
|
84
|
+
* even when its computed columns lag; all are null when the row is gone. */
|
|
85
|
+
export interface GrantStanding {
|
|
86
|
+
standing: 'active' | 'inactive' | 'lagging';
|
|
87
|
+
sub: string | null;
|
|
88
|
+
grantee: string | null;
|
|
89
|
+
status: GrantRecord['status'] | null;
|
|
90
|
+
removal_done_at: string | null;
|
|
91
|
+
record: GrantRecord | null;
|
|
92
|
+
}
|
|
93
|
+
export declare function grantStanding(grantId: string): Promise<GrantStanding>;
|
|
94
|
+
/** Ids of the grants in `status` (this runtime's), for a catch-up pass. */
|
|
95
|
+
export declare function grantIdsWhere(where: string): Promise<string[]>;
|
|
81
96
|
/** Who a grant's model calls are charged to: `app` only for a mirrored grant the directory marked app-paid, else the person. */
|
|
82
97
|
export declare function payerOfGrant(grantId: string | null | undefined): Promise<'user' | 'app'>;
|
|
83
98
|
export declare function activeGrant(grantId: string): Promise<ActiveGrant | null>;
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
var
|
|
1
|
+
var T=Object.defineProperty;var r=(e,n)=>T(e,"name",{value:n,configurable:!0});import{createHash as N}from"node:crypto";import{parseScope as O}from"@north-light/identity";import{openDb as d,withCanvasWrite as j}from"../canvas/db.js";import{isUnsandboxedMachine as w}from"../runtime/unsandboxed.js";import{replaceWrittenBy as h,userSubject as A}from"../permissions/facts.js";import{GROUP_TYPE as b}from"../permissions/builtin.js";const R=["not_started","pending","ready","failed","unavailable"],k=["ultra","strong","medium","light"];function D(){const e=process.env.CRTR_RUNTIME;return e?{sql:" AND runtime = ?",args:[e]}:{sql:"",args:[]}}r(D,"runtimeScope");async function u(e,n,t=[]){const s=D();return await(await d()).prepare(`SELECT ${e} FROM grants WHERE ${n}${s.sql}`).all(...t,...s.args)}r(u,"grantRows");async function c(e,n,t=[]){return(await u(e,n,t))[0]}r(c,"grantRow");function l(e){if(!Array.isArray(e))throw new TypeError("grant scopes must be a list");return e.map(n=>{if(!n||typeof n!="object"||typeof n.scope!="string"||!["always","ask"].includes(n.mode))throw new TypeError("invalid grant scope entry");return{scope:n.scope,mode:n.mode}})}r(l,"entries");function C(e){if(!e||typeof e!="object"||Array.isArray(e))return null;const{state:n,message:t,next:s,step:i}=e;return typeof n!="string"||!R.includes(n)||t!==void 0&&typeof t!="string"||i!==void 0&&typeof i!="string"||typeof s!="string"||!s?null:{state:n,...t===void 0?{}:{message:t},next:s,...i===void 0?{}:{step:i}}}r(C,"dependencyOf");function m(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[t,s]of Object.entries(e)){const i=C(s);i&&(n[t]=i)}return n}r(m,"dependenciesOf");function I(e){if(!e||typeof e!="object"||Array.isArray(e))return null;const{base_url:n,rungs:t}=e;if(typeof n!="string"||!n||!t||typeof t!="object"||Array.isArray(t))return null;const s={};for(const i of k){const a=t[i];typeof a=="string"&&a&&(s[i]=a)}return Object.keys(s).length?{base_url:n.replace(/\/+$/,""),rungs:s}:null}r(I,"inferenceEndpointOf");function y(e){if(e.computed_rev!==e.rev||e.scopes_json===null||e.resolved_scopes_json===null)throw new TypeError("grant columns are not computed for this revision");return{id:e.id,runtime:e.runtime,sub:e.sub,grantee:e.grantee,rev:e.rev,scopes:l(JSON.parse(e.scopes_json)),resolved_scopes:l(JSON.parse(e.resolved_scopes_json)),spend_cap:e.spend_cap,expires_at:e.expires_at,status:e.status,revoked_at:e.revoked_at,approved_at:e.approved_at,payer:e.payer,dependencies:m(JSON.parse(e.dependencies_json??"{}")),run_notice_url:e.run_notice_url??null,inference_endpoint:e.inference_endpoint_json?I(JSON.parse(e.inference_endpoint_json)):null,synced_at:e.synced_at??""}}r(y,"record");function p(e){if(!e||e.status!=="active")return null;try{return M(y(e))}catch(n){if(n instanceof TypeError||n instanceof SyntaxError)return null;throw n}}r(p,"active");function g(e){return e.grantee!=="app:terminal"&&w()}r(g,"mirrorOnly");async function B(){return(await F()).filter(e=>!g(e))}r(B,"localGrants");async function F(){return(await u("*","true")).flatMap(e=>{try{return[y(e)]}catch(n){if(n instanceof TypeError||n instanceof SyntaxError)return[];throw n}})}r(F,"allGrants");function L(e){return e.expires_at!==null&&!(Date.parse(e.expires_at)>Date.now())}r(L,"grantExpired");function M(e){if(e.status!=="active"||L(e))return null;try{const n=e.resolved_scopes.map(({scope:t})=>O(t));return{...e,resolved:e.resolved_scopes.flatMap(({mode:t},s)=>t==="always"?[n[s]]:[])}}catch(n){if(n instanceof TypeError||n instanceof SyntaxError)return null;throw n}}r(M,"activeRecord");function v(e){return Array.isArray(e)?`[${e.map(v).join(",")}]`:e&&typeof e=="object"?`{${Object.keys(e).sort().filter(n=>e[n]!==void 0).map(n=>`${JSON.stringify(n)}:${v(e[n])}`).join(",")}}`:JSON.stringify(e)??"null"}r(v,"canonicalJson");function X(e){const n={rev:e.rev,resolved_scopes:e.resolved_scopes,spend_cap:e.spend_cap,payer:e.payer,dependencies:e.dependencies??{},...e.inference_endpoint?{inference_endpoint:e.inference_endpoint}:{}};return N("sha256").update(v(n)).digest("base64url").slice(0,22)}r(X,"grantVersion");async function Y(e){return!!await c("1","id = ?",[e])}r(Y,"hasGrant");async function z(e){return await c("rev, status","id = ?",[e])??null}r(z,"grantSyncState");async function K(e,n){return await c("rev, status","grantee = ? AND sub = ?",[e,n])??null}r(K,"grantSyncStateFor");async function G(e){const n=await c("*","id = ?",[e]);if(!n)return null;try{return y(n)}catch(t){if(t instanceof TypeError||t instanceof SyntaxError)return null;throw t}}r(G,"grantRecord");async function Q(e){const n=await c("*","id = ?",[e]);if(!n)return{standing:"inactive",sub:null,grantee:null,status:null,removal_done_at:null,record:null};const t={sub:n.sub,grantee:n.grantee,status:n.status,removal_done_at:n.removal_done_at??null};if(n.status!=="active")return{...t,standing:"inactive",record:null};if(n.computed_rev!==n.rev)return{...t,standing:"lagging",record:null};const s=p(n);return s===null?{...t,standing:"inactive",record:null}:{...t,standing:"active",record:s}}r(Q,"grantStanding");async function Z(e){return(await u("id",e)).map(n=>n.id)}r(Z,"grantIdsWhere");async function ee(e){return(e?(await G(e))?.payer:null)??"user"}r(ee,"payerOfGrant");async function H(e){return p(await c("*","id = ?",[e]))}r(H,"activeGrant");async function ne(e,n){return p(await c("*","grantee = ? AND sub = ?",[e,n]))}r(ne,"grantFor");async function re(e){if(g({grantee:e}))return null;const n=await u("*","grantee = ? AND status = 'active'",[e]);if(n.length>1)throw new Error(`multiple active grants for ${e}`);return p(n[0])}r(re,"activeGrantForApp");async function te(e){const n=await H(e);return n&&n.run_notice_url&&!g(n)?{url:n.run_notice_url,sub:n.sub,grantee:n.grantee}:null}r(te,"runNoticeTarget");async function se(){const e=await u("*","grantee = 'app:terminal' AND status = 'active'");if(e.length>1)throw new Error("multiple active terminal grants");return p(e[0])}r(se,"terminalGrant");async function ae(){return(await(await d()).prepare("SELECT value FROM runtime_state WHERE key = 'grants_source'").get())?.value??null}r(ae,"grantsSource");async function oe(e){return(await(await d()).prepare("SELECT value FROM runtime_state WHERE key = 'grants_source'").get())?.value===e}r(oe,"hasSyncedGrants");async function ie(e){return(await e.prepare("SELECT value FROM runtime_state WHERE key = 'grants_source'").get())?.value!=="local"?0:(await e.prepare("DELETE FROM runtime_state WHERE key = 'grants_source'").run(),Number((await e.prepare("DELETE FROM grants").run()).changes))}r(ie,"dropLocalGrantMirror");function ce(e){if(e===void 0)return[];if(!Array.isArray(e))throw new TypeError("invalid grant sync response");return e.map(n=>{const{team:t,members:s}=n??{};if(typeof t!="string"||!/^team:\S+$/.test(t)||!Array.isArray(s)||s.some(i=>typeof i!="string"||!/^user:[^\s*]+$/.test(i)))throw new TypeError("invalid grant sync response");return{team:t,members:s}})}r(ce,"teamsOf");async function ue(e,n,t,s=[]){const i=new Set;for(const a of e){if(i.has(a.id)||!a.id||!a.runtime||!a.sub||!a.grantee||!Number.isInteger(a.rev)||!["active","revoked","removed"].includes(a.status))throw new TypeError("invalid grant sync response");i.add(a.id),l(a.scopes),l(a.resolved_scopes)}await j(async a=>{let _=0;const f=[...i];_+=Number((await(f.length?a.prepareUncached(`DELETE FROM grants WHERE id NOT IN (${f.map(()=>"?").join(",")})`).run(...f):a.prepareUncached("DELETE FROM grants").run())).changes);const E=a.prepare(`INSERT INTO grants
|
|
2
2
|
(id, runtime, sub, grantee, rev, scopes_json, resolved_scopes_json, spend_cap, expires_at,
|
|
3
|
-
status, revoked_at, approved_at, payer, dependencies_json, run_notice_url, inference_endpoint_json, synced_at)
|
|
4
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
|
3
|
+
status, revoked_at, approved_at, payer, dependencies_json, run_notice_url, inference_endpoint_json, synced_at, computed_rev)
|
|
4
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
5
|
+
ON CONFLICT (id) DO UPDATE SET runtime = excluded.runtime, sub = excluded.sub, grantee = excluded.grantee, rev = excluded.rev,
|
|
6
|
+
scopes_json = excluded.scopes_json, resolved_scopes_json = excluded.resolved_scopes_json, spend_cap = excluded.spend_cap,
|
|
7
|
+
expires_at = excluded.expires_at, status = excluded.status, revoked_at = excluded.revoked_at, approved_at = excluded.approved_at,
|
|
8
|
+
removal_done_at = CASE WHEN excluded.status = 'removed' AND grants.status = 'removed' THEN grants.removal_done_at END,
|
|
9
|
+
payer = excluded.payer, dependencies_json = excluded.dependencies_json, run_notice_url = excluded.run_notice_url,
|
|
10
|
+
inference_endpoint_json = excluded.inference_endpoint_json, synced_at = excluded.synced_at, computed_rev = excluded.computed_rev
|
|
11
|
+
WHERE (grants.runtime, grants.sub, grants.grantee, grants.rev, grants.scopes_json, grants.resolved_scopes_json, grants.spend_cap,
|
|
12
|
+
grants.expires_at, grants.status, grants.revoked_at, grants.approved_at, grants.payer, grants.dependencies_json,
|
|
13
|
+
grants.run_notice_url, grants.inference_endpoint_json, grants.computed_rev)
|
|
14
|
+
IS DISTINCT FROM (excluded.runtime, excluded.sub, excluded.grantee, excluded.rev, excluded.scopes_json, excluded.resolved_scopes_json,
|
|
15
|
+
excluded.spend_cap, excluded.expires_at, excluded.status, excluded.revoked_at, excluded.approved_at, excluded.payer,
|
|
16
|
+
excluded.dependencies_json, excluded.run_notice_url, excluded.inference_endpoint_json, excluded.computed_rev)`);for(const o of e)_+=Number((await E.run(o.id,o.runtime,o.sub,o.grantee,o.rev,JSON.stringify(o.scopes),JSON.stringify(o.resolved_scopes),o.spend_cap,o.expires_at,o.status,o.revoked_at,o.approved_at,o.payer,JSON.stringify(m(o.dependencies)),o.run_notice_url??null,o.inference_endpoint?JSON.stringify(o.inference_endpoint):null,o.synced_at,o.rev)).changes);await h(a,"directory",b,"member",s.flatMap(({team:o,members:x})=>x.map(S=>({resourceId:o,subject:A(S)})))),await a.prepare("INSERT INTO runtime_state (key, value) VALUES ('grants_source', ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(t),_>0&&await a.prepare("INSERT INTO runtime_state (key, value) VALUES ('grants_generation', '1') ON CONFLICT(key) DO UPDATE SET value = CAST(CAST(runtime_state.value AS INTEGER) + 1 AS TEXT)").run()})}r(ue,"replaceGrants");async function pe(){const e=await(await d()).prepare("SELECT value FROM runtime_state WHERE key = 'grants_generation'").get();return e?Number(e.value):0}r(pe,"grantsGeneration");export{H as activeGrant,re as activeGrantForApp,M as activeRecord,F as allGrants,m as dependenciesOf,ie as dropLocalGrantMirror,L as grantExpired,ne as grantFor,Z as grantIdsWhere,G as grantRecord,Q as grantStanding,z as grantSyncState,K as grantSyncStateFor,X as grantVersion,pe as grantsGeneration,ae as grantsSource,Y as hasGrant,oe as hasSyncedGrants,I as inferenceEndpointOf,B as localGrants,g as mirrorOnly,ee as payerOfGrant,ue as replaceGrants,te as runNoticeTarget,ce as teamsOf,se as terminalGrant};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { SandboxRecord } from '../../launcher/spec.js';
|
|
2
|
-
import { type GrantRecord } from './mirror.js';
|
|
3
2
|
/** Work that outlives the sync that started it; the daemon keeps ownership of it during shutdown. */
|
|
4
3
|
export type Detach = (work: Promise<void>) => void;
|
|
5
4
|
/** Why a sandbox must stop under the current mirror, or null when every
|
|
@@ -8,6 +7,10 @@ export declare function exceeds(sandbox: Pick<SandboxRecord, 'uid' | 'nodeId' |
|
|
|
8
7
|
app: string;
|
|
9
8
|
status: string;
|
|
10
9
|
}>): Promise<string | null>;
|
|
10
|
+
/** After a confirmed revocation stop: the node waits for its next message,
|
|
11
|
+
* whose broker gets the current mounts (runtime spec §15), and its run reads
|
|
12
|
+
* idle rather than running. */
|
|
13
|
+
export declare function afterRevocationStop(nodeId: string): Promise<void>;
|
|
11
14
|
/** R26 from current state (runtime spec §15 "Ending revoked file access"):
|
|
12
15
|
* compare every live launcher sandbox's launched mounts with what the current
|
|
13
16
|
* mirror grants, and stop each one that holds more. Runs after every sync and
|
|
@@ -16,7 +19,8 @@ export declare function exceeds(sandbox: Pick<SandboxRecord, 'uid' | 'nodeId' |
|
|
|
16
19
|
export declare function sweepSandboxes(): Promise<{
|
|
17
20
|
completion: Promise<void>;
|
|
18
21
|
}>;
|
|
19
|
-
/** R26
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
|
|
22
|
+
/** R26 after a sync replaced the grant mirror (runtime spec §15): stop the launcher sandboxes that now hold more than the mirror
|
|
23
|
+
* grants. Everything else a grant change causes (waking `grant.get` holds, closing streams, discarding tokens, stopping the
|
|
24
|
+
* grant's nodes, the removal cascade, provider bundles) is done by the `grant:<id>` handlers of `daemon/reconcilers/grant-effects.ts`,
|
|
25
|
+
* which the sync's row writes fire. Resolves once the stops have started; their completion continues as detached work. */
|
|
26
|
+
export declare function onGrantSync(detach?: Detach): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var v=Object.defineProperty;var d=(o,e)=>v(o,"name",{value:e,configurable:!0});import{relative as b,sep as g}from"node:path";import{runningJobs as x}from"../graph/jobs.js";import{appSpace as y}from"../layout.js";import{getNode as f,recordSettledTurn as h}from"../canvas/index.js";import{transition as S}from"../runtime/lifecycle.js";import{openDb as l}from"../canvas/db.js";import{emitEvent as m}from"../events/emit.js";import{grantedMounts as E,isGrantedSource as R,mountAllowed as k}from"../spaces/mounts.js";import{permissionsForRun as w}from"../spaces/permissions.js";import{stopNodeSandboxes as I}from"../spaces/stop.js";import{activeGrantForApp as P}from"./mirror.js";import{launcherPresent as A,listSandboxes as C,stopSandboxPid as F}from"./sandboxes.js";import{checkCronFire as M}from"../../daemon/cron/authority.js";import{cronExecutionFor as N}from"../../daemon/cron/live-runs.js";import{cronExecutionsReady as O}from"../../daemon/cron/run-socket.js";import{flatMapAsync as T}from"../async-array.js";import{personId as W}from"../canvas/person.js";async function _(){return new Map((await(await l()).prepare("SELECT uid, app, status FROM app_users").all()).map(o=>[o.uid,{app:o.app,status:o.status}]))}d(_,"appUserOwners");async function D(o,e){e??=await _();const n=e.get(o.uid),p=o.nodeId.startsWith("cron-"),a=p?N(o.nodeId.slice(5)):void 0;if(p&&(a===void 0||!n))return"permission_revoked";if(a!==void 0&&n.status==="active"){const r=await M({grantee:a.grantee,sub:a.sub,grant_id:a.grantId,scopes:a.scopes});if(!r.allowed)return a.refusal??={reason:r.reason,message:r.message},"permission_revoked"}if(!n||n.app==="app:terminal")return null;if(n.status!=="active")return"app_removed";const t=await f(o.nodeId);try{let r;if(a!==void 0)r=await w(a.grantee,a.sub,a.grantId,a.scopes);else if(t&&t.grantee===n.app)r=await w(n.app,t.sub??W(),t.grant_id??null,t.scopes??null);else{const i=await P(n.app);if(!i)return"permission_revoked";r=await w(n.app,i.sub,i.id,null)}const c=E(r),u=y(n.app).root;return o.mounts.every(i=>{const s=b(u,i.source);return s===""||s!==".."&&!s.startsWith(`..${g}`)&&!s.startsWith(g)||!R(n.app,i.source)||k(i,c)})?null:"permission_revoked"}catch{return"permission_revoked"}}d(D,"exceeds");async function G(o){const e=await f(o);if(!e)return;(e.status==="active"||e.status==="idle")&&await S(o,"release");const n=new Date().toISOString();await h(o,n),e.run_id&&e.run_id!==o&&await(await l()).prepare("UPDATE nodes SET last_settled_at = COALESCE(last_settled_at, ?) WHERE node_id = ?").run(n,e.run_id)}d(G,"afterRevocationStop");async function L(o){const e=new Set,n=await f(o);n?.pi_pid!=null&&e.add(n.pi_pid);for(const p of await x(await l(),o))p.pgid!==null&&e.add(p.pgid);return e}d(L,"nodePids");async function U(){if(!A())return{completion:Promise.resolve()};await O();const o=await C(),e=await _(),n=await T(o,async t=>{const r=await D(t,e);return r?[{sandbox:t,reason:r}]:[]}),p=[],a=new Map;for(const t of n){m({level:"info",event:"daemon.grants.sandbox_stop",fields:{sandbox_node:t.sandbox.nodeId,pid:t.sandbox.pid,grantee:e.get(t.sandbox.uid).app,reason:t.reason}});const r=a.get(t.sandbox.nodeId)??[];r.push(t),a.set(t.sandbox.nodeId,r)}for(const[t,r]of a){const c=await f(t),u=c?await L(t):new Set,i=c!==null&&r.some(({sandbox:s})=>u.has(s.pid));p.push((async()=>{if(i){const s=await I(t,"permission_revoked",{holdRecovery:!0,after:d(()=>G(t),"after")});if(!s.confirmed)throw s.error??new Error(`stop of ${t} was not confirmed`)}for(const{sandbox:s}of r)(!i||!u.has(s.pid))&&await F(s.pid)})().catch(s=>{m({level:"error",event:"daemon.grants.sandbox_stop_failed",...c?{node_id:t}:{fields:{sandbox_node:t}},error:s})}))}return{completion:Promise.all(p).then(()=>{})}}d(U,"sweepSandboxes");async function se(o=e=>{}){try{const{completion:e}=await U();o(e)}catch(e){m({level:"error",event:"daemon.grants.sweep_failed",error:e})}}d(se,"onGrantSync");export{G as afterRevocationStop,D as exceeds,se as onGrantSync,U as sweepSandboxes};
|
|
@@ -1,7 +1,2 @@
|
|
|
1
|
-
/** Run the removal cascade for every `removed` grant whose app still has an
|
|
2
|
-
* active OS-user row, and once for each app in `transitions` (its grant became
|
|
3
|
-
* `removed` at this sync) even with no row. Serialized; each cascade is
|
|
4
|
-
* idempotent and marks the row `removed` last, so an interrupted one resumes. */
|
|
5
|
-
export declare function runRemovalCascades(transitions?: ReadonlySet<string>): Promise<void>;
|
|
6
1
|
/** Runtime spec §15 "On removal" (design flow 10). Audit and usage rows stay. */
|
|
7
|
-
export declare function removeApp(app: string): Promise<void>;
|
|
2
|
+
export declare function removeApp(app: string, sub?: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var _=Object.defineProperty;var E=(r,o)=>_(r,"name",{value:o,configurable:!0});import{rmSync as v}from"node:fs";import{join as S}from"node:path";import{deleteNodes as h}from"../canvas/canvas.js";import{withCanvasWrite as c,openDb as d}from"../canvas/db.js";import{cancelCron as O}from"../canvas/crons.js";import{emitEvent as p}from"../events/emit.js";import{appSpace as T,appsRoot as w,secretsDir as C}from"../layout.js";import{notifyRunDeleted as D}from"../runs/events.js";import{cancelOpenQuestions as L}from"../runs/questions.js";import{removeTreeBeneath as W}from"../spaces/open-beneath.js";import{markGranteeUploadsDeletePending as F,releaseRunUploads as H,turnSharesOffFor as N}from"../storage/tables.js";import{stopNodeSandboxes as M}from"../spaces/stop.js";import{activeAppUser as $,markAppUserRemoved as y}from"../spaces/users.js";import{launcherRequest as A}from"../../launcher/client.js";import{LaunchRefused as U}from"../../launcher/spec.js";import{localGrants as q}from"./mirror.js";import{launcherPresent as u,listSandboxes as I,stopSandboxPid as P}from"./sandboxes.js";import{filterAsync as B}from"../async-array.js";async function se(r,o){if(r==="app:terminal")throw new Error("app:terminal cannot be removed");const m=T(r),s=o===void 0||!(await q()).some(e=>e.grantee===r&&e.sub!==o&&e.status!=="removed"),i=s?await $(r):null;p({level:"info",event:"daemon.grants.removal_started",fields:{grantee:r,...o===void 0?{}:{sub:o},uid:i?.uid??null}});const t=o===void 0?{sql:"grantee = ?",args:[r]}:{sql:"grantee = ? AND sub = ?",args:[r,o]};for(const{node_id:e}of await(await d()).prepare(`SELECT node_id FROM node_rows WHERE ${t.sql} ORDER BY created DESC`).all(...t.args))await L({node_id:e},"the app was removed");const a=await c(async e=>(await e.prepare(`UPDATE nodes SET deleting_at = COALESCE(deleting_at, ?) WHERE node_id IN (SELECT node_id FROM node_rows WHERE ${t.sql})`).run(new Date().toISOString(),...t.args),(await e.prepare(`SELECT node_id FROM node_rows WHERE ${t.sql} ORDER BY created DESC`).all(...t.args)).map(n=>n.node_id)));for(const{cron_id:e}of await(await d()).prepare(`SELECT cron_id FROM crons WHERE ${t.sql}`).all(...t.args))await O(e);const l=(await Promise.all(a.map(e=>M(e,"app_removed",{deleting:!0})))).filter(e=>!e.confirmed);if(l.length)throw new Error(`sandbox teardown could not be confirmed for ${l.length} node(s) of ${r}`);if(i&&u())for(const e of await I())e.uid===i.uid&&await P(e.pid);const R=await B(a,async e=>(await(await d()).prepare("SELECT run_id FROM nodes WHERE node_id = ?").get(e))?.run_id===e);await c(async e=>{if(s&&await N(r,e),await H(a,e),s&&await F(r,e),!a.length)return;const n=a.map(()=>"?").join(","),g=await e.prepareUncached(`SELECT message_id FROM messages WHERE sender_node_id IN (${n}) UNION SELECT message_id FROM deliveries WHERE destination_id IN (${n})`).all(...a,...a);await e.prepareUncached(`DELETE FROM deliveries WHERE destination_id IN (${n})`).run(...a);for(const{message_id:f}of g)await e.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(f,f)}),await h(a);for(const e of R)D(e);if(s&&(v(S(C(),"env",m.root.slice(w().length+1)),{recursive:!0,force:!0}),W(w(),m.root)),i&&u())try{await A({operation:"user.delete",uid:i.uid})}catch(e){if(!(e instanceof U&&e.refusal==="invalid_uid"))throw e}i&&await y(i.uid),p({level:"info",event:"daemon.grants.removal_completed",fields:{grantee:r,...o===void 0?{}:{sub:o},uid:i?.uid??null,nodes:a.length}})}E(se,"removeApp");export{se as removeApp};
|
package/dist/core/grants/sync.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var b=Object.defineProperty;var n=(e,r)=>b(e,"name",{value:r,configurable:!0});import{createPrivateKey as E,randomUUID as S,sign as j}from"node:crypto";import{readFileSync as x}from"node:fs";import{join as $}from"node:path";import{crtrHome as T}from"../canvas/paths.js";import{isUnsandboxedMachine as g}from"../runtime/unsandboxed.js";import{emitEvent as p}from"../events/emit.js";import{describeOutboundFailure as A,outboundFetch as v,outboundJson as h,outboundRefusal as k}from"../events/outbound.js";import{dependenciesOf as O,inferenceEndpointOf as P,replaceGrants as N,teamsOf as R}from"./mirror.js";import{onGrantSync as G}from"./on-sync.js";import{adoptInstallPerson as J}from"../scoped-state/migrate.js";import{PersonOutsideRequestError as B,PersonUnresolvedError as D,personId as F,resolvePerson as I,retireLocalPerson as M,setPersonId as U}from"../canvas/person.js";const ae=300;function q(e,r){const t=Math.floor(Date.now()/1e3),o=Buffer.from(JSON.stringify({alg:"ES256",typ:"JWT",kid:e.kid})).toString("base64url"),d=Buffer.from(JSON.stringify({iss:e.client_id,sub:e.client_id,aud:r,iat:t,exp:t+300,jti:S()})).toString("base64url"),i=`${o}.${d}`,s=j("sha256",Buffer.from(i),{key:E({key:e.jwk,format:"jwk"}),dsaEncoding:"ieee-p1363"});return`${i}.${s.toString("base64url")}`}n(q,"assertion");function y(){const e=JSON.parse(x($(T(),"secrets","runtime-client.json"),"utf8"));if(!e.jwk||e.alg!=="ES256"||!e.kid||!e.client_id||!e.runtime||e.jwk.kid!==e.kid||e.jwk.kty!=="EC"||e.jwk.crv!=="P-256"||!e.jwk.d)throw new TypeError("invalid runtime client key");return e}n(y,"runtimeClient");function ce(e=y()){return e.runtime.startsWith("runtime:")?e.runtime.slice(8):e.runtime}n(ce,"runtimeId");function C(e){return`This machine was removed from your Northlight account. To use it again, create a join token at ${e.replace(/\/$/,"")}/account/machines, and run \`crtr sys join\` from a plain terminal.`}n(C,"machineRevokedMessage");class w extends Error{static{n(this,"MachineRevokedError")}constructor(r){super(C(r)),this.name="MachineRevokedError"}}async function L(e,r){const t=y(),o=`${e.replace(/\/$/,"")}/token`,d=new URLSearchParams({grant_type:"client_credentials",client_id:t.client_id,client_assertion_type:"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",client_assertion:q(t,o),...r===void 0?{}:{audience:r}}),i=await v("directory_token",o,{method:"POST",body:d,signal:AbortSignal.timeout(1e4)});if(!i.ok)throw i.status===401&&g()&&await W(i)?new w(e):k("directory_token",o,`directory token request failed: ${i.status}`);const s=await h("directory_token",o,i);if(typeof s.access_token!="string")throw new TypeError("directory token response has no access_token");return{access_token:s.access_token,expires_at:z(s.access_token,s.expires_in)}}n(L,"mintDirectoryToken");async function W(e){try{return(await e.json()).error==="invalid_client"}catch{return!1}}n(W,"isInvalidClient");function z(e,r){if(typeof r=="number"&&Number.isFinite(r)&&r>0)return Date.now()+r*1e3;try{const t=JSON.parse(Buffer.from(e.split(".")[1]??"","base64url").toString("utf8"));if(typeof t.exp=="number")return t.exp*1e3}catch{}return Date.now()+3e5}n(z,"tokenExpiry");function H(e,r){if(!e||typeof e!="object")throw new TypeError("invalid grant sync response");const t=e,o=r.runtime.startsWith("runtime:")?r.runtime:`runtime:${r.runtime}`;if(!(t.runtime===o||g()&&typeof t.runtime=="string"&&t.runtime.startsWith("runtime:")&&t.grantee!=="app:terminal")||typeof t.id!="string"||typeof t.sub!="string"||typeof t.grantee!="string"||!Number.isInteger(t.rev)||!Array.isArray(t.scopes)||!Array.isArray(t.resolved_scopes)||!["active","revoked","removed"].includes(t.status??"")||typeof t.synced_at!="string")throw new TypeError("invalid grant sync response");const s=e.revisions?.find(a=>a.rev===t.rev)?.approved_at;if(typeof s!="string")throw new TypeError("grant revision has no approval time");const l=t.payer==="app"?"app":"user";return{...t,spend_cap:t.spend_cap??null,expires_at:t.expires_at??null,revoked_at:t.revoked_at??null,approved_at:s,payer:l,dependencies:O(t.dependencies),inference_endpoint:l==="app"?P(t.inference_endpoint):null,run_notice_url:typeof t.run_notice_url=="string"&&t.run_notice_url!==""?t.run_notice_url:null}}n(H,"responseGrant");async function K(){try{F();return}catch(t){if(t instanceof B)return;if(!(t instanceof D))throw t}const e=await I();if(e===null)return;U(e.id),await J(e.id);const r=await M();p({level:"info",event:"daemon.person.resolved",fields:{person_id:e.id,source:e.source}}),p({level:"info",event:"daemon.person.retired",fields:{person_id:r.person,retired:r.retired,columns:r.columns}})}n(K,"resolveLatePerson");let _;function ue(e){return _?_(e):Promise.resolve()}n(ue,"requestGrantSync");function de(e,r=t=>{}){let t;const o=e.replace(/\/$/,""),d=n(async()=>{const a=y(),c=await L(o),f=await v("grant_sync",`${o}/v1/runtime/grants`,{headers:{Authorization:`Bearer ${c.access_token}`},signal:AbortSignal.timeout(1e4)});if(!f.ok)throw k("grant_sync",`${o}/v1/runtime/grants`,`directory grant sync failed: ${f.status}`);const u=await h("grant_sync",`${o}/v1/runtime/grants`,f);if(!Array.isArray(u.grants)||typeof u.synced_at!="string")throw new TypeError("invalid grant sync response");await N(u.grants.map(m=>H(m,a)),u.synced_at,o,R(u.teams)),p({level:"info",event:"daemon.grants.synced",fields:{grants:u.grants.length,synced_at:u.synced_at}}),await K();try{await G(r)}catch(m){p({level:"error",event:"daemon.grants.on_sync_failed",error:m})}},"run");let i;const s=n(()=>{const a=d().catch(c=>{throw c instanceof w?p({level:"error",event:"daemon.grants.machine_revoked",error:c}):p({level:"error",event:"daemon.grants.sync_failed",error:c,fields:A(c)}),c}).finally(()=>{t===a&&(t=void 0)});return t=a,a},"start"),l=n((a={})=>t?a.fresh?(i??=t.catch(()=>{}).then(()=>(i=void 0,t??s())),i):t:s(),"sync");return _=l,l}n(de,"createGrantSync");export{ae as GRANT_SYNC_INTERVAL_S,w as MachineRevokedError,q as assertion,de as createGrantSync,C as machineRevokedMessage,L as mintDirectoryToken,ue as requestGrantSync,y as runtimeClient,ce as runtimeId};
|