@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
|
@@ -68,6 +68,13 @@ export interface LaunchSpec {
|
|
|
68
68
|
systemPrompt?: string;
|
|
69
69
|
/** Extra env injected into the pi process. */
|
|
70
70
|
env: Record<string, string>;
|
|
71
|
+
/** A managed-worktree request for a node in a Blaxel sandbox (D102): the start script switches the image's clone of
|
|
72
|
+
* `repository` to a new `branch` cut from `base`. Absent on a Mac, where crtrd makes the worktree. */
|
|
73
|
+
worktree?: {
|
|
74
|
+
repository: string;
|
|
75
|
+
branch: string;
|
|
76
|
+
base: string;
|
|
77
|
+
};
|
|
71
78
|
}
|
|
72
79
|
/** The repository fingerprint a refusal was decided against. An examination
|
|
73
80
|
* that reads the same values can skip the whole proof cascade: nothing about
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var M=Object.defineProperty;var c=(e,t)=>M(e,"name",{value:t,configurable:!0});import{randomBytes as k}from"node:crypto";import{spawn as _}from"node:child_process";import{PROCESS_GROUP_KILL_GRACE_MS as S,posixProcessGroupSpawnOptions as R,terminateProcessGroup as V}from"../../../hook-process.js";import{isRecord as L}from"../../../shared/predicates.js";import{diag as x}from"../../io.js";import{LIFECYCLE_CATALOG as O}from"../lifecycle-catalog.js";import{getNode as A}from"../../canvas/canvas.js";import{buildAppProcessEnv as C}from"../../runtime/spawn-env.js";import{appProcessSandboxed as D,launchAppProcess as G}from"../../spaces/process.js";const P=10*1024*1024;async function H(e,t,n){try{const r=await B(e,t,n);r.ok||x(`crtr: ${g(e)} failed: ${r.error.code}: ${r.error.message}`)}catch(r){x(`crtr: ${g(e)} failed: ${w(r)}`)}}c(H,"invokeLifecycleHook");async function te(e,t){if(e.length===0)return;const{hookTimeoutMs:n,eventBudgetMs:r}=O[e[0].event],s=Date.now()+r;for(const o of e){const a=s-Date.now(),u=Math.min(n,a-S);if(u<=0){x(`crtr: lifecycle hook event ${o.event} exceeded its ${r}ms aggregate budget; skipped ${g(o)}`);return}await H(o,t,u)}}c(te,"invokeLifecycleHooks");async function re(e,t){if(e.length===0)return null;const{hookTimeoutMs:n,eventBudgetMs:r}=O["node:create"],s=Date.now()+r;for(const o of e){const a=s-Date.now(),u=Math.min(n,a-S);if(u<=0)return T(o,`lifecycle hook event node:create exceeded its ${r}ms aggregate budget`);try{const i=await B(o,t,u);if(!i.ok)return{hook:o,message:i.error.message,next:i.error.next??E(o)}}catch(i){return T(o,w(i))}}return null}c(re,"invokeBlockingLifecycleHooks");function T(e,t){return{hook:e,message:`${g(e)} failed: ${t}`,next:E(e)}}c(T,"refusal");function ne(e){return E(e)}c(ne,"lifecycleHookAttribution");async function B(e,t,n){const r=e.event==="node:create"?N(e,t):I(e,t),s=D()?await J(e,t,JSON.stringify(r),n):await q(e,JSON.stringify(r),n);if(s.signal!==null)throw new Error(`executable was killed by signal ${s.signal}`);const o=K(s.stdout);return o.ok&&s.status!==0&&x(`crtr: ${g(e)} returned ok:true but exited ${s.status} (honoring the envelope)`),o}c(B,"executeLifecycleHook");function I(e,t){return{protocolVersion:1,op:e.op,event:e.event,phase:e.phase,operationId:k(16).toString("hex"),node:t.node,runtime:t.runtime,context:{cwd:t.node.cwd}}}c(I,"nodeRequest");function N(e,t){return{protocolVersion:1,op:e.op,event:"node:create",phase:"before",operationId:k(16).toString("hex"),create:t.create,runtime:t.runtime,context:{cwd:t.create.cwd}}}c(N,"createRequest");async function J(e,t,n,r){const s=e.event==="node:create",o=s?t.create.cwd:t.node.cwd,a=s?void 0:t.node.id,u=s?t.app:(await A(a))?.grantee;if(!u)throw new Error(`missing app for lifecycle hook ${e.event}`);const i=C(o,t.runtime.profile,u),m=await G({...s?{app:u}:{nodeId:a},command:[e.executable,"--crtr-hook-protocol","1"],cwd:e.plugin.root,pluginRoot:e.plugin.root,env:i,stdin:n,stdoutBytes:P,stderrBytes:64*1024});let l;try{const p=await Promise.race([m.completion,new Promise((b,f)=>{l=setTimeout(()=>{m.stop().then(()=>f(new Error(`executable timed out after ${r}ms`)),f)},r)})]);if(p.stdoutTruncated)throw new Error("stdout exceeded the 10 MiB cap");return{stdout:p.stdout,status:p.exitCode,signal:p.signal}}finally{l&&clearTimeout(l)}}c(J,"runSandboxedLifecycleProcess");async function q(e,t,n){let r;try{r=_(e.executable,["--crtr-hook-protocol","1"],{cwd:e.plugin.root,env:process.env,stdio:["pipe","pipe","inherit"],...R()})}catch(s){throw new Error(`executable could not be run (${w(s)})`)}return new Promise((s,o)=>{let a=0;const u=[];let i,m=!1,l=!1,p=null,b=null,f;const y=c(()=>{if(!(!m||i!==void 0&&!l)){if(f!==void 0&&clearTimeout(f),i?.kind==="timeout")return o(new Error(`executable timed out after ${n}ms`));if(i?.kind==="output_limit")return o(new Error("stdout exceeded the 10 MiB cap"));if(i?.kind==="spawn")return o(new Error(`executable could not be run (${w(i.error)})`));if(i?.kind==="cleanup")return o(new Error(`executable cleanup failed (${w(i.error)})`));s({stdout:Buffer.concat(u).toString("utf8"),status:p,signal:b})}},"finish"),$=c(d=>{i===void 0&&(i=d,f!==void 0&&clearTimeout(f),V(r).then(()=>{l=!0,y()},h=>{i={kind:"cleanup",error:h},l=!0,y()}))},"terminate");r.stdout.on("data",d=>{if(a+=d.byteLength,a>P)return $({kind:"output_limit"});u.push(d)}),r.once("error",d=>{if(r.pid===void 0){i={kind:"spawn",error:d},m=!0,l=!0,y();return}$({kind:"spawn",error:d})}),r.once("close",(d,h)=>{p=d,b=h,m=!0,y()}),f=setTimeout(()=>$({kind:"timeout"}),n),r.stdin.end(t)})}c(q,"runLifecycleProcess");function K(e){let t;try{t=JSON.parse(e.trim())}catch{throw new Error("stdout was not a single JSON envelope")}if(!L(t)||t.protocolVersion!==1)throw new Error("stdout was not a protocolVersion: 1 envelope");if(t.ok===!0&&v(t,["protocolVersion","ok"]))return{protocolVersion:1,ok:!0};if(t.ok!==!1||!v(t,["protocolVersion","ok","error"]))throw new Error("response envelope had missing or extra fields");const n=t.error;if(!L(n)||!v(n,["code","message"],["next"])||typeof n.code!="string"||n.code===""||typeof n.message!="string"||n.message===""||n.next!==void 0&&typeof n.next!="string")throw new Error("failure envelope had invalid error fields");return{protocolVersion:1,ok:!1,error:{code:n.code,message:n.message,...n.next===void 0?{}:{next:n.next}}}}c(K,"parseEnvelope");function v(e,t,n=[]){return t.every(r=>Object.hasOwn(e,r))&&Object.keys(e).every(r=>t.includes(r)||n.includes(r))}c(v,"exactKeys");function g(e){return`plugin "${e.plugin.name}" lifecycle hook "${e.op}" for ${e.event}`}c(g,"label");function E(e){return`Refused by plugin ${e.plugin.name}, op ${e.op}.`}c(E,"attribution");function w(e){return e instanceof Error?e.message:String(e)}c(w,"describeError");export{re as invokeBlockingLifecycleHooks,H as invokeLifecycleHook,te as invokeLifecycleHooks,ne as lifecycleHookAttribution};
|
|
1
|
+
var M=Object.defineProperty;var c=(e,t)=>M(e,"name",{value:t,configurable:!0});import{randomBytes as k}from"node:crypto";import{spawn as _}from"node:child_process";import{PROCESS_GROUP_KILL_GRACE_MS as S,posixProcessGroupSpawnOptions as R,terminateProcessGroup as V}from"../../../hook-process.js";import{isRecord as L}from"../../../shared/predicates.js";import{diag as x}from"../../io.js";import{LIFECYCLE_CATALOG as O}from"../lifecycle-catalog.js";import{getNode as A}from"../../canvas/canvas.js";import{buildAppProcessEnv as C}from"../../runtime/spawn-env-rows.js";import{appProcessSandboxed as D,launchAppProcess as G}from"../../spaces/process.js";const P=10*1024*1024;async function H(e,t,n){try{const r=await B(e,t,n);r.ok||x(`crtr: ${g(e)} failed: ${r.error.code}: ${r.error.message}`)}catch(r){x(`crtr: ${g(e)} failed: ${w(r)}`)}}c(H,"invokeLifecycleHook");async function te(e,t){if(e.length===0)return;const{hookTimeoutMs:n,eventBudgetMs:r}=O[e[0].event],s=Date.now()+r;for(const o of e){const a=s-Date.now(),u=Math.min(n,a-S);if(u<=0){x(`crtr: lifecycle hook event ${o.event} exceeded its ${r}ms aggregate budget; skipped ${g(o)}`);return}await H(o,t,u)}}c(te,"invokeLifecycleHooks");async function re(e,t){if(e.length===0)return null;const{hookTimeoutMs:n,eventBudgetMs:r}=O["node:create"],s=Date.now()+r;for(const o of e){const a=s-Date.now(),u=Math.min(n,a-S);if(u<=0)return T(o,`lifecycle hook event node:create exceeded its ${r}ms aggregate budget`);try{const i=await B(o,t,u);if(!i.ok)return{hook:o,message:i.error.message,next:i.error.next??E(o)}}catch(i){return T(o,w(i))}}return null}c(re,"invokeBlockingLifecycleHooks");function T(e,t){return{hook:e,message:`${g(e)} failed: ${t}`,next:E(e)}}c(T,"refusal");function ne(e){return E(e)}c(ne,"lifecycleHookAttribution");async function B(e,t,n){const r=e.event==="node:create"?N(e,t):I(e,t),s=D()?await J(e,t,JSON.stringify(r),n):await q(e,JSON.stringify(r),n);if(s.signal!==null)throw new Error(`executable was killed by signal ${s.signal}`);const o=K(s.stdout);return o.ok&&s.status!==0&&x(`crtr: ${g(e)} returned ok:true but exited ${s.status} (honoring the envelope)`),o}c(B,"executeLifecycleHook");function I(e,t){return{protocolVersion:1,op:e.op,event:e.event,phase:e.phase,operationId:k(16).toString("hex"),node:t.node,runtime:t.runtime,context:{cwd:t.node.cwd}}}c(I,"nodeRequest");function N(e,t){return{protocolVersion:1,op:e.op,event:"node:create",phase:"before",operationId:k(16).toString("hex"),create:t.create,runtime:t.runtime,context:{cwd:t.create.cwd}}}c(N,"createRequest");async function J(e,t,n,r){const s=e.event==="node:create",o=s?t.create.cwd:t.node.cwd,a=s?void 0:t.node.id,u=s?t.app:(await A(a))?.grantee;if(!u)throw new Error(`missing app for lifecycle hook ${e.event}`);const i=await C(o,t.runtime.profile,u),m=await G({...s?{app:u}:{nodeId:a},command:[e.executable,"--crtr-hook-protocol","1"],cwd:e.plugin.root,pluginRoot:e.plugin.root,env:i,stdin:n,stdoutBytes:P,stderrBytes:64*1024});let l;try{const p=await Promise.race([m.completion,new Promise((b,f)=>{l=setTimeout(()=>{m.stop().then(()=>f(new Error(`executable timed out after ${r}ms`)),f)},r)})]);if(p.stdoutTruncated)throw new Error("stdout exceeded the 10 MiB cap");return{stdout:p.stdout,status:p.exitCode,signal:p.signal}}finally{l&&clearTimeout(l)}}c(J,"runSandboxedLifecycleProcess");async function q(e,t,n){let r;try{r=_(e.executable,["--crtr-hook-protocol","1"],{cwd:e.plugin.root,env:process.env,stdio:["pipe","pipe","inherit"],...R()})}catch(s){throw new Error(`executable could not be run (${w(s)})`)}return new Promise((s,o)=>{let a=0;const u=[];let i,m=!1,l=!1,p=null,b=null,f;const y=c(()=>{if(!(!m||i!==void 0&&!l)){if(f!==void 0&&clearTimeout(f),i?.kind==="timeout")return o(new Error(`executable timed out after ${n}ms`));if(i?.kind==="output_limit")return o(new Error("stdout exceeded the 10 MiB cap"));if(i?.kind==="spawn")return o(new Error(`executable could not be run (${w(i.error)})`));if(i?.kind==="cleanup")return o(new Error(`executable cleanup failed (${w(i.error)})`));s({stdout:Buffer.concat(u).toString("utf8"),status:p,signal:b})}},"finish"),$=c(d=>{i===void 0&&(i=d,f!==void 0&&clearTimeout(f),V(r).then(()=>{l=!0,y()},h=>{i={kind:"cleanup",error:h},l=!0,y()}))},"terminate");r.stdout.on("data",d=>{if(a+=d.byteLength,a>P)return $({kind:"output_limit"});u.push(d)}),r.once("error",d=>{if(r.pid===void 0){i={kind:"spawn",error:d},m=!0,l=!0,y();return}$({kind:"spawn",error:d})}),r.once("close",(d,h)=>{p=d,b=h,m=!0,y()}),f=setTimeout(()=>$({kind:"timeout"}),n),r.stdin.end(t)})}c(q,"runLifecycleProcess");function K(e){let t;try{t=JSON.parse(e.trim())}catch{throw new Error("stdout was not a single JSON envelope")}if(!L(t)||t.protocolVersion!==1)throw new Error("stdout was not a protocolVersion: 1 envelope");if(t.ok===!0&&v(t,["protocolVersion","ok"]))return{protocolVersion:1,ok:!0};if(t.ok!==!1||!v(t,["protocolVersion","ok","error"]))throw new Error("response envelope had missing or extra fields");const n=t.error;if(!L(n)||!v(n,["code","message"],["next"])||typeof n.code!="string"||n.code===""||typeof n.message!="string"||n.message===""||n.next!==void 0&&typeof n.next!="string")throw new Error("failure envelope had invalid error fields");return{protocolVersion:1,ok:!1,error:{code:n.code,message:n.message,...n.next===void 0?{}:{next:n.next}}}}c(K,"parseEnvelope");function v(e,t,n=[]){return t.every(r=>Object.hasOwn(e,r))&&Object.keys(e).every(r=>t.includes(r)||n.includes(r))}c(v,"exactKeys");function g(e){return`plugin "${e.plugin.name}" lifecycle hook "${e.op}" for ${e.event}`}c(g,"label");function E(e){return`Refused by plugin ${e.plugin.name}, op ${e.op}.`}c(E,"attribution");function w(e){return e instanceof Error?e.message:String(e)}c(w,"describeError");export{re as invokeBlockingLifecycleHooks,H as invokeLifecycleHook,te as invokeLifecycleHooks,ne as lifecycleHookAttribution};
|
|
@@ -98,7 +98,7 @@ export declare function isInstalledGeneration(name: string, scope: Scope, root:
|
|
|
98
98
|
* are recorded either way, because both describe the bytes now at the root. */
|
|
99
99
|
export declare function recordCheckedGeneration(scope: Scope, name: string, etag: string | undefined, options: {
|
|
100
100
|
swapped: boolean;
|
|
101
|
-
}): void
|
|
101
|
+
}): Promise<void>;
|
|
102
102
|
/** Every file lands by temp file plus rename, fsynced, so a crash mid-write leaves the previous bytes or
|
|
103
103
|
* the whole new ones — never a 0-byte `plugin.json` or `commands.json` that crashes the next boot. */
|
|
104
104
|
export declare function writeStagedBundle(stagingRoot: string, manifest: PluginManifest, bundle: ValidatedBundle): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var P=Object.defineProperty;var c=(e,o)=>P(e,"name",{value:o,configurable:!0});import{Parser as J}from"tar";import{createHash as I}from"node:crypto";import{chmodSync as W,renameSync as k}from"node:fs";import{dirname as $,join as w,resolve as V,sep as z}from"node:path";import{validateCommandManifest as B}from"../../api/command-manifest/manifest.js";import{ensureScopeInitialized as R,invalidPluginKindsReasons as F,readConfig as M,updateConfig as D,updateState as T}from"../config.js";import{general as x}from"../errors.js";import{atomicWriteJson as C,atomicWriteText as q,ensureDir as j,nowIso as E,pathExists as _,removePath as S,syncDirectory as H,syncTree as U}from"../fs-utils.js";import{invalidPageComponentsReasons as K,normalizePageComponents as G}from"../human/page-catalog.js";import{validateMemoryExtensionDeclarations as X}from"../plugin-extensions.js";import{objectBlocksShapeReasons as Z}from"../plugin-objects-manifest.js";import{validateBundleTransport as L}from"./endpoint.js";const O=/^[A-Za-z0-9_-]{1,64}$/,Y=new Set(["id","major","groups"]),Q=new Set(["group","consent_line","rate","who","allowlist"]),ee=new Set(["own","user","allowlist","any"]),ne=/^team:[a-z0-9]+$/,oe=new Set(["bundleVersion","kinds","page_components","memory_extensions","version","transport","provider","object_kinds","scopes","groups"]);function re(e,o,n,r,s,a){return{code:e,message:o,received:n,expected:r,next:s,...a!==void 0?{path:a}:{}}}c(re,"issue");function u(e,o,n,r,s){return re("plugin_bundle_invalid",e,o,n,r,s)}c(u,"bundleInvalid");function se(e){if(e[0]===31&&e[1]===139)return u("bundle archive must be uncompressed tar data","gzip-compressed archive","an uncompressed tar archive","Serve the archive without compression.");if(e.length===0||e.length%512!==0)return u("bundle archive must be a non-empty whole number of 512-byte tar blocks",`${e.length} bytes`,"a non-empty tar stream with a 512-byte block length","Serve one complete uncompressed tar archive.");if(e.length<1024||!e.subarray(-1024).every(o=>o===0))return u("bundle archive is missing the required two zero-block terminator","archive tail is not 1024 zero bytes","a complete tar stream ending in two 512-byte zero blocks","Serve the complete uncompressed tar archive.")}c(se,"archiveEnvelopeIssue");function te(e,o){if(e.length===0||e.includes("\0")||e.includes("\\")||e.startsWith("/")||/^[A-Za-z]:($|\/)/.test(e))return u("bundle member path must be a safe relative POSIX path",e,"a relative path without absolute, drive-letter, backslash, or NUL forms","Use a safe relative POSIX member path.",e);if(o==="file"&&e.endsWith("/"))return u("only directory members may have a trailing slash",e,"a regular-file path without a trailing slash","Emit this member as a regular file path.",e);if((o==="directory"&&e.endsWith("/")?e.slice(0,-1):e).split("/").some(r=>r===""||r==="."||r===".."))return u("bundle member path contains an unsafe segment",e,"non-empty segments other than . or ..","Use a safe relative POSIX member path.",e)}c(te,"validateMemberName");function ie(e,o){if(o==="file")return e==="bundle.json"||e==="commands.json"||e==="hooks.json"||e.startsWith("memory/")&&e.endsWith(".md")||e.startsWith("hooks/")?void 0:u("bundle contains an unsupported file member",e,"bundle.json, commands.json, hooks.json, memory/**/*.md, or hooks/**","Remove unsupported members from the archive.",e);if(!(e==="memory"||e.startsWith("memory/")||e==="hooks"||e.startsWith("hooks/")))return u("bundle contains an unsupported directory member",e,"memory or hooks, or a directory below either subtree","Remove unsupported directory members from the archive.",e)}c(ie,"validateMemberShape");function de(e){return e.type==="directory"&&e.path.endsWith("/")?e.path.slice(0,-1):e.path}c(de,"materializedPath");function ae(e){const o=new Map;for(const n of e){const r=de(n),s=o.get(r);if(s!==void 0)return u(s===n.type?"bundle contains a duplicate member":"bundle claims one path as both a file and a directory",`${r} (${s} and ${n.type})`,"each materialized path exactly once, with one type","Emit each archive path once, as a single member type.",r);o.set(r,n.type)}for(const[n,r]of o)if(r==="file"){for(const s of o.keys())if(s.startsWith(`${n}/`))return u("bundle nests a member beneath a regular-file path",`${s} beneath file ${n}`,"members nested only beneath directory paths","Emit the parent path as a directory or remove the nested member.",s)}}c(ae,"validateMemberTree");async function ue(e){const o=[],n=new Set;let r;return await new Promise((s,a)=>{const p=new J({strict:!0,maxMetaEntrySize:Number.MAX_SAFE_INTEGER,gzip:!1,brotli:!1,zstd:!1,onReadEntry:c(t=>{const d=t.path,f=t.type==="File"||t.type==="OldFile"?"file":t.type==="Directory"?"directory":void 0;if(f===void 0||t.unsupported||t.ignore||t.linkpath!==void 0){r??=u("bundle member must be a regular file or directory without a link target",`${d} (${t.type})`,"a regular file or directory member without link metadata","Remove links and unsupported member types from the archive.",d),t.resume();return}r??=te(d,f),r??=ie(d,f),n.has(d)&&(r??=u("bundle contains a duplicate member",d,"each member path exactly once","Emit each archive member only once.",d)),n.add(d);const i=[];t.on("data",b=>i.push(b)),t.on("end",()=>{r===void 0&&o.push({path:d,type:f,bytes:new Uint8Array(Buffer.concat(i))})})},"onReadEntry")});p.on("ignoredEntry",t=>{const d=t.path;r??=u("bundle contains an ignored or unsupported archive member",`${d} (${t.type})`,"only supported regular file or directory members","Remove ignored or unsupported members from the archive.",d),t.resume()}),p.once("error",a),p.once("end",s);try{p.end(Buffer.from(e))}catch(t){a(t)}}).catch(s=>{r??=u("bundle archive could not be parsed",s instanceof Error?s.message:String(s),"a valid complete uncompressed tar archive","Fix the archive format and serve it again.")}),r===void 0?{members:o}:{issue:r}}c(ue,"parseArchive");function N(e){return typeof e=="number"&&Number.isInteger(e)&&e>=1}c(N,"isPositiveInt");function le(e){const o=c((t,d,f,i)=>({issue:u(t,d,f,"Fix the provider block in bundle.json.",`bundle.json.${i}`)}),"bad");if(typeof e!="object"||e===null||Array.isArray(e))return o("bundle.json provider must be an object",JSON.stringify(e),"{ id, major, groups }","provider");const n=e,r=Object.keys(n).filter(t=>!Y.has(t));if(r.length>0)return o("bundle.json provider has unknown keys",r.join(", "),"only: id, major, groups","provider");if(typeof n.id!="string"||!O.test(n.id))return o("provider id must match [A-Za-z0-9_-]{1,64}",JSON.stringify(n.id),'a provider id of 1-64 letters, digits, "_" or "-"',"provider.id");if(!N(n.major))return o("provider major must be an integer of at least 1",JSON.stringify(n.major),"the served major as an integer >= 1","provider.major");const s=n.groups;if(!Array.isArray(s)||s.length===0)return o("provider groups must be a non-empty array",JSON.stringify(s),"at least one { group, consent_line, rate?, who, allowlist }","provider.groups");const a=[],p=new Set;for(let t=0;t<s.length;t++){const d=`provider.groups[${t}]`,f=s[t];if(typeof f!="object"||f===null||Array.isArray(f))return o("provider group must be an object",JSON.stringify(f),"{ group, consent_line, rate?, who, allowlist }",d);const i=f,b=Object.keys(i).filter(v=>!Q.has(v));if(b.length>0)return o("provider group has unknown keys",b.join(", "),"only: group, consent_line, rate, who, allowlist",d);if(typeof i.group!="string"||!O.test(i.group))return o("provider group id must match [A-Za-z0-9_-]{1,64}",JSON.stringify(i.group),'a group id of 1-64 letters, digits, "_" or "-"',`${d}.group`);if(p.has(i.group))return o("provider group ids must be unique",i.group,"each group declared once",`${d}.group`);if(p.add(i.group),typeof i.consent_line!="string"||i.consent_line.trim().length===0)return o("provider group consent_line must be a non-empty string",JSON.stringify(i.consent_line),"the consent line shown for this group",`${d}.consent_line`);const h=i.rate;if(h!=null&&(typeof h!="number"||!Number.isFinite(h)||h<0))return o("provider group rate must be a non-negative number or null",JSON.stringify(h),"a finite number >= 0, null, or omitted",`${d}.rate`);if(typeof i.who!="string"||!(ee.has(i.who)||ne.test(i.who)))return o("provider group who must be own|user|allowlist|any|team:<id>",JSON.stringify(i.who),"own | user | allowlist | any | team:<id> (id of lowercase letters and digits)",`${d}.who`);const m=i.allowlist;if(!Array.isArray(m)||!m.every(v=>typeof v=="string"&&v.length>0))return o("provider group allowlist must be an array of non-empty strings",JSON.stringify(m),"an array of app principals ([] unless who is allowlist)",`${d}.allowlist`);if(m.length>0&&i.who!=="allowlist")return o("provider group allowlist must be empty unless who is allowlist",`who ${i.who}`,'who: "allowlist", or allowlist: []',`${d}.allowlist`);a.push({group:i.group,consent_line:i.consent_line,...h!==void 0?{rate:h}:{},who:i.who,allowlist:m})}return{provider:{id:n.id,major:n.major,groups:a}}}c(le,"parseProviderBlock");function pe(e){const o=[],n=c((r,s)=>{const a=[...s,r.name];if(r.kind==="leaf")o.push({path:a.join(" "),leaf:r});else for(const p of r.children)n(p,a)},"walk");for(const r of e.roots)n(r,[]);for(const r of e.coreMounts)n(r.node,r.parent);return o}c(pe,"collectLeaves");function ce(e,o){const n=e.provider;if(n===void 0)return;if(e.transport===void 0)return u("a provider bundle must declare its transport","(missing)",'transport { kind: "http", endpoint } in bundle.json',"Add the provider endpoint as bundle.json transport.","bundle.json.transport");if(e.transport.kind==="http"&&e.transport.authEnv!==void 0)return u("a provider bundle must not declare authEnv",e.transport.authEnv,"no authEnv: the runtime presents its own outbound token","Remove transport.authEnv from bundle.json.","bundle.json.transport.authEnv");const r=new Set(n.groups.map(s=>s.group));for(const{path:s,leaf:a}of pe(o)){const p="group"in a?a.group:void 0;if(p===void 0)return u(`provider leaf "${s}" has no group`,s,"a group on every leaf of a provider bundle",`Add a group to leaf "${s}".`,`commands.json:${s}.group`);if(!r.has(p))return u(`provider leaf "${s}" names undeclared group "${p}"`,p,`one of: ${[...r].join(", ")}`,`Declare group "${p}" in the provider block, or move leaf "${s}" to a declared group.`,`commands.json:${s}.group`);if("rest"in a&&a.rest.streaming===!0)return u(`provider leaf "${s}" streams`,"rest.streaming: true","no streaming leaves in a provider bundle",`Make leaf "${s}" return one response.`,`commands.json:${s}.rest.streaming`)}}c(ce,"providerBundleIssue");function me(e){let o;try{o=JSON.parse(Buffer.from(e).toString("utf8"))}catch{return{issue:u("bundle.json is not valid JSON","invalid JSON",'{"bundleVersion":1}',"Write valid bundle metadata.","bundle.json")}}if(typeof o!="object"||o===null||Array.isArray(o))return{issue:u("bundle.json must be a JSON object",JSON.stringify(o),"an object with bundleVersion set to 1 and optionally kinds",'Set bundle.json to {"bundleVersion":1}.',"bundle.json")};const n=o,r=Object.keys(n).filter(d=>!oe.has(d));if(n.bundleVersion!==1||r.length>0)return{issue:u("bundle.json must contain bundleVersion 1 and at most version, transport, provider, kinds, page_components, memory_extensions, object_kinds, scopes, and groups",JSON.stringify(o),"an object with bundleVersion set to 1 and optional version, transport, provider, kinds, page_components, memory_extensions, object_kinds, scopes, and groups",'Set bundle.json to {"bundleVersion":1} plus optional contribution blocks.',"bundle.json")};if(n.kinds!==void 0){const d=F(n.kinds);if(d.length>0)return{issue:u("bundle.json kinds block is invalid",d.join("; "),"each entry a full KindConfig (whenToUse required) or a sparse patch of launch fields","Fix the kinds entries in bundle.json.","bundle.json")}}if(n.page_components!==void 0){const d=K(n.page_components);if(d.length>0)return{issue:u("bundle.json page_components block is invalid",d.join("; "),"an array of page component registrations, each a kind string or {kind, description?, useWhen?, doc?, display?}","Fix the page_components entries in bundle.json.","bundle.json")}}const s=Z(n);if(n.provider!==void 0&&n.scopes!==void 0&&s.push("scopes is for local plugins; a provider gets its scopes from directory consent"),s.length>0)return{issue:u("bundle.json object_kinds or scopes block is invalid",s.join("; "),"object_kinds keyed by kind name with description, events and optional read.command; scopes an array of crtr:objects:<verb>:<target> strings (local plugins only)","Fix the object_kinds and scopes blocks in bundle.json.","bundle.json")};let a;if(n.memory_extensions!==void 0)try{a=X(n.memory_extensions)}catch(d){return{issue:u("bundle.json memory_extensions block is invalid",d instanceof Error?d.message:String(d),"a valid memory_extensions declaration object","Fix the memory_extensions declarations in bundle.json.","bundle.json")}}if(n.version!==void 0&&!N(n.version))return{issue:u("bundle.json version must be an integer of at least 1",JSON.stringify(n.version),"the plugin major as an integer >= 1, or omitted","Fix version in bundle.json.","bundle.json.version")};let p;if(n.transport!==void 0){const d=L(n.transport);if(d.transport===void 0)return{issue:u("bundle.json transport is invalid",d.errors.join("; "),'{ kind: "http", endpoint, authEnv? } or { kind: "machine" }',"Fix transport in bundle.json.","bundle.json.transport")};p=d.transport}let t;if(n.provider!==void 0){const d=le(n.provider);if(d.issue!==void 0)return{issue:d.issue};if(t=d.provider,n.version!==void 0&&n.version!==t.major)return{issue:u("bundle.json provider major must equal version",`version ${String(n.version)}, major ${t.major}`,"one major","Set provider.major and version to the same integer.","bundle.json.provider.major")}}return{...n.version!==void 0?{version:n.version}:{},...p!==void 0?{transport:p}:{},...t!==void 0?{provider:t}:{},...n.kinds!==void 0?{kinds:n.kinds}:{},...n.page_components!==void 0?{page_components:G(n.page_components)}:{},...a!==void 0?{memory_extensions:a}:{},...n.object_kinds!==void 0?{object_kinds:n.object_kinds}:{},...n.scopes!==void 0?{scopes:n.scopes}:{}}}c(me,"parseBundleMetadata");function fe(e,o,n,r=new Set){let s;try{s=JSON.parse(Buffer.from(e).toString("utf8"))}catch{return{issues:[u("commands.json is not valid JSON","invalid JSON","a valid command-manifest JSON object","Regenerate commands.json.","commands.json")]}}const a=B(s,{transport:"http",reservedCoreNames:o,extensibleCoreBranches:r,...n!==void 0?{coreCommandPaths:n}:{}});return{...a.manifest!==void 0?{commands:a.manifest}:{},issues:a.issues}}c(fe,"parseCommands");async function he(e,o){const n=se(e);if(n!==void 0)return{issues:[n]};const r=await ue(e);if(r.issue!==void 0||r.members===void 0)return{issues:[r.issue]};const s=ae(r.members);if(s!==void 0)return{issues:[s]};const a=r.members.find(l=>l.path==="bundle.json"&&l.type==="file"),p=r.members.find(l=>l.path==="commands.json"&&l.type==="file");if(a===void 0||p===void 0)return{issues:[u("bundle must contain exactly one bundle.json and one commands.json regular file",`bundle.json=${a!==void 0}, commands.json=${p!==void 0}`,"one regular bundle.json and one regular commands.json member","Add the required metadata members to the archive.")]};const t=r.members.find(l=>l.path==="hooks.json"&&l.type==="file"),d=r.members.filter(l=>l.type==="file"&&l.path.startsWith("hooks/"));if((t!==void 0||r.members.some(l=>l.path==="hooks"||l.path.startsWith("hooks/")))&&(t===void 0||!d.some(l=>l.path==="hooks/dispatch")))return{issues:[u("bundle hook payload must contain both hooks.json and hooks/dispatch regular files",`hooks.json=${t!==void 0}, hooks/dispatch=${d.some(l=>l.path==="hooks/dispatch")}`,"both hooks.json and hooks/dispatch regular files","Add both required hook members or remove the hook payload.")]};const i=me(a.bytes);if(i.issue!==void 0)return{issues:[i.issue]};const b=fe(p.bytes,o.reservedCoreNames,o.coreCommandPaths,o.extensibleCoreBranches);if(b.commands===void 0)return{issues:b.issues};const h=b.commands.version;if(i.version!==void 0&&h!==void 0&&i.version!==h)return{issues:[u("bundle.json version and commands.json version differ",`bundle.json ${i.version}, commands.json ${h}`,"one plugin major","Emit the same version in bundle.json and commands.json.","bundle.json.version")]};const m=i.version??h;if(i.provider!==void 0&&m===void 0)return{issues:[u("a provider bundle requires a plugin version","no version in bundle.json or commands.json",`version ${i.provider.major}, the provider major`,"Emit the provider major as the plugin version.","bundle.json.version")]};if(i.provider!==void 0&&m!==i.provider.major)return{issues:[u("bundle provider major must equal the plugin version",`version ${m}, major ${i.provider.major}`,"one major","Emit the provider major as the plugin version.","bundle.json.provider.major")]};const v=ce(i,b.commands);return v!==void 0?{issues:[v]}:{bundle:{bundleVersion:1,...m!==void 0?{version:m}:{},...i.transport!==void 0?{transport:i.transport}:{},...i.provider!==void 0?{provider:i.provider}:{},...i.kinds!==void 0?{kinds:i.kinds}:{},...i.page_components!==void 0?{page_components:i.page_components}:{},...i.memory_extensions!==void 0?{memory_extensions:i.memory_extensions}:{},...i.object_kinds!==void 0?{object_kinds:i.object_kinds}:{},...i.scopes!==void 0?{scopes:i.scopes}:{},commands:b.commands,commandsBytes:p.bytes,directories:r.members.filter(l=>l.type==="directory").map(l=>({path:l.path})),memory:r.members.filter(l=>l.type==="file"&&l.path.startsWith("memory/")).map(l=>({path:l.path,bytes:l.bytes})),...t!==void 0?{hooks:{manifest:t.bytes,files:d.map(l=>({path:l.path,bytes:l.bytes}))}}:{}},issues:[]}}c(he,"validatePluginBundle");function be(e){return I("sha256").update(e).digest("hex").slice(0,12)}c(be,"bundleVersion");function Je(e,o,n,r){return M(o).plugins[e]?.version!==r?!1:_(w(n,"commands.json"))}c(Je,"isInstalledGeneration");function ve(e,o,n,r){T(e,s=>{s.plugins[o]===void 0&&(s.plugins[o]={}),r.swapped&&(s.plugins[o].last_updated=E()),s.plugins[o].checked_at=E(),n===void 0?delete s.plugins[o].etag:s.plugins[o].etag=n})}c(ve,"recordCheckedGeneration");function g(e,o){const n=V(e,o);if(n===e||!n.startsWith(e+z))throw x(`bundle member path escapes the staging directory: ${o}`);return n}c(g,"stagedPath");function ge(e,o,n){const r=c((s,a,p=420)=>q(s,a,{mode:p,durable:!0}),"write");C(g(e,".crouter-plugin/plugin.json"),o,{durable:!0});for(const s of n.directories)j(g(e,s.path));r(g(e,"commands.json"),n.commandsBytes);for(const s of n.memory)r(g(e,s.path),s.bytes);if(n.hooks!==void 0){r(g(e,"hooks.json"),n.hooks.manifest);for(const s of n.hooks.files)r(g(e,s.path),s.bytes);W(g(e,"hooks/dispatch"),493)}U(e)}c(ge,"writeStagedBundle");async function Ie(e,o,n){const{scope:r,scopeRootPath:s,root:a}=n,p=await he(o,n.validation);if(p.bundle===void 0)throw n.invalid(`HTTP plugin bundle for "${e}" is invalid`,p.issues);const t=p.bundle,d=n.accept?.(t);if(d!==void 0)throw n.invalid(`HTTP plugin bundle for "${e}" is invalid`,[u(d,e,"the bundle this install asked for","Serve the requested bundle.")]);const f=n.version??be(o),i=t.provider!==void 0&&t.transport!==void 0?t.transport:n.transport,b={name:e,version:f,commands:"commands.json",transport:i,bundle:n.bundle,...t.kinds!==void 0?{kinds:t.kinds}:{},...t.page_components!==void 0?{page_components:t.page_components}:{},...t.memory_extensions!==void 0?{memory_extensions:t.memory_extensions}:{},...t.object_kinds!==void 0?{object_kinds:t.object_kinds}:{},...t.scopes!==void 0?{scopes:t.scopes}:{},...t.hooks!==void 0?{hooks:"hooks.json",hookExecutable:"hooks/dispatch"}:{},...t.provider!==void 0?{provider:t.provider}:{}},h=w(s,"tmp"),m=w(h,`${e}.${process.pid}`),v=`${m}.prev`;if(_(v))throw x(`cannot replace plugin "${e}": prior interrupted replacement remains at ${v}`);j(h),j($(a)),S(m);let l;try{j(m),ge(m,b,t),l=await n.validateStaged(m,b);let y=!1;_(a)&&(k(a,v),y=!0);try{k(m,a)}catch(A){throw y&&k(v,a),A}H($(a)),y&&S(v)}finally{S(m)}return R(r,s),D(r,y=>{y.plugins[e]={enabled:n.enable?!0:y.plugins[e]?.enabled??!0,version:f}}),ve(r,e,n.etag,{swapped:!0}),{manifest:b,validated:t,version:f,root:a,staged:l}}c(Ie,"installBundleArchive");export{be as bundleVersion,Ie as installBundleArchive,Je as isInstalledGeneration,ve as recordCheckedGeneration,he as validatePluginBundle,ge as writeStagedBundle};
|
|
1
|
+
var P=Object.defineProperty;var c=(e,o)=>P(e,"name",{value:o,configurable:!0});import{Parser as J}from"tar";import{createHash as I}from"node:crypto";import{chmodSync as W,renameSync as k}from"node:fs";import{dirname as $,join as w,resolve as V,sep as z}from"node:path";import{validateCommandManifest as B}from"../../api/command-manifest/manifest.js";import{ensureScopeInitialized as R,invalidPluginKindsReasons as F,readConfig as M,updateConfig as D,updateState as T}from"../config.js";import{general as x}from"../errors.js";import{atomicWriteJson as C,atomicWriteText as q,ensureDir as j,nowIso as E,pathExists as _,removePath as S,syncDirectory as H,syncTree as U}from"../fs-utils.js";import{invalidPageComponentsReasons as K,normalizePageComponents as G}from"../human/page-catalog.js";import{validateMemoryExtensionDeclarations as X}from"../plugin-extensions.js";import{objectBlocksShapeReasons as Z}from"../plugin-objects-manifest.js";import{validateBundleTransport as L}from"./endpoint.js";const O=/^[A-Za-z0-9_-]{1,64}$/,Y=new Set(["id","major","groups"]),Q=new Set(["group","consent_line","rate","who","allowlist"]),ee=new Set(["own","user","allowlist","any"]),ne=/^team:[a-z0-9]+$/,oe=new Set(["bundleVersion","kinds","page_components","memory_extensions","version","transport","provider","object_kinds","scopes","groups"]);function re(e,o,n,r,s,d){return{code:e,message:o,received:n,expected:r,next:s,...d!==void 0?{path:d}:{}}}c(re,"issue");function u(e,o,n,r,s){return re("plugin_bundle_invalid",e,o,n,r,s)}c(u,"bundleInvalid");function se(e){if(e[0]===31&&e[1]===139)return u("bundle archive must be uncompressed tar data","gzip-compressed archive","an uncompressed tar archive","Serve the archive without compression.");if(e.length===0||e.length%512!==0)return u("bundle archive must be a non-empty whole number of 512-byte tar blocks",`${e.length} bytes`,"a non-empty tar stream with a 512-byte block length","Serve one complete uncompressed tar archive.");if(e.length<1024||!e.subarray(-1024).every(o=>o===0))return u("bundle archive is missing the required two zero-block terminator","archive tail is not 1024 zero bytes","a complete tar stream ending in two 512-byte zero blocks","Serve the complete uncompressed tar archive.")}c(se,"archiveEnvelopeIssue");function te(e,o){if(e.length===0||e.includes("\0")||e.includes("\\")||e.startsWith("/")||/^[A-Za-z]:($|\/)/.test(e))return u("bundle member path must be a safe relative POSIX path",e,"a relative path without absolute, drive-letter, backslash, or NUL forms","Use a safe relative POSIX member path.",e);if(o==="file"&&e.endsWith("/"))return u("only directory members may have a trailing slash",e,"a regular-file path without a trailing slash","Emit this member as a regular file path.",e);if((o==="directory"&&e.endsWith("/")?e.slice(0,-1):e).split("/").some(r=>r===""||r==="."||r===".."))return u("bundle member path contains an unsafe segment",e,"non-empty segments other than . or ..","Use a safe relative POSIX member path.",e)}c(te,"validateMemberName");function ie(e,o){if(o==="file")return e==="bundle.json"||e==="commands.json"||e==="hooks.json"||e.startsWith("memory/")&&e.endsWith(".md")||e.startsWith("hooks/")?void 0:u("bundle contains an unsupported file member",e,"bundle.json, commands.json, hooks.json, memory/**/*.md, or hooks/**","Remove unsupported members from the archive.",e);if(!(e==="memory"||e.startsWith("memory/")||e==="hooks"||e.startsWith("hooks/")))return u("bundle contains an unsupported directory member",e,"memory or hooks, or a directory below either subtree","Remove unsupported directory members from the archive.",e)}c(ie,"validateMemberShape");function ae(e){return e.type==="directory"&&e.path.endsWith("/")?e.path.slice(0,-1):e.path}c(ae,"materializedPath");function de(e){const o=new Map;for(const n of e){const r=ae(n),s=o.get(r);if(s!==void 0)return u(s===n.type?"bundle contains a duplicate member":"bundle claims one path as both a file and a directory",`${r} (${s} and ${n.type})`,"each materialized path exactly once, with one type","Emit each archive path once, as a single member type.",r);o.set(r,n.type)}for(const[n,r]of o)if(r==="file"){for(const s of o.keys())if(s.startsWith(`${n}/`))return u("bundle nests a member beneath a regular-file path",`${s} beneath file ${n}`,"members nested only beneath directory paths","Emit the parent path as a directory or remove the nested member.",s)}}c(de,"validateMemberTree");async function ue(e){const o=[],n=new Set;let r;return await new Promise((s,d)=>{const p=new J({strict:!0,maxMetaEntrySize:Number.MAX_SAFE_INTEGER,gzip:!1,brotli:!1,zstd:!1,onReadEntry:c(t=>{const a=t.path,f=t.type==="File"||t.type==="OldFile"?"file":t.type==="Directory"?"directory":void 0;if(f===void 0||t.unsupported||t.ignore||t.linkpath!==void 0){r??=u("bundle member must be a regular file or directory without a link target",`${a} (${t.type})`,"a regular file or directory member without link metadata","Remove links and unsupported member types from the archive.",a),t.resume();return}r??=te(a,f),r??=ie(a,f),n.has(a)&&(r??=u("bundle contains a duplicate member",a,"each member path exactly once","Emit each archive member only once.",a)),n.add(a);const i=[];t.on("data",b=>i.push(b)),t.on("end",()=>{r===void 0&&o.push({path:a,type:f,bytes:new Uint8Array(Buffer.concat(i))})})},"onReadEntry")});p.on("ignoredEntry",t=>{const a=t.path;r??=u("bundle contains an ignored or unsupported archive member",`${a} (${t.type})`,"only supported regular file or directory members","Remove ignored or unsupported members from the archive.",a),t.resume()}),p.once("error",d),p.once("end",s);try{p.end(Buffer.from(e))}catch(t){d(t)}}).catch(s=>{r??=u("bundle archive could not be parsed",s instanceof Error?s.message:String(s),"a valid complete uncompressed tar archive","Fix the archive format and serve it again.")}),r===void 0?{members:o}:{issue:r}}c(ue,"parseArchive");function N(e){return typeof e=="number"&&Number.isInteger(e)&&e>=1}c(N,"isPositiveInt");function le(e){const o=c((t,a,f,i)=>({issue:u(t,a,f,"Fix the provider block in bundle.json.",`bundle.json.${i}`)}),"bad");if(typeof e!="object"||e===null||Array.isArray(e))return o("bundle.json provider must be an object",JSON.stringify(e),"{ id, major, groups }","provider");const n=e,r=Object.keys(n).filter(t=>!Y.has(t));if(r.length>0)return o("bundle.json provider has unknown keys",r.join(", "),"only: id, major, groups","provider");if(typeof n.id!="string"||!O.test(n.id))return o("provider id must match [A-Za-z0-9_-]{1,64}",JSON.stringify(n.id),'a provider id of 1-64 letters, digits, "_" or "-"',"provider.id");if(!N(n.major))return o("provider major must be an integer of at least 1",JSON.stringify(n.major),"the served major as an integer >= 1","provider.major");const s=n.groups;if(!Array.isArray(s)||s.length===0)return o("provider groups must be a non-empty array",JSON.stringify(s),"at least one { group, consent_line, rate?, who, allowlist }","provider.groups");const d=[],p=new Set;for(let t=0;t<s.length;t++){const a=`provider.groups[${t}]`,f=s[t];if(typeof f!="object"||f===null||Array.isArray(f))return o("provider group must be an object",JSON.stringify(f),"{ group, consent_line, rate?, who, allowlist }",a);const i=f,b=Object.keys(i).filter(v=>!Q.has(v));if(b.length>0)return o("provider group has unknown keys",b.join(", "),"only: group, consent_line, rate, who, allowlist",a);if(typeof i.group!="string"||!O.test(i.group))return o("provider group id must match [A-Za-z0-9_-]{1,64}",JSON.stringify(i.group),'a group id of 1-64 letters, digits, "_" or "-"',`${a}.group`);if(p.has(i.group))return o("provider group ids must be unique",i.group,"each group declared once",`${a}.group`);if(p.add(i.group),typeof i.consent_line!="string"||i.consent_line.trim().length===0)return o("provider group consent_line must be a non-empty string",JSON.stringify(i.consent_line),"the consent line shown for this group",`${a}.consent_line`);const h=i.rate;if(h!=null&&(typeof h!="number"||!Number.isFinite(h)||h<0))return o("provider group rate must be a non-negative number or null",JSON.stringify(h),"a finite number >= 0, null, or omitted",`${a}.rate`);if(typeof i.who!="string"||!(ee.has(i.who)||ne.test(i.who)))return o("provider group who must be own|user|allowlist|any|team:<id>",JSON.stringify(i.who),"own | user | allowlist | any | team:<id> (id of lowercase letters and digits)",`${a}.who`);const m=i.allowlist;if(!Array.isArray(m)||!m.every(v=>typeof v=="string"&&v.length>0))return o("provider group allowlist must be an array of non-empty strings",JSON.stringify(m),"an array of app principals ([] unless who is allowlist)",`${a}.allowlist`);if(m.length>0&&i.who!=="allowlist")return o("provider group allowlist must be empty unless who is allowlist",`who ${i.who}`,'who: "allowlist", or allowlist: []',`${a}.allowlist`);d.push({group:i.group,consent_line:i.consent_line,...h!==void 0?{rate:h}:{},who:i.who,allowlist:m})}return{provider:{id:n.id,major:n.major,groups:d}}}c(le,"parseProviderBlock");function pe(e){const o=[],n=c((r,s)=>{const d=[...s,r.name];if(r.kind==="leaf")o.push({path:d.join(" "),leaf:r});else for(const p of r.children)n(p,d)},"walk");for(const r of e.roots)n(r,[]);for(const r of e.coreMounts)n(r.node,r.parent);return o}c(pe,"collectLeaves");function ce(e,o){const n=e.provider;if(n===void 0)return;if(e.transport===void 0)return u("a provider bundle must declare its transport","(missing)",'transport { kind: "http", endpoint } in bundle.json',"Add the provider endpoint as bundle.json transport.","bundle.json.transport");if(e.transport.kind==="http"&&e.transport.authEnv!==void 0)return u("a provider bundle must not declare authEnv",e.transport.authEnv,"no authEnv: the runtime presents its own outbound token","Remove transport.authEnv from bundle.json.","bundle.json.transport.authEnv");const r=new Set(n.groups.map(s=>s.group));for(const{path:s,leaf:d}of pe(o)){const p="group"in d?d.group:void 0;if(p===void 0)return u(`provider leaf "${s}" has no group`,s,"a group on every leaf of a provider bundle",`Add a group to leaf "${s}".`,`commands.json:${s}.group`);if(!r.has(p))return u(`provider leaf "${s}" names undeclared group "${p}"`,p,`one of: ${[...r].join(", ")}`,`Declare group "${p}" in the provider block, or move leaf "${s}" to a declared group.`,`commands.json:${s}.group`);if("rest"in d&&d.rest.streaming===!0)return u(`provider leaf "${s}" streams`,"rest.streaming: true","no streaming leaves in a provider bundle",`Make leaf "${s}" return one response.`,`commands.json:${s}.rest.streaming`)}}c(ce,"providerBundleIssue");function me(e){let o;try{o=JSON.parse(Buffer.from(e).toString("utf8"))}catch{return{issue:u("bundle.json is not valid JSON","invalid JSON",'{"bundleVersion":1}',"Write valid bundle metadata.","bundle.json")}}if(typeof o!="object"||o===null||Array.isArray(o))return{issue:u("bundle.json must be a JSON object",JSON.stringify(o),"an object with bundleVersion set to 1 and optionally kinds",'Set bundle.json to {"bundleVersion":1}.',"bundle.json")};const n=o,r=Object.keys(n).filter(a=>!oe.has(a));if(n.bundleVersion!==1||r.length>0)return{issue:u("bundle.json must contain bundleVersion 1 and at most version, transport, provider, kinds, page_components, memory_extensions, object_kinds, scopes, and groups",JSON.stringify(o),"an object with bundleVersion set to 1 and optional version, transport, provider, kinds, page_components, memory_extensions, object_kinds, scopes, and groups",'Set bundle.json to {"bundleVersion":1} plus optional contribution blocks.',"bundle.json")};if(n.kinds!==void 0){const a=F(n.kinds);if(a.length>0)return{issue:u("bundle.json kinds block is invalid",a.join("; "),"each entry a full KindConfig (whenToUse required) or a sparse patch of launch fields","Fix the kinds entries in bundle.json.","bundle.json")}}if(n.page_components!==void 0){const a=K(n.page_components);if(a.length>0)return{issue:u("bundle.json page_components block is invalid",a.join("; "),"an array of page component registrations, each a kind string or {kind, description?, useWhen?, doc?, display?}","Fix the page_components entries in bundle.json.","bundle.json")}}const s=Z(n);if(n.provider!==void 0&&n.scopes!==void 0&&s.push("scopes is for local plugins; a provider gets its scopes from directory consent"),s.length>0)return{issue:u("bundle.json object_kinds or scopes block is invalid",s.join("; "),"object_kinds keyed by kind name with description, events and optional read.command; scopes an array of crtr:objects:<verb>:<target> strings (local plugins only)","Fix the object_kinds and scopes blocks in bundle.json.","bundle.json")};let d;if(n.memory_extensions!==void 0)try{d=X(n.memory_extensions)}catch(a){return{issue:u("bundle.json memory_extensions block is invalid",a instanceof Error?a.message:String(a),"a valid memory_extensions declaration object","Fix the memory_extensions declarations in bundle.json.","bundle.json")}}if(n.version!==void 0&&!N(n.version))return{issue:u("bundle.json version must be an integer of at least 1",JSON.stringify(n.version),"the plugin major as an integer >= 1, or omitted","Fix version in bundle.json.","bundle.json.version")};let p;if(n.transport!==void 0){const a=L(n.transport);if(a.transport===void 0)return{issue:u("bundle.json transport is invalid",a.errors.join("; "),'{ kind: "http", endpoint, authEnv? } or { kind: "machine" }',"Fix transport in bundle.json.","bundle.json.transport")};p=a.transport}let t;if(n.provider!==void 0){const a=le(n.provider);if(a.issue!==void 0)return{issue:a.issue};if(t=a.provider,n.version!==void 0&&n.version!==t.major)return{issue:u("bundle.json provider major must equal version",`version ${String(n.version)}, major ${t.major}`,"one major","Set provider.major and version to the same integer.","bundle.json.provider.major")}}return{...n.version!==void 0?{version:n.version}:{},...p!==void 0?{transport:p}:{},...t!==void 0?{provider:t}:{},...n.kinds!==void 0?{kinds:n.kinds}:{},...n.page_components!==void 0?{page_components:G(n.page_components)}:{},...d!==void 0?{memory_extensions:d}:{},...n.object_kinds!==void 0?{object_kinds:n.object_kinds}:{},...n.scopes!==void 0?{scopes:n.scopes}:{}}}c(me,"parseBundleMetadata");function fe(e,o,n,r=new Set){let s;try{s=JSON.parse(Buffer.from(e).toString("utf8"))}catch{return{issues:[u("commands.json is not valid JSON","invalid JSON","a valid command-manifest JSON object","Regenerate commands.json.","commands.json")]}}const d=B(s,{transport:"http",reservedCoreNames:o,extensibleCoreBranches:r,...n!==void 0?{coreCommandPaths:n}:{}});return{...d.manifest!==void 0?{commands:d.manifest}:{},issues:d.issues}}c(fe,"parseCommands");async function he(e,o){const n=se(e);if(n!==void 0)return{issues:[n]};const r=await ue(e);if(r.issue!==void 0||r.members===void 0)return{issues:[r.issue]};const s=de(r.members);if(s!==void 0)return{issues:[s]};const d=r.members.find(l=>l.path==="bundle.json"&&l.type==="file"),p=r.members.find(l=>l.path==="commands.json"&&l.type==="file");if(d===void 0||p===void 0)return{issues:[u("bundle must contain exactly one bundle.json and one commands.json regular file",`bundle.json=${d!==void 0}, commands.json=${p!==void 0}`,"one regular bundle.json and one regular commands.json member","Add the required metadata members to the archive.")]};const t=r.members.find(l=>l.path==="hooks.json"&&l.type==="file"),a=r.members.filter(l=>l.type==="file"&&l.path.startsWith("hooks/"));if((t!==void 0||r.members.some(l=>l.path==="hooks"||l.path.startsWith("hooks/")))&&(t===void 0||!a.some(l=>l.path==="hooks/dispatch")))return{issues:[u("bundle hook payload must contain both hooks.json and hooks/dispatch regular files",`hooks.json=${t!==void 0}, hooks/dispatch=${a.some(l=>l.path==="hooks/dispatch")}`,"both hooks.json and hooks/dispatch regular files","Add both required hook members or remove the hook payload.")]};const i=me(d.bytes);if(i.issue!==void 0)return{issues:[i.issue]};const b=fe(p.bytes,o.reservedCoreNames,o.coreCommandPaths,o.extensibleCoreBranches);if(b.commands===void 0)return{issues:b.issues};const h=b.commands.version;if(i.version!==void 0&&h!==void 0&&i.version!==h)return{issues:[u("bundle.json version and commands.json version differ",`bundle.json ${i.version}, commands.json ${h}`,"one plugin major","Emit the same version in bundle.json and commands.json.","bundle.json.version")]};const m=i.version??h;if(i.provider!==void 0&&m===void 0)return{issues:[u("a provider bundle requires a plugin version","no version in bundle.json or commands.json",`version ${i.provider.major}, the provider major`,"Emit the provider major as the plugin version.","bundle.json.version")]};if(i.provider!==void 0&&m!==i.provider.major)return{issues:[u("bundle provider major must equal the plugin version",`version ${m}, major ${i.provider.major}`,"one major","Emit the provider major as the plugin version.","bundle.json.provider.major")]};const v=ce(i,b.commands);return v!==void 0?{issues:[v]}:{bundle:{bundleVersion:1,...m!==void 0?{version:m}:{},...i.transport!==void 0?{transport:i.transport}:{},...i.provider!==void 0?{provider:i.provider}:{},...i.kinds!==void 0?{kinds:i.kinds}:{},...i.page_components!==void 0?{page_components:i.page_components}:{},...i.memory_extensions!==void 0?{memory_extensions:i.memory_extensions}:{},...i.object_kinds!==void 0?{object_kinds:i.object_kinds}:{},...i.scopes!==void 0?{scopes:i.scopes}:{},commands:b.commands,commandsBytes:p.bytes,directories:r.members.filter(l=>l.type==="directory").map(l=>({path:l.path})),memory:r.members.filter(l=>l.type==="file"&&l.path.startsWith("memory/")).map(l=>({path:l.path,bytes:l.bytes})),...t!==void 0?{hooks:{manifest:t.bytes,files:a.map(l=>({path:l.path,bytes:l.bytes}))}}:{}},issues:[]}}c(he,"validatePluginBundle");function be(e){return I("sha256").update(e).digest("hex").slice(0,12)}c(be,"bundleVersion");function Je(e,o,n,r){return M(o).plugins[e]?.version!==r?!1:_(w(n,"commands.json"))}c(Je,"isInstalledGeneration");async function ve(e,o,n,r){await T(e,s=>{s.plugins[o]===void 0&&(s.plugins[o]={}),r.swapped&&(s.plugins[o].last_updated=E()),s.plugins[o].checked_at=E(),n===void 0?delete s.plugins[o].etag:s.plugins[o].etag=n})}c(ve,"recordCheckedGeneration");function g(e,o){const n=V(e,o);if(n===e||!n.startsWith(e+z))throw x(`bundle member path escapes the staging directory: ${o}`);return n}c(g,"stagedPath");function ge(e,o,n){const r=c((s,d,p=420)=>q(s,d,{mode:p,durable:!0}),"write");C(g(e,".crouter-plugin/plugin.json"),o,{durable:!0});for(const s of n.directories)j(g(e,s.path));r(g(e,"commands.json"),n.commandsBytes);for(const s of n.memory)r(g(e,s.path),s.bytes);if(n.hooks!==void 0){r(g(e,"hooks.json"),n.hooks.manifest);for(const s of n.hooks.files)r(g(e,s.path),s.bytes);W(g(e,"hooks/dispatch"),493)}U(e)}c(ge,"writeStagedBundle");async function Ie(e,o,n){const{scope:r,scopeRootPath:s,root:d}=n,p=await he(o,n.validation);if(p.bundle===void 0)throw n.invalid(`HTTP plugin bundle for "${e}" is invalid`,p.issues);const t=p.bundle,a=n.accept?.(t);if(a!==void 0)throw n.invalid(`HTTP plugin bundle for "${e}" is invalid`,[u(a,e,"the bundle this install asked for","Serve the requested bundle.")]);const f=n.version??be(o),i=t.provider!==void 0&&t.transport!==void 0?t.transport:n.transport,b={name:e,version:f,commands:"commands.json",transport:i,bundle:n.bundle,...t.kinds!==void 0?{kinds:t.kinds}:{},...t.page_components!==void 0?{page_components:t.page_components}:{},...t.memory_extensions!==void 0?{memory_extensions:t.memory_extensions}:{},...t.object_kinds!==void 0?{object_kinds:t.object_kinds}:{},...t.scopes!==void 0?{scopes:t.scopes}:{},...t.hooks!==void 0?{hooks:"hooks.json",hookExecutable:"hooks/dispatch"}:{},...t.provider!==void 0?{provider:t.provider}:{}},h=w(s,"tmp"),m=w(h,`${e}.${process.pid}`),v=`${m}.prev`;if(_(v))throw x(`cannot replace plugin "${e}": prior interrupted replacement remains at ${v}`);j(h),j($(d)),S(m);let l;try{j(m),ge(m,b,t),l=await n.validateStaged(m,b);let y=!1;_(d)&&(k(d,v),y=!0);try{k(m,d)}catch(A){throw y&&k(v,d),A}H($(d)),y&&S(v)}finally{S(m)}return await R(r,s),await D(r,y=>{y.plugins[e]={enabled:n.enable?!0:y.plugins[e]?.enabled??!0,version:f}}),await ve(r,e,n.etag,{swapped:!0}),{manifest:b,validated:t,version:f,root:d,staged:l}}c(Ie,"installBundleArchive");export{be as bundleVersion,Ie as installBundleArchive,Je as isInstalledGeneration,ve as recordCheckedGeneration,he as validatePluginBundle,ge as writeStagedBundle};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BranchDef, LeafDef } from '../command.js';
|
|
2
2
|
import type { CommandRegistrySnapshot, CoreBranchMount } from '../command-manifests/registry.js';
|
|
3
|
-
import type { ProviderToolDescription, UnavailableProviderToolDescription } from '../providers/
|
|
3
|
+
import type { ProviderToolDescription, UnavailableProviderToolDescription } from '../providers/description.js';
|
|
4
4
|
import type { ValidatedContribution, ValidatedCoreMount } from './discovery.js';
|
|
5
5
|
/** A sandbox sees no user plugin files. Compose only daemon-projected help data,
|
|
6
6
|
* with an adapter that cannot execute plugin code or send provider HTTP. */
|
|
@@ -38,7 +38,6 @@ export interface PluginCommandValidation {
|
|
|
38
38
|
coreMounts: ValidatedCoreMount[];
|
|
39
39
|
issues: CommandDiscoveryIssue[];
|
|
40
40
|
}
|
|
41
|
-
export declare function effectiveCommandPlugins(startDir?: string, profileId?: string | null): InstalledPlugin[];
|
|
42
41
|
export declare function validatePluginCommands(plugin: InstalledPlugin, reservedNames?: ReadonlySet<string>, coreCommandPaths?: ReadonlySet<string>, extensibleCoreBranches?: ReadonlySet<string>): PluginCommandValidation;
|
|
43
42
|
export declare function discoverPluginCommandCandidates(startDir?: string, profileId?: string | null): PluginCommandValidation[];
|
|
44
43
|
export declare function validateEffectiveCommandPlugins(reservedNames: ReadonlySet<string>, startDir?: string, profileId?: string | null, coreCommandPaths?: ReadonlySet<string>, extensibleCoreBranches?: ReadonlySet<string>): PluginCommandValidation[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var P=Object.defineProperty;var u=(e,n)=>P(e,"name",{value:n,configurable:!0});import{realpathSync as k,readFileSync as N,statSync as g}from"node:fs";import{isSandboxedNode as F}from"../../shared/env.js";import{isAbsolute as O,resolve as _,sep as R}from"node:path";import{listInstalledPlugins as q,listInstalledPluginsInRoot as A}from"../resolver.js";import{projectScopeRoots as E}from"../scope.js";import{validateCommandManifest as I}from"../../api/command-manifest/manifest.js";import{qualifiedTopLevelCommandName as J,resolveCommandRegistry as $}from"../command-manifests/registry.js";import{adaptPluginContributions as T,adaptPluginCoreMounts as B}from"./compose.js";import{validateHttpPluginTransport as H}from"./endpoint.js";import{providerRootClaims as L}from"../providers/roots.js";import{applyCommandExtensions as W}from"./extensions.js";function w(e=process.cwd(),n){const i=new Set,o=[],r=u(s=>{i.has(s.name)||(i.add(s.name),o.push(s))},"consider");for(const s of E(e,n))for(const m of A("project",s))r(m);if(!F())for(const s of q("user"))r(s);const{skipped:a}=L(o);return o.filter(s=>!a.has(s.name)).filter(s=>s.enabled&&(s.manifest.commands!==void 0||s.manifest.transport!==void 0))}u(w,"effectiveCommandPlugins");function X(e,n){return i=>n.push({...i,plugin:e.name})}u(X,"issueFor");function v(e,n){if(typeof n!="string"||n.length===0)return null;try{const i=k(e),o=k(_(e,n));return(o===i||o.startsWith(i+R))&&g(o).isFile()?o:null}catch{return null}}u(v,"safePath");function z(e,n){const i=e.manifest.transport;if(i===void 0){n.push({code:"command_manifest_invalid",plugin:e.name,message:"commands requires transport in plugin.json",received:"(missing)",expected:"a transport object",next:"Add plugin.json.transport.",path:"transport"});return}if(typeof i!="object"||i===null||Array.isArray(i)){n.push({code:"command_manifest_invalid",plugin:e.name,message:"transport must be an object",received:Array.isArray(i)?"array":typeof i,expected:"an exec or http transport object",next:"Fix plugin.json.transport.",path:"transport"});return}const o=i;if(o.kind==="http"){const a=H(o);if(a.transport!==void 0)return a.transport;n.push({code:"command_manifest_invalid",plugin:e.name,message:a.errors.join("; "),received:JSON.stringify(i),expected:"a valid HTTP transport",next:"Fix plugin.json.transport.",path:"transport"});return}if(o.kind==="machine"){if(e.manifest.provider===void 0||Object.keys(o).length!==1){n.push({code:"command_manifest_invalid",plugin:e.name,message:e.manifest.provider===void 0?"a machine transport belongs to a capability provider bundle":"transport has unknown keys",received:JSON.stringify(i),expected:'{ kind: "machine" } on a provider bundle',next:"Fix plugin.json.transport.",path:"transport"});return}return{kind:"machine"}}const r=Object.keys(o).filter(a=>!["kind","executable"].includes(a));if(o.kind!=="exec"||r.length||o.executable!==void 0&&(typeof o.executable!="string"||o.executable.length===0)){n.push({code:"command_manifest_invalid",plugin:e.name,message:r.length?`transport has unknown keys: ${r.join(", ")}`:"exec transport requires a non-empty executable when declared",received:JSON.stringify(i),expected:'{ kind: "exec", executable?: "plugin-relative path" }',next:"Fix plugin.json.transport.",path:"transport"});return}return{kind:"exec",...o.executable!==void 0?{executable:o.executable}:{}}}u(z,"transportFor");function y(e){return e.kind==="leaf"||e.children.some(y)}u(y,"hasExecutableLeaf");function M(e){return[...e.roots,...e.coreMounts.map(n=>n.node)]}u(M,"manifestNodes");function G(e,n,i,o){if(n.executable===void 0){if(!M(i).some(y))return n;o.push({code:"command_manifest_invalid",plugin:e.name,message:"exec transport requires executable when commands.json declares executable leaves",received:"(missing)",expected:'{ kind: "exec", executable: "plugin-relative path" }',next:"Add plugin.json.transport.executable.",path:"transport.executable"});return}const r=v(e.root,n.executable);if(r===null){o.push({code:"command_path_unsafe",plugin:e.name,message:"executable escapes the plugin root or is not a regular file",received:n.executable,expected:"a relative path to a regular file inside the plugin root",next:"Fix plugin.json.transport.executable.",path:"transport.executable"});return}if((g(r).mode&73)===0){o.push({code:"command_not_executable",plugin:e.name,message:"executable lacks the POSIX exec bit",received:n.executable,expected:"a file with an executable permission bit",next:"chmod +x the plugin executable, then update the plugin.",path:"transport.executable"});return}return{kind:"exec",executable:r}}u(G,"validateExecExecutable");function K(e){return O(e)||e.startsWith(".")||e.includes("/")||e.includes("\\")}u(K,"namesPath");function Q(e,n,i){let o=!0;const r=u(a=>{if(a.kind!=="branch")return;const s=a.passthrough;if(s!==void 0&&K(s.bin)){const m=v(e.root,s.bin);m===null?(i.push({code:"command_path_unsafe",plugin:e.name,message:"passthrough binary escapes the plugin root or is not a regular file",received:s.bin,expected:"a relative path to a regular file inside the plugin root",next:"Fix passthrough.bin in commands.json.",path:"passthrough.bin"}),o=!1):(g(m).mode&73)===0?(i.push({code:"command_not_executable",plugin:e.name,message:"passthrough binary lacks the POSIX exec bit",received:s.bin,expected:"a file with an executable permission bit",next:"chmod +x the plugin executable, then update commands.json.",path:"passthrough.bin"}),o=!1):a.passthrough={...s,bin:m}}for(const m of a.children)r(m)},"visit");for(const a of M(n))r(a);return o}u(Q,"resolvePassthroughBinaries");function S(e,n=new Set,i,o=new Set){const r=[],a=e.manifest.commands,s=e.manifest.transport;let m=_(e.root,typeof a=="string"?a:"commands.json");const c=u(x=>({plugin:e,manifestPath:m,...x===void 0?{}:{transport:x},contributions:[],coreMounts:[],issues:r}),"empty");if(a===void 0&&s===void 0)return c();if(typeof a!="string"||a.length===0)return r.push({code:"command_manifest_invalid",plugin:e.name,message:"transport requires commands in plugin.json",received:"(missing)",expected:"a plugin-root-relative commands path",next:"Add plugin.json.commands or remove transport.",path:"commands"}),c();const t=z(e,r);if(t===void 0)return c();const d=v(e.root,a);if(d===null)return r.push({code:"command_path_unsafe",plugin:e.name,message:"commands pointer escapes the plugin root or is not a regular file",received:a,expected:"a relative path to a regular file inside the plugin root",next:"Fix plugin.json.commands.",path:"commands"}),c(t);m=d;let p;try{p=N(d)}catch{p=null}if(p===null)return r.push({code:"command_manifest_unreadable",plugin:e.name,message:"commands.json is missing or unreadable",received:d,expected:"a readable JSON file",next:"Reinstall or update the plugin."}),c(t);let h;try{h=JSON.parse(Buffer.from(p).toString("utf8"))}catch{return r.push({code:"command_manifest_invalid",plugin:e.name,message:"commands.json is not valid JSON",received:d,expected:"a JSON object",next:"Regenerate commands.json."}),c(t)}const f=I(h,{transport:t.kind==="machine"?"http":t.kind,reservedCoreNames:n,extensibleCoreBranches:o,...i!==void 0?{coreCommandPaths:i}:{}});if(f.manifest===void 0)return f.issues.forEach(X(e,r)),c(t);const l=t.kind==="exec"?G(e,t,f.manifest,r):t;if(l===void 0)return c(t);if(l.kind==="exec"&&!Q(e,f.manifest,r))return c(l);const b=e.manifest.provider,j=f.manifest.roots;if(!j.every(x=>x.kind==="branch"))throw new Error("plugin manifest validation returned a top-level leaf");return{plugin:e,manifestPath:m,transport:l,manifest:f.manifest,contributions:j.filter(x=>b===void 0||y(x)).map(x=>({plugin:e,transport:l,node:x,manifest:f.manifest,manifestName:x.name,...b!==void 0?{provider:b}:{}})),coreMounts:f.manifest.coreMounts.map(x=>({plugin:e,transport:l,parent:x.parent,node:x.node,manifest:f.manifest,...b!==void 0?{provider:b}:{}})),issues:r}}u(S,"validatePluginCommands");function ce(e=process.cwd(),n){return w(e,n).map(i=>S(i))}u(ce,"discoverPluginCommandCandidates");function C(e,n=process.cwd(),i,o,r=new Set){const a=w(n,i).map(c=>S(c,e,o,r)),s=new Map;for(const c of a)for(const t of c.contributions){const d=s.get(t.node.name);d===void 0?s.set(t.node.name,[t]):d.push(t)}for(const[c,t]of s)if(t.length>1)for(const d of t){const{plugin:p}=d,h=J({name:p.name,sourceMarketplace:p.sourceMarketplace},c),f=a.find(l=>l.plugin.root===p.root);f.contributions=f.contributions.map(l=>l===d?{...l,node:{...l.node,name:h}}:l),f.issues.push({code:"command_collision",plugin:p.name,path:c,message:`top-level command "${c}" is claimed by ${t.map(l=>l.plugin.name).join(", ")} \u2014 mounted as "${h}"`,received:t.map(l=>l.plugin.name).join(", "),expected:"an origin-qualified top-level command for each claimant",next:`Invoke "${h}" to use this plugin command.`})}const m=new Map;for(const c of a)for(const t of c.coreMounts){const d=[...t.parent,t.node.name].join("/"),p=m.get(d);p===void 0?m.set(d,[t]):p.push(t)}for(const[c,t]of m)if(t.length>1)for(const d of t){const p=a.find(h=>h.plugin.root===d.plugin.root);p.coreMounts=p.coreMounts.filter(h=>h!==d),p.issues.push({code:"command_collision",plugin:d.plugin.name,path:c.replace("/","."),message:`contributed command "${d.node.name}" conflicts with another plugin child below the extensible core branch`,received:t.map(h=>h.plugin.name).join(", "),expected:`a unique child name below ${d.parent.join(".")}`,next:"Rename the contributed command or remove this mount."})}return a}u(C,"validateEffectiveCommandPlugins");function U(e,n){return{...n,contributor:{name:e.name,scope:e.scope,sourceMarketplace:e.sourceMarketplace}}}u(U,"contributorIssue");function de(e,n=process.cwd(),i,o,r=new Set){const a=C(e,n,i,o,r);return{contributions:a.flatMap(s=>s.contributions),coreMounts:a.flatMap(s=>s.coreMounts),issues:a.flatMap(s=>s.issues)}}u(de,"discoverCommandContributions");function ue(e,n=process.cwd(),i,o,r=new Set){const a=C(e,n,i,o,r),s=T(a.flatMap(t=>t.contributions)).contributions,m=$(s,e);return{contributions:W(m.contributions,n).contributions,coreMounts:B(a.flatMap(t=>t.coreMounts)),issues:[...a.flatMap(t=>t.issues.map(d=>U(t.plugin,d))),...m.issues]}}u(ue,"buildExternalCommandSnapshot");export{ue as buildExternalCommandSnapshot,de as discoverCommandContributions,ce as discoverPluginCommandCandidates,w as effectiveCommandPlugins,C as validateEffectiveCommandPlugins,S as validatePluginCommands};
|
|
1
|
+
var P=Object.defineProperty;var m=(e,t)=>P(e,"name",{value:t,configurable:!0});import{realpathSync as k,readFileSync as F,statSync as b}from"node:fs";import{isAbsolute as N,resolve as _,sep as O}from"node:path";import{validateCommandManifest as q}from"../../api/command-manifest/manifest.js";import{qualifiedTopLevelCommandName as A,resolveCommandRegistry as E}from"../command-manifests/registry.js";import{adaptPluginContributions as J,adaptPluginCoreMounts as $}from"./compose.js";import{validateHttpPluginTransport as R}from"./endpoint.js";import{effectiveCommandPlugins as w}from"./presence.js";import{applyCommandExtensions as T}from"./extensions.js";function I(e,t){return i=>t.push({...i,plugin:e.name})}m(I,"issueFor");function v(e,t){if(typeof t!="string"||t.length===0)return null;try{const i=k(e),o=k(_(e,t));return(o===i||o.startsWith(i+O))&&b(o).isFile()?o:null}catch{return null}}m(v,"safePath");function B(e,t){const i=e.manifest.transport;if(i===void 0){t.push({code:"command_manifest_invalid",plugin:e.name,message:"commands requires transport in plugin.json",received:"(missing)",expected:"a transport object",next:"Add plugin.json.transport.",path:"transport"});return}if(typeof i!="object"||i===null||Array.isArray(i)){t.push({code:"command_manifest_invalid",plugin:e.name,message:"transport must be an object",received:Array.isArray(i)?"array":typeof i,expected:"an exec or http transport object",next:"Fix plugin.json.transport.",path:"transport"});return}const o=i;if(o.kind==="http"){const a=R(o);if(a.transport!==void 0)return a.transport;t.push({code:"command_manifest_invalid",plugin:e.name,message:a.errors.join("; "),received:JSON.stringify(i),expected:"a valid HTTP transport",next:"Fix plugin.json.transport.",path:"transport"});return}if(o.kind==="machine"){if(e.manifest.provider===void 0||Object.keys(o).length!==1){t.push({code:"command_manifest_invalid",plugin:e.name,message:e.manifest.provider===void 0?"a machine transport belongs to a capability provider bundle":"transport has unknown keys",received:JSON.stringify(i),expected:'{ kind: "machine" } on a provider bundle',next:"Fix plugin.json.transport.",path:"transport"});return}return{kind:"machine"}}const s=Object.keys(o).filter(a=>!["kind","executable"].includes(a));if(o.kind!=="exec"||s.length||o.executable!==void 0&&(typeof o.executable!="string"||o.executable.length===0)){t.push({code:"command_manifest_invalid",plugin:e.name,message:s.length?`transport has unknown keys: ${s.join(", ")}`:"exec transport requires a non-empty executable when declared",received:JSON.stringify(i),expected:'{ kind: "exec", executable?: "plugin-relative path" }',next:"Fix plugin.json.transport.",path:"transport"});return}return{kind:"exec",...o.executable!==void 0?{executable:o.executable}:{}}}m(B,"transportFor");function y(e){return e.kind==="leaf"||e.children.some(y)}m(y,"hasExecutableLeaf");function M(e){return[...e.roots,...e.coreMounts.map(t=>t.node)]}m(M,"manifestNodes");function H(e,t,i,o){if(t.executable===void 0){if(!M(i).some(y))return t;o.push({code:"command_manifest_invalid",plugin:e.name,message:"exec transport requires executable when commands.json declares executable leaves",received:"(missing)",expected:'{ kind: "exec", executable: "plugin-relative path" }',next:"Add plugin.json.transport.executable.",path:"transport.executable"});return}const s=v(e.root,t.executable);if(s===null){o.push({code:"command_path_unsafe",plugin:e.name,message:"executable escapes the plugin root or is not a regular file",received:t.executable,expected:"a relative path to a regular file inside the plugin root",next:"Fix plugin.json.transport.executable.",path:"transport.executable"});return}if((b(s).mode&73)===0){o.push({code:"command_not_executable",plugin:e.name,message:"executable lacks the POSIX exec bit",received:t.executable,expected:"a file with an executable permission bit",next:"chmod +x the plugin executable, then update the plugin.",path:"transport.executable"});return}return{kind:"exec",executable:s}}m(H,"validateExecExecutable");function L(e){return N(e)||e.startsWith(".")||e.includes("/")||e.includes("\\")}m(L,"namesPath");function W(e,t,i){let o=!0;const s=m(a=>{if(a.kind!=="branch")return;const d=a.passthrough;if(d!==void 0&&L(d.bin)){const l=v(e.root,d.bin);l===null?(i.push({code:"command_path_unsafe",plugin:e.name,message:"passthrough binary escapes the plugin root or is not a regular file",received:d.bin,expected:"a relative path to a regular file inside the plugin root",next:"Fix passthrough.bin in commands.json.",path:"passthrough.bin"}),o=!1):(b(l).mode&73)===0?(i.push({code:"command_not_executable",plugin:e.name,message:"passthrough binary lacks the POSIX exec bit",received:d.bin,expected:"a file with an executable permission bit",next:"chmod +x the plugin executable, then update commands.json.",path:"passthrough.bin"}),o=!1):a.passthrough={...d,bin:l}}for(const l of a.children)s(l)},"visit");for(const a of M(t))s(a);return o}m(W,"resolvePassthroughBinaries");function S(e,t=new Set,i,o=new Set){const s=[],a=e.manifest.commands,d=e.manifest.transport;let l=_(e.root,typeof a=="string"?a:"commands.json");const r=m(x=>({plugin:e,manifestPath:l,...x===void 0?{}:{transport:x},contributions:[],coreMounts:[],issues:s}),"empty");if(a===void 0&&d===void 0)return r();if(typeof a!="string"||a.length===0)return s.push({code:"command_manifest_invalid",plugin:e.name,message:"transport requires commands in plugin.json",received:"(missing)",expected:"a plugin-root-relative commands path",next:"Add plugin.json.commands or remove transport.",path:"commands"}),r();const n=B(e,s);if(n===void 0)return r();const c=v(e.root,a);if(c===null)return s.push({code:"command_path_unsafe",plugin:e.name,message:"commands pointer escapes the plugin root or is not a regular file",received:a,expected:"a relative path to a regular file inside the plugin root",next:"Fix plugin.json.commands.",path:"commands"}),r(n);l=c;let p;try{p=F(c)}catch{p=null}if(p===null)return s.push({code:"command_manifest_unreadable",plugin:e.name,message:"commands.json is missing or unreadable",received:c,expected:"a readable JSON file",next:"Reinstall or update the plugin."}),r(n);let h;try{h=JSON.parse(Buffer.from(p).toString("utf8"))}catch{return s.push({code:"command_manifest_invalid",plugin:e.name,message:"commands.json is not valid JSON",received:c,expected:"a JSON object",next:"Regenerate commands.json."}),r(n)}const f=q(h,{transport:n.kind==="machine"?"http":n.kind,reservedCoreNames:t,extensibleCoreBranches:o,...i!==void 0?{coreCommandPaths:i}:{}});if(f.manifest===void 0)return f.issues.forEach(I(e,s)),r(n);const u=n.kind==="exec"?H(e,n,f.manifest,s):n;if(u===void 0)return r(n);if(u.kind==="exec"&&!W(e,f.manifest,s))return r(u);const g=e.manifest.provider,j=f.manifest.roots;if(!j.every(x=>x.kind==="branch"))throw new Error("plugin manifest validation returned a top-level leaf");return{plugin:e,manifestPath:l,transport:u,manifest:f.manifest,contributions:j.filter(x=>g===void 0||y(x)).map(x=>({plugin:e,transport:u,node:x,manifest:f.manifest,manifestName:x.name,...g!==void 0?{provider:g}:{}})),coreMounts:f.manifest.coreMounts.map(x=>({plugin:e,transport:u,parent:x.parent,node:x.node,manifest:f.manifest,...g!==void 0?{provider:g}:{}})),issues:s}}m(S,"validatePluginCommands");function ee(e=process.cwd(),t){return w(e,t).map(i=>S(i))}m(ee,"discoverPluginCommandCandidates");function C(e,t=process.cwd(),i,o,s=new Set){const a=w(t,i).map(r=>S(r,e,o,s)),d=new Map;for(const r of a)for(const n of r.contributions){const c=d.get(n.node.name);c===void 0?d.set(n.node.name,[n]):c.push(n)}for(const[r,n]of d)if(n.length>1)for(const c of n){const{plugin:p}=c,h=A({name:p.name,sourceMarketplace:p.sourceMarketplace},r),f=a.find(u=>u.plugin.root===p.root);f.contributions=f.contributions.map(u=>u===c?{...u,node:{...u.node,name:h}}:u),f.issues.push({code:"command_collision",plugin:p.name,path:r,message:`top-level command "${r}" is claimed by ${n.map(u=>u.plugin.name).join(", ")} \u2014 mounted as "${h}"`,received:n.map(u=>u.plugin.name).join(", "),expected:"an origin-qualified top-level command for each claimant",next:`Invoke "${h}" to use this plugin command.`})}const l=new Map;for(const r of a)for(const n of r.coreMounts){const c=[...n.parent,n.node.name].join("/"),p=l.get(c);p===void 0?l.set(c,[n]):p.push(n)}for(const[r,n]of l)if(n.length>1)for(const c of n){const p=a.find(h=>h.plugin.root===c.plugin.root);p.coreMounts=p.coreMounts.filter(h=>h!==c),p.issues.push({code:"command_collision",plugin:c.plugin.name,path:r.replace("/","."),message:`contributed command "${c.node.name}" conflicts with another plugin child below the extensible core branch`,received:n.map(h=>h.plugin.name).join(", "),expected:`a unique child name below ${c.parent.join(".")}`,next:"Rename the contributed command or remove this mount."})}return a}m(C,"validateEffectiveCommandPlugins");function X(e,t){return{...t,contributor:{name:e.name,scope:e.scope,sourceMarketplace:e.sourceMarketplace}}}m(X,"contributorIssue");function ne(e,t=process.cwd(),i,o,s=new Set){const a=C(e,t,i,o,s);return{contributions:a.flatMap(d=>d.contributions),coreMounts:a.flatMap(d=>d.coreMounts),issues:a.flatMap(d=>d.issues)}}m(ne,"discoverCommandContributions");function te(e,t=process.cwd(),i,o,s=new Set){const a=C(e,t,i,o,s),d=J(a.flatMap(n=>n.contributions)).contributions,l=E(d,e);return{contributions:T(l.contributions,t).contributions,coreMounts:$(a.flatMap(n=>n.coreMounts)),issues:[...a.flatMap(n=>n.issues.map(c=>X(n.plugin,c))),...l.issues]}}m(te,"buildExternalCommandSnapshot");export{te as buildExternalCommandSnapshot,ne as discoverCommandContributions,ee as discoverPluginCommandCandidates,C as validateEffectiveCommandPlugins,S as validatePluginCommands};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var p=Object.defineProperty;var l=(r,n)=>p(r,"name",{value:n,configurable:!0});import{
|
|
1
|
+
var p=Object.defineProperty;var l=(r,n)=>p(r,"name",{value:n,configurable:!0});import{validatePluginCommands as c}from"./discovery.js";import{effectiveCommandPlugins as h}from"./presence.js";async function x(r,n,f,u){if(r.length===0)return[];const s=await n.extensibleCoreBranches(),i=[],a=h(f,u).filter(t=>{const e=c(t,n.reservedCoreNames,void 0,s).manifest;return e?.helpAddenda?.[r]===void 0?!1:(i.push(...Object.keys(e.helpAddenda),...e.coreMounts.map(d=>[...d.parent,d.node.name].join(" "))),!0)});if(a.length===0)return[];const m=await n.coreCommandPaths(i),o=[];for(const t of a){const e=c(t,n.reservedCoreNames,m,s).manifest?.helpAddenda?.[r];e!==void 0&&o.push({plugin:t.name,text:e})}return o.sort((t,e)=>t.plugin.localeCompare(e.plugin)),o}l(x,"collectHelpAddenda");export{x as collectHelpAddenda};
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
import type { InstalledPlugin } from '../../types.js';
|
|
1
2
|
/** Whether an enabled command plugin survives nearest-scope name shadowing. */
|
|
2
3
|
export declare function hasEffectiveCommandPlugins(startDir?: string, profileId?: string | null): boolean;
|
|
4
|
+
export declare function effectiveCommandPlugins(startDir?: string, profileId?: string | null): InstalledPlugin[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var u=Object.defineProperty;var f=(t,s)=>u(t,"name",{value:s,configurable:!0});import{listInstalledPlugins as d,listInstalledPluginsInRoot as a}from"../resolver.js";import{projectScopeRoots as i}from"../scope.js";import{isSandboxedNode as p}from"../../shared/env.js";import{providerRootClaims as l}from"../providers/roots.js";function j(t=process.cwd(),s){const r=new Set,n=f(o=>r.has(o.name)?!1:(r.add(o.name),o.enabled&&(o.manifest.commands!==void 0||o.manifest.transport!==void 0)),"consider");for(const o of i(t,s))if(a("project",o).some(n))return!0;return d("user").some(n)}f(j,"hasEffectiveCommandPlugins");function v(t=process.cwd(),s){const r=new Set,n=[],o=f(e=>{r.has(e.name)||(r.add(e.name),n.push(e))},"consider");for(const e of i(t,s))for(const c of a("project",e))o(c);if(!p())for(const e of d("user"))o(e);const{skipped:m}=l(n);return n.filter(e=>!m.has(e.name)).filter(e=>e.enabled&&(e.manifest.commands!==void 0||e.manifest.transport!==void 0))}f(v,"effectiveCommandPlugins");export{v as effectiveCommandPlugins,j as hasEffectiveCommandPlugins};
|
package/dist/core/config.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { PageComponentRegistration, Scope, ScopeConfig, ScopeState, HumanActionConfig, KindConfig, ModelLaddersConfig, ModelProvider, ModelStrength, ModelRouteConfig, ModelRoutingConfig, ProviderOptionsConfig } from '../types.js';
|
|
2
2
|
import { type BindingId } from './keybindings/catalog.js';
|
|
3
|
-
import type { RotationConfig } from './
|
|
3
|
+
import type { RotationConfig } from './managed-providers.js';
|
|
4
4
|
export declare function configPath(scope: Scope): string | null;
|
|
5
5
|
export declare function statePath(scope: Scope): string | null;
|
|
6
6
|
export interface BrokerConfigSnapshot {
|
|
@@ -26,16 +26,17 @@ export declare function readRawSettingsForTarget(target: RawSettingsTarget): {
|
|
|
26
26
|
settings: Record<string, unknown> | null;
|
|
27
27
|
revision: string;
|
|
28
28
|
};
|
|
29
|
-
export declare function replaceRawSettingsForTarget(target: RawSettingsTarget, next: Record<string, unknown>, ifRevision: string): {
|
|
29
|
+
export declare function replaceRawSettingsForTarget(target: RawSettingsTarget, next: Record<string, unknown>, ifRevision: string): Promise<{
|
|
30
30
|
revision: string;
|
|
31
31
|
changed: boolean;
|
|
32
|
-
}
|
|
32
|
+
}>;
|
|
33
33
|
type RawConfig = Record<string, unknown>;
|
|
34
|
-
export declare function updateRawConfigAtomically(scope: Scope, mutate: (latest: RawConfig) => RawConfig): RawConfig
|
|
35
|
-
export declare function writeConfig(scope: Scope, config: ScopeConfig): void
|
|
36
|
-
export declare function writeRawConfig(scope: Scope, config: Partial<ScopeConfig>): void
|
|
37
|
-
export declare function writeState(scope: Scope, state: ScopeState): void
|
|
38
|
-
|
|
34
|
+
export declare function updateRawConfigAtomically(scope: Scope, mutate: (latest: RawConfig) => RawConfig): Promise<RawConfig>;
|
|
35
|
+
export declare function writeConfig(scope: Scope, config: ScopeConfig): Promise<void>;
|
|
36
|
+
export declare function writeRawConfig(scope: Scope, config: Partial<ScopeConfig>): Promise<void>;
|
|
37
|
+
export declare function writeState(scope: Scope, state: ScopeState): Promise<void>;
|
|
38
|
+
/** A project scope is a directory holding `config.json`; the user and profile scopes are the person's rows and need no directory setup. */
|
|
39
|
+
export declare function ensureScopeInitialized(scope: Scope, root: string): Promise<void>;
|
|
39
40
|
/** Normalize the user-owned list of attach actions allowed to bridge through an
|
|
40
41
|
* occupied tmux root binding. Unknown and non-attach ids have no effect. */
|
|
41
42
|
export declare function normalizeTmuxPassthrough(raw: unknown): BindingId[];
|
|
@@ -207,16 +208,16 @@ export declare function persistModelLadders(root: string, patch: {
|
|
|
207
208
|
defaultProvider?: ModelProvider;
|
|
208
209
|
anthropic?: Partial<Record<ModelStrength, string>>;
|
|
209
210
|
openai?: Partial<Record<ModelStrength, string>>;
|
|
210
|
-
}): void
|
|
211
|
+
}): Promise<void>;
|
|
211
212
|
/** Persist one complete route at one exact config root. The route is the only
|
|
212
213
|
* raw route entry touched; unrelated routes and local ladder defaults remain
|
|
213
214
|
* absent. Pass `undefined` to remove this scope's entry, which resumes lower
|
|
214
215
|
* scope inheritance rather than introducing a tombstone. */
|
|
215
|
-
export declare function persistModelRoute(root: string, routeId: string, route: ModelRouteConfig | undefined): void
|
|
216
|
+
export declare function persistModelRoute(root: string, routeId: string, route: ModelRouteConfig | undefined): Promise<void>;
|
|
216
217
|
/** Mutate one exact config root. Setup uses this for profile and explicit
|
|
217
218
|
* project targets that cannot be represented by the user/project Scope enum. */
|
|
218
|
-
export declare function updateConfigAtRoot(root: string, mutate: (cfg: ScopeConfig) => void): ScopeConfig
|
|
219
|
-
export declare function updateConfig(scope: Scope, mutate: (cfg: ScopeConfig) => void): ScopeConfig
|
|
219
|
+
export declare function updateConfigAtRoot(root: string, mutate: (cfg: ScopeConfig) => void): Promise<ScopeConfig>;
|
|
220
|
+
export declare function updateConfig(scope: Scope, mutate: (cfg: ScopeConfig) => void): Promise<ScopeConfig>;
|
|
220
221
|
/** Persist one sparse kind-model field at an exact config root. The sparse
|
|
221
222
|
* patch keeps every unrelated kind and launch knob inherited from lower
|
|
222
223
|
* scopes instead of freezing a materialized registry snapshot. */
|
|
@@ -225,9 +226,9 @@ export declare function persistDefaultKindModel(opts: {
|
|
|
225
226
|
kind: string;
|
|
226
227
|
model: string;
|
|
227
228
|
orchestrator?: boolean;
|
|
228
|
-
}): {
|
|
229
|
+
}): Promise<{
|
|
229
230
|
path: string;
|
|
230
231
|
field: 'model' | 'orchestratorModel';
|
|
231
|
-
}
|
|
232
|
-
export declare function updateState(scope: Scope, mutate: (s: ScopeState) => void): ScopeState
|
|
232
|
+
}>;
|
|
233
|
+
export declare function updateState(scope: Scope, mutate: (s: ScopeState) => void): Promise<ScopeState>;
|
|
233
234
|
export {};
|
package/dist/core/config.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var qe=Object.defineProperty;var s=(e,n)=>qe(e,"name",{value:n,configurable:!0});import{envProfileId as Ge}from"../shared/env.js";import{basename as Q,join as ee}from"node:path";import{existsSync as Be,mkdirSync as We,statSync as He}from"node:fs";import{isDeepStrictEqual as Je}from"node:util";import{CONFIG_FILE as Ze,STATE_FILE as Ye,CONDENSED_HISTORY_MODES as Ve,MOUSE_MODE_DEFAULTS as Xe,WHIP_MESSAGE_MODES as Qe,DEFAULT_WHIP_MESSAGES as ne,defaultScopeConfig as w,defaultScopeState as oe,defaultModelLaddersConfig as en,defaultKindsConfig as nn,defaultRemoteCanvasConfig as on}from"../types.js";import{BINDING_CATALOG as tn,BINDING_IDS as rn,isAttachPaneBinding as sn}from"./keybindings/catalog.js";import{notFound as cn}from"./errors.js";import{emitEvent as un}from"./events/emit.js";import{atomicWriteJson as te,readJsonIfExists as q,ensureDir as dn}from"./fs-utils.js";import{scopeRoot as h,requireScopeRoot as A,findProjectScopeRoots as fn,userScopeRoot as I}from"./scope.js";import{listInstalledPluginsInRoot as re}from"./installed-plugins.js";import{profileDir as G,listProfiles as ie}from"./profiles/manifest.js";import{canonicalRoot as S,projectStore as ln,userStore as se}from"./scoped-state/paths.js";import{convertLegacyScopedStore as an,initializeFreshScopedStore as mn}from"./scoped-state/migrate.js";import{mutateRawSettings as pn,readBookkeeping as gn,readRawSettings as yn,readRawSettingsWithRevision as hn,replaceRawSettings as bn,writeBookkeeping as _n,writeRawSettings as vn}from"./scoped-state/settings.js";import{withExclusiveDirectoryLock as kn}from"./exclusive-lock.js";import{SCOPE_CONFIG_KEYS as wn}from"./user-settings.js";import{normalizeWorkingGerunds as An}from"../shared/working-activity.js";import{mergePageComponentLayers as Sn,normalizePageComponents as ce}from"./human/page-catalog.js";function _(e){return ee(e,Ze)}s(_,"configPathFor");function ue(e,n){return kn(`${e}.lock`,()=>n(e),{timeoutError:s(()=>new Error(`timed out waiting for config lock: ${e}`),"timeoutError")})}s(ue,"withConfigPathLock");function jn(e){return ee(e,Ye)}s(jn,"statePathFor");function ko(e){const n=h(e);return n?_(n):null}s(ko,"configPath");function wo(e){const n=h(e);return n?jn(n):null}s(wo,"statePath");function g(e){const n=S(e),o=S(I());if(n===o)return{store:se(o),key:"user",kind:"user",root:o};if(Q(n)===".crouter")return an({kind:"project",root:n}),{store:ln(n),key:"project",kind:"project",root:n};for(const t of ie()){const r=S(G(t.profileId));if(n===r)return{store:se(o),key:`profile:${t.profileId}`,kind:"profile",root:r,profileId:t.profileId}}throw new Error(`settings root is not a recognized owner: ${e}`)}s(g,"settingsOwnerForRoot");function P(e){if(Q(e)===".crouter"){let n;try{n=S(e)}catch(o){if(o.code==="ENOENT")return null;throw o}if(n!==S(I()))return q(_(e))}return yn(g(e))}s(P,"readRawAtRoot");function B(e,n){const o=g(e);if(o.kind==="project"){ue(_(o.root),t=>te(t,n,{createParent:!1}));return}vn(o,n)}s(B,"writeRawAtRoot");function j(e,n){const o=g(e);return o.kind==="project"?ue(_(o.root),t=>{const r=n(q(t)??{});return te(t,r.next,{createParent:!1}),r.value}):pn(o,t=>n(t))}s(j,"mutateRawAtRoot");const T=globalThis,C=Symbol.for("crtr.broker.config-snapshot");function Ao(e){T[C]=e}s(Ao,"installBrokerConfigSnapshot");function So(){return T[C]}s(So,"brokerConfigSnapshot");function Rn(e){const n=T[C];if(n){if(e!=="user")throw new Error(`broker config snapshot has no ${e} scope`);return n.user}const o=h(e);return o?xn(o):w()}s(Rn,"readConfig");function xn(e){const n=P(e);return n?D(n):w()}s(xn,"readConfigAtRoot");function On(e){const n=h(e);if(!n)return oe();try{return gn(g(n))}catch(o){if(e==="project"&&!Be(n))return oe();throw o}}s(On,"readState");class En extends Error{static{s(this,"InvalidRawSettingsError")}constructor(n){super(`settings cannot be merged: ${n instanceof Error?n.message:String(n)}`),this.name="InvalidRawSettingsError"}}function de(e){if(e.scope==="user")return g(I());if(!ie().some(n=>n.profileId===e.profileId))throw cn(`profile not found: ${e.profileId}`,{received:e.profileId,next:"Run `crtr profile list` to see available profiles."});return g(G(e.profileId))}s(de,"rawSettingsOwnerForTarget");function jo(e){return hn(de(e))}s(jo,"readRawSettingsForTarget");function Ro(e,n,o){return bn(de(e),n,o,t=>{try{D(t)}catch(r){throw new En(r)}})}s(Ro,"replaceRawSettingsForTarget");function xo(e,n){const o=A(e);return j(o,t=>{const r=n(t);return{value:r,next:r}})}s(xo,"updateRawConfigAtomically");function Oo(e,n){B(A(e),n)}s(Oo,"writeConfig");function Eo(e,n){B(A(e),n)}s(Eo,"writeRawConfig");function In(e,n){const o=A(e);_n(g(o),n)}s(In,"writeState");function Io(e,n){if(e==="project")try{We(n)}catch(t){if(t.code!=="EEXIST"||!He(n).isDirectory())throw t}else dn(n);const o=g(e==="user"?I():n);mn({kind:o.kind==="user"?"user":"project",root:o.store.root}),o.kind==="project"&&q(_(o.root))===null&&B(o.root,{schema_version:w().schema_version})}s(Io,"ensureScopeInitialized");function Pn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))Array.isArray(t)&&t.every(r=>typeof r=="string")&&(n[o]=[...t]);return n}s(Pn,"normalizeKeybindings");const Tn=new Set(tn.filter(sn).map(e=>e.id));function Cn(e){return Array.isArray(e)?[...new Set(e.filter(n=>typeof n=="string"&&rn.has(n)&&Tn.has(n)))]:[]}s(Cn,"normalizeTmuxPassthrough");function $(e,n=en()){const o=n;if(e===null||typeof e!="object")return o;const t=e,r={anthropic:{...o.anthropic},openai:{...o.openai},...o.defaultProvider!==void 0?{defaultProvider:o.defaultProvider}:{}};(t.defaultProvider==="anthropic"||t.defaultProvider==="openai")&&(r.defaultProvider=t.defaultProvider);for(const i of["anthropic","openai"]){const c=t[i];if(!(c===null||typeof c!="object"))for(const[u,d]of Object.entries(c))(u==="ultra"||u==="strong"||u==="medium"||u==="light")&&typeof d=="string"&&(r[i][u]=d)}return r}s($,"mergeModelLadders");function fe(e){return e==="ultra"||e==="strong"||e==="medium"||e==="light"}s(fe,"validStrength");const W=["ultra","strong","medium","light"];function H(){return Object.create(null)}s(H,"routeRecord");function R(e,n,o){Object.defineProperty(e,n,{value:o,writable:!0,enumerable:!0,configurable:!0})}s(R,"setRouteRecord");function le(e){const n=H();for(const[o,t]of Object.entries(e??{}))R(n,o,t);return n}s(le,"copyRouteRecord");function x(e,n){un({level:"warn",event:"config.model_routes.invalid",fields:{route_id:e,rule:n}})}s(x,"routeInvalid");function M(e,n={}){const o=le(n);if(e===null||typeof e!="object"||Array.isArray(e))return o;for(const[t,r]of Object.entries(e)){if(t.trim()===""){x(t,"route id must be a non-empty string");continue}if(r===null||typeof r!="object"||Array.isArray(r)){x(t,"route must be an object");continue}const i=r,c=o[t],u={...c};let d;for(const l of["family","credentialSource","providerId"]){const f=i[l];if(f!==void 0){if(typeof f!="string"||f.trim()===""){d=`${l} must be a non-empty string`;break}u[l]=f}}if(d===void 0&&i.models!==void 0)if(i.models===null||typeof i.models!="object"||Array.isArray(i.models))d="models must be an object";else{const l={...c?.models};for(const[f,a]of Object.entries(i.models)){if(!fe(f)){d=`models.${f} is not a model strength`;break}if(typeof a!="string"||a.trim()===""){d=`models.${f} must be a non-empty provider/id ref`;break}const m=a.indexOf("/");if(m<=0||m===a.length-1){d=`models.${f} must be provider/id`;break}l[f]=a}u.models=l}if(d===void 0&&u.models!==void 0&&u.providerId!==void 0){for(const[l,f]of Object.entries(u.models))if(f.slice(0,f.indexOf("/"))!==u.providerId){d=`models.${l} provider prefix must equal providerId`;break}}if(d!==void 0){x(t,d);continue}R(o,t,u)}return o}s(M,"mergeModelRoutePatches");function ae(e){const n=H(),o=H();for(const[t,r]of Object.entries(e)){if(r.family===void 0||r.credentialSource===void 0||r.providerId===void 0||r.models===void 0){x(t,"route must include family, credentialSource, providerId, and models");continue}const i=W.filter(c=>r.models[c]===void 0);if(i.length>0){x(t,`incomplete route; missing strengths: ${i.join(", ")}`),R(o,t,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models});continue}R(n,t,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models})}return{complete:n,legacy:o}}s(ae,"resolveModelRoutes");function $n(e,n){if(e.trim()==="")throw new Error("model route id must be a non-empty string");for(const t of["family","credentialSource","providerId"])if(typeof n[t]!="string"||n[t].trim()==="")throw new Error(`model route "${e}" ${t} must be a non-empty string`);const o=W.filter(t=>n.models?.[t]===void 0);if(o.length>0)throw new Error(`model route "${e}" is incomplete; missing strengths: ${o.join(", ")}`);for(const t of W){const r=n.models[t];if(typeof r!="string"||r.trim()==="")throw new Error(`model route "${e}" models.${t} must be a non-empty provider/id ref`);const i=r.indexOf("/");if(i<=0||i===r.length-1)throw new Error(`model route "${e}" models.${t} must be provider/id`);if(r.slice(0,i)!==n.providerId)throw new Error(`model route "${e}" models.${t} provider prefix must equal providerId`)}}s($n,"assertCompleteModelRoute");function N(e,n){if(e===void 0||e===null||typeof e!="object"||Array.isArray(e))return n;const o=e,t=s(i=>Array.isArray(i)&&i.every(c=>typeof c=="string"&&c.trim()!=="")?[...i]:void 0,"strings"),r=Array.isArray(o.strengthFallback)&&o.strengthFallback.every(i=>fe(i))?[...o.strengthFallback]:void 0;return{...t(o.credentialSourceOrder)!==void 0?{credentialSourceOrder:t(o.credentialSourceOrder)}:{},...t(o.familyOrder)!==void 0?{familyOrder:t(o.familyOrder)}:{},...r!==void 0?{strengthFallback:r}:{}}}s(N,"mergeModelRouting");function Mn(e){return e!==""&&e.replace(/\*/g,"")===""}s(Mn,"isInheritAllGlob");function L(e,n=[]){const o=e,t=Array.isArray(o?.allow)?o.allow.filter(r=>typeof r=="string"):[];for(const r of t)if(Mn(r))throw new Error(`spawnEnv.allow: "${r}" matches every env var name (inherit-all) \u2014 this is exactly the leak the spawn-env boundary closes. Name the specific vars/prefixes you actually need instead (e.g. "AWS_*", "GIT_ASKPASS").`);return{allow:[...new Set([...n,...t])]}}s(L,"mergeSpawnEnv");function F(e,n={}){const o={};for(const[t,r]of Object.entries(n))o[t]={...r};if(e!==null&&typeof e=="object")for(const[t,r]of Object.entries(e)){if(r===null||typeof r!="object")continue;const i={...o[t]},c=r.fastMode;typeof c=="boolean"&&(i.fastMode=c),o[t]=i}return o}s(F,"mergeProviderOptions");const me=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,Nn=new Set(["crtr","crtrd"]);function z(e,n){if(n==="bin"&&Nn.has(e))return`${n}.${e} is reserved by crouter \u2014 pick another bare command name`;if(!me.test(e))return`${n}.${e} is not a safe bare command name (expected ${me.source})`}s(z,"bareCommandNameIssue");function Ln(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"bin",message:"bin must be a JSON object mapping bare command name to a relative path"}];const n=[];for(const[o,t]of Object.entries(e)){const r=z(o,"bin");r!==void 0&&n.push({name:o,message:r}),(typeof t!="string"||t.trim()==="")&&n.push({name:o,message:`bin.${o} must be a non-empty relative path to an executable inside the contributor root`})}return n}s(Ln,"binDeclarationIssues");function Fn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))z(o,"bin")===void 0&&(typeof t!="string"||t.trim()===""||(n[o]=t));return n}s(Fn,"normalizeBin");const pe=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function zn(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"humanActions",reason:"humanActions must be a JSON object mapping action names to {argv, cwd}",block:!0}];const n=[];for(const[o,t]of Object.entries(e)){const r=[];if(pe.test(o)||r.push(`action name must match ${pe.source}`),t===null||typeof t!="object"||Array.isArray(t))r.push("action must be an object with argv and cwd");else{const i=t,c=Object.keys(i).filter(u=>u!=="argv"&&u!=="cwd");c.length>0&&r.push(`action has unsupported field${c.length===1?"":"s"}: ${c.join(", ")}`),(!Array.isArray(i.argv)||i.argv.length===0||!i.argv.every(u=>typeof u=="string"&&u.length>0))&&r.push("argv must be a non-empty array of non-empty strings"),(typeof i.cwd!="string"||i.cwd.length===0)&&r.push("cwd is required and must be a non-empty string")}r.length>0&&n.push({name:o,reason:r.join("; ")})}return n}s(zn,"humanActionDeclarationIssues");function Dn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n=new Set(zn(e).map(t=>t.name)),o={};for(const[t,r]of Object.entries(e)){if(n.has(t))continue;const i=r;o[t]={argv:[...i.argv],cwd:i.cwd}}return o}s(Dn,"normalizeHumanActions");function Po(e){return Ln(e).map(n=>n.message)}s(Po,"invalidPluginBinReasons");function To(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))z(o,"requires")===void 0&&(typeof t!="string"||t.trim()===""||/[\r\n]/.test(t)||(n[o]=t));return n}s(To,"normalizeRequires");function Co(e){if(e===null||typeof e!="object"||Array.isArray(e))return["requires must be a JSON object mapping a bare executable name to a one-line install hint"];const n=[];for(const[o,t]of Object.entries(e)){const r=z(o,"requires");r!==void 0&&n.push(r),typeof t!="string"||t.trim()===""?n.push(`requires.${o} must be a non-empty one-line install hint`):/[\r\n]/.test(t)&&n.push(`requires.${o} must be a one-line install hint`)}return n}s(Co,"invalidPluginRequiresReasons");function ge(e){if(e===null||typeof e!="object")return null;const n=e,o={};typeof n.whenToUse=="string"&&n.whenToUse.trim()!==""&&(o.whenToUse=n.whenToUse),typeof n.model=="string"&&n.model.trim()!==""&&(o.model=n.model),typeof n.orchestratorModel=="string"&&n.orchestratorModel.trim()!==""&&(o.orchestratorModel=n.orchestratorModel);const t=s(r=>Array.isArray(r)&&r.every(i=>typeof i=="string"),"isStringArray");return t(n.tools)&&(o.tools=n.tools),t(n.extensions)&&(o.extensions=n.extensions),t(n.availableTo)&&(o.availableTo=n.availableTo),Object.keys(o).length>0?o:null}s(ge,"normalizeKindFields");function O(e,n=nn()){const o={...n};if(e!==null&&typeof e=="object")for(const[t,r]of Object.entries(e)){const i=ge(r);if(i===null)continue;const c=o[t];c!==void 0?o[t]={...c,...i}:i.whenToUse!==void 0&&(o[t]=i)}return o}s(O,"mergeKinds");function ye(e,n,o){if(n===null)return o;const t=re(e,n).filter(i=>i.enabled&&i.manifest.kinds!==void 0).sort((i,c)=>i.name.localeCompare(c.name));let r=o;for(const i of t)r=O(i.manifest.kinds,r);return r}s(ye,"layerPluginKinds");function $o(){const e=[{origin:"config.json",components:Rn("user").page_components}],n=h("user");if(n!==null){const o=re("user",n).filter(t=>t.enabled&&t.manifest.page_components!==void 0).sort((t,r)=>t.name.localeCompare(r.name));for(const t of o){const r=`plugin "${t.name}" page_components`;e.push({origin:`plugin "${t.name}"`,components:ce(t.manifest.page_components,r)})}}return Sn(e)}s($o,"resolvePageComponents");const J=new Set(["whenToUse","model","orchestratorModel","tools","extensions","availableTo"]);function Mo(e){if(e===null||typeof e!="object"||Array.isArray(e))return["kinds must be a JSON object keyed by kind name"];const n=[],o=s(t=>Array.isArray(t)&&t.every(r=>typeof r=="string"),"isStringArray");for(const[t,r]of Object.entries(e)){if(t.trim()===""){n.push("kinds contains an empty kind name");continue}if(r===null||typeof r!="object"||Array.isArray(r)){n.push(`kinds.${t} must be a JSON object`);continue}const i=r;for(const c of Object.keys(i))J.has(c)||n.push(`kinds.${t}.${c} is not a KindConfig field (expected one of: ${[...J].join(", ")})`);i.whenToUse!==void 0&&(typeof i.whenToUse!="string"||i.whenToUse.trim()==="")&&n.push(`kinds.${t}.whenToUse must be a non-empty string`);for(const c of["model","orchestratorModel"])i[c]!==void 0&&(typeof i[c]!="string"||i[c].trim()==="")&&n.push(`kinds.${t}.${c} must be a non-empty string`);for(const c of["tools","extensions","availableTo"])i[c]!==void 0&&!o(i[c])&&n.push(`kinds.${t}.${c} must be an array of strings`);ge(r)===null&&n.push(`kinds.${t} has no valid KindConfig field \u2014 an entry must set at least one of: ${[...J].join(", ")} (whenToUse is required when the kind exists in no lower layer)`)}return n}s(Mo,"invalidPluginKindsReasons");function Un(e){if(e===null||typeof e!="object")return null;const n=e;if(typeof n.previewEndpoint!="string"||n.previewEndpoint.trim()===""||typeof n.relayTokenRef!="string"||n.relayTokenRef.trim()==="")return null;const o={previewEndpoint:n.previewEndpoint,relayTokenRef:n.relayTokenRef};return typeof n.cpOrigin=="string"&&n.cpOrigin.trim()!==""&&(o.cpOrigin=n.cpOrigin),o}s(Un,"normalizeRemoteCanvasTarget");function Kn(e,n=on()){const o={...n.targets};if(e!==null&&typeof e=="object"){const t=e;if(t.targets!==null&&typeof t.targets=="object")for(const[r,i]of Object.entries(t.targets)){const c=Un(i);c!==null&&(o[r]=c)}}return{targets:o}}s(Kn,"mergeRemoteCanvas");function he(e,n){return e===!0?"notify":e===!1?!1:e==="notify"||e==="apply"?e:n}s(he,"normalizeMode");function E(e,n){return typeof e=="number"&&Number.isSafeInteger(e)&&e>=1?e:n}s(E,"normalizePositiveInteger");function qn(e,n){const o=e!==null&&typeof e=="object"?e:{},t=E(o.warning,n.warning),r=E(o.automaticReviveCap,n.automaticReviveCap);return t<=r?{warning:t,automaticReviveCap:r}:{...n}}s(qn,"mergeBrokerThresholds");function Gn(e,n){return{unattendedParkMs:E((e!==null&&typeof e=="object"?e:{}).unattendedParkMs,n.unattendedParkMs)}}s(Gn,"mergeLifecycle");function Bn(e){if(!Array.isArray(e))return[...ne];const n=e.filter(o=>typeof o=="string"&&o.trim()!=="").map(o=>o.trim());return n.length>0?n:[...ne]}s(Bn,"normalizeWhipMessages");function Wn(e,n){if(e===null||typeof e!="object")return{...n};const o=e.tcp;return{tcp:typeof o=="string"?o:n.tcp}}s(Wn,"mergeApi");function D(e){const n=w(),o=n.schema_version,t=e.marketplaces===void 0?{}:e.marketplaces,r=e.plugins===void 0?{}:e.plugins,i=e.auto_update,c=i&&typeof i.interval_hours=="number"?i.interval_hours:void 0,u=c!==void 0&&Number.isFinite(c)&&c>=0?c:n.auto_update.interval_hours,d={crtr:he(i?.crtr,n.auto_update.crtr),content:he(i?.content,n.auto_update.content),interval_hours:u},l=e.max_panes_per_window,f=E(l,n.max_panes_per_window),a=typeof e.auto_open_child_viewers=="boolean"?e.auto_open_child_viewers:n.auto_open_child_viewers,m=qn(e.brokerThresholds,n.brokerThresholds),b=Gn(e.lifecycle,n.lifecycle),U=typeof e.completion_bell=="boolean"?e.completion_bell:n.completion_bell,p=e.working_gerunds===void 0?[...n.working_gerunds]:An(e.working_gerunds),_e=typeof e.whip_mode=="boolean"?e.whip_mode:n.whip_mode,ve=ce(e.page_components),ke=typeof e.page_surface=="boolean"?e.page_surface:n.page_surface,we=Bn(e.whip_messages),Ae=Qe.includes(e.whip_message_mode)?e.whip_message_mode:n.whip_message_mode,Se=Xe.includes(e.mouse_mode_default)?e.mouse_mode_default:n.mouse_mode_default,je=E(e.live_cycles,n.live_cycles),Re=Ve.includes(e.condensed_history)?e.condensed_history:n.condensed_history,xe=typeof e.bash_tool_purpose=="boolean"?e.bash_tool_purpose:n.bash_tool_purpose,Oe=typeof e.fold_finished_tools=="boolean"?e.fold_finished_tools:n.fold_finished_tools,Ee=typeof e.summarize_tool_calls=="boolean"?e.summarize_tool_calls:n.summarize_tool_calls,Ie=typeof e.detailed_tool_recaps=="boolean"?e.detailed_tool_recaps:n.detailed_tool_recaps,Pe=Number.isInteger(e.document_port)&&e.document_port>=1&&e.document_port<=65535?e.document_port:n.document_port,Te=typeof e.consolidate_replies=="boolean"?e.consolidate_replies:n.consolidate_replies,Ce=Pn(e.keybindings),$e=Cn(e.tmux_passthrough),Me=$(e.modelLadders),Ne=F(e.providerOptions,n.providerOptions),K=ae(M(e.modelRoutes)),Z=K.complete,Y=N(e.modelRouting,void 0),Le=O(e.kinds),Fe=Kn(e.remoteCanvas),ze=Wn(e.api,n.api),v=e.paths;if(v?.user_files!==void 0&&(typeof v.user_files!="string"||!v.user_files.startsWith("/")))throw new Error("paths.user_files must be an absolute path");const y=e.ledger;if(y?.take_pct!==void 0&&(typeof y.take_pct!="number"||!Number.isFinite(y.take_pct)||y.take_pct<0||y.take_pct>100))throw new Error("ledger.take_pct must be a number from 0 to 100");const V=e.store,k=e.runtime;if(k?.person_uids!==void 0&&(!Array.isArray(k.person_uids)||!k.person_uids.every(X=>Number.isSafeInteger(X)&&X>=0)))throw new Error("runtime.person_uids must be an array of nonnegative integer uids");const De=L(e.spawnEnv,n.spawnEnv?.allow),Ue=Fn(e.bin),Ke=Dn(e.humanActions);return{bin:Ue,humanActions:Ke,schema_version:o,marketplaces:t,plugins:r,auto_update:d,max_panes_per_window:f,auto_open_child_viewers:a,brokerThresholds:m,lifecycle:b,completion_bell:U,working_gerunds:p,whip_mode:_e,page_components:ve,page_surface:ke,whip_messages:we,whip_message_mode:Ae,mouse_mode_default:Se,live_cycles:je,condensed_history:Re,bash_tool_purpose:xe,fold_finished_tools:Oe,summarize_tool_calls:Ee,detailed_tool_recaps:Ie,document_port:Pe,consolidate_replies:Te,keybindings:Ce,tmux_passthrough:$e,modelLadders:Me,providerOptions:Ne,...Object.keys(Z).length>0?{modelRoutes:Z}:{},...Object.keys(K.legacy).length>0?{legacyModelRoutes:K.legacy}:{},...Y!==void 0?{modelRouting:Y}:{},kinds:Le,remoteCanvas:Fe,api:ze,...v?{paths:v}:{},...y?{ledger:y}:{},...V?{store:V}:{},...k?{runtime:k}:{},spawnEnv:De}}s(D,"mergeConfig");function Hn(e){return P(e)}s(Hn,"readRawConfigAtRoot");function Jn(e){const n=h(e);return n?Hn(n):null}s(Jn,"readRawScopeConfig");function Zn(e){if(e===null||e==="")return null;try{return P(G(e))}catch{return null}}s(Zn,"readRawProfileConfig");function Yn(e,n){return[...fn(e,n)].reverse().map(r=>({root:r,raw:P(r)}))}s(Yn,"readRawProjectScopeConfigs");function be(e=process.cwd(),n=Ge()||null){const o=T[C];if(o)return o.launch;const t=w(),r=Jn("user"),i=Zn(n),c=Yn(e,n);let u=O(r?.kinds,ye("user",h("user"),t.kinds)),d=$(r?.modelLadders,t.modelLadders),l=F(r?.providerOptions,t.providerOptions),f=M(r?.modelRoutes),a=N(r?.modelRouting,void 0),m=L(r?.spawnEnv,t.spawnEnv?.allow);i!==null&&(u=O(i.kinds,u),d=$(i.modelLadders,d),l=F(i.providerOptions,l),f=M(i.modelRoutes,f),a=N(i.modelRouting,a),m=L(i.spawnEnv,m.allow));for(const{root:U,raw:p}of c)u=O(p?.kinds,ye("project",U,u)),p!==null&&(d=$(p.modelLadders,d),l=F(p.providerOptions,l),f=M(p.modelRoutes,f),a=N(p.modelRouting,a),m=L(p.spawnEnv,m.allow));const b=ae(f);return{kinds:u,modelLadders:d,providerOptions:l,...Object.keys(b.complete).length>0?{modelRoutes:b.complete}:{},...Object.keys(b.legacy).length>0?{legacyModelRoutes:b.legacy}:{},...a!==void 0?{modelRouting:a}:{},spawnEnv:m}}s(be,"readMergedLaunchConfig");function No(e){return be().kinds[e]}s(No,"resolveKindConfig");function Lo(e){const n=be().kinds,o=[];for(const[t,r]of Object.entries(n)){const i=t.indexOf("/");if(i===-1)continue;const c=t.slice(0,i),u=r.availableTo??[c];(u.includes("*")||u.includes(e))&&o.push({kind:t,whenToUse:r.whenToUse})}return o.sort((t,r)=>t.kind.localeCompare(r.kind))}s(Lo,"subKindsAvailableTo");function Vn(e,n,o){const t={...e??{}};t.anthropic!==void 0&&(t.anthropic={...t.anthropic}),t.openai!==void 0&&(t.openai={...t.openai}),o.defaultProvider!==n.defaultProvider&&o.defaultProvider!==void 0&&(t.defaultProvider=o.defaultProvider);for(const i of["anthropic","openai"])for(const c of["ultra","strong","medium","light"])o[i][c]!==n[i][c]&&(t[i]={...t[i]??{},[c]:o[i][c]});return t.defaultProvider!==void 0||t.anthropic!==void 0||t.openai!==void 0?t:void 0}s(Vn,"sparseModelLaddersToPersist");function Xn(e,n){return j(e,o=>{const t=D(o),r=D(o);n(r);const i={...o};for(const u of wn)u!=="modelLadders"&&!Je(r[u],t[u])&&(i[u]=r[u]);const c=Vn(o.modelLadders,t.modelLadders,r.modelLadders);return c!==void 0?i.modelLadders=c:delete i.modelLadders,{value:r,next:i}})}s(Xn,"mutateConfigAtRoot");function Fo(e,n){j(e,o=>{const t=o.modelLadders??{},r={...t};n.defaultProvider!==void 0&&(r.defaultProvider=n.defaultProvider);for(const i of["anthropic","openai"])n[i]!==void 0&&(r[i]={...t[i]??{},...n[i]});return{value:void 0,next:{...o,modelLadders:r}}})}s(Fo,"persistModelLadders");function zo(e,n,o){if(o!==void 0)$n(n,o);else if(n.trim()==="")throw new Error("model route id must be a non-empty string");j(e,t=>{const r=le(t.modelRoutes??{});o===void 0?delete r[n]:R(r,n,{...o,models:{...o.models}});const i={...t};return Object.keys(r).length===0?delete i.modelRoutes:i.modelRoutes=r,{value:void 0,next:i}})}s(zo,"persistModelRoute");function Qn(e,n){return Xn(e,n)}s(Qn,"updateConfigAtRoot");function Do(e,n){return Qn(A(e),n)}s(Do,"updateConfig");function Uo(e){const n=e.orchestrator===!0?"orchestratorModel":"model";return j(e.root,o=>{const t={...o.kinds??{},[e.kind]:{...(o.kinds??{})[e.kind],[n]:e.model}};return{value:void 0,next:{...o,kinds:t}}}),{path:_(e.root),field:n}}s(Uo,"persistDefaultKindModel");function Ko(e,n){const o=On(e);return n(o),In(e,o),o}s(Ko,"updateState");export{En as InvalidRawSettingsError,Ln as binDeclarationIssues,So as brokerConfigSnapshot,ko as configPath,Io as ensureScopeInitialized,zn as humanActionDeclarationIssues,Ao as installBrokerConfigSnapshot,Po as invalidPluginBinReasons,Mo as invalidPluginKindsReasons,Co as invalidPluginRequiresReasons,Fn as normalizeBin,Dn as normalizeHumanActions,To as normalizeRequires,Cn as normalizeTmuxPassthrough,Uo as persistDefaultKindModel,Fo as persistModelLadders,zo as persistModelRoute,Rn as readConfig,xn as readConfigAtRoot,be as readMergedLaunchConfig,Hn as readRawConfigAtRoot,Jn as readRawScopeConfig,jo as readRawSettingsForTarget,On as readState,Ro as replaceRawSettingsForTarget,No as resolveKindConfig,$o as resolvePageComponents,wo as statePath,Lo as subKindsAvailableTo,Do as updateConfig,Qn as updateConfigAtRoot,xo as updateRawConfigAtomically,Ko as updateState,Oo as writeConfig,Eo as writeRawConfig,In as writeState};
|
|
1
|
+
var Ze=Object.defineProperty;var s=(e,n)=>Ze(e,"name",{value:n,configurable:!0});import{envProfileId as Ye}from"../shared/env.js";import{basename as re,join as ie}from"node:path";import{existsSync as Ve,mkdirSync as Xe,statSync as Qe}from"node:fs";import{isDeepStrictEqual as en}from"node:util";import{CONFIG_FILE as nn,STATE_FILE as on,CONDENSED_HISTORY_MODES as tn,MOUSE_MODE_DEFAULTS as rn,WHIP_MESSAGE_MODES as sn,DEFAULT_WHIP_MESSAGES as se,defaultScopeConfig as k,defaultScopeState as ce,defaultModelLaddersConfig as cn,defaultKindsConfig as un,defaultRemoteCanvasConfig as dn}from"../types.js";import{BINDING_CATALOG as an,BINDING_IDS as fn,isAttachPaneBinding as ln}from"./keybindings/catalog.js";import{notFound as mn}from"./errors.js";import{emitEvent as pn}from"./events/emit.js";import{atomicWriteJson as B,readJsonIfExists as C,ensureDir as gn}from"./fs-utils.js";import{scopeRoot as y,requireScopeRoot as A,findProjectScopeRoots as yn,userScopeRoot as ue}from"./scope.js";import{listInstalledPluginsInRoot as de}from"./installed-plugins.js";import{profileDir as ae,listProfiles as fe}from"./profiles/manifest.js";import{canonicalRoot as S}from"./scoped-state/paths.js";import{readCachedSettings as H,readCachedState as hn,revisionOf as J,SettingsRevisionConflictError as le,writeSettings as W}from"./scoped-state/person-store.js";import{withExclusiveDirectoryLock as _n}from"./exclusive-lock.js";import{SCOPE_CONFIG_KEYS as bn}from"./user-settings.js";import{normalizeWorkingGerunds as vn}from"../shared/working-activity.js";import{mergePageComponentLayers as wn,normalizePageComponents as me}from"./human/page-catalog.js";function _(e){return ie(e,nn)}s(_,"configPathFor");function Z(e,n){return _n(`${e}.lock`,()=>n(e),{timeoutError:s(()=>new Error(`timed out waiting for config lock: ${e}`),"timeoutError")})}s(Z,"withConfigPathLock");function Y(e){return ie(e,on)}s(Y,"statePathFor");function _o(e){const n=y(e);return n?_(n):null}s(_o,"configPath");function bo(e){const n=y(e);return n?Y(n):null}s(bo,"statePath");function j(e){const n=S(e),o=S(ue());if(n===o)return{key:"user",kind:"user",root:o};if(re(n)===".crouter")return{key:"project",kind:"project",root:n};for(const t of fe()){const r=S(ae(t.profileId));if(n===r)return{key:`profile:${t.profileId}`,kind:"profile",root:r,profileId:t.profileId}}throw new Error(`settings root is not a recognized owner: ${e}`)}s(j,"settingsOwnerForRoot");function T(e){if(re(e)===".crouter"){let n;try{n=S(e)}catch(o){if(o.code==="ENOENT")return null;throw o}if(n!==S(ue()))return C(_(e))}return H(j(e).key).settings}s(T,"readRawAtRoot");async function pe(e,n){let o;return await W(t=>{const r=t.settings[e],i=n(structuredClone(r??{}));return o=i.value,[{op:"settings.replace",owner:e,raw:i.next,ifRevision:J(r)}]}),o}s(pe,"mutatePersonSettings");async function V(e,n){const o=j(e);if(o.kind==="project"){Z(_(o.root),t=>B(t,n,{createParent:!1}));return}await pe(o.key,()=>({value:void 0,next:n}))}s(V,"writeRawAtRoot");async function x(e,n){const o=j(e);return o.kind==="project"?Z(_(o.root),t=>{const r=n(C(t)??{});return B(t,r.next,{createParent:!1}),r.value}):await pe(o.key,n)}s(x,"mutateRawAtRoot");const $=globalThis,M=Symbol.for("crtr.broker.config-snapshot");function vo(e){$[M]=e}s(vo,"installBrokerConfigSnapshot");function wo(){return $[M]}s(wo,"brokerConfigSnapshot");function kn(e){const n=$[M];if(n){if(e!=="user")throw new Error(`broker config snapshot has no ${e} scope`);return n.user}const o=y(e);return o?An(o):k()}s(kn,"readConfig");function An(e){const n=T(e);return n?U(n):k()}s(An,"readConfigAtRoot");function Sn(e){const n=C(Y(e));return{marketplaces:n?.marketplaces??{},plugins:n?.plugins??{},activeCanvas:n?.activeCanvas??null,...n?.last_self_check===void 0?{}:{last_self_check:n.last_self_check}}}s(Sn,"readProjectState");function jn(e){const n=y(e);return n?e==="project"?Ve(n)?Sn(n):ce():hn(j(n).key):ce()}s(jn,"readState");class xn extends Error{static{s(this,"InvalidRawSettingsError")}constructor(n){super(`settings cannot be merged: ${n instanceof Error?n.message:String(n)}`),this.name="InvalidRawSettingsError"}}function ge(e){if(e.scope==="user")return"user";if(!fe().some(n=>n.profileId===e.profileId))throw mn(`profile not found: ${e.profileId}`,{received:e.profileId,next:"Run `crtr profile list` to see available profiles."});return`profile:${e.profileId}`}s(ge,"rawSettingsKeyForTarget");function ko(e){return H(ge(e))}s(ko,"readRawSettingsForTarget");async function Ao(e,n,o){const t=ge(e);try{U(n)}catch(u){throw new xn(u)}if(H(t).revision!==o)throw new le;const i=await W(u=>J(u.settings[t])===o?[{op:"settings.replace",owner:t,raw:n,ifRevision:o}]:(()=>{throw new le})()),c=J(i.settings[t]);return{revision:c,changed:c!==o}}s(Ao,"replaceRawSettingsForTarget");async function So(e,n){const o=A(e);return await x(o,t=>{const r=n(t);return{value:r,next:r}})}s(So,"updateRawConfigAtomically");async function jo(e,n){await V(A(e),n)}s(jo,"writeConfig");async function xo(e,n){await V(A(e),n)}s(xo,"writeRawConfig");function Rn(e,n){Z(Y(e),o=>B(o,n,{createParent:!1}))}s(Rn,"writeProjectState");async function En(e,n){const o=A(e);if(e==="project"){Rn(o,n);return}const t=j(o).key;await W(()=>[{op:"state.write",owner:t,state:n}])}s(En,"writeState");async function Ro(e,n){if(e!=="project"){gn(n);return}try{Xe(n)}catch(o){if(o.code!=="EEXIST"||!Qe(n).isDirectory())throw o}C(_(n))===null&&await V(n,{schema_version:k().schema_version})}s(Ro,"ensureScopeInitialized");function On(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))Array.isArray(t)&&t.every(r=>typeof r=="string")&&(n[o]=[...t]);return n}s(On,"normalizeKeybindings");const Pn=new Set(an.filter(ln).map(e=>e.id));function In(e){return Array.isArray(e)?[...new Set(e.filter(n=>typeof n=="string"&&fn.has(n)&&Pn.has(n)))]:[]}s(In,"normalizeTmuxPassthrough");function N(e,n=cn()){const o=n;if(e===null||typeof e!="object")return o;const t=e,r={anthropic:{...o.anthropic},openai:{...o.openai},...o.defaultProvider!==void 0?{defaultProvider:o.defaultProvider}:{}};(t.defaultProvider==="anthropic"||t.defaultProvider==="openai")&&(r.defaultProvider=t.defaultProvider);for(const i of["anthropic","openai"]){const c=t[i];if(!(c===null||typeof c!="object"))for(const[u,d]of Object.entries(c))(u==="ultra"||u==="strong"||u==="medium"||u==="light")&&typeof d=="string"&&(r[i][u]=d)}return r}s(N,"mergeModelLadders");function ye(e){return e==="ultra"||e==="strong"||e==="medium"||e==="light"}s(ye,"validStrength");const X=["ultra","strong","medium","light"];function Q(){return Object.create(null)}s(Q,"routeRecord");function R(e,n,o){Object.defineProperty(e,n,{value:o,writable:!0,enumerable:!0,configurable:!0})}s(R,"setRouteRecord");function he(e){const n=Q();for(const[o,t]of Object.entries(e??{}))R(n,o,t);return n}s(he,"copyRouteRecord");function E(e,n){pn({level:"warn",event:"config.model_routes.invalid",fields:{route_id:e,rule:n}})}s(E,"routeInvalid");function L(e,n={}){const o=he(n);if(e===null||typeof e!="object"||Array.isArray(e))return o;for(const[t,r]of Object.entries(e)){if(t.trim()===""){E(t,"route id must be a non-empty string");continue}if(r===null||typeof r!="object"||Array.isArray(r)){E(t,"route must be an object");continue}const i=r,c=o[t],u={...c};let d;for(const f of["family","credentialSource","providerId"]){const a=i[f];if(a!==void 0){if(typeof a!="string"||a.trim()===""){d=`${f} must be a non-empty string`;break}u[f]=a}}if(d===void 0&&i.models!==void 0)if(i.models===null||typeof i.models!="object"||Array.isArray(i.models))d="models must be an object";else{const f={...c?.models};for(const[a,l]of Object.entries(i.models)){if(!ye(a)){d=`models.${a} is not a model strength`;break}if(typeof l!="string"||l.trim()===""){d=`models.${a} must be a non-empty provider/id ref`;break}const m=l.indexOf("/");if(m<=0||m===l.length-1){d=`models.${a} must be provider/id`;break}f[a]=l}u.models=f}if(d===void 0&&u.models!==void 0&&u.providerId!==void 0){for(const[f,a]of Object.entries(u.models))if(a.slice(0,a.indexOf("/"))!==u.providerId){d=`models.${f} provider prefix must equal providerId`;break}}if(d!==void 0){E(t,d);continue}R(o,t,u)}return o}s(L,"mergeModelRoutePatches");function _e(e){const n=Q(),o=Q();for(const[t,r]of Object.entries(e)){if(r.family===void 0||r.credentialSource===void 0||r.providerId===void 0||r.models===void 0){E(t,"route must include family, credentialSource, providerId, and models");continue}const i=X.filter(c=>r.models[c]===void 0);if(i.length>0){E(t,`incomplete route; missing strengths: ${i.join(", ")}`),R(o,t,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models});continue}R(n,t,{family:r.family,credentialSource:r.credentialSource,providerId:r.providerId,models:r.models})}return{complete:n,legacy:o}}s(_e,"resolveModelRoutes");function Cn(e,n){if(e.trim()==="")throw new Error("model route id must be a non-empty string");for(const t of["family","credentialSource","providerId"])if(typeof n[t]!="string"||n[t].trim()==="")throw new Error(`model route "${e}" ${t} must be a non-empty string`);const o=X.filter(t=>n.models?.[t]===void 0);if(o.length>0)throw new Error(`model route "${e}" is incomplete; missing strengths: ${o.join(", ")}`);for(const t of X){const r=n.models[t];if(typeof r!="string"||r.trim()==="")throw new Error(`model route "${e}" models.${t} must be a non-empty provider/id ref`);const i=r.indexOf("/");if(i<=0||i===r.length-1)throw new Error(`model route "${e}" models.${t} must be provider/id`);if(r.slice(0,i)!==n.providerId)throw new Error(`model route "${e}" models.${t} provider prefix must equal providerId`)}}s(Cn,"assertCompleteModelRoute");function F(e,n){if(e===void 0||e===null||typeof e!="object"||Array.isArray(e))return n;const o=e,t=s(i=>Array.isArray(i)&&i.every(c=>typeof c=="string"&&c.trim()!=="")?[...i]:void 0,"strings"),r=Array.isArray(o.strengthFallback)&&o.strengthFallback.every(i=>ye(i))?[...o.strengthFallback]:void 0;return{...t(o.credentialSourceOrder)!==void 0?{credentialSourceOrder:t(o.credentialSourceOrder)}:{},...t(o.familyOrder)!==void 0?{familyOrder:t(o.familyOrder)}:{},...r!==void 0?{strengthFallback:r}:{}}}s(F,"mergeModelRouting");function Tn(e){return e!==""&&e.replace(/\*/g,"")===""}s(Tn,"isInheritAllGlob");function z(e,n=[]){const o=e,t=Array.isArray(o?.allow)?o.allow.filter(r=>typeof r=="string"):[];for(const r of t)if(Tn(r))throw new Error(`spawnEnv.allow: "${r}" matches every env var name (inherit-all) \u2014 this is exactly the leak the spawn-env boundary closes. Name the specific vars/prefixes you actually need instead (e.g. "AWS_*", "GIT_ASKPASS").`);return{allow:[...new Set([...n,...t])]}}s(z,"mergeSpawnEnv");function D(e,n={}){const o={};for(const[t,r]of Object.entries(n))o[t]={...r};if(e!==null&&typeof e=="object")for(const[t,r]of Object.entries(e)){if(r===null||typeof r!="object")continue;const i={...o[t]},c=r.fastMode;typeof c=="boolean"&&(i.fastMode=c),o[t]=i}return o}s(D,"mergeProviderOptions");const be=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,$n=new Set(["crtr","crtrd"]);function K(e,n){if(n==="bin"&&$n.has(e))return`${n}.${e} is reserved by crouter \u2014 pick another bare command name`;if(!be.test(e))return`${n}.${e} is not a safe bare command name (expected ${be.source})`}s(K,"bareCommandNameIssue");function Mn(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"bin",message:"bin must be a JSON object mapping bare command name to a relative path"}];const n=[];for(const[o,t]of Object.entries(e)){const r=K(o,"bin");r!==void 0&&n.push({name:o,message:r}),(typeof t!="string"||t.trim()==="")&&n.push({name:o,message:`bin.${o} must be a non-empty relative path to an executable inside the contributor root`})}return n}s(Mn,"binDeclarationIssues");function Nn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))K(o,"bin")===void 0&&(typeof t!="string"||t.trim()===""||(n[o]=t));return n}s(Nn,"normalizeBin");const ve=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;function Ln(e){if(e===null||typeof e!="object"||Array.isArray(e))return[{name:"humanActions",reason:"humanActions must be a JSON object mapping action names to {argv, cwd}",block:!0}];const n=[];for(const[o,t]of Object.entries(e)){const r=[];if(ve.test(o)||r.push(`action name must match ${ve.source}`),t===null||typeof t!="object"||Array.isArray(t))r.push("action must be an object with argv and cwd");else{const i=t,c=Object.keys(i).filter(u=>u!=="argv"&&u!=="cwd");c.length>0&&r.push(`action has unsupported field${c.length===1?"":"s"}: ${c.join(", ")}`),(!Array.isArray(i.argv)||i.argv.length===0||!i.argv.every(u=>typeof u=="string"&&u.length>0))&&r.push("argv must be a non-empty array of non-empty strings"),(typeof i.cwd!="string"||i.cwd.length===0)&&r.push("cwd is required and must be a non-empty string")}r.length>0&&n.push({name:o,reason:r.join("; ")})}return n}s(Ln,"humanActionDeclarationIssues");function Fn(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n=new Set(Ln(e).map(t=>t.name)),o={};for(const[t,r]of Object.entries(e)){if(n.has(t))continue;const i=r;o[t]={argv:[...i.argv],cwd:i.cwd}}return o}s(Fn,"normalizeHumanActions");function Eo(e){return Mn(e).map(n=>n.message)}s(Eo,"invalidPluginBinReasons");function Oo(e){if(e===null||typeof e!="object"||Array.isArray(e))return{};const n={};for(const[o,t]of Object.entries(e))K(o,"requires")===void 0&&(typeof t!="string"||t.trim()===""||/[\r\n]/.test(t)||(n[o]=t));return n}s(Oo,"normalizeRequires");function Po(e){if(e===null||typeof e!="object"||Array.isArray(e))return["requires must be a JSON object mapping a bare executable name to a one-line install hint"];const n=[];for(const[o,t]of Object.entries(e)){const r=K(o,"requires");r!==void 0&&n.push(r),typeof t!="string"||t.trim()===""?n.push(`requires.${o} must be a non-empty one-line install hint`):/[\r\n]/.test(t)&&n.push(`requires.${o} must be a one-line install hint`)}return n}s(Po,"invalidPluginRequiresReasons");function we(e){if(e===null||typeof e!="object")return null;const n=e,o={};typeof n.whenToUse=="string"&&n.whenToUse.trim()!==""&&(o.whenToUse=n.whenToUse),typeof n.model=="string"&&n.model.trim()!==""&&(o.model=n.model),typeof n.orchestratorModel=="string"&&n.orchestratorModel.trim()!==""&&(o.orchestratorModel=n.orchestratorModel);const t=s(r=>Array.isArray(r)&&r.every(i=>typeof i=="string"),"isStringArray");return t(n.tools)&&(o.tools=n.tools),t(n.extensions)&&(o.extensions=n.extensions),t(n.availableTo)&&(o.availableTo=n.availableTo),Object.keys(o).length>0?o:null}s(we,"normalizeKindFields");function O(e,n=un()){const o={...n};if(e!==null&&typeof e=="object")for(const[t,r]of Object.entries(e)){const i=we(r);if(i===null)continue;const c=o[t];c!==void 0?o[t]={...c,...i}:i.whenToUse!==void 0&&(o[t]=i)}return o}s(O,"mergeKinds");function ke(e,n,o){if(n===null)return o;const t=de(e,n).filter(i=>i.enabled&&i.manifest.kinds!==void 0).sort((i,c)=>i.name.localeCompare(c.name));let r=o;for(const i of t)r=O(i.manifest.kinds,r);return r}s(ke,"layerPluginKinds");function Io(){const e=[{origin:"config.json",components:kn("user").page_components}],n=y("user");if(n!==null){const o=de("user",n).filter(t=>t.enabled&&t.manifest.page_components!==void 0).sort((t,r)=>t.name.localeCompare(r.name));for(const t of o){const r=`plugin "${t.name}" page_components`;e.push({origin:`plugin "${t.name}"`,components:me(t.manifest.page_components,r)})}}return wn(e)}s(Io,"resolvePageComponents");const ee=new Set(["whenToUse","model","orchestratorModel","tools","extensions","availableTo"]);function Co(e){if(e===null||typeof e!="object"||Array.isArray(e))return["kinds must be a JSON object keyed by kind name"];const n=[],o=s(t=>Array.isArray(t)&&t.every(r=>typeof r=="string"),"isStringArray");for(const[t,r]of Object.entries(e)){if(t.trim()===""){n.push("kinds contains an empty kind name");continue}if(r===null||typeof r!="object"||Array.isArray(r)){n.push(`kinds.${t} must be a JSON object`);continue}const i=r;for(const c of Object.keys(i))ee.has(c)||n.push(`kinds.${t}.${c} is not a KindConfig field (expected one of: ${[...ee].join(", ")})`);i.whenToUse!==void 0&&(typeof i.whenToUse!="string"||i.whenToUse.trim()==="")&&n.push(`kinds.${t}.whenToUse must be a non-empty string`);for(const c of["model","orchestratorModel"])i[c]!==void 0&&(typeof i[c]!="string"||i[c].trim()==="")&&n.push(`kinds.${t}.${c} must be a non-empty string`);for(const c of["tools","extensions","availableTo"])i[c]!==void 0&&!o(i[c])&&n.push(`kinds.${t}.${c} must be an array of strings`);we(r)===null&&n.push(`kinds.${t} has no valid KindConfig field \u2014 an entry must set at least one of: ${[...ee].join(", ")} (whenToUse is required when the kind exists in no lower layer)`)}return n}s(Co,"invalidPluginKindsReasons");function zn(e){if(e===null||typeof e!="object")return null;const n=e;if(typeof n.previewEndpoint!="string"||n.previewEndpoint.trim()===""||typeof n.relayTokenRef!="string"||n.relayTokenRef.trim()==="")return null;const o={previewEndpoint:n.previewEndpoint,relayTokenRef:n.relayTokenRef};return typeof n.cpOrigin=="string"&&n.cpOrigin.trim()!==""&&(o.cpOrigin=n.cpOrigin),o}s(zn,"normalizeRemoteCanvasTarget");function Dn(e,n=dn()){const o={...n.targets};if(e!==null&&typeof e=="object"){const t=e;if(t.targets!==null&&typeof t.targets=="object")for(const[r,i]of Object.entries(t.targets)){const c=zn(i);c!==null&&(o[r]=c)}}return{targets:o}}s(Dn,"mergeRemoteCanvas");function Ae(e,n){return e===!0?"notify":e===!1?!1:e==="notify"||e==="apply"?e:n}s(Ae,"normalizeMode");function P(e,n){return typeof e=="number"&&Number.isSafeInteger(e)&&e>=1?e:n}s(P,"normalizePositiveInteger");function Kn(e,n){const o=e!==null&&typeof e=="object"?e:{},t=P(o.warning,n.warning),r=P(o.automaticReviveCap,n.automaticReviveCap);return t<=r?{warning:t,automaticReviveCap:r}:{...n}}s(Kn,"mergeBrokerThresholds");function Un(e,n){return{unattendedParkMs:P((e!==null&&typeof e=="object"?e:{}).unattendedParkMs,n.unattendedParkMs)}}s(Un,"mergeLifecycle");function qn(e){if(!Array.isArray(e))return[...se];const n=e.filter(o=>typeof o=="string"&&o.trim()!=="").map(o=>o.trim());return n.length>0?n:[...se]}s(qn,"normalizeWhipMessages");function Gn(e,n){if(e===null||typeof e!="object")return{...n};const o=e.tcp;return{tcp:typeof o=="string"?o:n.tcp}}s(Gn,"mergeApi");function U(e){const n=k(),o=n.schema_version,t=e.marketplaces===void 0?{}:e.marketplaces,r=e.plugins===void 0?{}:e.plugins,i=e.auto_update,c=i&&typeof i.interval_hours=="number"?i.interval_hours:void 0,u=c!==void 0&&Number.isFinite(c)&&c>=0?c:n.auto_update.interval_hours,d={crtr:Ae(i?.crtr,n.auto_update.crtr),content:Ae(i?.content,n.auto_update.content),interval_hours:u},f=e.max_panes_per_window,a=P(f,n.max_panes_per_window),l=typeof e.auto_open_child_viewers=="boolean"?e.auto_open_child_viewers:n.auto_open_child_viewers,m=Kn(e.brokerThresholds,n.brokerThresholds),h=Un(e.lifecycle,n.lifecycle),q=typeof e.completion_bell=="boolean"?e.completion_bell:n.completion_bell,g=e.working_gerunds===void 0?[...n.working_gerunds]:vn(e.working_gerunds),je=typeof e.whip_mode=="boolean"?e.whip_mode:n.whip_mode,xe=me(e.page_components),Re=typeof e.page_surface=="boolean"?e.page_surface:n.page_surface,Ee=qn(e.whip_messages),Oe=sn.includes(e.whip_message_mode)?e.whip_message_mode:n.whip_message_mode,Pe=rn.includes(e.mouse_mode_default)?e.mouse_mode_default:n.mouse_mode_default,Ie=P(e.live_cycles,n.live_cycles),Ce=tn.includes(e.condensed_history)?e.condensed_history:n.condensed_history,Te=typeof e.bash_tool_purpose=="boolean"?e.bash_tool_purpose:n.bash_tool_purpose,$e=typeof e.fold_finished_tools=="boolean"?e.fold_finished_tools:n.fold_finished_tools,Me=typeof e.summarize_tool_calls=="boolean"?e.summarize_tool_calls:n.summarize_tool_calls,Ne=typeof e.detailed_tool_recaps=="boolean"?e.detailed_tool_recaps:n.detailed_tool_recaps,Le=Number.isInteger(e.document_port)&&e.document_port>=1&&e.document_port<=65535?e.document_port:n.document_port,Fe=typeof e.consolidate_replies=="boolean"?e.consolidate_replies:n.consolidate_replies,ze=On(e.keybindings),De=In(e.tmux_passthrough),Ke=N(e.modelLadders),Ue=D(e.providerOptions,n.providerOptions),G=_e(L(e.modelRoutes)),ne=G.complete,oe=F(e.modelRouting,void 0),qe=O(e.kinds),Ge=Dn(e.remoteCanvas),Be=Gn(e.api,n.api),b=e.paths;if(b?.user_files!==void 0&&(typeof b.user_files!="string"||!b.user_files.startsWith("/")))throw new Error("paths.user_files must be an absolute path");const p=e.ledger;if(p?.take_pct!==void 0&&(typeof p.take_pct!="number"||!Number.isFinite(p.take_pct)||p.take_pct<0||p.take_pct>100))throw new Error("ledger.take_pct must be a number from 0 to 100");for(const w of["sandbox_usd_per_gb_hour","sandbox_standby_s","storage_usd_per_gb_month","sandbox_disk_usd_per_gb_month","infra_free_usd_per_month"]){const I=p?.[w];if(I!==void 0&&(typeof I!="number"||!Number.isFinite(I)||I<0))throw new Error(`ledger.${w} must be a number of at least 0`)}if(p?.r2_move!==void 0&&typeof p.r2_move!="boolean")throw new Error("ledger.r2_move must be true or false");const te=e.store,v=e.runtime;if(v?.person_uids!==void 0&&(!Array.isArray(v.person_uids)||!v.person_uids.every(w=>Number.isSafeInteger(w)&&w>=0)))throw new Error("runtime.person_uids must be an array of nonnegative integer uids");const He=z(e.spawnEnv,n.spawnEnv?.allow),Je=Nn(e.bin),We=Fn(e.humanActions);return{bin:Je,humanActions:We,schema_version:o,marketplaces:t,plugins:r,auto_update:d,max_panes_per_window:a,auto_open_child_viewers:l,brokerThresholds:m,lifecycle:h,completion_bell:q,working_gerunds:g,whip_mode:je,page_components:xe,page_surface:Re,whip_messages:Ee,whip_message_mode:Oe,mouse_mode_default:Pe,live_cycles:Ie,condensed_history:Ce,bash_tool_purpose:Te,fold_finished_tools:$e,summarize_tool_calls:Me,detailed_tool_recaps:Ne,document_port:Le,consolidate_replies:Fe,keybindings:ze,tmux_passthrough:De,modelLadders:Ke,providerOptions:Ue,...Object.keys(ne).length>0?{modelRoutes:ne}:{},...Object.keys(G.legacy).length>0?{legacyModelRoutes:G.legacy}:{},...oe!==void 0?{modelRouting:oe}:{},kinds:qe,remoteCanvas:Ge,api:Be,...b?{paths:b}:{},...p?{ledger:p}:{},...te?{store:te}:{},...v?{runtime:v}:{},spawnEnv:He}}s(U,"mergeConfig");function Bn(e){return T(e)}s(Bn,"readRawConfigAtRoot");function Hn(e){const n=y(e);return n?Bn(n):null}s(Hn,"readRawScopeConfig");function Jn(e){if(e===null||e==="")return null;try{return T(ae(e))}catch{return null}}s(Jn,"readRawProfileConfig");function Wn(e,n){return[...yn(e,n)].reverse().map(r=>({root:r,raw:T(r)}))}s(Wn,"readRawProjectScopeConfigs");function Se(e=process.cwd(),n=Ye()||null){const o=$[M];if(o)return o.launch;const t=k(),r=Hn("user"),i=Jn(n),c=Wn(e,n);let u=O(r?.kinds,ke("user",y("user"),t.kinds)),d=N(r?.modelLadders,t.modelLadders),f=D(r?.providerOptions,t.providerOptions),a=L(r?.modelRoutes),l=F(r?.modelRouting,void 0),m=z(r?.spawnEnv,t.spawnEnv?.allow);i!==null&&(u=O(i.kinds,u),d=N(i.modelLadders,d),f=D(i.providerOptions,f),a=L(i.modelRoutes,a),l=F(i.modelRouting,l),m=z(i.spawnEnv,m.allow));for(const{root:q,raw:g}of c)u=O(g?.kinds,ke("project",q,u)),g!==null&&(d=N(g.modelLadders,d),f=D(g.providerOptions,f),a=L(g.modelRoutes,a),l=F(g.modelRouting,l),m=z(g.spawnEnv,m.allow));const h=_e(a);return{kinds:u,modelLadders:d,providerOptions:f,...Object.keys(h.complete).length>0?{modelRoutes:h.complete}:{},...Object.keys(h.legacy).length>0?{legacyModelRoutes:h.legacy}:{},...l!==void 0?{modelRouting:l}:{},spawnEnv:m}}s(Se,"readMergedLaunchConfig");function To(e){return Se().kinds[e]}s(To,"resolveKindConfig");function $o(e){const n=Se().kinds,o=[];for(const[t,r]of Object.entries(n)){const i=t.indexOf("/");if(i===-1)continue;const c=t.slice(0,i),u=r.availableTo??[c];(u.includes("*")||u.includes(e))&&o.push({kind:t,whenToUse:r.whenToUse})}return o.sort((t,r)=>t.kind.localeCompare(r.kind))}s($o,"subKindsAvailableTo");function Zn(e,n,o){const t={...e??{}};t.anthropic!==void 0&&(t.anthropic={...t.anthropic}),t.openai!==void 0&&(t.openai={...t.openai}),o.defaultProvider!==n.defaultProvider&&o.defaultProvider!==void 0&&(t.defaultProvider=o.defaultProvider);for(const i of["anthropic","openai"])for(const c of["ultra","strong","medium","light"])o[i][c]!==n[i][c]&&(t[i]={...t[i]??{},[c]:o[i][c]});return t.defaultProvider!==void 0||t.anthropic!==void 0||t.openai!==void 0?t:void 0}s(Zn,"sparseModelLaddersToPersist");async function Yn(e,n){return await x(e,o=>{const t=U(o),r=U(o);n(r);const i={...o};for(const u of bn)u!=="modelLadders"&&!en(r[u],t[u])&&(i[u]=r[u]);const c=Zn(o.modelLadders,t.modelLadders,r.modelLadders);return c!==void 0?i.modelLadders=c:delete i.modelLadders,{value:r,next:i}})}s(Yn,"mutateConfigAtRoot");async function Mo(e,n){await x(e,o=>{const t=o.modelLadders??{},r={...t};n.defaultProvider!==void 0&&(r.defaultProvider=n.defaultProvider);for(const i of["anthropic","openai"])n[i]!==void 0&&(r[i]={...t[i]??{},...n[i]});return{value:void 0,next:{...o,modelLadders:r}}})}s(Mo,"persistModelLadders");async function No(e,n,o){if(o!==void 0)Cn(n,o);else if(n.trim()==="")throw new Error("model route id must be a non-empty string");await x(e,t=>{const r=he(t.modelRoutes??{});o===void 0?delete r[n]:R(r,n,{...o,models:{...o.models}});const i={...t};return Object.keys(r).length===0?delete i.modelRoutes:i.modelRoutes=r,{value:void 0,next:i}})}s(No,"persistModelRoute");async function Vn(e,n){return await Yn(e,n)}s(Vn,"updateConfigAtRoot");async function Lo(e,n){return await Vn(A(e),n)}s(Lo,"updateConfig");async function Fo(e){const n=e.orchestrator===!0?"orchestratorModel":"model";return await x(e.root,o=>{const t={...o.kinds??{},[e.kind]:{...(o.kinds??{})[e.kind],[n]:e.model}};return{value:void 0,next:{...o,kinds:t}}}),{path:_(e.root),field:n}}s(Fo,"persistDefaultKindModel");async function zo(e,n){const o=jn(e);return n(o),await En(e,o),o}s(zo,"updateState");export{xn as InvalidRawSettingsError,Mn as binDeclarationIssues,wo as brokerConfigSnapshot,_o as configPath,Ro as ensureScopeInitialized,Ln as humanActionDeclarationIssues,vo as installBrokerConfigSnapshot,Eo as invalidPluginBinReasons,Co as invalidPluginKindsReasons,Po as invalidPluginRequiresReasons,Nn as normalizeBin,Fn as normalizeHumanActions,Oo as normalizeRequires,In as normalizeTmuxPassthrough,Fo as persistDefaultKindModel,Mo as persistModelLadders,No as persistModelRoute,kn as readConfig,An as readConfigAtRoot,Se as readMergedLaunchConfig,Bn as readRawConfigAtRoot,Hn as readRawScopeConfig,ko as readRawSettingsForTarget,jn as readState,Ao as replaceRawSettingsForTarget,To as resolveKindConfig,Io as resolvePageComponents,bo as statePath,$o as subKindsAvailableTo,Lo as updateConfig,Vn as updateConfigAtRoot,So as updateRawConfigAtomically,zo as updateState,jo as writeConfig,xo as writeRawConfig,En as writeState};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var E=Object.defineProperty;var s=(e,t)=>E(e,"name",{value:t,configurable:!0});import{parentPort as M,workerData as N}from"node:worker_threads";import{request as v}from"node:http";import{request as $}from"node:https";const{address:l,token:b}=N,r=[],m=new Set;let w=!1,d=0,c=500,y;const I=Number(process.env.CRTR_CONVERSATION_COMMIT_DEADLINE_MS??15*6e4),k=process.env.CRTR_NODE_DEADLINE_AT?Date.parse(process.env.CRTR_NODE_DEADLINE_AT):1/0,O=s(()=>Math.max(1e3,Math.min(6e4,k-Date.now())),"requestTimeoutMs");function P(e){return new Promise(t=>setTimeout(t,e))}s(P,"wait");function _(e){return new Promise(t=>{const i=`/v1${e.path}`,n=l.startsWith("http")?new URL(l.replace(/\/$/,"")+i):null,u=e.data===void 0?void 0:JSON.stringify(e.data);let g=!1;const f=s(o=>{g||(g=!0,t(o))},"finish"),T=s(o=>{const D=[];o.on("data",h=>D.push(h)),o.on("aborted",()=>f({error:"conversation store response ended before completion"})),o.on("error",h=>f({error:h.message})),o.on("end",()=>f({status:o.statusCode,body:Buffer.concat(D).toString("utf8"),path:o.headers["x-conversation-path"],tail:o.headers["x-conversation-tail"]}))},"onResponse"),a=n?(n.protocol==="https:"?$:v)(n,{method:e.method},T):v({socketPath:l,path:i,method:e.method},T);a.on("error",o=>f({error:o.message})),a.setTimeout(O(),()=>{f({error:"conversation store request timed out"}),a.destroy()}),e.reply?.on("message",o=>{o==="cancel"&&a.destroy()}),b&&a.setHeader("authorization",`Bearer ${b}`),u!==void 0?(a.setHeader("content-type","application/json"),a.end(u)):a.end()})}s(_,"send");function p(e,t){e.reply?.postMessage(t),e.signal&&(Atomics.store(new Int32Array(e.signal),0,1),Atomics.notify(new Int32Array(e.signal),0)),e.reply?.close()}s(p,"answer");function q(e){y=e;for(const t of r.splice(0))t.kind!=="append"&&p(t,{error:`conversation_write_failed: ${e}`});d=0,c=500}s(q,"giveUp");const A=s(e=>!!e.error||!e.status||e.status>=400,"failed");async function R(e){if(d||(d=Date.now()),Date.now()-d>=I||Date.now()>=k){q(e);return}await P(c),c=Math.min(c*2,3e4)}s(R,"backoff");async function S(){if(!w){w=!0;try{for(;r.length;){const e=r[0];if(e.kind==="append"){const t=[];for(;r[t.length]?.kind==="append"&&r[t.length]?.path===e.path;)t.push(r[t.length]);const i=t.flatMap(u=>u.data.entries),n=await _({method:"POST",path:e.path,data:{entries:i}});if(A(n)){await R(n.error??n.body??`HTTP ${n.status}`);continue}d=0,c=500,m.add(e.path.replace(/\/entries$/,"")),r.splice(0,t.length);continue}if(e.kind==="flush"){if(y){p(e,{error:`conversation_write_failed: ${y}`}),r.shift();continue}let t;for(const i of m){const n=await _({method:"POST",path:`${i}/commit`});if(A(n)){t=n.error??n.body??`HTTP ${n.status}`;break}m.delete(i)}if(t){await R(t);continue}d=0,c=500,p(e,{status:200}),r.shift();continue}p(e,await _(e)),r.shift()}}finally{w=!1}}}s(S,"drain"),M?.on("message",e=>{r.push(e),S()});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
2
|
-
`).map(
|
|
1
|
+
var P=Object.defineProperty;var s=(l,f)=>P(l,"name",{value:f,configurable:!0});import{MessageChannel as p,Worker as S,receiveMessageOnPort as O}from"node:worker_threads";import{ConversationNotFoundError as b}from"./index.js";function A(l,f){const i=new S(new URL(import.meta.url.endsWith(".ts")?"./client-worker.ts":"./client-worker.js",import.meta.url),{workerData:{address:l,token:f}});i.unref();let n;i.on("error",e=>{n=e}),i.on("exit",e=>{n=new Error(`conversation store worker exited with ${e}`)});function m(e,r,t){if(!t)throw new Error("conversation store worker returned no reply");if(t.error)throw new Error(t.error);if(t.status===404)throw new b(r.split("/")[2]??r);if(!t.status||t.status>=400)throw new Error(`conversation store ${e} ${r} failed (${t.status}): ${t.body}`);return{body:t.body??"",...t.path?{path:t.path}:{},...t.tail?{tail:Number(t.tail)}:{}}}s(m,"settle");function c(e,r,t){if(n)throw n;const o=new SharedArrayBuffer(4),{port1:a,port2:d}=new p;try{if(i.postMessage({method:e,path:r,data:t,signal:o,reply:d},[d]),Atomics.wait(new Int32Array(o),0,0,3e4)==="timed-out")throw a.postMessage("cancel"),new Error(`conversation store request timed out: ${e} ${r}`);return m(e,r,O(a)?.message)}finally{a.close()}}s(c,"call");function E(e,r){if(n)return Promise.reject(n);const{port1:t,port2:o}=new p;return new Promise((a,d)=>{const w=setTimeout(()=>{t.postMessage("cancel"),t.close(),d(new Error(`conversation store request timed out: ${e} ${r}`))},3e4);w.unref(),t.once("message",g=>{clearTimeout(w),t.close();try{a(m(e,r,g))}catch(k){d(k)}}),i.postMessage({method:e,path:r,reply:o},[o])})}s(E,"callAsync");const u=s(e=>`/conversations/${encodeURIComponent(e)}`,"url");function v(e,r){if(n)throw n;i.postMessage({kind:"append",method:"POST",path:`${u(e)}/entries`,data:{entries:r}})}s(v,"enqueueAppend");function T(){if(n)return Promise.reject(n);const{port1:e,port2:r}=new p;return new Promise((t,o)=>{e.once("message",a=>{e.close();try{m("POST","/commit",a),t()}catch(d){o(d)}}),i.postMessage({kind:"flush",method:"POST",path:"/commit",reply:r},[r])})}s(T,"flush");const h=s(e=>{const[r,...t]=e.body.trimEnd().split(`
|
|
2
|
+
`).map(a=>JSON.parse(a)),o=t;return e.tail===void 0?{header:r,entries:o,path:e.path??""}:{header:r,entries:o.slice(0,e.tail-1),tail:o.slice(e.tail-1),path:e.path??""}},"parseRead"),$=s((e,r)=>r?`${u(e)}?head=${r.head}&tail=${r.tail}`:u(e),"readPath");return{create(e,r,t,o){return JSON.parse(c("POST","/conversations",{node_id:e,header:r,entries:t,path:o}).body).conversation_id},append(e,r){v(e,r)},flush:T,replace(e,r,t){c("PUT",u(e),{header:r,entries:t})},read(e,r){return h(c("GET",$(e,r)))},async readAsync(e,r){return h(await E("GET",$(e,r)))},header(e){return JSON.parse(c("GET",`${u(e)}/header`).body)},fork(e,r,t,o){return JSON.parse(c("POST",`${u(e)}/fork`,{node_id:r,leaf_id:t,cwd:o}).body).conversation_id},list(e){const r=e===void 0?"":`?node_id=${encodeURIComponent(e)}`;return JSON.parse(c("GET",`/conversations${r}`).body).conversations},delete(e){c("DELETE",u(e))}}}s(A,"createStoreClient");export{A as createStoreClient};
|
|
@@ -23,12 +23,10 @@ export interface ConversationWindow {
|
|
|
23
23
|
* `ConversationStore` so a change to the daemon's store never changes pi's contract. */
|
|
24
24
|
export interface ConversationStoreClient {
|
|
25
25
|
create(nodeId: string, header: SessionHeader, entries: SessionEntry[], path?: string): string;
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
dedupe?: boolean;
|
|
31
|
-
}): void;
|
|
26
|
+
/** Enqueue entries in order without blocking the broker's event loop. */
|
|
27
|
+
append(id: string, entries: SessionEntry[]): void;
|
|
28
|
+
/** Wait for pending appends and seal each dirty conversation. */
|
|
29
|
+
flush(): Promise<void>;
|
|
32
30
|
replace(id: string, header: SessionHeader, entries: SessionEntry[]): void;
|
|
33
31
|
/** Given a window and a file larger than head + tail bytes, `entries` holds the entries wholly
|
|
34
32
|
* inside the first `head` bytes and `tail` those wholly inside the last `tail` bytes.
|
|
@@ -55,9 +53,7 @@ export interface ConversationStoreClient {
|
|
|
55
53
|
/** The daemon's file store (`createFileStore`, installed by `sessions.ts`). */
|
|
56
54
|
export interface ConversationStore {
|
|
57
55
|
create(nodeId: string, header: SessionHeader, entries: SessionEntry[], path?: string): Promise<string>;
|
|
58
|
-
append(id: string, entries: SessionEntry[]
|
|
59
|
-
dedupe?: boolean;
|
|
60
|
-
}): Promise<void>;
|
|
56
|
+
append(id: string, entries: SessionEntry[]): Promise<void>;
|
|
61
57
|
replace(id: string, header: SessionHeader, entries: SessionEntry[]): Promise<void>;
|
|
62
58
|
read(id: string, window?: ConversationWindow): Promise<{
|
|
63
59
|
header: SessionHeader;
|
|
@@ -84,15 +80,17 @@ export interface ConversationStore {
|
|
|
84
80
|
}
|
|
85
81
|
export declare function conversationIdFromPath(path: string): string | null;
|
|
86
82
|
export declare function defaultConversationRoot(): string;
|
|
87
|
-
|
|
83
|
+
/** Where the client reaches the daemon's /v1 API: `CRTR_API_URL` (an http(s) URL) or the API socket path. */
|
|
84
|
+
export declare function conversationApiAddress(): string;
|
|
88
85
|
export declare function installConversationStore(store: ConversationStore | undefined): void;
|
|
89
86
|
/** The installed store, else the client over the store socket with each call awaited. */
|
|
90
87
|
export declare function conversationStore(): ConversationStore;
|
|
91
88
|
/** The synchronous store pi's `SessionManager` statics call: always the client over the store socket (the installed
|
|
92
89
|
* store is async, so it cannot serve a synchronous caller). */
|
|
93
90
|
export declare function conversationClient(): ConversationStoreClient;
|
|
91
|
+
/** The broker settles mail only after its queued entries and part object are durable. */
|
|
92
|
+
export declare function flushConversation(): Promise<void>;
|
|
94
93
|
/** Read a conversation without parking the event loop on the store worker. */
|
|
95
94
|
export declare function readConversationAsync(id: string, window?: ConversationWindow): Promise<Awaited<ReturnType<ConversationStore['read']>>>;
|
|
96
|
-
export { createFileStore, sessionDirectory, type AppendSection, type ConversationCanvas, type ConversationWrite } from './file-store.js';
|
|
97
95
|
export { installSessionManagerStorePatch } from './patch.js';
|
|
98
96
|
export { findOrphanedParents, relinkOrphanedParents, repairConversationFile, type FileRepair, type OrphanRelink } from './repair.js';
|