@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,11 +1,11 @@
|
|
|
1
|
-
var
|
|
1
|
+
var H=Object.defineProperty;var c=(n,e)=>H(n,"name",{value:e,configurable:!0});import{randomBytes as W}from"node:crypto";import{CrtrError as T}from"../errors.js";import{PersonUnresolvedError as g,PersonOutsideRequestError as A,setPersonId as y,markCloudRole as b,isCloudRole as D,runAsPerson as v,personId as $,bootPersonId as k,requestPersonId as C}from"./person-state.js";import{readConfig as j}from"../config.js";import{joinedIssuer as M,joinedOwner as S}from"../directory/join.js";import{installLocalTerminalGrant as F}from"../grants/local.js";import{dropLocalGrantMirror as x}from"../grants/mirror.js";import{ownerForGrantee as G,ensureOwner as J}from"../graph/objects.js";import{canvasDatabaseUrl as q,CanvasConstraintError as B,withCanvasWrite as h}from"./db.js";import{LEGACY_LOCAL_PERSON as E,LEGACY_LOCAL_TERMINAL_GRANT as Y}from"./legacy-person.js";import{rebuildTotalsFor as z}from"../ledger/totals.js";const l="person_id",O="local_person_retired",K=/^user:[A-Za-z0-9._-]+$/,I="abcdefghijklmnopqrstuvwxyz0123456789",L=new Map;async function Te(){const n=C();if(n!==void 0)return n;if(D())throw new A;const e=k();if(e!==void 0)return e;const r=await q(),t=L.get(r);if(t!==void 0)return t;const a=await Z();if(a===null)throw new g;return L.set(r,a),a}c(Te,"personIdAsync");function X(){const n=W(12);let e="user:";for(let r=0;r<12;r++)e+=I[n[r]%I.length];return e}c(X,"mintPersonId");async function m(n,e){return(await n.prepare("SELECT value FROM canvas_meta WHERE key = ?").get(e))?.value??null}c(m,"readMeta");async function d(n,e,r){await n.prepare("INSERT INTO canvas_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(e,r)}c(d,"writeMeta");async function V(){return await h(async n=>{const e=await m(n,l);if(e!==null)return{id:e,source:"stored"};const r=S();if(r!==null)return await d(n,l,r),{id:r,source:"joined"};if(j("user").runtime?.issuer){const a=await n.prepare("SELECT DISTINCT sub FROM grants").all();return a.length!==1?null:(await d(n,l,a[0].sub),{id:a[0].sub,source:"grants"})}const t=X();return await d(n,l,t),{id:t,source:"minted"}})}c(V,"resolvePerson");async function Z(){return(await V())?.id??null}c(Z,"resolvePersonId");const o=c(n=>Number(n.changes),"changes"),Q=[["nodes","sub"],["node_tokens","sub"],["grants","sub"],["crons","sub"],["audit_rows","sub"],["provider_approvals","sub"],["audit_rows","grantee"],["run_events","grantee"],["node_tokens","grantee"],["uploads","grantee"],["provider_approvals","grantee"]],ee=["profiles","profile_defaults","scope_settings","scope_bookkeeping","scope_marketplaces","scope_plugins","person_settings","model_accounts","model_account_cooldowns","model_api_keys","model_settings","model_sign_in_flows","env_vars"],ne=[["charges","sub"],["charges","payer"],["charges","grantee"],["limits","payer"],["limits","sub"],["limits","grantee"]];function P(n,e){if(!K.test(e))throw new T("invalid_person",`${n} must be a user:<id> principal, got ${JSON.stringify(e)}`)}c(P,"assertPerson");async function re(n,e){return await n.prepare("SELECT 1 AS found FROM charge_totals WHERE payer = ? OR sub = ? OR grantee = ? UNION ALL SELECT 1 FROM charge_chunks WHERE payer = ? LIMIT 1").get(e,e,e,e)!==void 0}c(re,"namesPerson");async function U(n,e,r){if(P("from",e),P("to",r),e===r)throw new T("invalid_person","cannot substitute a person with itself");const t={};try{t.identities=o(await n.prepare("UPDATE identities SET scheme = 'user', external_id = ? WHERE scheme IN ('local-user', 'user') AND external_id = ?").run(r,e))}catch(s){throw s instanceof B?new T("person_conflict",`another person object already holds ${r}; merging two person objects is not supported (${s.message})`,void 0,{from:e,to:r}):s}t["daemon_actions.principal_sub"]=o(await n.prepare(`UPDATE daemon_actions SET adapter_json = jsonb_set(adapter_json::jsonb, '{principal,sub}', to_jsonb(?::text))::text
|
|
2
2
|
WHERE state IN ('pending', 'handed_off') AND adapter_json::jsonb ->> 'adapter' = 'cron_spawn'
|
|
3
|
-
AND adapter_json::jsonb #>> '{principal,sub}' = ?`).run(r,
|
|
3
|
+
AND adapter_json::jsonb #>> '{principal,sub}' = ?`).run(r,e));for(const[s,i]of Q)t[`${s}.${i}`]=o(await n.prepareUncached(`UPDATE ${s} SET ${i} = ? WHERE ${i} = ?`).run(r,e));t["idempotency_keys.grantee"]=o(await n.prepare("DELETE FROM idempotency_keys WHERE grantee = ? AND key IN (SELECT key FROM idempotency_keys WHERE grantee = ?)").run(e,r))+o(await n.prepare("UPDATE idempotency_keys SET grantee = ? WHERE grantee = ?").run(r,e));const a=e.replace(/^user:/,""),p=r.replace(/^user:/,"");t["relations.subject_id"]=o(await n.prepare(`DELETE FROM relations r WHERE r.subject_type = 'user' AND r.subject_id = ?
|
|
4
4
|
AND EXISTS (SELECT 1 FROM relations n WHERE n.subject_type = 'user' AND n.subject_id = ? AND n.resource_type = r.resource_type
|
|
5
|
-
AND n.resource_id = r.resource_id AND n.relation = r.relation AND n.subject_relation = r.subject_relation)`).run(a,p))+
|
|
6
|
-
WHERE o.type = 'node' AND i.scheme = 'local-user' AND i.external_id = '${
|
|
5
|
+
AND n.resource_id = r.resource_id AND n.relation = r.relation AND n.subject_relation = r.subject_relation)`).run(a,p))+o(await n.prepare("UPDATE relations SET subject_id = ? WHERE subject_type = 'user' AND subject_id = ?").run(p,a)),t["relations.written_by"]=o(await n.prepare("UPDATE relations SET written_by = ? WHERE written_by = ?").run(r,e)),t["revisions.acting_for"]=o(await n.prepare("UPDATE revisions SET acting_for = ? WHERE acting_for = ?").run(r,e));for(const[s,i]of ne)t[`${s}.${i}`]=o(await n.prepareUncached(`UPDATE ${s} SET ${i} = ? WHERE ${i} = ?`).run(r,e));for(const s of ee){const u=o(await n.prepareUncached(`DELETE FROM ${s} WHERE person = ? AND EXISTS (SELECT 1 FROM ${s} WHERE person = ?)`).run(e,r))+o(await n.prepareUncached(`UPDATE ${s} SET person = ? WHERE person = ?`).run(r,e));u!==0&&(t[`${s}.person`]=u)}return(Object.entries(t).some(([s,i])=>s.startsWith("charges.")&&i!==0)||await re(n,e))&&(await z(n,e,r),t["charge_totals.rebuilt"]=1),t}c(U,"substitutePerson");async function te(n){const e=`SELECT o.id FROM objects o JOIN identities i ON i.object = o.owner JOIN nodes n ON n.node_id = o.id
|
|
6
|
+
WHERE o.type = 'node' AND i.scheme = 'local-user' AND i.external_id = '${E}'`;return(await n.prepareUncached(`${e} LIMIT 1`).get()!==void 0?o(await n.prepareUncached(`UPDATE objects SET owner = ? WHERE id IN (${e})`).run((await G(n,"app:terminal")).id)):0)+o(await n.prepare("UPDATE node_tokens SET grantee = 'app:terminal' WHERE grantee = ?").run(E))+o(await n.prepare("UPDATE run_events SET grantee = 'app:terminal' WHERE grantee = ?").run(E))+o(await n.prepare("DELETE FROM idempotency_keys WHERE grantee = ? AND key IN (SELECT key FROM idempotency_keys WHERE grantee = 'app:terminal')").run(E))+o(await n.prepare("UPDATE idempotency_keys SET grantee = 'app:terminal' WHERE grantee = ?").run(E))}c(te,"rewriteLegacyGrantees");async function ae(n,e,r){const t=[Y,`terminal:${e}`].filter(i=>i!==r),a=t.map(()=>"?").join(", "),p={};p["nodes.grant_id"]=o(await n.prepareUncached(`UPDATE nodes SET grant_id = ? WHERE grant_id IN (${a})`).run(r,...t)),p["node_tokens.grant"]=o(await n.prepareUncached(`UPDATE node_tokens SET "grant" = ? WHERE "grant" IN (${a})`).run(r,...t)),p["crons.grant_id"]=o(await n.prepareUncached(`UPDATE crons SET grant_id = ? WHERE grant_id IN (${a})`).run(r,...t));const s=r===null?"'null'::jsonb":"to_jsonb(?::text)";return p["daemon_actions.principal_grant_id"]=o(await n.prepareUncached(`UPDATE daemon_actions SET adapter_json = jsonb_set(adapter_json::jsonb, '{principal,grant_id}', ${s})::text
|
|
7
7
|
WHERE state IN ('pending', 'handed_off') AND adapter_json::jsonb ->> 'adapter' = 'cron_spawn'
|
|
8
|
-
AND adapter_json::jsonb #>> '{principal,grant_id}' IN (${a})`).run(...r===null?[]:[r],...t)),p}
|
|
9
|
-
WHERE o.type = 'node' AND o.reception = 2 AND s.envelope_json ->> 'app' IS NULL AND i.scheme = 'app' AND i.external_id = 'app:terminal'`;if(await
|
|
8
|
+
AND adapter_json::jsonb #>> '{principal,grant_id}' IN (${a})`).run(...r===null?[]:[r],...t)),p}c(ae,"repointGrantReferences");async function ge(){const n=await h(async e=>{const r={},t=c((_,w="")=>{for(const[N,R]of Object.entries(_))R!==0&&(r[w+N]=(r[w+N]??0)+R)},"add");let a=await m(e,l);if(a===null)throw new g;let p=null;const s=S();s!==null&&s!==a&&(t(await U(e,a,s),"join."),await d(e,l,s),p=a,a=s);const i=M()??j("user").runtime?.issuer,u=await m(e,"install_id");if(u===null)throw new Error("retireLocalPerson: the install id is not stored");const f=await m(e,O)!==a;if(f){t({legacy_grantees:await te(e)}),t(await U(e,E,a));const _=`SELECT o.id FROM objects o JOIN peer_stubs s ON s.object = o.id JOIN identities i ON i.object = o.owner
|
|
9
|
+
WHERE o.type = 'node' AND o.reception = 2 AND s.envelope_json ->> 'app' IS NULL AND i.scheme = 'app' AND i.external_id = 'app:terminal'`;if(await e.prepareUncached(`${_} LIMIT 1`).get()!==void 0){const w=await J(e,"person","user",a,"user");t({repaired_stubs:o(await e.prepareUncached(`UPDATE objects SET owner = ? WHERE id IN (${_})`).run(w.id))})}t({"nodes.sub_null_terminal":o(await e.prepare(`UPDATE nodes SET sub = ? WHERE sub IS NULL AND node_id IN (
|
|
10
10
|
SELECT n.node_id FROM nodes n JOIN identities i ON i.object = n.app
|
|
11
|
-
WHERE i.scheme = 'app' AND i.external_id = 'app:terminal')`).run(a))}),t(await
|
|
11
|
+
WHERE i.scheme = 'app' AND i.external_id = 'app:terminal')`).run(a))}),t(await ae(e,u,i?null:`terminal:${u}`)),i&&t({local_grant_mirror:await x(e)}),await d(e,O,a)}return i||await F(u,a),{person:a,joinedFrom:p,retired:f,columns:r}});return y(n.person),n}c(ge,"retireLocalPerson");export{E as LEGACY_LOCAL_PERSON,A as PersonOutsideRequestError,g as PersonUnresolvedError,D as isCloudRole,b as markCloudRole,$ as personId,Te as personIdAsync,V as resolvePerson,Z as resolvePersonId,ge as retireLocalPerson,v as runAsPerson,y as setPersonId,U as substitutePerson};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** A claim owner is a fresh token for each attempt, not a process id: a timed-out worker cannot renew a successor's claim. */
|
|
2
|
+
export interface ReconcilerLease {
|
|
3
|
+
cursor: string | null;
|
|
4
|
+
}
|
|
5
|
+
/** Claim an unowned or expired lane/key; retain its cursor across owner changes. */
|
|
6
|
+
export declare function claimReconcilerLease(lane: string, key: string, owner: string, ttlMs: number): Promise<ReconcilerLease | undefined>;
|
|
7
|
+
/** Only the still-current claim may extend its lifetime. */
|
|
8
|
+
export declare function renewReconcilerLease(lane: string, key: string, owner: string, ttlMs: number): Promise<boolean>;
|
|
9
|
+
/** An expired owner cannot advance the cursor. Cursor changes and row work that require exact-once must share a transaction. */
|
|
10
|
+
export declare function advanceReconcilerCursor(lane: string, key: string, owner: string, cursor: string | null): Promise<boolean>;
|
|
11
|
+
/** Release only the current claim, preserving its cursor for the next worker. */
|
|
12
|
+
export declare function releaseReconcilerLease(lane: string, key: string, owner: string): Promise<boolean>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
var u=Object.defineProperty;var a=(e,r)=>u(e,"name",{value:r,configurable:!0});import{openDb as i}from"./db.js";function c(e){if(!Number.isFinite(e)||e<=0)throw new Error("reconciler lease duration must be positive");return new Date(Date.now()+e).toISOString()}a(c,"expiry");async function E(e,r,n,t){const o=c(t),s=new Date().toISOString();return(await i()).prepare(`INSERT INTO reconciler_leases (lane, key, owner, expires_at)
|
|
2
|
+
VALUES (?, ?, ?, ?)
|
|
3
|
+
ON CONFLICT (lane, key) DO UPDATE SET owner = EXCLUDED.owner, expires_at = EXCLUDED.expires_at
|
|
4
|
+
WHERE reconciler_leases.expires_at <= ?
|
|
5
|
+
RETURNING cursor`).get(e,r,n,o,s)}a(E,"claimReconcilerLease");async function S(e,r,n,t){const o=c(t),s=new Date().toISOString();return(await(await i()).prepare(`UPDATE reconciler_leases SET expires_at = ?
|
|
6
|
+
WHERE lane = ? AND key = ? AND owner = ? AND expires_at > ?`).run(o,e,r,n,s)).changes===1}a(S,"renewReconcilerLease");async function N(e,r,n,t){return(await(await i()).prepare(`UPDATE reconciler_leases SET cursor = ?
|
|
7
|
+
WHERE lane = ? AND key = ? AND owner = ? AND expires_at > ?`).run(t,e,r,n,new Date().toISOString())).changes===1}a(N,"advanceReconcilerCursor");async function x(e,r,n){return(await(await i()).prepare(`UPDATE reconciler_leases SET expires_at = ?
|
|
8
|
+
WHERE lane = ? AND key = ? AND owner = ? AND expires_at > ?`).run(new Date(0).toISOString(),e,r,n,new Date().toISOString())).changes===1}a(x,"releaseReconcilerLease");export{N as advanceReconcilerCursor,E as claimReconcilerLease,x as releaseReconcilerLease,S as renewReconcilerLease};
|
|
@@ -105,11 +105,15 @@ export interface PendingProviderRetry {
|
|
|
105
105
|
fault: StoredFault;
|
|
106
106
|
/** When the fault row last changed (ISO) — the daemon's anchor for "due". */
|
|
107
107
|
updatedAt: string;
|
|
108
|
+
/** When a reconciler last claimed this fault for a nudge (ISO), or null. */
|
|
109
|
+
nudgedAt: string | null;
|
|
108
110
|
}
|
|
109
111
|
/** Every node with an active daemon-retried provider fault (connection,
|
|
110
112
|
* rate-limit, overloaded) and a pending episode on its live session binding.
|
|
111
113
|
* The daemon backstop reads this to find retries whose broker timer died. */
|
|
112
114
|
export declare function listPendingProviderRetries(): Promise<PendingProviderRetry[]>;
|
|
115
|
+
/** Claim one nudge of a fault: only the caller whose conditional UPDATE changes the row may send it, and a later claim waits out `graceMs`. */
|
|
116
|
+
export declare function claimFaultNudge(faultId: string, nowMs: number, graceMs: number): Promise<boolean>;
|
|
113
117
|
export declare function beginBootFaultAttempt(nodeId: string): Promise<BootFaultAttempt>;
|
|
114
118
|
/** Import legacy witness and recovery files inside the parent's one shared consolidation transaction. */
|
|
115
119
|
/** v98 — `notified_since` on a fault row: the episode start its fatal notice was published for.
|
|
@@ -23,4 +23,4 @@ CREATE TABLE IF NOT EXISTS node_faults (
|
|
|
23
23
|
);
|
|
24
24
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_node_faults_active ON node_faults(node_id) WHERE active = 1;
|
|
25
25
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_node_faults_episode ON node_faults(node_id) WHERE episode_state IS NOT NULL;
|
|
26
|
-
`)}o(me,"createFaultTable");function g(e,t){return typeof t=="string"&&e.includes(t)}o(g,"contains");function W(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}o(W,"isRecord");function q(e){if(!W(e)||typeof e.provider!="string"||e.provider===""||typeof e.model!="string"||e.model==="")return;const t=typeof e.status=="number"&&Number.isFinite(e.status)?e.status:void 0,n=typeof e.code=="string"||typeof e.code=="number"?e.code:void 0,r=typeof e.errno=="string"?e.errno:void 0,i=typeof e.body=="string"?e.body:void 0,a=le(e.ratelimit),d=Array.isArray(e.causes)?e.causes.flatMap(s=>{if(!W(s))return[];const E={...typeof s.message=="string"?{message:s.message}:{},...typeof s.status=="number"&&Number.isFinite(s.status)?{status:s.status}:{},...typeof s.code=="string"||typeof s.code=="number"?{code:s.code}:{},...typeof s.errno=="string"?{errno:s.errno}:{},...typeof s.body=="string"?{body:s.body}:{}};return Object.keys(E).length===0?[]:[E]}):void 0;return{provider:e.provider,model:e.model,...t===void 0?{}:{status:t},...n===void 0?{}:{code:n},...r===void 0?{}:{errno:r},...i===void 0?{}:{body:i},...d===void 0||d.length===0?{}:{causes:d},...a===void 0?{}:{ratelimit:a}}}o(q,"parseProviderError");function V(e){try{const t=JSON.parse(e);if(!g(fe,t.link)||typeof t.op!="string"||t.op===""||!g(ye,t.kind)||typeof t.message!="string"||typeof t.since!="string")return null;const n=Y(t.operation_id);if(!W(t.retry)||!g(Te,t.retry.disposition)||t.retry.by!==void 0&&!g(Ne,t.retry.by)||t.retry.attempt!==void 0&&typeof t.retry.attempt!="number"||t.retry.max!==void 0&&typeof t.retry.max!="number"||t.retry.nextAt!==void 0&&typeof t.retry.nextAt!="string"||t.anchorEntryId!==void 0&&(typeof t.anchorEntryId!="string"||t.anchorEntryId===""))return null;const r=t.providerError===void 0?void 0:q(t.providerError);return t.providerError!==void 0&&r===void 0?null:{link:t.link,op:t.op,kind:t.kind,retry:{disposition:t.retry.disposition,...t.retry.by===void 0?{}:{by:t.retry.by},...t.retry.attempt===void 0?{}:{attempt:t.retry.attempt},...t.retry.max===void 0?{}:{max:t.retry.max},...t.retry.nextAt===void 0?{}:{nextAt:t.retry.nextAt}},message:t.message,since:t.since,operation_id:n,...t.anchorEntryId===void 0?{}:{anchorEntryId:t.anchorEntryId},...r===void 0?{}:{providerError:r}}}catch{return null}}o(V,"parseLegacyFault");function Ae(e){const t=_e(e);try{return ue(t)}catch{return t}}o(Ae,"canonicalPath");function Se(e){try{const t=JSON.parse(e);if(!g(ge,t.state)||typeof t.sessionFile!="string"||t.sessionFile==="")return null;const n=JSON.stringify(t.fault),r=V(n);if(r===null||r.link!=="pi\u2192provider"||r.retry.disposition!=="auto"||r.retry.by!=="daemon")return null;const i=t.anchorEntryId;return i!==null&&typeof i!="string"||(r.anchorEntryId??null)!==i?null:{state:t.state,sessionFile:Ae(t.sessionFile),fault:r}}catch{return null}}o(Se,"parseLegacyEpisode");function Q(e){return e!==void 0?Y(e):K.current()??K.fresh(n=>n)}o(Q,"resolveOperationId");function xe(e){return e.slice(0,Ee)}o(xe,"clampMessage");function w(e){return e.link==="pi\u2192provider"&&e.retry.disposition==="auto"&&e.retry.by==="daemon"?3:e.retry.disposition==="fatal"?2:1}o(w,"faultPriority");function z(e){return{link:e.link,op:e.op,kind:e.kind,message:e.message,since:e.since,operationId:e.operation_id,anchorEntryId:e.anchorEntryId??null,retryDisposition:e.retry.disposition,retryBy:e.retry.by??null,retryAttempt:e.retry.attempt??null,retryMax:e.retry.max??null,retryNextAt:e.retry.nextAt??null,providerError:e.providerError===void 0?null:JSON.stringify(e.providerError)}}o(z,"encodeFault");function b(e){const t=e.provider_error_json,n=typeof t=="string"?q(JSON.parse(t)):void 0;if(typeof t=="string"&&n===void 0)throw new Error(`invalid provider error on stored fault ${e.fault_id}`);const r={disposition:e.retry_disposition,...e.retry_by===null?{}:{by:e.retry_by},...e.retry_attempt===null?{}:{attempt:e.retry_attempt},...e.retry_max===null?{}:{max:e.retry_max},...e.retry_next_at===null?{}:{nextAt:e.retry_next_at}};return{faultId:e.fault_id,link:e.link,op:e.op,kind:e.kind,message:e.message,since:e.since,operation_id:e.operation_id,retry:r,...e.anchor_entry_id===null?{}:{anchorEntryId:e.anchor_entry_id},...n===void 0?{}:{providerError:n},...typeof e.notified_since=="string"?{notifiedSince:e.notified_since}:{}}}o(b,"hydrateFault");async function L(e,t){const n=await e.prepare("SELECT * FROM node_faults WHERE node_id = ? AND active = 1").get(t);return n===void 0?null:b(n)}o(L,"activeFault");function P(e){if(!g(G,e.link))throw new Error(`fault link is not durable: ${e.link}`);return{link:e.link,op:e.op,kind:e.kind,retry:e.retry,message:xe(e.message),since:e.since??u(),operation_id:Q(e.operation_id),...typeof e.anchorEntryId=="string"&&e.anchorEntryId!==""?{anchorEntryId:e.anchorEntryId}:{},...e.providerError===void 0?{}:{providerError:e.providerError}}}o(P,"storedFault");function M(e,t){J({level:t.retry.disposition==="fatal"?"error":"warn",event:"fault.recorded",operation_id:t.operation_id,node_id:e,error_class:B(t),fields:{link:t.link,op:t.op,kind:t.kind,retry:t.retry,message:t.message,...t.anchorEntryId===void 0?{}:{anchor_entry_id:t.anchorEntryId},...t.providerError===void 0?{}:{provider_error:t.providerError}}})}o(M,"emitRecordedFault");const Z="INSERT INTO node_faults (fault_id, node_id, link, op, kind, message, since, operation_id, anchor_entry_id, retry_disposition, retry_by, retry_attempt, retry_max, retry_next_at, provider_error_json, active, episode_state, episode_binding_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";function ee(e,t,n,r,i){const a=z(n),d=u();return[e,t,a.link,a.op,a.kind,a.message,a.since,a.operationId,a.anchorEntryId,a.retryDisposition,a.retryBy,a.retryAttempt,a.retryMax,a.retryNextAt,a.providerError,r?1:0,i?.state??null,i?.bindingId??null,d,d]}o(ee,"faultInsertParams");async function te(e,t,n,r,i){const a=I();return await e.prepare(Z).run(...ee(a,t,n,r,i)),{...n,faultId:a}}o(te,"insertFault");async function D(e,t,n,r){const i=z(n);return await e.prepare("UPDATE node_faults SET link = ?, op = ?, kind = ?, message = ?, since = ?, operation_id = ?, anchor_entry_id = ?, retry_disposition = ?, retry_by = ?, retry_attempt = ?, retry_max = ?, retry_next_at = ?, provider_error_json = ?, episode_state = COALESCE(?, episode_state), episode_binding_id = COALESCE(?, episode_binding_id), updated_at = ? WHERE fault_id = ?").run(i.link,i.op,i.kind,i.message,i.since,i.operationId,i.anchorEntryId,i.retryDisposition,i.retryBy,i.retryAttempt,i.retryMax,i.retryNextAt,i.providerError,r?.state??null,r?.bindingId??null,u(),t),{...n,faultId:t}}o(D,"updateFault");async function U(e,t){await e.prepare("DELETE FROM node_faults WHERE fault_id = ? AND active = 0 AND episode_state IS NULL").run(t)}o(U,"deleteIfUnretained");async function ne(e,t,n,r){const i=await L(e,t);if(i===null){const a=await e.prepare("SELECT fault_id, link, kind, since, operation_id FROM node_faults WHERE node_id = ? AND active = 0 AND episode_state IS NOT NULL").get(t);return a!==void 0&&a.link===n.link&&a.kind===n.kind&&a.since===n.since&&a.operation_id===n.operation_id?(await e.prepare("UPDATE node_faults SET active = 1, updated_at = ? WHERE fault_id = ?").run(u(),a.fault_id),await D(e,a.fault_id,n)):await te(e,t,n,!0,r)}if(i.link===n.link&&i.kind===n.kind){const a=n.retry.disposition==="auto"?{...i.retry,...n.retry}:n.retry,d=i.retry.disposition===n.retry.disposition&&(n.retry.disposition!=="fatal"||i.message===n.message),s=d?i.since:n.since,E=await D(e,i.faultId,{...n,since:s,anchorEntryId:n.anchorEntryId??i.anchorEntryId,retry:a},r);return d||await e.prepare("UPDATE node_faults SET notified_since = NULL WHERE fault_id = ?").run(i.faultId),E}return i.link!==n.link&&w(i)>w(n)?null:(await e.prepare("UPDATE node_faults SET active = 0, updated_at = ? WHERE fault_id = ?").run(u(),i.faultId),await U(e,i.faultId),await te(e,t,n,!0,r))}o(ne,"replaceActiveFault");async function m(e,t,n){return(await e.prepare("SELECT binding_id FROM sessions WHERE node_id = ? AND session_id = ? AND unbound_at IS NULL").get(t,n))?.binding_id??null}o(m,"liveBinding");async function Xe(e,t){return await l(async n=>{const r=u();return(await n.prepare("UPDATE executions SET turn_progress_at = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(r,e)).changes>0?!0:(await n.prepare("UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = NULL, turn_end_reason = NULL WHERE execution_id = ? AND state != 'exited'").run(r,r,e)).changes>0})}o(Xe,"openTurn");async function $e(e){return(await(await p()).prepare("UPDATE executions SET turn_progress_at = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(u(),e)).changes>0}o($e,"recordTurnProgress");async function je(e,t){return await l(async n=>{const r=u(),i=(await n.prepare("UPDATE executions SET turn_closed_at = ?, turn_end_reason = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(r,t.endReason,e)).changes>0;if(i&&t.endReason==="settled"){const a="(SELECT node_id FROM executions WHERE execution_id = ?)";t.viewerPresent===!0?await n.prepare(`UPDATE nodes SET reply_at = ?, read_at = ? WHERE node_id = ${a}`).run(r,r,e):await n.prepare(`UPDATE nodes SET reply_at = ? WHERE node_id = ${a}`).run(r,e)}return i})}o(je,"closeTurn");async function Be(e){return(await(await p()).prepare("UPDATE nodes SET read_at = ? WHERE node_id = ?").run(u(),e)).changes>0}o(Be,"markNodeRead");async function Je(e,t){if(!Number.isInteger(t.consecutivePasses)||t.consecutivePasses<1||t.routes.length===0||!t.routes.every(n=>n!==""))throw new Error("invalid transport-poison verdict");return(await(await p()).prepare("UPDATE executions SET exit_diagnostic_json = ? WHERE execution_id = ? AND state != 'exited'").run(JSON.stringify({schema:"crtr.execution-exit-diagnostic/v1",transport_poison:{consecutive_passes:t.consecutivePasses,routes:t.routes}}),e)).changes>0}o(Je,"recordTransportPoisonVerdict");async function Ke(e){const t=await(await p()).prepare("SELECT exit_diagnostic_json FROM executions WHERE node_id = ? ORDER BY seq DESC LIMIT 1").get(e);if(t===void 0||t.exit_diagnostic_json===null)return null;try{const n=JSON.parse(t.exit_diagnostic_json),r=n.transport_poison;return n.schema!=="crtr.execution-exit-diagnostic/v1"||r===void 0||!Number.isInteger(r.consecutive_passes)||r.consecutive_passes<1||!Array.isArray(r.routes)||r.routes.length===0||!r.routes.every(i=>typeof i=="string"&&i!=="")?null:{consecutivePasses:r.consecutive_passes,routes:r.routes}}catch{return null}}o(Ke,"readTransportPoisonVerdict");async function Ye(e){const t=await(await p()).prepare("SELECT turn_open_at, turn_closed_at, turn_progress_at FROM executions WHERE node_id = ? AND state != 'exited'").get(e);return t===void 0?null:{busy:t.turn_open_at!==null&&t.turn_closed_at===null,progressAt:t.turn_progress_at}}o(Ye,"readLiveTurn");async function Ge(e){const t=await p(),n=await t.prepare("SELECT turn_closed_at, turn_progress_at FROM executions WHERE node_id = ? AND turn_open_at IS NOT NULL ORDER BY seq DESC LIMIT 1").get(e);if(n===void 0)return null;const r=await t.prepare("SELECT turn_end_reason FROM executions WHERE node_id = ? ORDER BY seq DESC LIMIT 1").get(e);return{interrupted:n.turn_closed_at===null||r?.turn_end_reason==="teardown-aborted",progressAt:n.turn_progress_at}}o(Ge,"readInterruptedTurn");async function qe(e){return await(await p()).prepare("SELECT 1 FROM executions WHERE node_id = ? AND turn_open_at IS NOT NULL LIMIT 1").get(e)!==void 0}o(qe,"hasAdmittedTurn");async function Ve(e,t){const n=P(t);return M(e,n),await l(async r=>await ne(r,e,n))}o(Ve,"recordFault");async function Qe(e){return await l(async t=>(await t.prepare("UPDATE node_faults SET notified_since = since, updated_at = ? WHERE fault_id = ?").run(u(),e)).changes>0)}o(Qe,"markFaultNotified");function Re(e){return e.link==="pi\u2192provider"&&e.retry.disposition==="fatal"&&e.notifiedSince!==e.since}o(Re,"isUnnotifiedFatalProviderFault");async function ze(){return(await(await p()).prepare("SELECT f.node_id FROM node_faults f JOIN nodes n ON n.node_id = f.node_id WHERE f.active = 1 AND f.link = 'pi\u2192provider' AND f.retry_disposition = 'fatal' AND (f.notified_since IS NULL OR f.notified_since != f.since) AND n.status IN ('active', 'idle')").all()).map(e=>e.node_id)}o(ze,"listUnnotifiedFatalFaultNodes");let X=null;function Ze(e){X=e}o(Ze,"setFatalFaultAnnouncer");async function et(e,t){const n=await L(await p(),e);return n===null||t?.link!==void 0&&n.link!==t.link?!1:await l(async r=>{const i=await L(r,e);if(i===null||t?.link!==void 0&&i.link!==t.link)return!1;X!==null&&Re(i)&&await X(e);const a=await r.prepare("SELECT episode_state FROM node_faults WHERE fault_id = ?").get(i.faultId);await r.prepare("UPDATE node_faults SET active = 0, updated_at = ? WHERE fault_id = ?").run(u(),i.faultId),a.episode_state==="pending"&&t?.preserveEpisode!==!0&&await r.prepare("UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE fault_id = ?").run(u(),i.faultId),await U(r,i.faultId);const d=Q();return J({level:"info",event:"fault.cleared",operation_id:d,node_id:e,error_class:B(i),fields:{cleared_fault_operation_id:i.operation_id,link:i.link,op:i.op,kind:i.kind,retry:i.retry,message:i.message,since:i.since,...i.anchorEntryId===void 0?{}:{anchor_entry_id:i.anchorEntryId}}}),!0})}o(et,"clearFault");async function re(e){return await L(await p(),e)}o(re,"readFault");async function tt(e,t){const n=P(t.input);if(n.link!=="pi\u2192provider"||n.retry.disposition!=="auto"||n.retry.by!=="daemon")throw new Error("provider retry episode requires an automatic daemon provider fault");return M(e,n),await l(async r=>{const i=await m(r,e,t.sessionId);if(i===null)return null;const a=await L(r,e);if(a!==null&&(a.link!==n.link||a.kind!==n.kind)&&w(a)>w(n))return null;const d=await r.prepare("SELECT fault_id FROM node_faults WHERE node_id = ? AND episode_state IS NOT NULL").all(e);await r.prepare("UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE node_id = ? AND episode_state IS NOT NULL").run(u(),e);for(const E of d)await U(r,E.fault_id);const s=await ne(r,e,n,{state:"pending",bindingId:i});return s===null?null:(await r.prepare("UPDATE node_faults SET episode_state = ?, episode_binding_id = ?, updated_at = ? WHERE fault_id = ?").run("pending",i,u(),s.faultId),s)})}o(tt,"recordPendingEpisode");async function nt(e,t){return await l(async n=>{if(await n.prepare("SELECT 1 FROM nodes WHERE node_id = ? AND intent = 'refresh'").get(e)!==void 0)return!1;const r=await m(n,e,t.sessionId);return r===null?!1:(await n.prepare("UPDATE node_faults SET episode_state = 'admitted', retry_disposition = ?, retry_by = ?, retry_attempt = ?, retry_max = ?, retry_next_at = ?, updated_at = ? WHERE node_id = ? AND fault_id = ? AND episode_state = 'pending' AND episode_binding_id = ?").run(t.retry.disposition,t.retry.by??null,t.retry.attempt??null,t.retry.max??null,t.retry.nextAt??null,u(),e,t.faultId,r)).changes>0})}o(nt,"admitEpisode");async function rt(e,t){const n=P(t.fault);return await l(async r=>{const i=await m(r,e,t.sessionId);return i===null||(await L(r,e))?.faultId!==t.faultId||await r.prepare("SELECT 1 FROM node_faults WHERE node_id = ? AND fault_id = ? AND episode_state = 'admitted' AND episode_binding_id = ?").get(e,t.faultId,i)===void 0?!1:(M(e,n),t.reopen?await D(r,t.faultId,n,{state:"pending",bindingId:i}):(await D(r,t.faultId,n),await r.prepare("UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE fault_id = ?").run(u(),t.faultId),await r.prepare("UPDATE node_faults SET notified_since = NULL WHERE fault_id = ?").run(t.faultId)),!0)})}o(rt,"settleRejectedEpisode");async function it(e,t){return await l(async n=>{const r=await m(n,e,t.sessionId);return r===null?!1:(await n.prepare("UPDATE node_faults SET episode_state = 'pending', updated_at = ? WHERE node_id = ? AND episode_state = 'admitted' AND episode_binding_id = ?").run(u(),e,r)).changes>0})}o(it,"reopenEpisode");async function ot(e,t){return await l(async n=>{const r=await m(n,e,t.sessionId);return r===null?!1:(await n.prepare("UPDATE node_faults SET episode_state = 'invalidated', updated_at = ? WHERE node_id = ? AND episode_state != 'invalidated' AND episode_state IS NOT NULL AND episode_binding_id = ?").run(u(),e,r)).changes>0})}o(ot,"invalidateEpisode");async function at(e,t){return await l(async n=>{const r=await m(n,e,t.sessionId);if(r===null)return!1;const i=await n.prepare("SELECT fault_id FROM node_faults WHERE node_id = ? AND episode_binding_id = ? AND episode_state IS NOT NULL").all(e,r);if(i.length===0)return!1;await n.prepare("UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE node_id = ? AND episode_binding_id = ? AND episode_state IS NOT NULL").run(u(),e,r);for(const a of i)await U(n,a.fault_id);return!0})}o(at,"clearEpisode");async function st(e){const t=await(await p()).prepare("SELECT f.*, s.session_id FROM node_faults f JOIN sessions s ON s.binding_id = f.episode_binding_id WHERE f.node_id = ? AND f.episode_state IS NOT NULL").get(e);return t===void 0?null:{state:t.episode_state,sessionId:t.session_id,fault:b(t)}}o(st,"readEpisode");async function dt(){return(await(await p()).prepare("SELECT f.*, s.session_id AS bound_session_id FROM node_faults f JOIN sessions s ON s.binding_id = f.episode_binding_id WHERE f.active = 1 AND f.episode_state = 'pending' AND s.unbound_at IS NULL AND s.session_id IS NOT NULL AND f.link = 'pi\u2192provider' AND f.retry_disposition = 'auto' AND f.retry_by = 'daemon' AND f.kind IN ('connection', 'rate-limit', 'overloaded')").all()).map(t=>({nodeId:t.node_id,sessionId:t.bound_session_id,fault:b(t),updatedAt:t.updated_at}))}o(dt,"listPendingProviderRetries");async function ut(e){const t=await re(e)===null;return{async explanation(){if(!t)return null;const n=await re(e);if(n===null||n.link!=="crtr\u2192pi"||n.retry.disposition!=="fatal")return null;const r=n.op.trim(),i=n.message.trim();return r===""||i===""?null:`${r}: ${i}`}}}o(ut,"beginBootFaultAttempt");function ie(e,t){try{return ce(e).mtime.toISOString()}catch{return t}}o(ie,"markerMtime");function $(e,t){if(!f(e))return null;try{return de(e,"utf8")}catch(n){if(!t)return null;throw new Error(`cannot import recovery input ${e}: ${n.message}`)}}o($,"legacyFile");function Ie(e,t){return _(e,"SELECT execution_id, started_at FROM executions WHERE node_id = ? ORDER BY rowid DESC LIMIT 1").get(t)??null}o(Ie,"latestExecution");function we(e,t){const r=H(e,"nodes").has("launched_at")?_(e,"SELECT COALESCE(launched_at, created) AS started_at FROM nodes WHERE node_id = ?").get(t):_(e,"SELECT created AS started_at FROM nodes WHERE node_id = ?").get(t);if(r===void 0)throw new Error(`cannot import recovery witness for unknown node ${t}`);const i=I();return _(e,"INSERT INTO executions (execution_id, node_id, daemon_epoch, pid, process_identity, state, started_at, ended_at, exit_reason) VALUES (?, ?, NULL, NULL, NULL, 'exited', ?, ?, 'pre-consolidation')").run(i,t,r.started_at,r.started_at),{execution_id:i,started_at:r.started_at}}o(we,"syntheticExecution");function oe(e,t,n,r,i){const a=I();return _(e,Z).run(...ee(a,t,n,r,i)),{...n,faultId:a}}o(oe,"insertMigratedFault");function De(e,t,n,r){const i=_(e,"SELECT binding_id, node_id FROM sessions WHERE transcript_path = ? AND unbound_at IS NULL").get(n);if(i!==void 0){if(i.node_id!==t)throw new Error(`cannot import provider retry ${r}: transcript is live-owned by ${i.node_id}`);return i.binding_id}const a=_(e,"SELECT binding_id FROM sessions WHERE node_id = ? AND transcript_path = ? ORDER BY rowid DESC LIMIT 1").get(t,n);if(a!==void 0)return a.binding_id;const d=_(e,"SELECT created FROM nodes WHERE node_id = ?").get(t);if(d===void 0)throw new Error(`cannot import provider retry ${r}: unknown node ${t}`);const s=I();return _(e,"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, ?, ?, NULL, NULL, ?, ?, ?)").run(s,t,n,d.created,d.created,u()),s}o(De,"migrationBinding");function ct(e){e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'node_faults'").get()!==void 0&&(H(e,"node_faults").has("notified_since")||e.exec("ALTER TABLE node_faults ADD COLUMN notified_since TEXT"))}o(ct,"addFaultNotifiedSince");function _t(e){if(Le(e),me(e),!f(C()))return;const t=se(C(),{withFileTypes:!0}).filter(r=>r.isDirectory()).sort((r,i)=>r.name.localeCompare(i.name)),n=_(e,"SELECT 1 FROM nodes WHERE node_id = ?");for(const r of t){const i=r.name,a=pe(i),d=N(a,"busy"),s=N(a,"clean-abort"),E=N(a,"transport-poison.json"),O=N(a,"fault"),A=N(a,"provider-retry"),h=f(d),k=f(s);if(!h&&!k&&!f(E)&&!f(O)&&!f(A)||!f(N(C(),i,"meta.json"))&&n.get(i)===void 0)continue;const v=$(E,!1),S=$(O,!0),x=$(A,!0);if(!h&&!k&&v===null&&S===null&&x===null)continue;let y=Ie(e,i);if(y===null&&(y=we(e,i)),h){const c=ie(d,y.started_at);_(e,"UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = NULL, turn_end_reason = NULL WHERE execution_id = ?").run(c,c,y.execution_id)}else if(k){const c=ie(s,y.started_at);_(e,"UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = ?, turn_end_reason = 'teardown-aborted' WHERE execution_id = ?").run(c,c,c,y.execution_id)}if(v!==null)try{const c=JSON.parse(v);Number.isInteger(c.consecutivePasses)&&c.consecutivePasses>=1&&Array.isArray(c.routes)&&c.routes.length>0&&c.routes.every(j=>typeof j=="string"&&j!=="")&&_(e,"UPDATE executions SET exit_diagnostic_json = ? WHERE execution_id = ?").run(JSON.stringify({schema:"crtr.execution-exit-diagnostic/v1",transport_poison:{consecutive_passes:c.consecutivePasses,routes:c.routes}}),y.execution_id)}catch{}const R=S===null?null:V(S);if(S!==null&&R===null)throw new Error(`cannot import recovery fault ${O}`);const T=x===null?null:Se(x);if(x!==null&&T===null)throw new Error(`cannot import provider retry ${A}`);let F=R===null||R.link==="broker\u2194crtrd"?null:oe(e,i,R,!0);if(T!==null){const c=De(e,i,T.sessionFile,A);F!==null&&F.since===T.fault.since?_(e,"UPDATE node_faults SET episode_state = ?, episode_binding_id = ?, updated_at = ? WHERE fault_id = ?").run(T.state,c,u(),F.faultId):oe(e,i,T.fault,!1,{state:T.state,bindingId:c})}}}o(_t,"migrateRecoveryWitnesses");export{Me as FAULT_QUIET_MS,ct as addFaultNotifiedSince,nt as admitEpisode,ut as beginBootFaultAttempt,at as clearEpisode,et as clearFault,je as closeTurn,qe as hasAdmittedTurn,b as hydrateFault,ot as invalidateEpisode,dt as listPendingProviderRetries,ze as listUnnotifiedFatalFaultNodes,Qe as markFaultNotified,Be as markNodeRead,_t as migrateRecoveryWitnesses,Xe as openTurn,q as parseProviderError,st as readEpisode,re as readFault,Ge as readInterruptedTurn,Ye as readLiveTurn,Ke as readTransportPoisonVerdict,Ve as recordFault,tt as recordPendingEpisode,Je as recordTransportPoisonVerdict,$e as recordTurnProgress,it as reopenEpisode,Ze as setFatalFaultAnnouncer,rt as settleRejectedEpisode};
|
|
26
|
+
`)}o(me,"createFaultTable");function g(e,t){return typeof t=="string"&&e.includes(t)}o(g,"contains");function W(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}o(W,"isRecord");function q(e){if(!W(e)||typeof e.provider!="string"||e.provider===""||typeof e.model!="string"||e.model==="")return;const t=typeof e.status=="number"&&Number.isFinite(e.status)?e.status:void 0,n=typeof e.code=="string"||typeof e.code=="number"?e.code:void 0,r=typeof e.errno=="string"?e.errno:void 0,i=typeof e.body=="string"?e.body:void 0,a=le(e.ratelimit),d=Array.isArray(e.causes)?e.causes.flatMap(s=>{if(!W(s))return[];const E={...typeof s.message=="string"?{message:s.message}:{},...typeof s.status=="number"&&Number.isFinite(s.status)?{status:s.status}:{},...typeof s.code=="string"||typeof s.code=="number"?{code:s.code}:{},...typeof s.errno=="string"?{errno:s.errno}:{},...typeof s.body=="string"?{body:s.body}:{}};return Object.keys(E).length===0?[]:[E]}):void 0;return{provider:e.provider,model:e.model,...t===void 0?{}:{status:t},...n===void 0?{}:{code:n},...r===void 0?{}:{errno:r},...i===void 0?{}:{body:i},...d===void 0||d.length===0?{}:{causes:d},...a===void 0?{}:{ratelimit:a}}}o(q,"parseProviderError");function V(e){try{const t=JSON.parse(e);if(!g(fe,t.link)||typeof t.op!="string"||t.op===""||!g(ye,t.kind)||typeof t.message!="string"||typeof t.since!="string")return null;const n=Y(t.operation_id);if(!W(t.retry)||!g(Te,t.retry.disposition)||t.retry.by!==void 0&&!g(Ne,t.retry.by)||t.retry.attempt!==void 0&&typeof t.retry.attempt!="number"||t.retry.max!==void 0&&typeof t.retry.max!="number"||t.retry.nextAt!==void 0&&typeof t.retry.nextAt!="string"||t.anchorEntryId!==void 0&&(typeof t.anchorEntryId!="string"||t.anchorEntryId===""))return null;const r=t.providerError===void 0?void 0:q(t.providerError);return t.providerError!==void 0&&r===void 0?null:{link:t.link,op:t.op,kind:t.kind,retry:{disposition:t.retry.disposition,...t.retry.by===void 0?{}:{by:t.retry.by},...t.retry.attempt===void 0?{}:{attempt:t.retry.attempt},...t.retry.max===void 0?{}:{max:t.retry.max},...t.retry.nextAt===void 0?{}:{nextAt:t.retry.nextAt}},message:t.message,since:t.since,operation_id:n,...t.anchorEntryId===void 0?{}:{anchorEntryId:t.anchorEntryId},...r===void 0?{}:{providerError:r}}}catch{return null}}o(V,"parseLegacyFault");function Ae(e){const t=_e(e);try{return ue(t)}catch{return t}}o(Ae,"canonicalPath");function Se(e){try{const t=JSON.parse(e);if(!g(ge,t.state)||typeof t.sessionFile!="string"||t.sessionFile==="")return null;const n=JSON.stringify(t.fault),r=V(n);if(r===null||r.link!=="pi\u2192provider"||r.retry.disposition!=="auto"||r.retry.by!=="daemon")return null;const i=t.anchorEntryId;return i!==null&&typeof i!="string"||(r.anchorEntryId??null)!==i?null:{state:t.state,sessionFile:Ae(t.sessionFile),fault:r}}catch{return null}}o(Se,"parseLegacyEpisode");function Q(e){return e!==void 0?Y(e):K.current()??K.fresh(n=>n)}o(Q,"resolveOperationId");function Re(e){return e.slice(0,Ee)}o(Re,"clampMessage");function w(e){return e.link==="pi\u2192provider"&&e.retry.disposition==="auto"&&e.retry.by==="daemon"?3:e.retry.disposition==="fatal"?2:1}o(w,"faultPriority");function z(e){return{link:e.link,op:e.op,kind:e.kind,message:e.message,since:e.since,operationId:e.operation_id,anchorEntryId:e.anchorEntryId??null,retryDisposition:e.retry.disposition,retryBy:e.retry.by??null,retryAttempt:e.retry.attempt??null,retryMax:e.retry.max??null,retryNextAt:e.retry.nextAt??null,providerError:e.providerError===void 0?null:JSON.stringify(e.providerError)}}o(z,"encodeFault");function b(e){const t=e.provider_error_json,n=typeof t=="string"?q(JSON.parse(t)):void 0;if(typeof t=="string"&&n===void 0)throw new Error(`invalid provider error on stored fault ${e.fault_id}`);const r={disposition:e.retry_disposition,...e.retry_by===null?{}:{by:e.retry_by},...e.retry_attempt===null?{}:{attempt:e.retry_attempt},...e.retry_max===null?{}:{max:e.retry_max},...e.retry_next_at===null?{}:{nextAt:e.retry_next_at}};return{faultId:e.fault_id,link:e.link,op:e.op,kind:e.kind,message:e.message,since:e.since,operation_id:e.operation_id,retry:r,...e.anchor_entry_id===null?{}:{anchorEntryId:e.anchor_entry_id},...n===void 0?{}:{providerError:n},...typeof e.notified_since=="string"?{notifiedSince:e.notified_since}:{}}}o(b,"hydrateFault");async function L(e,t){const n=await e.prepare("SELECT * FROM node_faults WHERE node_id = ? AND active = 1").get(t);return n===void 0?null:b(n)}o(L,"activeFault");function P(e){if(!g(G,e.link))throw new Error(`fault link is not durable: ${e.link}`);return{link:e.link,op:e.op,kind:e.kind,retry:e.retry,message:Re(e.message),since:e.since??u(),operation_id:Q(e.operation_id),...typeof e.anchorEntryId=="string"&&e.anchorEntryId!==""?{anchorEntryId:e.anchorEntryId}:{},...e.providerError===void 0?{}:{providerError:e.providerError}}}o(P,"storedFault");function M(e,t){J({level:t.retry.disposition==="fatal"?"error":"warn",event:"fault.recorded",operation_id:t.operation_id,node_id:e,error_class:B(t),fields:{link:t.link,op:t.op,kind:t.kind,retry:t.retry,message:t.message,...t.anchorEntryId===void 0?{}:{anchor_entry_id:t.anchorEntryId},...t.providerError===void 0?{}:{provider_error:t.providerError}}})}o(M,"emitRecordedFault");const Z="INSERT INTO node_faults (fault_id, node_id, link, op, kind, message, since, operation_id, anchor_entry_id, retry_disposition, retry_by, retry_attempt, retry_max, retry_next_at, provider_error_json, active, episode_state, episode_binding_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";function ee(e,t,n,r,i){const a=z(n),d=u();return[e,t,a.link,a.op,a.kind,a.message,a.since,a.operationId,a.anchorEntryId,a.retryDisposition,a.retryBy,a.retryAttempt,a.retryMax,a.retryNextAt,a.providerError,r?1:0,i?.state??null,i?.bindingId??null,d,d]}o(ee,"faultInsertParams");async function te(e,t,n,r,i){const a=I();return await e.prepare(Z).run(...ee(a,t,n,r,i)),{...n,faultId:a}}o(te,"insertFault");async function D(e,t,n,r){const i=z(n);return await e.prepare("UPDATE node_faults SET link = ?, op = ?, kind = ?, message = ?, since = ?, operation_id = ?, anchor_entry_id = ?, retry_disposition = ?, retry_by = ?, retry_attempt = ?, retry_max = ?, retry_next_at = ?, provider_error_json = ?, episode_state = COALESCE(?, episode_state), episode_binding_id = COALESCE(?, episode_binding_id), updated_at = ? WHERE fault_id = ?").run(i.link,i.op,i.kind,i.message,i.since,i.operationId,i.anchorEntryId,i.retryDisposition,i.retryBy,i.retryAttempt,i.retryMax,i.retryNextAt,i.providerError,r?.state??null,r?.bindingId??null,u(),t),{...n,faultId:t}}o(D,"updateFault");async function U(e,t){await e.prepare("DELETE FROM node_faults WHERE fault_id = ? AND active = 0 AND episode_state IS NULL").run(t)}o(U,"deleteIfUnretained");async function ne(e,t,n,r){const i=await L(e,t);if(i===null){const a=await e.prepare("SELECT fault_id, link, kind, since, operation_id FROM node_faults WHERE node_id = ? AND active = 0 AND episode_state IS NOT NULL").get(t);return a!==void 0&&a.link===n.link&&a.kind===n.kind&&a.since===n.since&&a.operation_id===n.operation_id?(await e.prepare("UPDATE node_faults SET active = 1, updated_at = ? WHERE fault_id = ?").run(u(),a.fault_id),await D(e,a.fault_id,n)):await te(e,t,n,!0,r)}if(i.link===n.link&&i.kind===n.kind){const a=n.retry.disposition==="auto"?{...i.retry,...n.retry}:n.retry,d=i.retry.disposition===n.retry.disposition&&(n.retry.disposition!=="fatal"||i.message===n.message),s=d?i.since:n.since,E=await D(e,i.faultId,{...n,since:s,anchorEntryId:n.anchorEntryId??i.anchorEntryId,retry:a},r);return d||await e.prepare("UPDATE node_faults SET notified_since = NULL WHERE fault_id = ?").run(i.faultId),E}return i.link!==n.link&&w(i)>w(n)?null:(await e.prepare("UPDATE node_faults SET active = 0, updated_at = ? WHERE fault_id = ?").run(u(),i.faultId),await U(e,i.faultId),await te(e,t,n,!0,r))}o(ne,"replaceActiveFault");async function m(e,t,n){return(await e.prepare("SELECT binding_id FROM sessions WHERE node_id = ? AND session_id = ? AND unbound_at IS NULL").get(t,n))?.binding_id??null}o(m,"liveBinding");async function Xe(e,t){return await l(async n=>{const r=u();return(await n.prepare("UPDATE executions SET turn_progress_at = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(r,e)).changes>0?!0:(await n.prepare("UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = NULL, turn_end_reason = NULL WHERE execution_id = ? AND state != 'exited'").run(r,r,e)).changes>0})}o(Xe,"openTurn");async function $e(e){return(await(await p()).prepare("UPDATE executions SET turn_progress_at = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(u(),e)).changes>0}o($e,"recordTurnProgress");async function je(e,t){return await l(async n=>{const r=u(),i=(await n.prepare("UPDATE executions SET turn_closed_at = ?, turn_end_reason = ? WHERE execution_id = ? AND state != 'exited' AND turn_open_at IS NOT NULL AND turn_closed_at IS NULL").run(r,t.endReason,e)).changes>0;if(i&&t.endReason==="settled"){const a="(SELECT node_id FROM executions WHERE execution_id = ?)";t.viewerPresent===!0?await n.prepare(`UPDATE nodes SET reply_at = ?, read_at = ? WHERE node_id = ${a}`).run(r,r,e):await n.prepare(`UPDATE nodes SET reply_at = ? WHERE node_id = ${a}`).run(r,e)}return i})}o(je,"closeTurn");async function Be(e){return(await(await p()).prepare("UPDATE nodes SET read_at = ? WHERE node_id = ?").run(u(),e)).changes>0}o(Be,"markNodeRead");async function Je(e,t){if(!Number.isInteger(t.consecutivePasses)||t.consecutivePasses<1||t.routes.length===0||!t.routes.every(n=>n!==""))throw new Error("invalid transport-poison verdict");return(await(await p()).prepare("UPDATE executions SET exit_diagnostic_json = ? WHERE execution_id = ? AND state != 'exited'").run(JSON.stringify({schema:"crtr.execution-exit-diagnostic/v1",transport_poison:{consecutive_passes:t.consecutivePasses,routes:t.routes}}),e)).changes>0}o(Je,"recordTransportPoisonVerdict");async function Ke(e){const t=await(await p()).prepare("SELECT exit_diagnostic_json FROM executions WHERE node_id = ? ORDER BY seq DESC LIMIT 1").get(e);if(t===void 0||t.exit_diagnostic_json===null)return null;try{const n=JSON.parse(t.exit_diagnostic_json),r=n.transport_poison;return n.schema!=="crtr.execution-exit-diagnostic/v1"||r===void 0||!Number.isInteger(r.consecutive_passes)||r.consecutive_passes<1||!Array.isArray(r.routes)||r.routes.length===0||!r.routes.every(i=>typeof i=="string"&&i!=="")?null:{consecutivePasses:r.consecutive_passes,routes:r.routes}}catch{return null}}o(Ke,"readTransportPoisonVerdict");async function Ye(e){const t=await(await p()).prepare("SELECT turn_open_at, turn_closed_at, turn_progress_at FROM executions WHERE node_id = ? AND state != 'exited'").get(e);return t===void 0?null:{busy:t.turn_open_at!==null&&t.turn_closed_at===null,progressAt:t.turn_progress_at}}o(Ye,"readLiveTurn");async function Ge(e){const t=await p(),n=await t.prepare("SELECT turn_closed_at, turn_progress_at FROM executions WHERE node_id = ? AND turn_open_at IS NOT NULL ORDER BY seq DESC LIMIT 1").get(e);if(n===void 0)return null;const r=await t.prepare("SELECT turn_end_reason FROM executions WHERE node_id = ? ORDER BY seq DESC LIMIT 1").get(e);return{interrupted:n.turn_closed_at===null||r?.turn_end_reason==="teardown-aborted",progressAt:n.turn_progress_at}}o(Ge,"readInterruptedTurn");async function qe(e){return await(await p()).prepare("SELECT 1 FROM executions WHERE node_id = ? AND turn_open_at IS NOT NULL LIMIT 1").get(e)!==void 0}o(qe,"hasAdmittedTurn");async function Ve(e,t){const n=P(t);return M(e,n),await l(async r=>await ne(r,e,n))}o(Ve,"recordFault");async function Qe(e){return await l(async t=>(await t.prepare("UPDATE node_faults SET notified_since = since, updated_at = ? WHERE fault_id = ?").run(u(),e)).changes>0)}o(Qe,"markFaultNotified");function xe(e){return e.link==="pi\u2192provider"&&e.retry.disposition==="fatal"&&e.notifiedSince!==e.since}o(xe,"isUnnotifiedFatalProviderFault");async function ze(){return(await(await p()).prepare("SELECT f.node_id FROM node_faults f JOIN nodes n ON n.node_id = f.node_id WHERE f.active = 1 AND f.link = 'pi\u2192provider' AND f.retry_disposition = 'fatal' AND (f.notified_since IS NULL OR f.notified_since != f.since) AND n.status IN ('active', 'idle')").all()).map(e=>e.node_id)}o(ze,"listUnnotifiedFatalFaultNodes");let X=null;function Ze(e){X=e}o(Ze,"setFatalFaultAnnouncer");async function et(e,t){const n=await L(await p(),e);return n===null||t?.link!==void 0&&n.link!==t.link?!1:await l(async r=>{const i=await L(r,e);if(i===null||t?.link!==void 0&&i.link!==t.link)return!1;X!==null&&xe(i)&&await X(e);const a=await r.prepare("SELECT episode_state FROM node_faults WHERE fault_id = ?").get(i.faultId);await r.prepare("UPDATE node_faults SET active = 0, updated_at = ? WHERE fault_id = ?").run(u(),i.faultId),a.episode_state==="pending"&&t?.preserveEpisode!==!0&&await r.prepare("UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE fault_id = ?").run(u(),i.faultId),await U(r,i.faultId);const d=Q();return J({level:"info",event:"fault.cleared",operation_id:d,node_id:e,error_class:B(i),fields:{cleared_fault_operation_id:i.operation_id,link:i.link,op:i.op,kind:i.kind,retry:i.retry,message:i.message,since:i.since,...i.anchorEntryId===void 0?{}:{anchor_entry_id:i.anchorEntryId}}}),!0})}o(et,"clearFault");async function re(e){return await L(await p(),e)}o(re,"readFault");async function tt(e,t){const n=P(t.input);if(n.link!=="pi\u2192provider"||n.retry.disposition!=="auto"||n.retry.by!=="daemon")throw new Error("provider retry episode requires an automatic daemon provider fault");return M(e,n),await l(async r=>{const i=await m(r,e,t.sessionId);if(i===null)return null;const a=await L(r,e);if(a!==null&&(a.link!==n.link||a.kind!==n.kind)&&w(a)>w(n))return null;const d=await r.prepare("SELECT fault_id FROM node_faults WHERE node_id = ? AND episode_state IS NOT NULL").all(e);await r.prepare("UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE node_id = ? AND episode_state IS NOT NULL").run(u(),e);for(const E of d)await U(r,E.fault_id);const s=await ne(r,e,n,{state:"pending",bindingId:i});return s===null?null:(await r.prepare("UPDATE node_faults SET episode_state = ?, episode_binding_id = ?, updated_at = ? WHERE fault_id = ?").run("pending",i,u(),s.faultId),s)})}o(tt,"recordPendingEpisode");async function nt(e,t){return await l(async n=>{if(await n.prepare("SELECT 1 FROM nodes WHERE node_id = ? AND intent = 'refresh'").get(e)!==void 0)return!1;const r=await m(n,e,t.sessionId);return r===null?!1:(await n.prepare("UPDATE node_faults SET episode_state = 'admitted', retry_disposition = ?, retry_by = ?, retry_attempt = ?, retry_max = ?, retry_next_at = ?, updated_at = ? WHERE node_id = ? AND fault_id = ? AND episode_state = 'pending' AND episode_binding_id = ?").run(t.retry.disposition,t.retry.by??null,t.retry.attempt??null,t.retry.max??null,t.retry.nextAt??null,u(),e,t.faultId,r)).changes>0})}o(nt,"admitEpisode");async function rt(e,t){const n=P(t.fault);return await l(async r=>{const i=await m(r,e,t.sessionId);return i===null||(await L(r,e))?.faultId!==t.faultId||await r.prepare("SELECT 1 FROM node_faults WHERE node_id = ? AND fault_id = ? AND episode_state = 'admitted' AND episode_binding_id = ?").get(e,t.faultId,i)===void 0?!1:(M(e,n),t.reopen?await D(r,t.faultId,n,{state:"pending",bindingId:i}):(await D(r,t.faultId,n),await r.prepare("UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE fault_id = ?").run(u(),t.faultId),await r.prepare("UPDATE node_faults SET notified_since = NULL WHERE fault_id = ?").run(t.faultId)),!0)})}o(rt,"settleRejectedEpisode");async function it(e,t){return await l(async n=>{const r=await m(n,e,t.sessionId);return r===null?!1:(await n.prepare("UPDATE node_faults SET episode_state = 'pending', updated_at = ? WHERE node_id = ? AND episode_state = 'admitted' AND episode_binding_id = ?").run(u(),e,r)).changes>0})}o(it,"reopenEpisode");async function ot(e,t){return await l(async n=>{const r=await m(n,e,t.sessionId);return r===null?!1:(await n.prepare("UPDATE node_faults SET episode_state = 'invalidated', updated_at = ? WHERE node_id = ? AND episode_state != 'invalidated' AND episode_state IS NOT NULL AND episode_binding_id = ?").run(u(),e,r)).changes>0})}o(ot,"invalidateEpisode");async function at(e,t){return await l(async n=>{const r=await m(n,e,t.sessionId);if(r===null)return!1;const i=await n.prepare("SELECT fault_id FROM node_faults WHERE node_id = ? AND episode_binding_id = ? AND episode_state IS NOT NULL").all(e,r);if(i.length===0)return!1;await n.prepare("UPDATE node_faults SET episode_state = NULL, episode_binding_id = NULL, updated_at = ? WHERE node_id = ? AND episode_binding_id = ? AND episode_state IS NOT NULL").run(u(),e,r);for(const a of i)await U(n,a.fault_id);return!0})}o(at,"clearEpisode");async function st(e){const t=await(await p()).prepare("SELECT f.*, s.session_id FROM node_faults f JOIN sessions s ON s.binding_id = f.episode_binding_id WHERE f.node_id = ? AND f.episode_state IS NOT NULL").get(e);return t===void 0?null:{state:t.episode_state,sessionId:t.session_id,fault:b(t)}}o(st,"readEpisode");async function dt(){return(await(await p()).prepare("SELECT f.*, s.session_id AS bound_session_id FROM node_faults f JOIN sessions s ON s.binding_id = f.episode_binding_id WHERE f.active = 1 AND f.episode_state = 'pending' AND s.unbound_at IS NULL AND s.session_id IS NOT NULL AND f.link = 'pi\u2192provider' AND f.retry_disposition = 'auto' AND f.retry_by = 'daemon' AND f.kind IN ('connection', 'rate-limit', 'overloaded')").all()).map(t=>({nodeId:t.node_id,sessionId:t.bound_session_id,fault:b(t),updatedAt:t.updated_at,nudgedAt:t.nudged_at??null}))}o(dt,"listPendingProviderRetries");async function ut(e,t,n){return(await(await p()).prepare("UPDATE node_faults SET nudged_at = ? WHERE fault_id = ? AND active = 1 AND episode_state = 'pending' AND (nudged_at IS NULL OR nudged_at <= ?)").run(new Date(t).toISOString(),e,new Date(t-n).toISOString())).changes===1}o(ut,"claimFaultNudge");async function ct(e){const t=await re(e)===null;return{async explanation(){if(!t)return null;const n=await re(e);if(n===null||n.link!=="crtr\u2192pi"||n.retry.disposition!=="fatal")return null;const r=n.op.trim(),i=n.message.trim();return r===""||i===""?null:`${r}: ${i}`}}}o(ct,"beginBootFaultAttempt");function ie(e,t){try{return ce(e).mtime.toISOString()}catch{return t}}o(ie,"markerMtime");function $(e,t){if(!f(e))return null;try{return de(e,"utf8")}catch(n){if(!t)return null;throw new Error(`cannot import recovery input ${e}: ${n.message}`)}}o($,"legacyFile");function Ie(e,t){return _(e,"SELECT execution_id, started_at FROM executions WHERE node_id = ? ORDER BY rowid DESC LIMIT 1").get(t)??null}o(Ie,"latestExecution");function we(e,t){const r=H(e,"nodes").has("launched_at")?_(e,"SELECT COALESCE(launched_at, created) AS started_at FROM nodes WHERE node_id = ?").get(t):_(e,"SELECT created AS started_at FROM nodes WHERE node_id = ?").get(t);if(r===void 0)throw new Error(`cannot import recovery witness for unknown node ${t}`);const i=I();return _(e,"INSERT INTO executions (execution_id, node_id, daemon_epoch, pid, process_identity, state, started_at, ended_at, exit_reason) VALUES (?, ?, NULL, NULL, NULL, 'exited', ?, ?, 'pre-consolidation')").run(i,t,r.started_at,r.started_at),{execution_id:i,started_at:r.started_at}}o(we,"syntheticExecution");function oe(e,t,n,r,i){const a=I();return _(e,Z).run(...ee(a,t,n,r,i)),{...n,faultId:a}}o(oe,"insertMigratedFault");function De(e,t,n,r){const i=_(e,"SELECT binding_id, node_id FROM sessions WHERE transcript_path = ? AND unbound_at IS NULL").get(n);if(i!==void 0){if(i.node_id!==t)throw new Error(`cannot import provider retry ${r}: transcript is live-owned by ${i.node_id}`);return i.binding_id}const a=_(e,"SELECT binding_id FROM sessions WHERE node_id = ? AND transcript_path = ? ORDER BY rowid DESC LIMIT 1").get(t,n);if(a!==void 0)return a.binding_id;const d=_(e,"SELECT created FROM nodes WHERE node_id = ?").get(t);if(d===void 0)throw new Error(`cannot import provider retry ${r}: unknown node ${t}`);const s=I();return _(e,"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, ?, ?, NULL, NULL, ?, ?, ?)").run(s,t,n,d.created,d.created,u()),s}o(De,"migrationBinding");function _t(e){e.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'node_faults'").get()!==void 0&&(H(e,"node_faults").has("notified_since")||e.exec("ALTER TABLE node_faults ADD COLUMN notified_since TEXT"))}o(_t,"addFaultNotifiedSince");function pt(e){if(Le(e),me(e),!f(C()))return;const t=se(C(),{withFileTypes:!0}).filter(r=>r.isDirectory()).sort((r,i)=>r.name.localeCompare(i.name)),n=_(e,"SELECT 1 FROM nodes WHERE node_id = ?");for(const r of t){const i=r.name,a=pe(i),d=N(a,"busy"),s=N(a,"clean-abort"),E=N(a,"transport-poison.json"),O=N(a,"fault"),A=N(a,"provider-retry"),h=f(d),v=f(s);if(!h&&!v&&!f(E)&&!f(O)&&!f(A)||!f(N(C(),i,"meta.json"))&&n.get(i)===void 0)continue;const k=$(E,!1),S=$(O,!0),R=$(A,!0);if(!h&&!v&&k===null&&S===null&&R===null)continue;let y=Ie(e,i);if(y===null&&(y=we(e,i)),h){const c=ie(d,y.started_at);_(e,"UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = NULL, turn_end_reason = NULL WHERE execution_id = ?").run(c,c,y.execution_id)}else if(v){const c=ie(s,y.started_at);_(e,"UPDATE executions SET turn_open_at = ?, turn_progress_at = ?, turn_closed_at = ?, turn_end_reason = 'teardown-aborted' WHERE execution_id = ?").run(c,c,c,y.execution_id)}if(k!==null)try{const c=JSON.parse(k);Number.isInteger(c.consecutivePasses)&&c.consecutivePasses>=1&&Array.isArray(c.routes)&&c.routes.length>0&&c.routes.every(j=>typeof j=="string"&&j!=="")&&_(e,"UPDATE executions SET exit_diagnostic_json = ? WHERE execution_id = ?").run(JSON.stringify({schema:"crtr.execution-exit-diagnostic/v1",transport_poison:{consecutive_passes:c.consecutivePasses,routes:c.routes}}),y.execution_id)}catch{}const x=S===null?null:V(S);if(S!==null&&x===null)throw new Error(`cannot import recovery fault ${O}`);const T=R===null?null:Se(R);if(R!==null&&T===null)throw new Error(`cannot import provider retry ${A}`);let F=x===null||x.link==="broker\u2194crtrd"?null:oe(e,i,x,!0);if(T!==null){const c=De(e,i,T.sessionFile,A);F!==null&&F.since===T.fault.since?_(e,"UPDATE node_faults SET episode_state = ?, episode_binding_id = ?, updated_at = ? WHERE fault_id = ?").run(T.state,c,u(),F.faultId):oe(e,i,T.fault,!1,{state:T.state,bindingId:c})}}}o(pt,"migrateRecoveryWitnesses");export{Me as FAULT_QUIET_MS,_t as addFaultNotifiedSince,nt as admitEpisode,ct as beginBootFaultAttempt,ut as claimFaultNudge,at as clearEpisode,et as clearFault,je as closeTurn,qe as hasAdmittedTurn,b as hydrateFault,ot as invalidateEpisode,dt as listPendingProviderRetries,ze as listUnnotifiedFatalFaultNodes,Qe as markFaultNotified,Be as markNodeRead,pt as migrateRecoveryWitnesses,Xe as openTurn,q as parseProviderError,st as readEpisode,re as readFault,Ge as readInterruptedTurn,Ye as readLiveTurn,Ke as readTransportPoisonVerdict,Ve as recordFault,tt as recordPendingEpisode,Je as recordTransportPoisonVerdict,$e as recordTurnProgress,it as reopenEpisode,Ze as setFatalFaultAnnouncer,rt as settleRejectedEpisode};
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
-- database that still holds un-migrated rows in `usage`, `grantee_usage` or `provider_receipts` would strand them. Refuse until a
|
|
7
7
|
-- cycle 4 build has run against it. A fresh database, or one that never had cycle-3 rows, has all three empty, so the chain from the
|
|
8
8
|
-- baseline to here still applies (D71). The three tables stay: the version-2 build still lists them in its SQLite import and export,
|
|
9
|
-
-- and a later delta (
|
|
9
|
+
-- and a later delta (007, with the `jobs` columns, once the reader floor reaches 3) drops them.
|
|
10
10
|
DO $$
|
|
11
11
|
BEGIN
|
|
12
12
|
IF NOT EXISTS (SELECT 1 FROM canvas_meta WHERE key = 'ledger_migrated')
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- 005-fleet-blobs.sql — cycle 5 additions for the blob store (design-fleet "Data model", D98, D100). One transaction, additions only:
|
|
2
|
+
-- `schema_min_reader` is not touched and stays 2.
|
|
3
|
+
-- The previous release (version 3, the build that shipped 003) opens the result: it never names `blob_key`, and the index changes no
|
|
4
|
+
-- row it reads or writes.
|
|
5
|
+
|
|
6
|
+
-- D98: the control plane puts each fetched upload in the blob store at `attachments/<run root node>/<sha256>` and records that key here.
|
|
7
|
+
-- Null for a use recorded before this release, and for any use whose bytes the storage service still holds.
|
|
8
|
+
ALTER TABLE upload_uses ADD COLUMN IF NOT EXISTS blob_key text;
|
|
9
|
+
|
|
10
|
+
-- D100: the node blob-deletion pass in `storage-due-work` claims node rows whose `deleted_at` is more than 90 days old. Partial, so it
|
|
11
|
+
-- holds only the soft-deleted node rows, not every object. A plain CREATE INDEX (the chain runs each step in a transaction, so not
|
|
12
|
+
-- CONCURRENTLY): it blocks writes to `objects` for the time it takes to scan the table.
|
|
13
|
+
CREATE INDEX IF NOT EXISTS objects_node_deleted ON objects(deleted_at) WHERE type = 'node';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- 006-job-rows.sql — cycle 5 additions for bash jobs as rows (design-fleet "A bash job outlives the turn", D7). One transaction, additions only:
|
|
2
|
+
-- `schema_min_reader` is not touched and stays 2. The previous release never names these columns.
|
|
3
|
+
-- Each column holds a fact another process reads that the bash valve used to leave in a file under `context/jobs/<id>/`.
|
|
4
|
+
-- The broker's valve is the only writer (POST /v1/nodes/:id/jobs/:jobId/report); `job_dir` and `log_path` stay nullable and unused until the removals delta.
|
|
5
|
+
ALTER TABLE jobs
|
|
6
|
+
ADD COLUMN IF NOT EXISTS purpose text,
|
|
7
|
+
ADD COLUMN IF NOT EXISTS quiet_ok boolean NOT NULL DEFAULT false,
|
|
8
|
+
ADD COLUMN IF NOT EXISTS pgid bigint,
|
|
9
|
+
ADD COLUMN IF NOT EXISTS pgid_identity text,
|
|
10
|
+
ADD COLUMN IF NOT EXISTS activity_last_ms bigint,
|
|
11
|
+
ADD COLUMN IF NOT EXISTS activity_sampled_ms bigint,
|
|
12
|
+
ADD COLUMN IF NOT EXISTS activity_files text,
|
|
13
|
+
ADD COLUMN IF NOT EXISTS silence_activity_ms bigint,
|
|
14
|
+
ADD COLUMN IF NOT EXISTS silence_threshold_ms bigint,
|
|
15
|
+
ADD COLUMN IF NOT EXISTS exit_reported_at text;
|
|
16
|
+
|
|
17
|
+
-- A job recorded before this delta has no output key: give it the key the new rows get. Its deadline and process identity
|
|
18
|
+
-- are still in its supervisor files, which the daemon's reconciler moves onto the row.
|
|
19
|
+
UPDATE jobs SET output_key = 'jobs/' || o.owner || '/' || jobs.object || '/output'
|
|
20
|
+
FROM objects o WHERE o.id = jobs.object AND jobs.output_key IS NULL;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
-- 007-ledger-check.sql — cycle 5 L7 (design-fleet "Money", D58, D59, D89): the one limit rule as a SQL function, and the
|
|
2
|
+
-- `charges` rollup trigger that now adds `usd` on INSERT. One transaction, additions only: `schema_min_reader` is not touched
|
|
3
|
+
-- and stays 2. The previous build never names `ledger_check`, `ledger_holder` or the new column.
|
|
4
|
+
|
|
5
|
+
-- A writer at version 7 or above sets this on every row it inserts. The previous build leaves it false and keeps calling
|
|
6
|
+
-- `addToTotals` for `usd`, so the trigger must not add that row's `usd` a second time.
|
|
7
|
+
ALTER TABLE charges ADD COLUMN IF NOT EXISTS usd_rolled_by_trigger boolean NOT NULL DEFAULT false;
|
|
8
|
+
|
|
9
|
+
-- D-3's `$0` card-stop bill limit (D68) has `source card`.
|
|
10
|
+
ALTER TABLE limits DROP CONSTRAINT IF EXISTS limits_source_check;
|
|
11
|
+
ALTER TABLE limits ADD CONSTRAINT limits_source_check CHECK (source IN ('grant_sync', 'person', 'operator', 'billing', 'card'));
|
|
12
|
+
|
|
13
|
+
-- Replaces 002's function. INSERT adds `billed_usd` for every row (as 002 did) and adds `usd` only for a marked row. UPDATE is
|
|
14
|
+
-- as in 002: it moves both amounts, the old negative and the new positive; the old `usd` is in the rollup whichever way it got
|
|
15
|
+
-- there. Refused rows and `take` rows are never rolled up, as in `rebuildTotals`.
|
|
16
|
+
CREATE OR REPLACE FUNCTION charge_totals_rollup() RETURNS trigger LANGUAGE plpgsql AS $$
|
|
17
|
+
BEGIN
|
|
18
|
+
IF TG_OP = 'UPDATE' AND OLD.refused IS NULL AND OLD.kind <> 'take' THEN
|
|
19
|
+
INSERT INTO charge_totals (month, payer, funding, sub, grantee, provider, usd, billed_usd)
|
|
20
|
+
VALUES (OLD.month, OLD.payer, OLD.funding, COALESCE(OLD.sub, ''), OLD.grantee, COALESCE(OLD.provider, ''),
|
|
21
|
+
-COALESCE(OLD.usd, 0), -COALESCE(OLD.billed_usd, 0))
|
|
22
|
+
ON CONFLICT (month, payer, funding, sub, grantee, provider) DO UPDATE
|
|
23
|
+
SET usd = charge_totals.usd + EXCLUDED.usd, billed_usd = charge_totals.billed_usd + EXCLUDED.billed_usd;
|
|
24
|
+
END IF;
|
|
25
|
+
IF NEW.refused IS NULL AND NEW.kind <> 'take'
|
|
26
|
+
AND (TG_OP = 'UPDATE' OR COALESCE(NEW.billed_usd, 0) <> 0 OR (NEW.usd_rolled_by_trigger AND COALESCE(NEW.usd, 0) <> 0)) THEN
|
|
27
|
+
INSERT INTO charge_totals (month, payer, funding, sub, grantee, provider, usd, billed_usd)
|
|
28
|
+
VALUES (NEW.month, NEW.payer, NEW.funding, COALESCE(NEW.sub, ''), NEW.grantee, COALESCE(NEW.provider, ''),
|
|
29
|
+
CASE WHEN TG_OP = 'UPDATE' OR NEW.usd_rolled_by_trigger THEN COALESCE(NEW.usd, 0) ELSE 0 END, COALESCE(NEW.billed_usd, 0))
|
|
30
|
+
ON CONFLICT (month, payer, funding, sub, grantee, provider) DO UPDATE
|
|
31
|
+
SET usd = charge_totals.usd + EXCLUDED.usd, billed_usd = charge_totals.billed_usd + EXCLUDED.billed_usd;
|
|
32
|
+
END IF;
|
|
33
|
+
RETURN NULL;
|
|
34
|
+
END $$;
|
|
35
|
+
|
|
36
|
+
-- Who Northlight invoices for a payer (`billingAccountOf`, directory `billing/payer.ts`): a user payer is its own account; an
|
|
37
|
+
-- app payer's account is the team with an `admin` tuple on the app, else the user with one; null when it has neither. A
|
|
38
|
+
-- directory tuple's team subject is type `crtr/group` with the id `team:<id>`; a person is type `user` with the bare id.
|
|
39
|
+
CREATE FUNCTION ledger_holder(payer text) RETURNS text LANGUAGE sql STABLE AS $$
|
|
40
|
+
SELECT CASE
|
|
41
|
+
WHEN payer LIKE 'user:%' THEN payer
|
|
42
|
+
WHEN payer LIKE 'app:%' THEN COALESCE(
|
|
43
|
+
(SELECT r.subject_id FROM relations r
|
|
44
|
+
WHERE r.resource_type = 'app' AND r.resource_id = substr(payer, 5) AND r.relation = 'admin'
|
|
45
|
+
AND r.subject_type = 'crtr/group' AND r.subject_id LIKE 'team:%' ORDER BY r.subject_id LIMIT 1),
|
|
46
|
+
(SELECT 'user:' || r.subject_id FROM relations r
|
|
47
|
+
WHERE r.resource_type = 'app' AND r.resource_id = substr(payer, 5) AND r.relation = 'admin'
|
|
48
|
+
AND r.subject_type = 'user' ORDER BY r.subject_id LIMIT 1))
|
|
49
|
+
END
|
|
50
|
+
$$;
|
|
51
|
+
|
|
52
|
+
-- The one limit rule (design-ledger "The check", cycle 4's `findRefusal`, now in SQL). Input `{payer, account, funding, sub,
|
|
53
|
+
-- grantee, provider, scope: 'call' | 'start', month?}`; `month` defaults to the current UTC month. Result: null, or the first
|
|
54
|
+
-- refusing limit (by id) as `{limit, usd, month, reset_at}`. No reservation: a limit refuses when the month's rollup
|
|
55
|
+
-- is already at or over it.
|
|
56
|
+
-- * A limit matches when its `payer`, `account`, `funding`, `grantee`, `provider` and `sub` filters (null = any) equal the
|
|
57
|
+
-- candidate's. A `call` is checked against every such limit; a `start` only against limits with null `funding` and
|
|
58
|
+
-- `provider`. A limit's `account` matches the candidate's `account`, or the holder `ledger_holder(payer)` finds when the candidate gives none (a house-paid payer's candidate carries none, and the house limit is on the team's account).
|
|
59
|
+
-- * Spent = this month's `charge_totals` rows matching the limit's non-null filters. A limit with an `account` filter counts
|
|
60
|
+
-- the rows whose payer is that account or an app it holds now (D89). A limit with `funding bill` sums `billed_usd`; any
|
|
61
|
+
-- other limit sums `usd` (so the house limit counts full price).
|
|
62
|
+
CREATE FUNCTION ledger_check(candidate jsonb) RETURNS jsonb LANGUAGE plpgsql STABLE AS $$
|
|
63
|
+
DECLARE
|
|
64
|
+
m text := COALESCE(candidate->>'month', to_char(now() AT TIME ZONE 'UTC', 'YYYY-MM'));
|
|
65
|
+
scope text := candidate->>'scope';
|
|
66
|
+
pay text := candidate->>'payer';
|
|
67
|
+
acct text := COALESCE(candidate->>'account', ledger_holder(candidate->>'payer'));
|
|
68
|
+
result jsonb;
|
|
69
|
+
BEGIN
|
|
70
|
+
IF scope IS NULL OR scope NOT IN ('call', 'start') THEN RAISE EXCEPTION 'ledger_check: scope must be call or start'; END IF;
|
|
71
|
+
IF pay IS NULL THEN RAISE EXCEPTION 'ledger_check: payer is required'; END IF;
|
|
72
|
+
SELECT jsonb_build_object(
|
|
73
|
+
'limit', jsonb_build_object('id', q.id, 'payer', q.payer, 'account', q.account, 'funding', q.funding, 'grantee', q.grantee,
|
|
74
|
+
'provider', q.provider, 'sub', q.sub, 'usd_per_month', q.usd_per_month, 'source', q.source,
|
|
75
|
+
'updated_at', q.updated_at),
|
|
76
|
+
'usd', q.spent, 'month', m,
|
|
77
|
+
'reset_at', to_char((m || '-01')::date + interval '1 month', 'YYYY-MM-DD"T"00:00:00.000"Z"'))
|
|
78
|
+
INTO result
|
|
79
|
+
FROM (SELECT l.*, s.spent
|
|
80
|
+
FROM limits l
|
|
81
|
+
-- The payers an `account` limit counts: the account itself and the apps it holds now. Built once per limit from the
|
|
82
|
+
-- apps with an `admin` tuple for the account (one `relations_subject` lookup), each kept only when `ledger_holder`
|
|
83
|
+
-- agrees (a team admin wins over a user admin), so the answer equals `ledger_holder`'s and the sum below can use the
|
|
84
|
+
-- (month, payer, ...) key. A limit with no `account` has the one payer; every limit has a payer or an account.
|
|
85
|
+
CROSS JOIN LATERAL (
|
|
86
|
+
SELECT CASE WHEN l.account IS NULL THEN ARRAY[l.payer] ELSE
|
|
87
|
+
ARRAY[l.account] || COALESCE((SELECT array_agg(a.app)
|
|
88
|
+
FROM (SELECT DISTINCT 'app:' || r.resource_id AS app FROM relations r
|
|
89
|
+
WHERE r.subject_type = CASE WHEN l.account LIKE 'team:%' THEN 'crtr/group' ELSE 'user' END
|
|
90
|
+
AND r.subject_id = CASE WHEN l.account LIKE 'user:%' THEN substr(l.account, 6) ELSE l.account END
|
|
91
|
+
AND r.relation = 'admin' AND r.resource_type = 'app') a
|
|
92
|
+
WHERE ledger_holder(a.app) = l.account), ARRAY[]::text[]) END AS payers) h
|
|
93
|
+
CROSS JOIN LATERAL (
|
|
94
|
+
SELECT COALESCE(SUM(CASE WHEN l.funding = 'bill' THEN t.billed_usd ELSE t.usd END), 0) AS spent
|
|
95
|
+
FROM charge_totals t
|
|
96
|
+
WHERE t.month = m
|
|
97
|
+
AND (l.payer IS NULL OR t.payer = l.payer)
|
|
98
|
+
AND t.payer = ANY(h.payers)
|
|
99
|
+
AND (l.funding IS NULL OR t.funding = l.funding)
|
|
100
|
+
AND (l.grantee IS NULL OR t.grantee = l.grantee)
|
|
101
|
+
AND (l.provider IS NULL OR t.provider = l.provider)
|
|
102
|
+
AND (l.sub IS NULL OR t.sub = l.sub)) s
|
|
103
|
+
WHERE (l.payer IS NOT NULL OR l.account IS NOT NULL)
|
|
104
|
+
AND (l.payer IS NULL OR l.payer = pay)
|
|
105
|
+
AND (l.account IS NULL OR l.account = acct)
|
|
106
|
+
AND (l.grantee IS NULL OR l.grantee = candidate->>'grantee')
|
|
107
|
+
AND (l.sub IS NULL OR l.sub = COALESCE(candidate->>'sub', ''))
|
|
108
|
+
AND (CASE WHEN scope = 'call'
|
|
109
|
+
THEN (l.funding IS NULL OR l.funding = candidate->>'funding')
|
|
110
|
+
AND (l.provider IS NULL OR l.provider = COALESCE(candidate->>'provider', ''))
|
|
111
|
+
ELSE l.funding IS NULL AND l.provider IS NULL END)
|
|
112
|
+
AND s.spent >= l.usd_per_month
|
|
113
|
+
ORDER BY l.id LIMIT 1) q;
|
|
114
|
+
RETURN result;
|
|
115
|
+
END $$;
|
|
116
|
+
|
|
117
|
+
INSERT INTO canvas_meta (key, value) VALUES ('schema_min_reader', '2') ON CONFLICT (key) DO NOTHING;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** The canvas schema version this build supports: the number of the highest delta in `schema-pg/` (the baseline
|
|
2
2
|
* `schema-pg.sql` is version 1). `scripts/install-runtime.mjs` reads this module from a candidate generation to refuse
|
|
3
3
|
* one below the live database's `schema_min_reader`. */
|
|
4
|
-
export declare const CANVAS_SCHEMA_VERSION =
|
|
4
|
+
export declare const CANVAS_SCHEMA_VERSION = 7;
|
|
5
5
|
/** The Postgres schema holding the canvas tables: `CRTR_DATABASE_SCHEMA` (`crtr` in the cloud deploy). Unset or empty
|
|
6
6
|
* means the role's own search_path (`public` on a Mac and on a VM). A name that is not a plain identifier is an error:
|
|
7
7
|
* it is put in a `search_path` connection option. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var m=Object.defineProperty;var r=(n,e)=>m(n,"name",{value:e,configurable:!0});const A=
|
|
1
|
+
var m=Object.defineProperty;var r=(n,e)=>m(n,"name",{value:e,configurable:!0});const A=7;function _(n=process.env){const e=n.CRTR_DATABASE_SCHEMA?.trim();if(e){if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(e))throw new Error(`CRTR_DATABASE_SCHEMA must be a plain identifier (letters, digits, underscore); got ${JSON.stringify(e)}`);return e}}r(_,"canvasDatabaseSchema");function h(n=process.env){return n.CRTR_SCHEMA_DATABASE_URL?.trim()||void 0}r(h,"canvasSchemaDatabaseUrl");function E(n=process.env){const e=_(n);return e===void 0?void 0:`-c search_path=${e}`}r(E,"canvasSearchPathOptions");async function v(n,e){const t=e===void 0?"canvas_meta":`"${e.replace(/"/g,'""')}".canvas_meta`;if((await n.query(`SELECT to_regclass('${t.replace(/'/g,"''")}') IS NOT NULL AS found`)).rows[0].found!==!0)return;const u=(await n.query(`SELECT key, value FROM ${t} WHERE key IN ('schema_version', 'schema_min_reader')`)).rows,o=r(c=>{const i=u.find(f=>f.key===c);if(i===void 0)return;const d=Number(i.value);if(!Number.isSafeInteger(d))throw new Error(`canvas_meta.${c} is not an integer: ${String(i.value)}`);return d},"value"),s=o("schema_version");return s===void 0?void 0:{version:s,minReader:o("schema_min_reader")??s}}r(v,"readStoredVersions");async function l(n,e,t){const a=await v(n,t);if(a!==void 0&&a.minReader>e)throw new Error(`refusing to select runtime with canvas schema ${e}: the live database requires readers at version ${a.minReader} or above (it is at ${a.version}); install a descendant build instead`)}r(l,"assertCandidateMayOpen");export{A as CANVAS_SCHEMA_VERSION,l as assertCandidateMayOpen,_ as canvasDatabaseSchema,h as canvasSchemaDatabaseUrl,E as canvasSearchPathOptions,v as readStoredVersions};
|
|
@@ -31,27 +31,24 @@ export declare function transferSession(input: {
|
|
|
31
31
|
transcriptPath: string | null;
|
|
32
32
|
}): Promise<'transferred' | 'shutdown' | 'changed'>;
|
|
33
33
|
export declare function unbindSession(nodeId: string): Promise<void>;
|
|
34
|
-
/** Rewrite the header `cwd` of every
|
|
35
|
-
* the sessions bound. Pi opens a transcript with its header cwd and a resume is vetoed once that
|
|
36
|
-
* directory is gone, so a same-directory relocation must move the header too. Each file is replaced
|
|
37
|
-
* atomically (temp + fsync + rename) and a run node's indexed `event_offset` shifts by the byte
|
|
38
|
-
* delta, in one canvas write that also serializes against `appendSection`. Returns files rewritten. */
|
|
34
|
+
/** Rewrite the header `cwd` of every conversation this node owns from `oldCwd` to `newCwd`, keeping the sessions bound. Returns conversations rewritten. */
|
|
39
35
|
export declare function relocateSessionCwd(nodeId: string, oldCwd: string, newCwd: string): Promise<number>;
|
|
40
36
|
export declare function setCyclePending(nodeId: string, pending: boolean): Promise<void>;
|
|
41
37
|
export declare function conversationOwner(conversationId: string): Promise<string | null>;
|
|
42
|
-
/**
|
|
43
|
-
export declare function openCanvasConversationStore(
|
|
38
|
+
/** Open the row store: durable tail rows plus immutable blob parts. `root` is unused; it stays so test callers keep one signature. */
|
|
39
|
+
export declare function openCanvasConversationStore(_root?: string): ConversationStore & {
|
|
40
|
+
commit(id: string): Promise<number>;
|
|
41
|
+
importLegacy(runId?: string): Promise<void>;
|
|
44
42
|
recover(rows: Array<{
|
|
45
43
|
session_id: string;
|
|
46
44
|
node_id: string;
|
|
47
45
|
transcript_path: string | null;
|
|
48
46
|
}>): void;
|
|
49
|
-
repair(id: string): void;
|
|
50
47
|
};
|
|
48
|
+
/** Record each run conversation's existing transcript file as part 0 (first boot after the file store). */
|
|
51
49
|
export declare function repairRunConversations(runId: string): Promise<void>;
|
|
52
|
-
/**
|
|
53
|
-
*
|
|
54
|
-
* `<CRTR_HOME>/store.sock`. */
|
|
50
|
+
/** Install the row store in this process and import any transcript files not yet recorded as part 0.
|
|
51
|
+
* Brokers reach it over the /v1 API; no socket is bound here. */
|
|
55
52
|
export declare function serveCanvasConversationStore(): Promise<{
|
|
56
53
|
close(): Promise<void>;
|
|
57
54
|
}>;
|
|
@@ -1,4 +1 @@
|
|
|
1
|
-
var
|
|
2
|
-
FROM sessions s JOIN nodes n ON n.node_id = s.node_id WHERE s.session_id = ? ORDER BY s.unbound_at IS NULL DESC, s.created_at DESC, s.seq DESC LIMIT 1`).get(n);if(!s?.run_id||s.event_offset===null)return;if(s.event_offset===0&&!N(e)){await(await c()).prepare("DELETE FROM sessions WHERE binding_id = ?").run(s.binding_id);return}const i=H(e).size;if(i<s.event_offset)throw new Error(`conversation shorter than indexed offset: ${n}`);if(i===s.event_offset)return;const o=T(e,"r"),r=[];try{const d=Buffer.allocUnsafe(65536);for(let p=s.event_offset;p<i;){const g=A(o,d,0,Math.min(d.length,i-p),p);if(!g)throw new Error(`conversation read ended early: ${n}`);r.push(Buffer.from(d.subarray(0,g))),p+=g}}finally{y(o)}const t=Buffer.concat(r).toString("utf8"),_=t.lastIndexOf(`
|
|
3
|
-
`);if(_<0){s.event_offset===0?(D(e),await(await c()).prepare("DELETE FROM sessions WHERE binding_id = ?").run(s.binding_id)):I(e,s.event_offset);return}const f=t.slice(0,_+1),u=f.split(`
|
|
4
|
-
`).filter(Boolean).map(d=>JSON.parse(d)).filter(d=>d.type!=="session"),E=s.event_offset+Buffer.byteLength(f);E<i&&I(e,E),await l(async d=>{const p=s.source_session_id?[]:await h(d,s.run_id,s.node_id,u,JSON.parse(s.input_ids_json));await d.prepare("UPDATE sessions SET event_offset = ?, indexed_entry_id = ?, input_ids_json = ? WHERE binding_id = ?").run(E,u.at(-1)?.id??null,JSON.stringify(p),s.binding_id)})}a(V,"repairConversationTail");function q(n){return B(n,Y)}a(q,"openCanvasConversationStore");async function ln(n){const e=await(await c()).prepare("SELECT DISTINCT s.session_id FROM sessions s JOIN nodes n ON n.node_id = s.node_id WHERE n.run_id = ? AND s.session_id IS NOT NULL").all(n),s=$();for(const i of e)s.repair?.(i.session_id)}a(ln,"repairRunConversations");async function wn(){const n=x("user").store,e=n?.address??O(P(),"store.sock"),s=q(n?.root??k());b(s),process.env.CRTR_STORE_ADDRESS=e;const i=await J(e,s);return{async close(){await i.close(),b(void 0)}}}a(wn,"serveCanvasConversationStore");export{dn as bindSession,fn as conversationOwner,an as findNodeBySessionFileSql,q as openCanvasConversationStore,rn as readLiveSession,En as relocateSessionCwd,ln as repairRunConversations,cn as resetSession,wn as serveCanvasConversationStore,pn as setCyclePending,_n as transferSession,un as unbindSession};
|
|
1
|
+
var l=Object.defineProperty;var i=(n,e)=>l(n,"name",{value:e,configurable:!0});import{randomUUID as _}from"node:crypto";import{openDb as a,withCanvasWrite as c}from"./db.js";import{canonicalSessionFile as d}from"./canvas.js";import{conversationStore as f,installConversationStore as p}from"../conversation-store/index.js";import{createRowStore as L,relocateConversationHeader as I}from"../conversation-store/row-store.js";function u(){return new Date().toISOString()}i(u,"now");async function S(n,e,s){return await n.prepare("SELECT 1 FROM executions WHERE execution_id = ? AND node_id = ? AND state != 'exited'").get(s,e)!==void 0}i(S,"liveExecution");function w(n){return{bindingId:n.binding_id,sessionId:n.session_id??null,nodeId:n.node_id,transcriptPath:n.transcript_path??null,sourceSessionId:n.source_session_id??null,forkEntryId:n.fork_entry_id??null,createdAt:n.created_at,boundAt:n.bound_at,unboundAt:n.unbound_at??null}}i(w,"hydrate");async function b(n){const e=await(await a()).prepare("SELECT * FROM sessions WHERE node_id = ? AND unbound_at IS NULL").get(n);return e===void 0?null:w(e)}i(b,"readLiveSession");async function C(n){return(await(await a()).prepare("SELECT node_id FROM sessions WHERE transcript_path = ? AND unbound_at IS NULL").get(d(n)))?.node_id??null}i(C,"findNodeBySessionFileSql");async function h(n,e){return await c(async s=>{if(!await S(s,n,e.executionId))return"shutdown";if(e.sessionId!==null&&await s.prepare("SELECT 1 FROM sessions WHERE session_id = ? AND node_id <> ? LIMIT 1").get(e.sessionId,n)!==void 0)throw new Error(`session ${e.sessionId} is bound to another node`);const o=u(),r=e.transcriptPath===null?null:d(e.transcriptPath),t=await s.prepare("SELECT binding_id, session_id FROM sessions WHERE node_id = ? AND unbound_at IS NULL").get(n);if(t!==void 0&&t.session_id===e.sessionId)await s.prepare("UPDATE sessions SET transcript_path = ?, source_session_id = ?, bound_at = ? WHERE binding_id = ?").run(r,e.sourceSessionId??null,o,t.binding_id);else{t!==void 0&&await s.prepare("UPDATE sessions SET unbound_at = ? WHERE binding_id = ?").run(o,t.binding_id);const E=e.sessionId===null?void 0:await s.prepare("SELECT binding_id FROM sessions WHERE node_id = ? AND session_id = ? ORDER BY created_at DESC LIMIT 1").get(n,e.sessionId);E?await s.prepare("UPDATE sessions SET transcript_path = ?, source_session_id = ?, bound_at = ?, unbound_at = NULL WHERE binding_id = ?").run(r,e.sourceSessionId??null,o,E.binding_id):await s.prepare("INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at) VALUES (?, ?, ?, ?, ?, NULL, ?, ?)").run(_(),e.sessionId,n,r,e.sourceSessionId??null,o,o)}return await s.prepare("UPDATE nodes SET cycle_pending = 0 WHERE node_id = ?").run(n),"bound"})}i(h,"bindSession");async function W(n,e){await c(async s=>{const o=u();await s.prepare("UPDATE sessions SET unbound_at = ? WHERE node_id = ? AND unbound_at IS NULL").run(o,n),await s.prepare("INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at) VALUES (?, ?, ?, ?, NULL, NULL, ?, ?)").run(_(),e.sessionId,n,e.transcriptPath===null?null:d(e.transcriptPath),o,o),await s.prepare("UPDATE nodes SET cycle_pending = 0 WHERE node_id = ?").run(n)})}i(W,"resetSession");async function H(n){return await c(async e=>{if(!await S(e,n.toNodeId,n.executionId))return"shutdown";if(await e.prepare("SELECT binding_id FROM sessions WHERE node_id = ? AND binding_id = ? AND unbound_at IS NULL").get(n.fromNodeId,n.fromBindingId)===void 0)return"changed";if(await e.prepare("SELECT run_id FROM nodes WHERE node_id IN (?, ?) AND run_id IS NOT NULL LIMIT 1").get(n.fromNodeId,n.toNodeId))throw new Error("run conversation transfer is not supported");const r=u();return await e.prepare("UPDATE sessions SET unbound_at = ? WHERE binding_id = ?").run(r,n.fromBindingId),await e.prepare("UPDATE sessions SET unbound_at = ? WHERE node_id = ? AND unbound_at IS NULL").run(r,n.toNodeId),await e.prepare("INSERT INTO sessions (binding_id, session_id, node_id, transcript_path, source_session_id, fork_entry_id, created_at, bound_at) VALUES (?, ?, ?, ?, NULL, NULL, ?, ?)").run(_(),n.sessionId,n.toNodeId,n.transcriptPath===null?null:d(n.transcriptPath),r,r),await e.prepare("UPDATE nodes SET cycle_pending = 0 WHERE node_id = ?").run(n.toNodeId),"transferred"})}i(H,"transferSession");async function O(n){await(await a()).prepare("UPDATE sessions SET unbound_at = ? WHERE node_id = ? AND unbound_at IS NULL").run(u(),n)}i(O,"unbindSession");async function P(n,e,s){const o=await(await a()).prepare("SELECT DISTINCT session_id FROM sessions WHERE node_id = ? AND session_id IS NOT NULL").all(n);let r=0;for(const t of o)await I(t.session_id,e,s)&&r++;return r}i(P,"relocateSessionCwd");async function x(n,e){await(await a()).prepare("UPDATE nodes SET cycle_pending = ? WHERE node_id = ?").run(e?1:0,n)}i(x,"setCyclePending");const N="unbound_at IS NULL DESC, created_at DESC, seq DESC";async function m(n){return(await(await a()).prepare(`SELECT node_id FROM sessions WHERE session_id = ? ORDER BY ${N} LIMIT 1`).get(n))?.node_id??null}i(m,"conversationOwner");function T(n){return L()}i(T,"openCanvasConversationStore");async function v(n){await f().importLegacy?.(n)}i(v,"repairRunConversations");async function M(){const n=T();return p(n),await n.importLegacy(),{async close(){p(void 0)}}}i(M,"serveCanvasConversationStore");export{h as bindSession,m as conversationOwner,C as findNodeBySessionFileSql,T as openCanvasConversationStore,b as readLiveSession,P as relocateSessionCwd,v as repairRunConversations,W as resetSession,M as serveCanvasConversationStore,x as setCyclePending,H as transferSession,O as unbindSession};
|
|
@@ -6,8 +6,10 @@ export interface RosterEdge {
|
|
|
6
6
|
active: boolean;
|
|
7
7
|
created: string;
|
|
8
8
|
}
|
|
9
|
-
/** Every in-tree node→node watch, oldest first — the roster's topology half.
|
|
10
|
-
|
|
9
|
+
/** Every in-tree node→node watch, oldest first — the roster's topology half. `visible` is the node ids the requester may
|
|
10
|
+
* see: only edges between two of them are read, so each person on a shared database gets their own edges; `null` reads
|
|
11
|
+
* every edge. */
|
|
12
|
+
export declare function rosterEdges(visible?: ReadonlySet<string> | null): Promise<RosterEdge[]>;
|
|
11
13
|
/** `subscriber` asks to watch `publisher` (an `ask` watch, in the tree). Re-running sets the
|
|
12
14
|
* pair's tree subscriptions active or passive (`{"3":"next-turn"}`). */
|
|
13
15
|
export declare function subscribe(subscriber: string, publisher: string, active?: boolean): Promise<void>;
|
package/dist/core/canvas/tree.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
var O=Object.defineProperty;var i=(o,t)=>O(o,"name",{value:t,configurable:!0});import{openDb as c,withCanvasWrite as
|
|
1
|
+
var O=Object.defineProperty;var i=(o,t)=>O(o,"name",{value:t,configurable:!0});import{openDb as c,withCanvasWrite as u}from"./db.js";import{getById as m,nodeObject as r}from"../graph/objects.js";import{recordWatch as y,unwatch as I,configFromJson as l,configToJson as b}from"../graph/watches.js";import{publish as T}from"../graph/events.js";import{DEFAULT_LISTEN as D}from"../graph/types.js";const v=["spawn","job-start","ask"],E="('spawn','job-start','ask')",R=[{threshold:3,delivery:"next-turn"}];function S(o){const t=o.find(a=>a.threshold<=7);return t!==void 0&&t.delivery!=="next-turn"}i(S,"wakesAtSeven");async function w(o,t,...a){const e=await o.prepareUncached(`SELECT wo.id AS from_id, oo.id AS to_id, ws.config_json, ws.created_at,
|
|
2
2
|
wo.listen_json, wn.status AS from_status, onode.status AS to_status
|
|
3
3
|
FROM watches w
|
|
4
4
|
JOIN objects wo ON wo.id = w.watcher AND wo.type = 'node'
|
|
5
5
|
JOIN objects oo ON oo.id = w.object AND oo.type = 'node'
|
|
6
|
-
JOIN watch_subscriptions ws ON ws.watch = w.watch_id AND ws.started_by IN ${
|
|
6
|
+
JOIN watch_subscriptions ws ON ws.watch = w.watch_id AND ws.started_by IN ${E}
|
|
7
7
|
JOIN nodes wn ON wn.node_id = wo.id
|
|
8
8
|
JOIN nodes onode ON onode.node_id = oo.id
|
|
9
9
|
WHERE w.in_tree = 1 ${t}
|
|
10
|
-
ORDER BY ws.created_at, ws.seq`).all(...a),s=new Map;for(const n of e){const
|
|
11
|
-
WHERE started_by IN ${
|
|
12
|
-
AND watch IN (SELECT watch_id FROM watches WHERE watcher = ? AND object = ?)`).run(a?null:b(R),(await r(e,o)).id,(await r(e,t)).id)})}i(j,"setSubscriptionActive");async function $(o){return(await w(await c(),"AND oo.id = ?",o)).map(t=>({node_id:t.from_id,active:t.active,created:t.created}))}i($,"subscribersOf");async function B(o){return(await w(await c(),"AND wo.id = ?",o)).map(t=>({node_id:t.to_id,active:t.active,created:t.created}))}i(B,"subscriptionsOf");function
|
|
10
|
+
ORDER BY ws.created_at, ws.seq`).all(...a),s=new Map;for(const n of e){const d=n.config_json,_=n.listen_json,f=d!=null?l(d):_!=null?l(_):D,N=`${n.from_id}\0${n.to_id}`,p=s.get(N);if(p){p.active||=S(f);continue}s.set(N,{from_id:n.from_id,to_id:n.to_id,active:S(f),created:n.created_at,from_status:n.from_status??null,to_status:n.to_status??null})}return[...s.values()]}i(w,"treeEdges");async function F(o=null){const t=o===null?null:[...o];return(t===null?await w(await c(),""):await w(await c(),"AND wo.id = ANY(?::text[]) AND oo.id = ANY(?::text[])",t,t)).map(({from_id:e,to_id:s,active:n,created:d})=>({from_id:e,to_id:s,active:n,created:d}))}i(F,"rosterEdges");async function W(o,t,a=!0){await u(async e=>{const s=await r(e,o),n=await r(e,t);await y(e,s,n,"ask"),await j(o,t,a),await T(e,{event:"watched",object:n,actor:s,attrs:{}})})}i(W,"subscribe");async function M(o,t){await u(async a=>{const e=await r(a,o),s=await r(a,t);for(const n of v)await I(a,e,s,{startedBy:n})})}i(M,"unsubscribe");async function j(o,t,a){await u(async e=>{await e.prepareUncached(`UPDATE watch_subscriptions SET config_json = ?
|
|
11
|
+
WHERE started_by IN ${E}
|
|
12
|
+
AND watch IN (SELECT watch_id FROM watches WHERE watcher = ? AND object = ?)`).run(a?null:b(R),(await r(e,o)).id,(await r(e,t)).id)})}i(j,"setSubscriptionActive");async function $(o){return(await w(await c(),"AND oo.id = ?",o)).map(t=>({node_id:t.from_id,active:t.active,created:t.created}))}i($,"subscribersOf");async function B(o){return(await w(await c(),"AND wo.id = ?",o)).map(t=>({node_id:t.to_id,active:t.active,created:t.created}))}i(B,"subscriptionsOf");function A(o){return`WITH RECURSIVE walk(id) AS (
|
|
13
13
|
SELECT CAST(? AS text)
|
|
14
14
|
UNION
|
|
15
15
|
SELECT w.object FROM walk
|
|
16
16
|
JOIN watches w ON w.watcher = walk.id AND w.in_tree = 1
|
|
17
17
|
${o?`JOIN objects oo ON oo.id = w.object AND oo.type = 'node' AND oo.kind IS DISTINCT FROM 'human'
|
|
18
18
|
JOIN nodes onode ON onode.node_id = oo.id`:"JOIN nodes onode ON onode.node_id = w.object"}
|
|
19
|
-
) SELECT id FROM walk WHERE id != ?`}i(
|
|
19
|
+
) SELECT id FROM walk WHERE id != ?`}i(A,"subtreeSql");const H=A(!0),x=A(!1);async function P(o){const t=await c(),a=await m(t,o);return a?.type!=="node"?[]:(await t.prepareUncached(x).all(a.id,a.id)).map(e=>e.id)}i(P,"view");const h=new Set(["active","idle"]);async function Q(o){return(await w(await c(),"AND wo.id = ?",o)).some(t=>t.active&&h.has(t.to_status??""))}i(Q,"hasActiveLiveSubscription");async function V(o){return(await w(await c(),"AND oo.id = ?",o)).some(t=>t.active&&h.has(t.from_status??""))}i(V,"hasLiveSubscriber");export{x as SUBTREE_ALL_IDS_SQL,H as SUBTREE_IDS_SQL,Q as hasActiveLiveSubscription,V as hasLiveSubscriber,F as rosterEdges,j as setSubscriptionActive,W as subscribe,$ as subscribersOf,B as subscriptionsOf,M as unsubscribe,P as view};
|