@north-light/cli 0.3.561 → 0.3.563
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.d.ts +27 -4
- package/dist/api/client.js +3 -3
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/bash-jobs.d.ts +5 -1
- package/dist/api/dto/broker-ops.d.ts +25 -1
- package/dist/api/dto/charges.d.ts +9 -2
- package/dist/api/dto/delivery.d.ts +26 -2
- package/dist/api/dto/execution-start.d.ts +57 -0
- package/dist/api/dto/execution-start.js +0 -0
- package/dist/api/dto/modelauth.d.ts +5 -0
- package/dist/api/dto/node-records.d.ts +16 -0
- package/dist/api/dto/objects.d.ts +1 -1
- package/dist/api/dto/reports.d.ts +0 -3
- package/dist/api/dto/run-events.d.ts +7 -1
- package/dist/api/dto/settings.d.ts +55 -0
- package/dist/api/dto/settings.js +0 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +1 -1
- package/dist/api/routes.d.ts +11 -0
- package/dist/api/routes.js +1 -1
- package/dist/build-root.d.ts +1 -0
- package/dist/build-root.js +1 -1
- package/dist/builtin-memory/crouter-sdk/release-notes.md +4 -0
- package/dist/cli.js +7 -7
- package/dist/clients/attach/chrome/bash-jobs.d.ts +11 -1
- package/dist/clients/attach/chrome/bash-jobs.js +1 -1
- package/dist/clients/attach/chrome/canvas-panels.d.ts +1 -1
- package/dist/clients/attach/chrome/roster.js +6 -4
- package/dist/clients/attach/overlays/auth.js +2 -2
- package/dist/clients/attach/render/chat-view.js +1 -1
- package/dist/clients/attach/viewer.js +550 -567
- package/dist/commands/canvas-config.js +2 -2
- package/dist/commands/canvas-use.js +1 -1
- package/dist/commands/human.js +2 -2
- package/dist/commands/node/bash.js +3 -3
- package/dist/commands/node/create.js +2 -2
- package/dist/commands/person-settings.d.ts +1 -0
- package/dist/commands/person-settings.js +1 -0
- package/dist/commands/pkg/market-manage.d.ts +2 -2
- package/dist/commands/pkg/market-manage.js +1 -1
- package/dist/commands/pkg/plugin-manage.js +13 -13
- package/dist/commands/pkg/shared.js +1 -1
- package/dist/commands/profile/default.js +1 -1
- package/dist/commands/push.js +2 -3
- package/dist/commands/sys/config.js +1 -1
- package/dist/commands/sys/connect.js +1 -1
- package/dist/commands/sys/context/sysprompt.js +2 -2
- package/dist/commands/sys/doctor.js +1 -1
- package/dist/commands/sys/join.js +1 -1
- package/dist/commands/sys/panels/broker-limits-panel.js +1 -1
- package/dist/commands/sys/panels/keybindings-panel.js +1 -1
- package/dist/commands/sys/panels/models-panel.d.ts +8 -2
- package/dist/commands/sys/panels/models-panel.js +1 -1
- package/dist/commands/sys/panels/prefs-panel.d.ts +1 -0
- package/dist/commands/sys/panels/prefs-panel.js +1 -1
- package/dist/commands/sys/panels/profiles-panel.js +1 -1
- package/dist/commands/sys/panels/provider-panel.d.ts +4 -0
- package/dist/commands/sys/panels/provider-panel.js +1 -1
- package/dist/commands/sys/provider-login.js +5 -5
- package/dist/commands/sys/setup-core.js +3 -3
- package/dist/commands/sys/setup-settings-runner.js +1 -1
- package/dist/commands/sys/spend.js +3 -3
- package/dist/commands/sys/update.js +1 -1
- package/dist/core/auth-file.d.ts +11 -19
- package/dist/core/auth-file.js +1 -2
- package/dist/core/auto-update.d.ts +1 -1
- package/dist/core/auto-update.js +4 -4
- package/dist/core/bash-jobs.d.ts +29 -71
- package/dist/core/bash-jobs.js +9 -10
- package/dist/core/blobs/directory.d.ts +3 -0
- package/dist/core/blobs/directory.js +1 -0
- package/dist/core/blobs/fault.d.ts +3 -0
- package/dist/core/blobs/fault.js +1 -0
- package/dist/core/blobs/index.d.ts +21 -0
- package/dist/core/blobs/index.js +1 -0
- package/dist/core/blobs/r2.d.ts +9 -0
- package/dist/core/blobs/r2.js +4 -0
- package/dist/core/bootstrap.d.ts +1 -1
- package/dist/core/bootstrap.js +2 -2
- package/dist/core/canvas/canvas.d.ts +9 -7
- package/dist/core/canvas/canvas.js +8 -8
- package/dist/core/canvas/crons.d.ts +3 -2
- package/dist/core/canvas/crons.js +3 -3
- package/dist/core/canvas/daemon-owner.d.ts +5 -0
- package/dist/core/canvas/daemon-owner.js +1 -1
- package/dist/core/canvas/db.d.ts +10 -9
- package/dist/core/canvas/db.js +4 -4
- package/dist/core/canvas/executions.d.ts +100 -4
- package/dist/core/canvas/executions.js +1 -1
- package/dist/core/canvas/export-sqlite.js +1 -1
- package/dist/core/canvas/focuses.d.ts +4 -0
- package/dist/core/canvas/focuses.js +1 -1
- package/dist/core/canvas/history.js +9 -9
- package/dist/core/canvas/managed-worktree-sweep-candidates.d.ts +2 -1
- package/dist/core/canvas/managed-worktree-sweep-candidates.js +3 -2
- package/dist/core/canvas/node-tokens.d.ts +1 -4
- package/dist/core/canvas/node-tokens.js +3 -3
- package/dist/core/canvas/paths.d.ts +0 -1
- package/dist/core/canvas/paths.js +1 -1
- package/dist/core/canvas/person-state.d.ts +26 -0
- package/dist/core/canvas/person-state.js +1 -0
- package/dist/core/canvas/person.d.ts +3 -10
- package/dist/core/canvas/person.js +7 -7
- package/dist/core/canvas/reconciler-leases.d.ts +12 -0
- package/dist/core/canvas/reconciler-leases.js +8 -0
- package/dist/core/canvas/recovery.d.ts +4 -0
- package/dist/core/canvas/recovery.js +1 -1
- package/dist/core/canvas/schema-pg/003-fleet-removals.sql +1 -1
- package/dist/core/canvas/schema-pg/005-fleet-blobs.sql +13 -0
- package/dist/core/canvas/schema-pg/006-job-rows.sql +20 -0
- package/dist/core/canvas/schema-pg/007-ledger-check.sql +117 -0
- package/dist/core/canvas/schema-version.d.ts +1 -1
- package/dist/core/canvas/schema-version.js +1 -1
- package/dist/core/canvas/sessions.d.ts +8 -11
- package/dist/core/canvas/sessions.js +1 -4
- package/dist/core/canvas/tree.d.ts +4 -2
- package/dist/core/canvas/tree.js +6 -6
- package/dist/core/canvas/types.d.ts +7 -0
- package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
- package/dist/core/command-plugins/bundle.d.ts +1 -1
- package/dist/core/command-plugins/bundle.js +1 -1
- package/dist/core/command-plugins/compose.d.ts +1 -1
- package/dist/core/command-plugins/discovery.d.ts +0 -1
- package/dist/core/command-plugins/discovery.js +1 -1
- package/dist/core/command-plugins/help-addenda.js +1 -1
- package/dist/core/command-plugins/presence.d.ts +2 -0
- package/dist/core/command-plugins/presence.js +1 -1
- package/dist/core/config.d.ts +16 -15
- package/dist/core/config.js +1 -1
- package/dist/core/conversation-store/client-worker.js +1 -1
- package/dist/core/conversation-store/client.js +2 -2
- package/dist/core/conversation-store/index.d.ts +9 -11
- package/dist/core/conversation-store/index.js +1 -1
- package/dist/core/conversation-store/patch.js +1 -1
- package/dist/core/conversation-store/row-store.d.ts +14 -0
- package/dist/core/conversation-store/row-store.js +13 -0
- package/dist/core/directory/join.d.ts +5 -3
- package/dist/core/directory/join.js +1 -1
- package/dist/core/env-name.d.ts +1 -0
- package/dist/core/env-name.js +1 -1
- package/dist/core/environment-recipe.d.ts +15 -0
- package/dist/core/environment-recipe.js +1 -0
- package/dist/core/environments.js +1 -1
- package/dist/core/events/emit.js +2 -2
- package/dist/core/events/run-event-chunks.d.ts +25 -0
- package/dist/core/events/run-event-chunks.js +5 -0
- package/dist/core/feed/messages.js +5 -5
- package/dist/core/grants/mirror.d.ts +15 -0
- package/dist/core/grants/mirror.js +15 -3
- package/dist/core/grants/on-sync.d.ts +9 -5
- package/dist/core/grants/on-sync.js +1 -1
- package/dist/core/grants/remove.d.ts +1 -6
- package/dist/core/grants/remove.js +1 -1
- package/dist/core/grants/sync.js +1 -1
- package/dist/core/grants/watch.d.ts +15 -9
- package/dist/core/grants/watch.js +1 -1
- package/dist/core/graph/custom.js +8 -8
- package/dist/core/graph/jobs.d.ts +83 -5
- package/dist/core/graph/jobs.js +11 -2
- package/dist/core/graph/kinds/job.js +2 -2
- package/dist/core/graph/names.js +7 -7
- package/dist/core/graph/objects.d.ts +5 -1
- package/dist/core/graph/objects.js +11 -11
- package/dist/core/graph/reader.d.ts +3 -0
- package/dist/core/graph/reader.js +3 -3
- package/dist/core/graph/repo-sync/identity.d.ts +3 -1
- package/dist/core/graph/repo-sync/identity.js +1 -1
- package/dist/core/graph/repo-sync/repos.d.ts +1 -1
- package/dist/core/graph/repo-sync/repos.js +2 -2
- package/dist/core/graph/repo-sync/sync.js +2 -2
- package/dist/core/installed-plugins.js +1 -1
- package/dist/core/keybindings/persistence.d.ts +1 -1
- package/dist/core/keybindings/persistence.js +1 -1
- package/dist/core/layout-migrate/loose-keys.d.ts +1 -1
- package/dist/core/layout-migrate/loose-keys.js +1 -1
- package/dist/core/ledger/account.d.ts +12 -0
- package/dist/core/ledger/account.js +2 -0
- package/dist/core/ledger/charges.d.ts +2 -2
- package/dist/core/ledger/charges.js +1 -1
- package/dist/core/ledger/check.d.ts +5 -1
- package/dist/core/ledger/check.js +1 -7
- package/dist/core/ledger/chunks.d.ts +8 -0
- package/dist/core/ledger/chunks.js +2 -0
- package/dist/core/ledger/index.d.ts +2 -1
- package/dist/core/ledger/index.js +1 -1
- package/dist/core/ledger/infra-allowance.d.ts +9 -0
- package/dist/core/ledger/infra-allowance.js +1 -0
- package/dist/core/ledger/limits.js +3 -3
- package/dist/core/ledger/payer.d.ts +1 -1
- package/dist/core/ledger/payer.js +1 -1
- package/dist/core/ledger/read.d.ts +14 -4
- package/dist/core/ledger/read.js +2 -3
- package/dist/core/ledger/totals.d.ts +5 -16
- package/dist/core/ledger/totals.js +4 -4
- package/dist/core/ledger/types.d.ts +12 -3
- package/dist/core/llm/run.js +2 -2
- package/dist/core/managed-providers.d.ts +72 -0
- package/dist/core/managed-providers.js +1 -0
- package/dist/core/model-auth/api-credential-store.d.ts +10 -0
- package/dist/core/model-auth/api-credential-store.js +1 -0
- package/dist/core/model-auth/daemon-login.d.ts +1 -1
- package/dist/core/model-auth/daemon-login.js +1 -1
- package/dist/core/model-auth/flows.d.ts +5 -4
- package/dist/core/model-auth/flows.js +1 -1
- package/dist/core/model-auth/handoff-jti.d.ts +3 -4
- package/dist/core/model-auth/handoff-jti.js +1 -1
- package/dist/core/model-auth/readiness.js +1 -1
- package/dist/core/model-config.d.ts +1 -1
- package/dist/core/model-config.js +1 -1
- package/dist/core/model-routes-pool.d.ts +14 -0
- package/dist/core/model-routes-pool.js +1 -0
- package/dist/core/model-routes.d.ts +11 -16
- package/dist/core/model-routes.js +1 -1
- package/dist/core/peer/ingest.d.ts +2 -0
- package/dist/core/peer/ingest.js +1 -1
- package/dist/core/peer/stubs.d.ts +8 -0
- package/dist/core/peer/stubs.js +1 -1
- package/dist/core/permissions/evaluator.d.ts +7 -2
- package/dist/core/permissions/evaluator.js +2 -2
- package/dist/core/plugin-env.js +1 -1
- package/dist/core/pool-credential-store.d.ts +2 -5
- package/dist/core/pool-credential-store.js +1 -1
- package/dist/core/profiles/app-env-store.d.ts +5 -5
- package/dist/core/profiles/app-env-store.js +1 -2
- package/dist/core/profiles/default-binding.d.ts +5 -5
- package/dist/core/profiles/default-binding.js +1 -1
- package/dist/core/profiles/env-store.d.ts +10 -21
- package/dist/core/profiles/env-store.js +1 -2
- package/dist/core/profiles/manifest.d.ts +14 -18
- package/dist/core/profiles/manifest.js +1 -1
- package/dist/core/profiles/relocate.js +1 -1
- package/dist/core/profiles/select.js +21 -21
- package/dist/core/provider-credential.d.ts +1 -1
- package/dist/core/provider-credential.js +1 -1
- package/dist/core/provider-management.d.ts +3 -4
- package/dist/core/provider-management.js +1 -1
- package/dist/core/providers/bundles.js +2 -2
- package/dist/core/providers/call.d.ts +3 -34
- package/dist/core/providers/description.d.ts +34 -0
- package/dist/core/providers/description.js +0 -0
- package/dist/core/providers/token-cache.d.ts +14 -14
- package/dist/core/providers/token-cache.js +1 -1
- package/dist/core/review/companion.js +1 -1
- package/dist/core/runs/activity.d.ts +1 -1
- package/dist/core/runs/activity.js +1 -1
- package/dist/core/runs/events.d.ts +7 -5
- package/dist/core/runs/events.js +2 -6
- package/dist/core/runs/operations.d.ts +1 -1
- package/dist/core/runs/operations.js +6 -6
- package/dist/core/runtime/bearings.js +1 -1
- package/dist/core/runtime/broker/attachments-fetch.d.ts +5 -0
- package/dist/core/runtime/broker/attachments-fetch.js +1 -0
- package/dist/core/runtime/broker/bash-job-launch.d.ts +4 -2
- package/dist/core/runtime/broker/bash-job-launch.js +1 -1
- package/dist/core/runtime/broker/boot-state.d.ts +9 -0
- package/dist/core/runtime/broker/boot-state.js +1 -0
- package/dist/core/runtime/broker/cli-relay.d.ts +2 -1
- package/dist/core/runtime/broker/cli-relay.js +1 -1
- package/dist/core/runtime/broker/client-registry.d.ts +3 -3
- package/dist/core/runtime/broker/daemon-ops.d.ts +10 -1
- package/dist/core/runtime/broker/daemon-ops.js +1 -1
- package/dist/core/runtime/broker/fault-retry.d.ts +2 -0
- package/dist/core/runtime/broker/fault-retry.js +1 -1
- package/dist/core/runtime/broker/frame-engine-control.js +1 -1
- package/dist/core/runtime/broker/held-deferred-inbox.d.ts +3 -0
- package/dist/core/runtime/broker/held-deferred-inbox.js +1 -1
- package/dist/core/runtime/broker/job-reporter.d.ts +18 -0
- package/dist/core/runtime/broker/job-reporter.js +2 -0
- package/dist/core/runtime/broker/model-adapter.d.ts +3 -0
- package/dist/core/runtime/broker/model-adapter.js +3 -2
- package/dist/core/runtime/broker/signal-stream.js +1 -1
- package/dist/core/runtime/broker/spilled-body.d.ts +5 -0
- package/dist/core/runtime/broker/spilled-body.js +1 -0
- package/dist/core/runtime/broker/summaries-post.d.ts +5 -0
- package/dist/core/runtime/broker/summaries-post.js +1 -0
- package/dist/core/runtime/broker/tool-groups.d.ts +3 -0
- package/dist/core/runtime/broker/tool-groups.js +1 -1
- package/dist/core/runtime/broker/turn-replies.d.ts +1 -0
- package/dist/core/runtime/broker/turn-replies.js +1 -1
- package/dist/core/runtime/broker-persona-guidance.js +2 -2
- package/dist/core/runtime/broker.js +1 -1
- package/dist/core/runtime/deliver-live.js +1 -1
- package/dist/core/runtime/first-boot-rows.d.ts +8 -0
- package/dist/core/runtime/first-boot-rows.js +2 -0
- package/dist/core/runtime/fleet.d.ts +13 -12
- package/dist/core/runtime/front-door-login.js +1 -1
- package/dist/core/runtime/front-door.js +6 -6
- package/dist/core/runtime/headless-pi.js +1 -1
- package/dist/core/runtime/host.d.ts +14 -3
- package/dist/core/runtime/host.js +3 -3
- package/dist/core/runtime/invocation.d.ts +6 -0
- package/dist/core/runtime/kickoff.d.ts +2 -14
- package/dist/core/runtime/kickoff.js +17 -19
- package/dist/core/runtime/launch-config-worker.js +1 -1
- package/dist/core/runtime/launch.js +2 -2
- package/dist/core/runtime/model-registry.js +1 -1
- package/dist/core/runtime/node-read.d.ts +4 -6
- package/dist/core/runtime/node-read.js +3 -3
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/core/runtime/outcome-document.d.ts +0 -1
- package/dist/core/runtime/outcome-document.js +1 -1
- package/dist/core/runtime/output-result.d.ts +15 -0
- package/dist/core/runtime/output-result.js +5 -0
- package/dist/core/runtime/placement.d.ts +17 -1
- package/dist/core/runtime/placement.js +1 -1
- package/dist/core/runtime/provider-credential-gate.d.ts +6 -2
- package/dist/core/runtime/provider-credential-gate.js +2 -2
- package/dist/core/runtime/recovery-hold.d.ts +21 -2
- package/dist/core/runtime/recovery-hold.js +2 -1
- package/dist/core/runtime/recycle.js +1 -1
- package/dist/core/runtime/reset.js +1 -1
- package/dist/core/runtime/revive.d.ts +2 -2
- package/dist/core/runtime/revive.js +2 -2
- package/dist/core/runtime/runner/blaxel/client.d.ts +81 -0
- package/dist/core/runtime/runner/blaxel/client.js +1 -0
- package/dist/core/runtime/runner/blaxel/image-build.d.ts +74 -0
- package/dist/core/runtime/runner/blaxel/image-build.js +5 -0
- package/dist/core/runtime/runner/blaxel/runner.d.ts +41 -0
- package/dist/core/runtime/runner/blaxel/runner.js +3 -0
- package/dist/core/runtime/runner/index.d.ts +8 -0
- package/dist/core/runtime/runner/index.js +1 -0
- package/dist/core/runtime/runner/process.d.ts +11 -0
- package/dist/core/runtime/runner/process.js +1 -0
- package/dist/core/runtime/runner/types.d.ts +95 -0
- package/dist/core/runtime/runner/types.js +0 -0
- package/dist/core/runtime/situational-context.d.ts +3 -6
- package/dist/core/runtime/situational-context.js +2 -2
- package/dist/core/runtime/situational-live.js +1 -1
- package/dist/core/runtime/spawn-env-rows.d.ts +5 -0
- package/dist/core/runtime/spawn-env-rows.js +1 -0
- package/dist/core/runtime/spawn-env.d.ts +4 -18
- package/dist/core/runtime/spawn-env.js +1 -1
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/core/runtime/stop-guard.d.ts +1 -1
- package/dist/core/runtime/stop-guard.js +2 -8
- package/dist/core/runtime/structured-output.d.ts +0 -67
- package/dist/core/runtime/structured-output.js +3 -8
- package/dist/core/runtime/tmux-driver.d.ts +8 -0
- package/dist/core/runtime/tmux-driver.js +6 -6
- package/dist/core/runtime/view-socket.d.ts +20 -0
- package/dist/core/runtime/view-socket.js +3 -1
- package/dist/core/runtime/warm-pool.d.ts +13 -1
- package/dist/core/runtime/warm-pool.js +1 -1
- package/dist/core/scoped-state/legacy-profiles.d.ts +11 -0
- package/dist/core/scoped-state/legacy-profiles.js +1 -0
- package/dist/core/scoped-state/materialized-plugins.d.ts +18 -0
- package/dist/core/scoped-state/materialized-plugins.js +1 -0
- package/dist/core/scoped-state/migrate.d.ts +8 -1
- package/dist/core/scoped-state/migrate.js +3 -3
- package/dist/core/scoped-state/person-rows.d.ts +10 -0
- package/dist/core/scoped-state/person-rows.js +6 -0
- package/dist/core/scoped-state/person-store.d.ts +72 -0
- package/dist/core/scoped-state/person-store.js +1 -0
- package/dist/core/secrets/blaxel-launch.d.ts +24 -0
- package/dist/core/secrets/blaxel-launch.js +4 -0
- package/dist/core/secrets/blaxel-register.d.ts +2 -0
- package/dist/core/secrets/blaxel-register.js +1 -0
- package/dist/core/secrets/env-rows.d.ts +17 -0
- package/dist/core/secrets/env-rows.js +4 -0
- package/dist/core/secrets/environment-owner.d.ts +8 -0
- package/dist/core/secrets/environment-owner.js +1 -0
- package/dist/core/secrets/environment-secrets.d.ts +14 -0
- package/dist/core/secrets/environment-secrets.js +1 -0
- package/dist/core/secrets/index.d.ts +2 -0
- package/dist/core/secrets/index.js +1 -0
- package/dist/core/secrets/key.d.ts +3 -0
- package/dist/core/secrets/key.js +2 -0
- package/dist/core/secrets/seal.d.ts +18 -0
- package/dist/core/secrets/seal.js +1 -0
- package/dist/core/spaces/mounts.d.ts +1 -1
- package/dist/core/spaces/mounts.js +1 -1
- package/dist/core/spaces/process.d.ts +1 -1
- package/dist/core/spaces/stop.d.ts +7 -5
- package/dist/core/spaces/stop.js +2 -2
- package/dist/core/spaces/users.d.ts +2 -1
- package/dist/core/spaces/users.js +1 -1
- package/dist/core/storage/attachments.d.ts +11 -8
- package/dist/core/storage/attachments.js +1 -1
- package/dist/core/storage/tables.d.ts +4 -0
- package/dist/core/storage/tables.js +3 -3
- package/dist/core/subscription-state.d.ts +34 -72
- package/dist/core/subscription-state.js +1 -4
- package/dist/core/substrate/delivery/plan.js +1 -1
- package/dist/core/user-settings.js +1 -1
- package/dist/daemon/api/app-listener.js +10 -10
- package/dist/daemon/api/auth/person-bearer.d.ts +14 -0
- package/dist/daemon/api/auth/person-bearer.js +1 -0
- package/dist/daemon/api/bridge.js +4 -4
- package/dist/daemon/api/document-listener.js +3 -3
- package/dist/daemon/api/environment-of.d.ts +18 -0
- package/dist/daemon/api/environment-of.js +5 -0
- package/dist/daemon/api/handlers/analytics.js +1 -1
- package/dist/daemon/api/handlers/app-profiles.d.ts +2 -2
- package/dist/daemon/api/handlers/app-profiles.js +1 -1
- package/dist/daemon/api/handlers/bash-jobs.js +1 -1
- package/dist/daemon/api/handlers/bash.js +1 -1
- package/dist/daemon/api/handlers/broker-ops.d.ts +3 -0
- package/dist/daemon/api/handlers/broker-ops.js +1 -1
- package/dist/daemon/api/handlers/broker-recovery.js +1 -1
- package/dist/daemon/api/handlers/broker-signals.d.ts +0 -3
- package/dist/daemon/api/handlers/broker-signals.js +2 -2
- package/dist/daemon/api/handlers/canvas.js +4 -4
- package/dist/daemon/api/handlers/charges.d.ts +1 -1
- package/dist/daemon/api/handlers/charges.js +1 -1
- package/dist/daemon/api/handlers/conversations.d.ts +2 -0
- package/dist/daemon/api/handlers/conversations.js +3 -0
- package/dist/daemon/api/handlers/crons.js +1 -1
- package/dist/daemon/api/handlers/daemon.js +1 -1
- package/dist/daemon/api/handlers/delivery.d.ts +1 -1
- package/dist/daemon/api/handlers/delivery.js +1 -1
- package/dist/daemon/api/handlers/docs.js +1 -1
- package/dist/daemon/api/handlers/exec.js +1 -1
- package/dist/daemon/api/handlers/execution-start.d.ts +2 -0
- package/dist/daemon/api/handlers/execution-start.js +2 -0
- package/dist/daemon/api/handlers/files.js +1 -1
- package/dist/daemon/api/handlers/git-credential.d.ts +11 -0
- package/dist/daemon/api/handlers/git-credential.js +1 -0
- package/dist/daemon/api/handlers/hook-exec.d.ts +1 -1
- package/dist/daemon/api/handlers/hook-exec.js +1 -1
- package/dist/daemon/api/handlers/human-requests.js +1 -1
- package/dist/daemon/api/handlers/inbox.js +1 -1
- package/dist/daemon/api/handlers/messages.js +1 -1
- package/dist/daemon/api/handlers/model-config.js +1 -1
- package/dist/daemon/api/handlers/modelauth.d.ts +1 -1
- package/dist/daemon/api/handlers/modelauth.js +1 -1
- package/dist/daemon/api/handlers/node-events.d.ts +6 -0
- package/dist/daemon/api/handlers/node-events.js +3 -3
- package/dist/daemon/api/handlers/node-outcomes.js +1 -1
- package/dist/daemon/api/handlers/node-records.js +3 -2
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/objects.js +3 -3
- package/dist/daemon/api/handlers/profiles.js +1 -1
- package/dist/daemon/api/handlers/providers.js +1 -1
- package/dist/daemon/api/handlers/reports.js +9 -13
- package/dist/daemon/api/handlers/reviews.js +1 -1
- package/dist/daemon/api/handlers/runs.js +1 -1
- package/dist/daemon/api/handlers/settings.d.ts +2 -0
- package/dist/daemon/api/handlers/settings.js +1 -0
- package/dist/daemon/api/handlers/structured-requests.js +1 -1
- package/dist/daemon/api/handlers/vendor-status.d.ts +1 -1
- package/dist/daemon/api/handlers/vendor-status.js +1 -1
- package/dist/daemon/api/handlers/worktree.js +1 -1
- package/dist/daemon/api/map.d.ts +2 -2
- package/dist/daemon/api/map.js +2 -2
- package/dist/daemon/api/operations.js +1 -1
- package/dist/daemon/api/reader.d.ts +8 -1
- package/dist/daemon/api/reader.js +1 -1
- package/dist/daemon/api/router.d.ts +4 -2
- package/dist/daemon/api/router.js +1 -1
- package/dist/daemon/api/server.d.ts +15 -3
- package/dist/daemon/api/server.js +1 -1
- package/dist/daemon/api/vendor-signin.d.ts +2 -1
- package/dist/daemon/api/vendor-signin.js +19 -19
- package/dist/daemon/api/viewer-presence.d.ts +20 -6
- package/dist/daemon/api/viewer-presence.js +2 -1
- package/dist/daemon/boot-settings.d.ts +3 -0
- package/dist/daemon/boot-settings.js +1 -0
- package/dist/daemon/broker-signals/bus.d.ts +48 -11
- package/dist/daemon/broker-signals/bus.js +1 -1
- package/dist/daemon/cron/armed-context.js +1 -1
- package/dist/daemon/cron/lease-recovery.js +1 -1
- package/dist/daemon/cron/live-runs.d.ts +6 -0
- package/dist/daemon/cron/live-runs.js +1 -1
- package/dist/daemon/cron/run-socket.js +1 -1
- package/dist/daemon/cron-run.js +2 -2
- package/dist/daemon/crtrd-cli.js +1 -1
- package/dist/daemon/crtrd.d.ts +10 -0
- package/dist/daemon/crtrd.js +18 -17
- package/dist/daemon/delivery/run-delivery.d.ts +1 -1
- package/dist/daemon/delivery/run-delivery.js +1 -1
- package/dist/daemon/due-sources.d.ts +1 -1
- package/dist/daemon/due-sources.js +1 -1
- package/dist/daemon/due.js +7 -6
- package/dist/daemon/fleet.d.ts +6 -6
- package/dist/daemon/fleet.js +9 -9
- package/dist/daemon/park-activity.d.ts +2 -1
- package/dist/daemon/park-activity.js +1 -1
- package/dist/daemon/park-pending.d.ts +20 -13
- package/dist/daemon/park-pending.js +3 -1
- package/dist/daemon/profile-delete.js +1 -1
- package/dist/daemon/reconcilers/bash-deadline.d.ts +15 -10
- package/dist/daemon/reconcilers/bash-deadline.js +1 -3
- package/dist/daemon/reconcilers/broker-supervision.d.ts +13 -3
- package/dist/daemon/reconcilers/broker-supervision.js +4 -4
- package/dist/daemon/reconcilers/cron-lane.d.ts +0 -1
- package/dist/daemon/reconcilers/cron-lane.js +1 -1
- package/dist/daemon/reconcilers/fault-retry-backstop.d.ts +2 -9
- package/dist/daemon/reconcilers/fault-retry-backstop.js +1 -1
- package/dist/daemon/reconcilers/grant-effects.d.ts +8 -0
- package/dist/daemon/reconcilers/grant-effects.js +1 -0
- package/dist/daemon/reconcilers/grove-instance-sweep.d.ts +1 -3
- package/dist/daemon/reconcilers/grove-instance-sweep.js +1 -1
- package/dist/daemon/reconcilers/ledger-r2.d.ts +27 -0
- package/dist/daemon/reconcilers/ledger-r2.js +7 -0
- package/dist/daemon/reconcilers/ledger-sandbox.d.ts +55 -0
- package/dist/daemon/reconcilers/ledger-sandbox.js +9 -0
- package/dist/daemon/reconcilers/ledger-storage.d.ts +22 -0
- package/dist/daemon/reconcilers/ledger-storage.js +5 -0
- package/dist/daemon/reconcilers/live-obligation.d.ts +3 -2
- package/dist/daemon/reconcilers/live-obligation.js +1 -1
- package/dist/daemon/reconcilers/managed-worktree-sweep.d.ts +0 -5
- package/dist/daemon/reconcilers/managed-worktree-sweep.js +1 -1
- package/dist/daemon/reconcilers/node-deadline.d.ts +2 -1
- package/dist/daemon/reconcilers/node-deadline.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -2
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/remote-wake.d.ts +31 -0
- package/dist/daemon/reconcilers/node-lifecycle/remote-wake.js +1 -0
- package/dist/daemon/reconcilers/node-lifecycle/requested-stops.d.ts +5 -0
- package/dist/daemon/reconcilers/node-lifecycle/requested-stops.js +2 -0
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
- package/dist/daemon/reconcilers/pending-review-submit.js +1 -1
- package/dist/daemon/reconcilers/recipe-image.d.ts +49 -0
- package/dist/daemon/reconcilers/recipe-image.js +7 -0
- package/dist/daemon/reconcilers/row-claim.d.ts +19 -0
- package/dist/daemon/reconcilers/row-claim.js +2 -0
- package/dist/daemon/reconcilers/storage-due-work.d.ts +18 -3
- package/dist/daemon/reconcilers/storage-due-work.js +2 -1
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +5 -13
- package/dist/daemon/reconcilers/storage-maintenance.js +1 -1
- package/dist/daemon/reconcilers/structured-request-lane.js +1 -1
- package/dist/daemon/reconcilers/throttled-lane.d.ts +11 -0
- package/dist/daemon/reconcilers/throttled-lane.js +1 -0
- package/dist/daemon/review/finish.js +1 -1
- package/dist/daemon/run-notices.d.ts +3 -0
- package/dist/daemon/run-notices.js +1 -1
- package/dist/daemon/runs/append-section.d.ts +4 -1
- package/dist/daemon/runs/append-section.js +2 -2
- package/dist/daemon/runs/observer.d.ts +3 -2
- package/dist/daemon/runs/observer.js +3 -2
- package/dist/daemon/runs/view-transport.d.ts +19 -0
- package/dist/daemon/runs/view-transport.js +1 -0
- package/dist/daemon/structured-requests/boot.d.ts +2 -1
- package/dist/daemon/structured-requests/boot.js +1 -1
- package/dist/daemon/structured-requests/effects.d.ts +4 -3
- package/dist/daemon/structured-requests/effects.js +1 -1
- package/dist/daemon/structured-requests/notifier.d.ts +2 -0
- package/dist/daemon/structured-requests/notifier.js +1 -1
- package/dist/daemon/structured-requests/sidecar.d.ts +4 -3
- package/dist/daemon/structured-requests/sidecar.js +1 -1
- package/dist/launcher/validate.js +1 -1
- package/dist/migrations/004-canvas-documents/index.js +2 -2
- package/dist/pi-extensions/broker-local.d.ts +3 -3
- package/dist/pi-extensions/broker-local.js +1 -2
- package/dist/pi-extensions/canvas-bash-valve.js +6 -6
- package/dist/pi-extensions/canvas-context-intro.js +2 -2
- package/dist/pi-extensions/canvas-elapsed.js +2 -2
- package/dist/pi-extensions/canvas-goal-capture.js +1 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +2 -2
- package/dist/pi-extensions/canvas-review-boundary.d.ts +11 -1
- package/dist/pi-extensions/canvas-review-boundary.js +3 -3
- package/dist/pi-extensions/canvas-stophook.js +1 -1
- package/dist/pi-extensions/canvas-structured-output.d.ts +5 -3
- package/dist/pi-extensions/canvas-structured-output.js +6 -11
- package/dist/pi-extensions/canvas-tool-guide.d.ts +9 -2
- package/dist/pi-extensions/canvas-tool-guide.js +6 -6
- package/dist/shared/inbox-entry-body.js +7 -7
- package/dist/types.d.ts +12 -0
- package/docs/sdk/release-notes.md +4 -0
- package/package.json +7 -4
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -13
- package/scripts/git-credential-crtr +33 -0
- package/scripts/sandbox-bootstrap.sh +54 -0
- package/scripts/sandbox-start.mjs +320 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +0 -78
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +0 -1179
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +0 -1406
- package/dist/core/conversation-store/file-store.d.ts +0 -37
- package/dist/core/conversation-store/file-store.js +0 -9
- package/dist/core/conversation-store/listener.d.ts +0 -4
- package/dist/core/conversation-store/listener.js +0 -8
- package/dist/core/scoped-state/profiles.d.ts +0 -27
- package/dist/core/scoped-state/profiles.js +0 -1
- package/dist/core/scoped-state/providers.d.ts +0 -24
- package/dist/core/scoped-state/providers.js +0 -1
- package/dist/core/scoped-state/settings.d.ts +0 -28
- package/dist/core/scoped-state/settings.js +0 -1
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
var Ce=Object.defineProperty;var d=(e,n)=>Ce(e,"name",{value:n,configurable:!0});import{envProfileId as
|
|
1
|
+
var Ce=Object.defineProperty;var d=(e,n)=>Ce(e,"name",{value:n,configurable:!0});import{envProfileId as ee}from"../../shared/env.js";import{invalidPluginEnvReasons as Me}from"../../core/plugin-env.js";import{collectPluginEnv as ne}from"./plugin-env.js";import{dirname as te,join as v,resolve as F,isAbsolute as _e,relative as L}from"node:path";import{renameSync as j}from"node:fs";import{defineLeaf as B}from"../../core/command.js";import{cliClient as Le,rethrowAsCliError as Be}from"../api-client.js";import{notFound as g,usage as b,general as m,network as He,CrtrError as De}from"../../core/errors.js";import{findMarketplaceByName as Ie,findPluginByName as A,listAllPlugins as ie}from"../../core/resolver.js";import{pluginsDir as C,ensureProjectScopeRoot as z,userScopeRoot as S,resolveScopeArg as oe,projectScopeRoot as ae,requireScopeRoot as M}from"../../core/scope.js";import{readState as Ne,updateConfig as H,updateState as V,ensureScopeInitialized as G,invalidPluginKindsReasons as Ue,invalidPluginBinReasons as Fe,invalidPluginRequiresReasons as Ve,normalizeRequires as Oe}from"../../core/config.js";import{withExclusiveDirectoryLockAsync as Ke}from"../../core/exclusive-lock.js";import{bundleSwapLockPath as re}from"../../core/plugin-swap-lock.js";import{invalidPageComponentsReasons as We}from"../../core/human/page-catalog.js";import{pathExists as $,ensureDir as _,removePath as E,nowIso as J,linkOrCopy as se,isSymlink as O,readSymlinkTarget as ze,readText as Ge,realpathOrSelf as Je,walkFiles as Ye}from"../../core/fs-utils.js";import{clone as K,deriveNameFromUrl as Qe,currentSha as T,gitSync as le,isGitRepo as Y}from"../../core/git.js";import{readMarketplaceManifest as ce,readPluginManifest as x}from"../../core/manifest.js";import{pluginExtensionCatalog as Xe,validateMemoryExtensionValues as Ze,validatePluginMemoryExtensions as en}from"../../core/plugin-extensions.js";import{lintPackageFrontmatter as nn,packageFiles as tn}from"../../core/graph/package-files.js";import{parseFrontmatterGeneric as on}from"../../core/frontmatter.js";import{validatePluginCommands as Q,validateEffectiveCommandPlugins as an}from"../../core/command-plugins/discovery.js";import{normalizeEndpoint as rn,validateEndpoint as sn,validateHttpPluginTransport as ln}from"../../core/command-plugins/endpoint.js";import{composeAppProcessEnv as cn,overlayBrokerEnv as dn,resolvePathExecutable as un}from"../../core/runtime/spawn-env.js";import{bundleVersion as pn,installBundleArchive as mn,isInstalledGeneration as fn,recordCheckedGeneration as hn,validatePluginBundle as gn}from"../../core/command-plugins/bundle.js";import{compileHookRegistry as de,discoverCandidateHookRegistry as vn,discoverCandidateHookRegistryForCandidates as yn,discoverHookRegistry as kn}from"../../core/command-hooks/discovery.js";import{hasDeclaredHooks as ue,hookReport as pe}from"../../core/command-hooks/report.js";import{fetchHttpPluginBundle as me}from"../../core/command-plugins/transport/http-fetch.js";import{leafPathsBelowRoot as wn,objectBlocksReasons as bn,streamingLeafPathsBelowRoot as $n}from"../../core/plugin-objects-manifest.js";import{SUBTREE_NAMES as D,coreCommandPaths as I,coreHookCatalog as fe,extensibleCoreBranches as N}from"../../build-root.js";import{ExitCode as jn}from"../../types.js";import{isGitUrl as he,resolvePluginConfigTarget as Pn,setPluginEnabled as ge,resolveInstallScope as Rn}from"./shared.js";async function X(e,n){const t=A(e,n);if(t===null||typeof t.manifest.commands!="string"||t.manifest.commands.length===0)return;const i=new Set(D),[o,r]=await Promise.all([I(),N()]),a=an(i,void 0,void 0,o,r).find(l=>l.plugin.root===t.root)??Q(t,i,o,r);return{mounts:[...a.contributions.map(l=>l.node.name),...a.coreMounts.map(l=>[...l.parent,l.node.name].join(" "))],issues:a.issues}}d(X,"commandReport");const xn=/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;function ve(e,n,t){if(typeof e!="string"||!xn.test(e))throw b("invalid --name: expected a lowercase kebab-case plugin handle");const i=sn(n);if(!i.isValid)throw b(`invalid --endpoint: ${i.errors.join("; ")}`);const o=rn(n),r=ln({kind:"http",endpoint:o,...t!==void 0?{authEnv:t}:{}});if(r.transport===void 0)throw b(`invalid HTTP plugin transport: ${r.errors.join("; ")}`);return r.transport}d(ve,"validateHttpInstall");function W(e,n){const t=n.map(i=>`- ${i.code}${i.path!==void 0?` at ${i.path}`:""}: ${i.message} (received ${JSON.stringify(i.received)}, expected ${i.expected})`);return m(`${e}:
|
|
2
2
|
${t.join(`
|
|
3
|
-
`)}`,{issues:n,...n.length>0?{next:n[0].next}:{}})}d(W,"invalidBundleError");function
|
|
3
|
+
`)}`,{issues:n,...n.length>0?{next:n[0].next}:{}})}d(W,"invalidBundleError");function Sn(e,n){if(e.kinds===void 0)return;const t=Ue(e.kinds);if(t.length>0)throw m(`plugin manifest at ${n} declares an invalid kinds block:
|
|
4
4
|
${t.map(i=>`- ${i}`).join(`
|
|
5
|
-
`)}`,{issues:t})}d(
|
|
5
|
+
`)}`,{issues:t})}d(Sn,"assertManifestKindsValid");function En(e,n){if(e.bin===void 0)return;const t=Fe(e.bin);if(t.length>0)throw m(`plugin manifest at ${n} declares an invalid bin block:
|
|
6
6
|
${t.map(i=>`- ${i}`).join(`
|
|
7
|
-
`)}`,{issues:t})}d(
|
|
7
|
+
`)}`,{issues:t})}d(En,"assertManifestBinValid");function Tn(e,n){if(e.requires===void 0)return;const t=Ve(e.requires);if(t.length>0)throw m(`plugin manifest at ${n} declares an invalid requires block:
|
|
8
8
|
${t.map(i=>`- ${i}`).join(`
|
|
9
|
-
`)}`,{issues:t})}d(
|
|
9
|
+
`)}`,{issues:t})}d(Tn,"assertManifestRequiresValid");function ye(e){if(e.requires===void 0)return[];const n={argv:[],env:{CRTR_NODE_CWD:process.cwd(),CRTR_PROFILE_ID:ee()??""}},t=dn(n,cn(process.cwd(),ee()??null,"app:terminal",{},{}));return Object.entries(Oe(e.requires)).filter(([i])=>un(i,t,process.cwd())===null).map(([i,o])=>`Warning: plugin "${e.name}" requires "${i}" on PATH \u2014 ${o}`)}d(ye,"missingRequirementWarnings");function qn(e,n){if(e.page_components===void 0)return;const t=We(e.page_components);if(t.length>0)throw m(`plugin manifest at ${n} declares an invalid page_components block:
|
|
10
10
|
${t.map(i=>`- ${i}`).join(`
|
|
11
|
-
`)}`,{issues:t})}d(
|
|
11
|
+
`)}`,{issues:t})}d(qn,"assertManifestPageComponentsValid");async function Z(e,n){const t=A(e,n);if(t===null||!ue(t.manifest))return;const i=await fe(),o=kn(i),r=o.validations.find(a=>a.plugin.root===t.root);if(r===void 0){const a=de(i,[t]);return pe(a.validations[0])}return pe(r,o.issues.filter(a=>a.plugin===t.name&&a.scope===t.scope))}d(Z,"hookLifecycleReport");async function An(e,n,t,i,o,r){if(!ue(e))return;const a={name:e.name,scope:t,root:n,manifest:e,enabled:!0},l=r??[{plugin:a,scopeRoot:i}],c=await fe(),s=r===void 0?vn(c,a,i):yn(c,l),y=s.validations.find(p=>p.plugin.root===n)===void 0?de(c,[a]).issues:s.issues.filter(p=>p.plugin===a.name&&p.scope===a.scope);if(y.length>0)throw W(`plugin hook behavior at ${o} is invalid`,y)}d(An,"assertManifestHooksValid");function Cn(e,n){const t=L(e,n);return t===""?e:t}d(Cn,"storeRelative");function Mn(e,n,t,i,o){const r=v(n,"memory");if(!$(r))return;const{files:a,invalid:l}=tn(r);if(l.length>0){const c=l.map(s=>`- ${Cn(r,s.path)}: ${s.error}`);throw m(`plugin "${e.name}" memory corpus at ${i} has documents that cannot be named:
|
|
12
12
|
${c.join(`
|
|
13
|
-
`)}`,{issues:l,next:`Correct the package's memory documents, then retry \u2014 "${e.name}" was not activated.`})}return{docs:a.length,...o==="linked"?{linkedSource:Je(r)}:{}}}d(
|
|
14
|
-
${
|
|
15
|
-
`)}`,{issues:
|
|
16
|
-
${y.map(
|
|
17
|
-
`)}`,{issues:y});await
|
|
18
|
-
`)[0]:String(R)}`)}const w=nn(h);if(w!==null)throw
|
|
19
|
-
Accepted forms: marketplace/plugin, git URL (https://, ssh://, git@, file://, or *.git), or local path starting ./, ../, or /. Bare plugin names are not install refs.`)}d(Un,"classifyInstallRef");function Re(e){return e.startsWith("./")||e.startsWith("../")||!_e(e)&&!me(e)}d(Re,"isMarketplaceRelativeSource");async function xe(e,n,t){const i=n.get(e);if(i!==void 0)return i;const o=Ie(e);if(o===null){if(t.strict)throw g(`marketplace not found: ${e}`);return null}const r=le(o.root);if(r===null)throw g(`marketplace manifest not found: ${o.root}/.crouter-marketplace/marketplace.json`);if(!Y(o.root)){const s={marketplace:o,manifest:r,pull:{updated:!1,sha:T(o.root)??""}};return n.set(e,s),s}const a=T(o.root),l=v(ne(o.root),`.${e}.${process.pid}.${Date.now()}.candidate`),c=`${l}.previous`;try{K(o.url,l,{ref:o.ref,depth:1});const s=le(l);if(s===null)throw g(`marketplace manifest not found in candidate checkout: ${l}/.crouter-marketplace/marketplace.json`);const u=te().filter(p=>p.sourceMarketplace===e&&O(p.root));for(const p of u){const k=s.plugins.find(qe=>qe.name===p.name);if(k===void 0||!Re(k.source))throw f(`marketplace candidate removes relative-source plugin "${p.name}" while it is installed`);const m=ze(p.root);if(m===null)throw f(`installed marketplace plugin "${p.name}" has no readable symlink target`);const h=L(o.root,F(ne(p.root),m)),w=F(l,k.source);if(w!==F(l,h))throw f(`marketplace candidate moves installed relative-source plugin "${p.name}" from ${h} to ${k.source}`);if(!$(w))throw g(`marketplace candidate source path does not exist for plugin "${p.name}": ${w}`);const R=x(w);if(R===null)throw g(`plugin manifest not found in marketplace candidate: ${w}/.crouter-plugin/plugin.json`);const Te=p.scope==="project"?M("project"):S();await P(R,w,p.scope,Te,`${w}/.crouter-plugin/plugin.json`)}j(o.root,c);try{j(l,o.root)}catch(p){throw j(c,o.root),p}E(c);for(const p of u){const k=s.plugins.find(m=>m.name===p.name);Se(p.scope,p.name,k.version??p.manifest.version)}V(o.scope,p=>{p.marketplaces[e]===void 0&&(p.marketplaces[e]={}),p.marketplaces[e].last_updated=J()});const y={marketplace:o,manifest:s,pull:{updated:a!==T(o.root),sha:T(o.root)??""}};return n.set(e,y),y}finally{E(l),$(c)&&!$(o.root)&&j(c,o.root)}}d(xe,"refreshMarketplace");function Se(e,n,t){H(e,i=>{const o=i.plugins[n];o!==void 0?t!==void 0&&(o.version=t):i.plugins[n]={enabled:!0,version:t}}),V(e,i=>{i.plugins[n]===void 0&&(i.plugins[n]={}),i.plugins[n].last_updated=J()})}d(Se,"updatePluginVersion");async function Fn(e,n,t){const i=t==="project"?z():S();G(t,i);const o=A(t),r=Qe(e),a=v(i,"tmp",`${r}.${process.pid}.${Date.now()}`);_(v(i,"tmp"));try{K(e,a,{ref:n,depth:1});const l=x(a);if(l===null)throw f(`cloned repo does not contain a valid .crouter-plugin/plugin.json: ${e}`);const c=await P(l,a,t,i,`${e}/.crouter-plugin/plugin.json`),s=v(o,l.name);if($(s))throw f(`plugin "${l.name}" is already installed at ${s}`);return _(o),j(a,s),H(t,u=>{u.plugins[l.name]={enabled:!0,version:l.version}}),{name:l.name,scope:t,path:s,...c!==void 0?{memory:c}:{}}}finally{E(a)}}d(Fn,"installFromGit");async function Vn(e,n){const t=F(e),i=x(t);if(i===null)throw g(`plugin manifest not found at ${t}/.crouter-plugin/plugin.json`);const o=n==="project"?z():S(),r=await P(i,t,n,o,`${t}/.crouter-plugin/plugin.json`,void 0,"linked");G(n,o);const a=v(A(n),i.name);if($(a))throw f(`plugin "${i.name}" is already installed at ${a}`);return re(t,a),H(n,l=>{l.plugins[i.name]={enabled:!0,version:i.version}}),{name:i.name,scope:n,path:a,...r!==void 0?{memory:r}:{}}}d(Vn,"installFromLocal");async function On(e,n){const t=await xe(e.marketplace,new Map,{strict:!0});if(t===null)throw g(`marketplace not found: ${e.marketplace}`);const i=t.manifest.plugins.find(s=>s.name===e.plugin);if(i===void 0)throw g(`plugin "${e.plugin}" not found in marketplace "${e.marketplace}"`);const o=M(n);G(n,o);const r=v(A(n),e.plugin);if($(r))throw f(`plugin "${e.plugin}" is already installed at ${r}`);let a,l;if(Re(i.source)){const s=v(t.marketplace.root,i.source);if(!$(s))throw g(`plugin source path does not exist: ${s}`);const u=x(s);if(u===null)throw g(`plugin manifest not found at ${s}/.crouter-plugin/plugin.json`);l=await P(u,s,n,o,`${s}/.crouter-plugin/plugin.json`,void 0,"linked"),re(s,r),a=u}else{const s=v(o,"tmp",`${e.plugin}.${process.pid}.${Date.now()}`);_(v(o,"tmp"));try{K(i.source,s,{depth:1});const u=x(s);if(u===null)throw g(`plugin manifest not found at ${s}/.crouter-plugin/plugin.json`);l=await P(u,s,n,o,`${s}/.crouter-plugin/plugin.json`),_(A(n)),j(s,r),a=u}finally{E(s)}}const c=i.version??a.version;return H(n,s=>{const u={enabled:!0,source_marketplace:e.marketplace};c!==void 0&&(u.version=c),s.plugins[e.plugin]=u}),{name:e.plugin,scope:n,path:r,...l!==void 0?{memory:l}:{}}}d(On,"installFromMarketplace");async function Kn(e){if(O(e.root)){const l=x(e.root);if(l===null)throw g(`plugin manifest not found at ${e.root}/.crouter-plugin/plugin.json`);const c=e.scope==="project"?M("project"):S(),s=await P(l,e.root,e.scope,c,`${e.root}/.crouter-plugin/plugin.json`,void 0,"linked");return{updated:!1,sha:T(e.root)??"",manifest:l,...s!==void 0?{memory:s}:{}}}if(!Y(e.root)){const l=x(e.root);if(l===null)throw g(`plugin manifest not found at ${e.root}/.crouter-plugin/plugin.json`);const c=e.scope==="project"?M("project"):S(),s=await P(l,e.root,e.scope,c,`${e.root}/.crouter-plugin/plugin.json`);return{updated:!1,sha:"",manifest:l,...s!==void 0?{memory:s}:{}}}const n=se(["config","--get","remote.origin.url"],e.root).stdout.trim();if(n==="")throw f(`plugin "${e.name}" has no origin remote to stage an update from`);const t=se(["symbolic-ref","--short","HEAD"],e.root).stdout.trim();if(t==="")throw f(`plugin "${e.name}" is detached at its installed revision and has no tracked branch to update`);const i=e.scope==="project"?M("project"):S(),o=v(i,"tmp",`${e.name}.${process.pid}.${Date.now()}.candidate`),r=`${o}.previous`,a=T(e.root);_(v(i,"tmp"));try{K(n,o,{ref:t,depth:1});const l=x(o);if(l===null)throw g(`plugin manifest not found in update candidate: ${o}/.crouter-plugin/plugin.json`);const c=await P(l,o,e.scope,i,`${o}/.crouter-plugin/plugin.json`);j(e.root,r);try{j(o,e.root)}catch(u){throw j(r,e.root),u}E(r);const s=T(e.root)??"";return{updated:a!==s,sha:s,manifest:l,...c!==void 0?{memory:c}:{}}}finally{E(o),$(r)&&!$(e.root)&&j(r,e.root)}}d(Kn,"updateGitPluginCandidate");async function Ee(e,n,t){if(e.manifest.provider!==void 0)return{name:e.name,transport:"http",updated:!1,warnings:[`"${e.name}" is a capability provider bundle; the runtime refreshes it on grant sync`]};const i=ye(e);if(!i&&e.manifest.bundle!==void 0){const u=await je(e.name,e.manifest.bundle,e.scope,{enable:e.enabled});return{name:e.name,transport:"http",updated:!0,version:u.version,docs:u.docs,kinds:u.kinds,pageComponents:u.pageComponents,objectKinds:u.objectKinds,scopes:u.scopes,commands:u.commands,...u.hooks!==void 0?{hooks:u.hooks}:{},...u.memory!==void 0?{memory:u.memory}:{}}}e.manifest.transport?.kind==="http"&&!i&&ke(e.name);let o,r=!1;if(e.sourceMarketplace!==void 0){const u=await xe(e.sourceMarketplace,n,t);u!==null&&(o=u.manifest.plugins.find(p=>p.name===e.name)?.version,r=u.pull.updated)}const a=await Kn(e);Se(e.scope,e.name,o??a.manifest.version);const l=await X(e.name,e.scope),c=await Z(e.name,e.scope),s=[...ve(a.manifest),...await ee(a.manifest)];return{name:e.name,...e.manifest.transport!==void 0?{transport:e.manifest.transport.kind==="machine"?"http":e.manifest.transport.kind}:{},updated:r||a.updated,sha:a.sha,...l!==void 0?{commands:l}:{},...c!==void 0?{hooks:c}:{},...a.memory!==void 0?{memory:a.memory}:{},...s.length>0?{warnings:s}:{}}}d(Ee,"updateOnePlugin");async function q(e){const n=await Le().documents.reconcilePackages().catch(i=>Be(i)),t=n.conflicts.find(i=>i.plugin===e);if(t)throw new De("conflict",`plugin "${e}" is installed but its documents are not on the canvas: ${t.message}`,$n.GENERAL,{plugin:e,next:"Uninstall the other package providing that plugin name, then run `crtr pkg plugin update --name "+e+"`."});return n}d(q,"reconcilePluginDocuments");function Wn(e,n){const t=[...(e.kinds?.refused??[]).filter(o=>o.plugin===n).map(o=>`object kind ${o.kind} not registered: ${o.message}`),...(e.kinds?.invalid??[]).filter(o=>o.plugin===n).map(o=>`object kinds and scopes not applied; the plugin holds no app token until this is fixed: ${o.error}`)],i=e.tokens?.granted.find(o=>o.plugin===n);return{warnings:t,...i!==void 0?{appScopes:i.scopes}:{}}}d(Wn,"pluginObjectReport");function U(e,n,t){const{warnings:i,appScopes:o}=Wn(n,t),a=[...e.warnings??[],...i];return{...e,...a.length>0?{warnings:a}:{},...o!==void 0?{appScopes:o}:{}}}d(U,"withObjectReport");const St=B({name:"install",description:"install from a ref or HTTP endpoint",whenToUse:"installing one plugin from a marketplace ref, git URL, local path, or an HTTP directory-archive endpoint",help:{name:"pkg plugin install",summary:"install a plugin from a ref or HTTP endpoint",params:[{kind:"positional",name:"install-ref",type:"string",required:!1,constraint:"Plugin install ref. Provide exactly one of INSTALL-REF or --endpoint. Accepted ref forms: marketplace/plugin; git URL starting https://, ssh://, git@, file://, or ending .git; local path starting ./, ../, or /."},{kind:"flag",name:"endpoint",type:"string",required:!1,constraint:"HTTP plugin directory-archive endpoint. Provide exactly one of --endpoint or INSTALL-REF. Must be an absolute https: URL; http: is permitted only for localhost, any *.localhost host, 127.0.0.1, [::1], ::1, or host.docker.internal. Credentials and fragments are rejected."},{kind:"flag",name:"name",type:"string",required:!1,constraint:"Required with --endpoint and rejected without it. Lowercase kebab-case plugin handle."},{kind:"flag",name:"auth-env",type:"string",required:!1,constraint:"Optional environment variable holding the HTTP bearer token. Accepted only with --endpoint; its value is never stored."},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Default: project if available, else user."},{kind:"flag",name:"ref",type:"string",required:!1,constraint:"Git ref (branch/tag) for git URL installs. Rejected with --endpoint; ignored for marketplace and local path refs."}],output:[{name:"name",type:"string",required:!0,constraint:"Plugin name as installed."},{name:"scope",type:"string",required:!0,constraint:"Scope the plugin was installed into."},{name:"path",type:"string",required:!0,constraint:"Absolute path to the installed plugin directory."},{name:"transport",type:"string",required:!1,constraint:"exec or http when the plugin declares commands. Always http for an --endpoint install."},{name:"version",type:"string",required:!1,constraint:"First 12 hex characters of the fetched archive SHA-256 for an --endpoint install."},{name:"docs",type:"integer",required:!1,constraint:"Memory document count written from an --endpoint archive."},{name:"kinds",type:"integer",required:!1,constraint:"Kind-registry entry count declared by an --endpoint archive\u2019s bundle.json."},{name:"pageComponents",type:"integer",required:!1,constraint:"Page-component registration count declared by an --endpoint archive\u2019s bundle.json."},{name:"commands",type:"object",required:!1,constraint:"Present only when the plugin declares a command manifest. {mounts: string[] (accepted command paths now live for the next invocation), issues: object[] (typed validation issues that rejected a contribution \u2014 {code, path?, message, received, expected, next})}. Validated statically; commands are never executed."},{name:"hooks",type:"object",required:!1,constraint:"Present only when the plugin declares hooks. {manifestPath?, executablePath?, declarations: {target, phase, op, description, effects}[], lifecycle?: {event, phase, op, description, effects}[], issues: object[], trust: string}. Command targets, lifecycle events, and replacement collisions are validated statically; hook executables are never run."},{name:"objectKinds",type:"integer",required:!1,constraint:"Canvas object kind count declared by an --endpoint archive\u2019s bundle.json `object_kinds` block."},{name:"scopes",type:"integer",required:!1,constraint:"Canvas scope count declared by an --endpoint archive\u2019s bundle.json `scopes` block."},{name:"appScopes",type:"string[]",required:!1,constraint:"Present when the plugin holds an app token after install: the canvas scopes that token carries (the manifest `scopes`; empty for a plugin that declares kinds or serves over HTTP but asks for none)."},{name:"warnings",type:"string[]",required:!1,constraint:"Advisory missing PATH executable requirements declared by the installed plugin, kinds another owner already holds (`object kind <kind> not registered`), and an invalid `object_kinds`/`scopes` block that leaves the plugin without an app token. The install still succeeds and leaves the plugin enabled."},{name:"memory",type:"object",required:!1,constraint:"Present only when the plugin ships documents (its `memory/` folder). {docs: integer (documents checked), linkedSource?: string (the caller-owned directory, present only when the install keeps that directory as a live link)}."}],outputKind:"object",effects:["A ref install clones, links, or copies the plugin into the scope plugins directory and registers it with enabled=true. Marketplace installs refresh the source marketplace before resolving the plugin entry.","An --endpoint install fetches and validates one authenticated uncompressed tar archive before writing. It replaces the complete plugin directory with synthesized provenance and invocation metadata, commands.json, memory docs, and, when declared, hooks.json plus the hooks/ tree; it also copies any kind-registry entries the bundle.json declares (they join the launch registry below this scope\u2019s own config.json kinds), and any page components it declares (they join the active page-component catalog alongside the user config entries); a fetch or validation failure preserves the prior package.","If the plugin declares a command manifest, its commands go live on the next crtr invocation. Exec commands run trusted local code only when explicitly invoked; HTTP commands call their declared endpoint only when explicitly invoked.","Plugin command hooks go live on the next crtr invocation. They run implicitly with caller authority, may receive normalized inputs and after results, may block or replace declared targets, and may transmit received data. Lifecycle hooks run unprompted at every declared event before node launch and may transmit node identity and resolved paths. Hook executables are never run during install or update validation.","A plugin manifest `requires` declaration is checked against the PATH a node bash receives after install. Missing executables emit a warning with the declared install hint but never fail the install, disable the plugin, or remove its bare-binary contributions.","Before activation the candidate\u2019s `memory/` documents are checked for identity findings and refused if it cannot mount; a local path or marketplace-relative source stays a live link, named as `memory.linkedSource`. A refused package installs nothing."]},run:d(async e=>{const n=e.installRef,t=e.endpoint,i=e.name,o=e.authEnv,r=e.scope,a=e.ref,l=Pn(r);if(n===void 0==(t===void 0))throw b("provide exactly one of INSTALL-REF or --endpoint");if(t!==void 0){if(i===void 0)throw b("--name is required with --endpoint");if(a!==void 0)throw b("--ref is only valid with a git INSTALL-REF, not --endpoint");const h=await Nn(i,t,o,l);return U(h,await q(i),i)}if(i!==void 0)throw b("--name is only valid with --endpoint");if(o!==void 0)throw b("--auth-env is only valid with --endpoint");const c=Un(n),s=c.kind==="marketplace"?await On(c.value,l):c.kind==="local"?await Vn(c.value,l):await Fn(c.value,a,l),u=C(s.name,s.scope),y=await X(s.name,s.scope),p=await Z(s.name,s.scope),k=u===null?[]:[...ve(u.manifest),...await ee(u.manifest)],m=await q(s.name);return U({...s,...u?.manifest.transport!==void 0?{transport:u.manifest.transport.kind}:{},...y!==void 0?{commands:y}:{},...p!==void 0?{hooks:p}:{},...k.length>0?{warnings:k}:{}},m,s.name)},"run")}),Et=B({name:"remove",description:"remove plugin and directory",whenToUse:"uninstalling a plugin: deletes its directory and removes it from config",help:{name:"pkg plugin remove",summary:"remove a plugin and its directory from the given scope",params:[{kind:"positional",name:"name",type:"string",required:!0,constraint:"Plugin name to remove."},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Default: searches every scope."}],output:[{name:"scopes",type:"string[]",required:!0,constraint:"Scopes the plugin was removed from."}],outputKind:"object",effects:["Deletes the plugin directory. Removes the plugin entry from config.json."]},run:d(async e=>{const n=e.name,t=e.scope;if(n==="crtr")throw b('cannot remove builtin plugin "crtr" \u2014 it ships with the binary');let i;if(t!==void 0){const r=ie(t);if(r==="builtin")throw b("cannot remove plugins from builtin scope");i=r==="all"?["project","user"].filter(a=>a!=="project"||oe()!==null):[r]}else i=["project","user"].filter(r=>r!=="project"||oe()!==null);const o=[];for(const r of i){const a=A(r);if(a===null)continue;const l=v(a,n);$(l)&&(E(l),H(r,c=>{delete c.plugins[n]}),V(r,c=>{delete c.plugins[n]}),o.push(r))}if(o.length===0)throw g(`plugin not found: ${n}`);return await q(),{scopes:o}},"run")}),Tt=B({name:"enable",description:"enable a plugin",whenToUse:"reactivating a plugin that was previously disabled so its memory docs resolve again",help:{name:"pkg plugin enable",summary:"enable a plugin in the given scope",params:[{kind:"positional",name:"name",type:"string",required:!0,constraint:"Plugin name to enable."},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Default: scope where the plugin is installed."}],output:[{name:"scope",type:"string",required:!0,constraint:"Scope the change was applied in."},{name:"memory",type:"object",required:!1,constraint:"Present only when the plugin ships documents (its `memory/` folder). {docs: integer (documents checked), linkedSource?: string (the caller-owned directory, present only for a symlinked install)}."},{name:"appScopes",type:"string[]",required:!1,constraint:"Present when the plugin holds an app token: the canvas scopes it carries."},{name:"warnings",type:"string[]",required:!1,constraint:"Kinds another owner holds, or an invalid `object_kinds`/`scopes` block. Enabling still succeeds."}],outputKind:"object",effects:["Validates the installed package before any config change: its `memory/` documents are checked for identity findings and refused if it cannot mount. A refusal leaves the plugin disabled.","Sets plugin enabled=true in config.json."]},run:d(async e=>{const n=e.name,t=jn(n,e.scope);if(t===null)throw g(`plugin not found: ${n}`);const i=x(t.root);if(i===null)throw g(`plugin manifest not found at ${t.root}/.crouter-plugin/plugin.json`);const o=t.scope==="project"?M("project"):S(),r=await P(i,t.root,t.scope,o,`${t.root}/.crouter-plugin/plugin.json`,void 0,O(t.root)?"linked":"package"),a=await he(e,!0),l=await q(n);return U({scope:a.scope,...r!==void 0?{memory:r}:{}},l,n)},"run")}),qt=B({name:"disable",description:"disable without removing",whenToUse:"hiding a plugin from resolution without deleting it, so you can re-enable it later",help:{name:"pkg plugin disable",summary:"disable a plugin (keeps files, hides from resolution)",params:[{kind:"positional",name:"name",type:"string",required:!0,constraint:"Plugin name to disable."},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Default: scope where the plugin is installed."}],output:[{name:"scope",type:"string",required:!0,constraint:"Scope the change was applied in."}],outputKind:"object",effects:["Sets plugin enabled=false in config.json."]},run:d(async e=>{const n=await he(e,!1);return await q(),{scope:n.scope}},"run")}),Ct=B({name:"update",description:"update installed plugin content",whenToUse:"refreshing one named plugin or all installed plugins: archive plugins replace their complete package, while source-installed plugins retain their source update behavior",help:{name:"pkg plugin update",summary:"refresh one or all installed plugins",params:[{kind:"flag",name:"name",type:"string",required:!1,constraint:"Plugin name to update. Omit to update all installed plugins."},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Narrows resolution."}],output:[{name:"updated",type:"object[]",required:!0,constraint:"One entry per plugin processed: {name, transport?, updated, sha?, version?, docs?, kinds?, pageComponents?, commands?, hooks?, memory?, warnings?, error?}. memory is present for a plugin shipping documents and reports the same memory check install performs: {docs, linkedSource?}. Archive plugins report transport=http and replace their complete directory after an authenticated refetch; version is the archive content identifier, docs is the written memory-document count, kinds is the declared kind-registry entry count, pageComponents is the declared page-component registration count, objectKinds is the declared canvas object kind count, and scopes is the declared canvas scope count. appScopes lists the scopes the plugin\u2019s app token carries after the update. sha is present for git updates. A bulk update reports and skips a failed archive plugin. commands is present for validated command plugins: {mounts: string[] (accepted command paths), issues: object[]}. hooks is present for plugins declaring hooks: {manifestPath?, executablePath?, declarations: {target, phase, op, description, effects}[], lifecycle?: {event, phase, op, description, effects}[], issues: object[], trust: string}; it is static and never executes hooks. warnings lists advisory PATH requirements that remain absent after update, kinds another owner holds, and an invalid object_kinds/scopes block."}],outputKind:"object",effects:["Archive plugins unconditionally re-fetch, validate, and replace their complete package; a named failure exits nonzero and preserves the prior package. Bulk update reports a failed archive plugin and continues. Source-installed plugins retain their source update, version, and last_updated behavior.","A capability provider bundle (installed by the runtime from the directory) is skipped with a warning: the runtime refreshes it on grant sync.","Each candidate passes the same pre-activation memory check install performs."]},run:d(async e=>{const n=e.name,t=e.scope,i=t===void 0?void 0:ie(t),o=new Map;if(n!==void 0){const c=i===void 0||i==="all"||i==="builtin"?C(n):C(n,i);if(c===null)throw g(`plugin not found: ${n}${i===void 0||i==="all"||i==="builtin"?"":` (scope: ${i})`}`);const s=await Ee(c,o,{strict:!0}),u=await q(n);return{updated:[U(s,u,s.name)]}}const r=te().filter(c=>c.scope!=="builtin"&&(i===void 0||i==="all"||c.scope===i)),a=[];for(const c of r)try{a.push(await Ee(c,o,{strict:!1}))}catch(s){a.push({name:c.name,...c.manifest.transport!==void 0?{transport:c.manifest.transport.kind}:{},updated:!1,error:s instanceof Error?s.message:String(s)})}const l=await q();return{updated:a.map(c=>c.error===void 0?U(c,l,c.name):c)}},"run")});export{P as assertPluginCandidateValid,On as installFromMarketplace,In as installPluginArchive,Re as isMarketplaceRelativeSource,qt as pluginDisable,Tt as pluginEnable,St as pluginInstall,Et as pluginRemove,Ct as pluginUpdate,Rt as revalidateBundlePlugin,xt as validatePluginArchive};
|
|
13
|
+
`)}`,{issues:l,next:`Correct the package's memory documents, then retry \u2014 "${e.name}" was not activated.`})}return{docs:a.length,...o==="linked"?{linkedSource:Je(r)}:{}}}d(Mn,"migratePluginMemory");async function P(e,n,t,i,o,r,a="package"){try{en(e)}catch(f){const h=f instanceof Error?f.message:String(f);throw m(`plugin manifest at ${o} declares invalid memory_extensions: ${h}`)}if(Sn(e,o),qn(e,o),En(e,o),Tn(e,o),e.env!==void 0){const f=Me(e.env);if(f.length)throw m(`plugin manifest at ${o} declares an invalid env block:
|
|
14
|
+
${f.map(h=>`- ${h}`).join(`
|
|
15
|
+
`)}`,{issues:f})}const[l,c]=await Promise.all([I(),N()]),s=Q({name:e.name,scope:t,root:n,manifest:e,enabled:!0},new Set(D),l,c);if(s.issues.length>0)throw W(`plugin command behavior at ${o} is invalid`,s.issues);const u=s.manifest?.roots??[],y=bn(e,{name:e.name,leafPaths:wn(e.name,e,u),streamingLeafPaths:$n(e.name,e,u)});if(y.length>0)throw m(`plugin manifest at ${o} declares an invalid object_kinds or scopes block:
|
|
16
|
+
${y.map(f=>`- ${f}`).join(`
|
|
17
|
+
`)}`,{issues:y});await An(e,n,t,i,o,r);const p=v(n,"memory"),k=Xe(t,i,{candidate:e});for(const f of Ye(p,h=>h.endsWith(".md"),h=>h.startsWith("."))){let h;try{h=on(Ge(f)).data}catch(R){throw m(`plugin memory document ${L(n,f)} has invalid YAML frontmatter: ${R instanceof Error?R.message.split(`
|
|
18
|
+
`)[0]:String(R)}`)}const w=nn(h);if(w!==null)throw m(`plugin memory document ${L(n,f)} is invalid: ${w}`);for(const R of Ze(h?.extensions,k))throw m(`plugin memory document ${L(n,f)} is invalid: ${R.path}: ${R.message}`)}return Mn(e,n,t,o,a)}d(P,"assertPluginCandidateValid");function _n(e){return{kind:"http",endpoint:new URL(e.endpoint).origin,...e.authEnv!==void 0?{authEnv:e.authEnv}:{}}}d(_n,"invocationTransport");async function Ln(e,n,t,i,o){const r=await P(o,t,n,i,`${t}/.crouter-plugin/plugin.json`),a={name:e,scope:n,root:t,manifest:o,enabled:!0},[l,c]=await Promise.all([I(),N()]),s=Q(a,new Set(D),l,c);if(s.issues.length>0)throw W(`bundle staged package for "${e}" is invalid`,s.issues);return r}d(Ln,"validateStagedBundle");function ke(e){return e.sourceMarketplace!==void 0||Y(e.root)||O(e.root)}d(ke,"isSourceInstalled");function we(e){throw m(`HTTP plugin "${e}" uses the removed commands-only endpoint format`,{next:`Run \`crtr pkg plugin remove ${e}\`, then reinstall it with \`crtr pkg plugin install --name ${e} --endpoint <archive-url>\`.`})}d(we,"rejectLegacyHttpPlugin");function Bn(e,n,t){if(!$(t))return;const i=A(e,n);if(i?.manifest.bundle!==void 0)return i;throw i?.manifest.transport?.kind==="http"&&i!==void 0&&!ke(i)&&we(e),m(`plugin "${e}" already exists at ${t}; run \`crtr pkg plugin remove ${e}\` before installing the archive plugin.`)}d(Bn,"existingBundleRoot");function be(e,n,t,i){const o=ve(e,n.endpoint,n.authEnv),r={endpoint:o.endpoint,...o.authEnv!==void 0?{authEnv:o.authEnv}:{}},a=v(C(t),e);return Bn(e,t,a),{bundle:r,transport:_n(r),scopeRootPath:i,root:a}}d(be,"resolveBundleTarget");function $e(e,n){return{name:e,endpoint:n.endpoint,...n.authEnv!==void 0?{authEnv:n.authEnv}:{}}}d($e,"fetchTarget");const Hn=6e4,Dn=1e4;async function je(e,n,t,i){const o=n==="project"?z():S();return _(v(o,"tmp")),Ke(re(o,e),()=>i(o),{timeoutMs:t,timeoutError:d(()=>m(`timed out waiting for another crtr process to finish replacing plugin "${e}"`,{next:`Re-run once that process has finished, or check for a stalled crtr holding ${re(o,e)}.`}),"timeoutError")})}d(je,"withBundleSwapLock");async function Pe(e,n,t,i){return je(e,t,Hn,async o=>{const r=be(e,n,t,o),a=await me($e(e,r.bundle));if(a.status!==200){const l=`HTTP plugin bundle fetch failed for "${e}": ${a.message}`;throw a.status==="auth_env_missing"?b(l):a.status==="cli_unreachable"?He(l):m(l)}return Re(e,t,r,a.raw,a.etag,i)})}d(Pe,"replaceBundlePlugin");async function xt(e,n,t,i){return je(e,t,Dn,async o=>{try{const r=be(e,n,t,o),a=i.conditional?Ne(t).plugins[e]?.etag:void 0,l={...a!==void 0?{ifNoneMatch:a}:{},...i.timeoutMs!==void 0?{timeoutMs:i.timeoutMs}:{}},c=await me($e(e,r.bundle),l);if(c.status===304)return;if(c.status!==200)throw m(`HTTP plugin bundle revalidation failed for "${e}": ${c.message}`);const s=pn(c.raw);if(fn(e,t,r.root,s)){await hn(t,e,c.etag,{swapped:!1});return}return await Re(e,t,r,c.raw,c.etag,i,s)}finally{await In(t,e)}})}d(xt,"revalidateBundlePlugin");async function In(e,n){await V(e,t=>{t.plugins[n]===void 0&&(t.plugins[n]={}),t.plugins[n].checked_at=J()})}d(In,"recordPluginCheck");async function Re(e,n,t,i,o,r,a){const{bundle:l,transport:c,scopeRootPath:s,root:u}=t,y=await Nn(e,i,{scope:n,scopeRootPath:s,root:u,bundle:l,transport:c,etag:o,enable:r.enable,...a!==void 0?{version:a}:{}}),{validated:p,version:k,staged:f}=y,h=await X(e,n);if(h===void 0)throw m(`bundle plugin "${e}" has no staged command report`);const w=await Z(e,n);return{name:e,scope:n,path:u,transport:"http",version:k,docs:p.memory.length,kinds:Object.keys(p.kinds??{}).length,pageComponents:(p.page_components??[]).length,objectKinds:Object.keys(p.object_kinds??{}).length,scopes:(p.scopes??[]).length,commands:h,...w!==void 0?{hooks:w}:{},...f!==void 0?{memory:f}:{}}}d(Re,"applyBundleArchive");async function St(e){const[n,t]=await Promise.all([I(),N()]);return gn(e,{reservedCoreNames:new Set(D),coreCommandPaths:n,extensibleCoreBranches:t})}d(St,"validatePluginArchive");async function Nn(e,n,t){const[i,o]=await Promise.all([I(),N()]);return mn(e,n,{...t,validation:{reservedCoreNames:new Set(D),coreCommandPaths:i,extensibleCoreBranches:o},validateStaged:d((r,a)=>Ln(e,t.scope,r,t.scopeRootPath,a),"validateStaged"),invalid:d((r,a)=>W(r,a),"invalid")})}d(Nn,"installPluginArchive");async function Un(e,n,t,i){const o=ve(e,n,t);return Pe(e,{endpoint:o.endpoint,...o.authEnv!==void 0?{authEnv:o.authEnv}:{}},i,{enable:!0})}d(Un,"installHttpPlugin");function Fn(e){if(e.startsWith("./")||e.startsWith("../")||e.startsWith("/"))return{kind:"local",value:e};if(he(e))return{kind:"git",value:e};const n=e.split("/");if(n.length===2&&n[0]!==""&&n[1]!=="")return{kind:"marketplace",value:{marketplace:n[0],plugin:n[1]}};throw b(`invalid plugin install ref: ${e}
|
|
19
|
+
Accepted forms: marketplace/plugin, git URL (https://, ssh://, git@, file://, or *.git), or local path starting ./, ../, or /. Bare plugin names are not install refs.`)}d(Fn,"classifyInstallRef");function xe(e){return e.startsWith("./")||e.startsWith("../")||!_e(e)&&!he(e)}d(xe,"isMarketplaceRelativeSource");async function Se(e,n,t){const i=n.get(e);if(i!==void 0)return i;const o=Ie(e);if(o===null){if(t.strict)throw g(`marketplace not found: ${e}`);return null}const r=ce(o.root);if(r===null)throw g(`marketplace manifest not found: ${o.root}/.crouter-marketplace/marketplace.json`);if(!Y(o.root)){const s={marketplace:o,manifest:r,pull:{updated:!1,sha:T(o.root)??""}};return n.set(e,s),s}const a=T(o.root),l=v(te(o.root),`.${e}.${process.pid}.${Date.now()}.candidate`),c=`${l}.previous`;try{K(o.url,l,{ref:o.ref,depth:1});const s=ce(l);if(s===null)throw g(`marketplace manifest not found in candidate checkout: ${l}/.crouter-marketplace/marketplace.json`);const u=ie().filter(p=>p.sourceMarketplace===e&&O(p.root));for(const p of u){const k=s.plugins.find(Ae=>Ae.name===p.name);if(k===void 0||!xe(k.source))throw m(`marketplace candidate removes relative-source plugin "${p.name}" while it is installed`);const f=ze(p.root);if(f===null)throw m(`installed marketplace plugin "${p.name}" has no readable symlink target`);const h=L(o.root,F(te(p.root),f)),w=F(l,k.source);if(w!==F(l,h))throw m(`marketplace candidate moves installed relative-source plugin "${p.name}" from ${h} to ${k.source}`);if(!$(w))throw g(`marketplace candidate source path does not exist for plugin "${p.name}": ${w}`);const R=x(w);if(R===null)throw g(`plugin manifest not found in marketplace candidate: ${w}/.crouter-plugin/plugin.json`);const qe=p.scope==="project"?M("project"):S();await P(R,w,p.scope,qe,`${w}/.crouter-plugin/plugin.json`)}j(o.root,c);try{j(l,o.root)}catch(p){throw j(c,o.root),p}E(c);for(const p of u){const k=s.plugins.find(f=>f.name===p.name);await Ee(p.scope,p.name,k.version??p.manifest.version)}await V(o.scope,p=>{p.marketplaces[e]===void 0&&(p.marketplaces[e]={}),p.marketplaces[e].last_updated=J()});const y={marketplace:o,manifest:s,pull:{updated:a!==T(o.root),sha:T(o.root)??""}};return n.set(e,y),y}finally{E(l),$(c)&&!$(o.root)&&j(c,o.root)}}d(Se,"refreshMarketplace");async function Ee(e,n,t){await H(e,i=>{const o=i.plugins[n];o!==void 0?t!==void 0&&(o.version=t):i.plugins[n]={enabled:!0,version:t}}),await V(e,i=>{i.plugins[n]===void 0&&(i.plugins[n]={}),i.plugins[n].last_updated=J()})}d(Ee,"updatePluginVersion");async function Vn(e,n,t){const i=t==="project"?z():S();await G(t,i);const o=C(t),r=Qe(e),a=v(i,"tmp",`${r}.${process.pid}.${Date.now()}`);_(v(i,"tmp"));try{K(e,a,{ref:n,depth:1});const l=x(a);if(l===null)throw m(`cloned repo does not contain a valid .crouter-plugin/plugin.json: ${e}`);const c=await P(l,a,t,i,`${e}/.crouter-plugin/plugin.json`),s=v(o,l.name);if($(s))throw m(`plugin "${l.name}" is already installed at ${s}`);return _(o),j(a,s),await H(t,u=>{u.plugins[l.name]={enabled:!0,version:l.version}}),{name:l.name,scope:t,path:s,...c!==void 0?{memory:c}:{}}}finally{E(a)}}d(Vn,"installFromGit");async function On(e,n){const t=F(e),i=x(t);if(i===null)throw g(`plugin manifest not found at ${t}/.crouter-plugin/plugin.json`);const o=n==="project"?z():S(),r=await P(i,t,n,o,`${t}/.crouter-plugin/plugin.json`,void 0,"linked");await G(n,o);const a=v(C(n),i.name);if($(a))throw m(`plugin "${i.name}" is already installed at ${a}`);return se(t,a),await H(n,l=>{l.plugins[i.name]={enabled:!0,version:i.version}}),{name:i.name,scope:n,path:a,...r!==void 0?{memory:r}:{}}}d(On,"installFromLocal");async function Kn(e,n){const t=await Se(e.marketplace,new Map,{strict:!0});if(t===null)throw g(`marketplace not found: ${e.marketplace}`);const i=t.manifest.plugins.find(s=>s.name===e.plugin);if(i===void 0)throw g(`plugin "${e.plugin}" not found in marketplace "${e.marketplace}"`);const o=M(n);await G(n,o);const r=v(C(n),e.plugin);if($(r))throw m(`plugin "${e.plugin}" is already installed at ${r}`);let a,l;if(xe(i.source)){const s=v(t.marketplace.root,i.source);if(!$(s))throw g(`plugin source path does not exist: ${s}`);const u=x(s);if(u===null)throw g(`plugin manifest not found at ${s}/.crouter-plugin/plugin.json`);l=await P(u,s,n,o,`${s}/.crouter-plugin/plugin.json`,void 0,"linked"),se(s,r),a=u}else{const s=v(o,"tmp",`${e.plugin}.${process.pid}.${Date.now()}`);_(v(o,"tmp"));try{K(i.source,s,{depth:1});const u=x(s);if(u===null)throw g(`plugin manifest not found at ${s}/.crouter-plugin/plugin.json`);l=await P(u,s,n,o,`${s}/.crouter-plugin/plugin.json`),_(C(n)),j(s,r),a=u}finally{E(s)}}const c=i.version??a.version;return await H(n,s=>{const u={enabled:!0,source_marketplace:e.marketplace};c!==void 0&&(u.version=c),s.plugins[e.plugin]=u}),{name:e.plugin,scope:n,path:r,...l!==void 0?{memory:l}:{}}}d(Kn,"installFromMarketplace");async function Wn(e){if(O(e.root)){const l=x(e.root);if(l===null)throw g(`plugin manifest not found at ${e.root}/.crouter-plugin/plugin.json`);const c=e.scope==="project"?M("project"):S(),s=await P(l,e.root,e.scope,c,`${e.root}/.crouter-plugin/plugin.json`,void 0,"linked");return{updated:!1,sha:T(e.root)??"",manifest:l,...s!==void 0?{memory:s}:{}}}if(!Y(e.root)){const l=x(e.root);if(l===null)throw g(`plugin manifest not found at ${e.root}/.crouter-plugin/plugin.json`);const c=e.scope==="project"?M("project"):S(),s=await P(l,e.root,e.scope,c,`${e.root}/.crouter-plugin/plugin.json`);return{updated:!1,sha:"",manifest:l,...s!==void 0?{memory:s}:{}}}const n=le(["config","--get","remote.origin.url"],e.root).stdout.trim();if(n==="")throw m(`plugin "${e.name}" has no origin remote to stage an update from`);const t=le(["symbolic-ref","--short","HEAD"],e.root).stdout.trim();if(t==="")throw m(`plugin "${e.name}" is detached at its installed revision and has no tracked branch to update`);const i=e.scope==="project"?M("project"):S(),o=v(i,"tmp",`${e.name}.${process.pid}.${Date.now()}.candidate`),r=`${o}.previous`,a=T(e.root);_(v(i,"tmp"));try{K(n,o,{ref:t,depth:1});const l=x(o);if(l===null)throw g(`plugin manifest not found in update candidate: ${o}/.crouter-plugin/plugin.json`);const c=await P(l,o,e.scope,i,`${o}/.crouter-plugin/plugin.json`);j(e.root,r);try{j(o,e.root)}catch(u){throw j(r,e.root),u}E(r);const s=T(e.root)??"";return{updated:a!==s,sha:s,manifest:l,...c!==void 0?{memory:c}:{}}}finally{E(o),$(r)&&!$(e.root)&&j(r,e.root)}}d(Wn,"updateGitPluginCandidate");async function Te(e,n,t){if(e.manifest.provider!==void 0)return{name:e.name,transport:"http",updated:!1,warnings:[`"${e.name}" is a capability provider bundle; the runtime refreshes it on grant sync`]};const i=ke(e);if(!i&&e.manifest.bundle!==void 0){const u=await Pe(e.name,e.manifest.bundle,e.scope,{enable:e.enabled});return{name:e.name,transport:"http",updated:!0,version:u.version,docs:u.docs,kinds:u.kinds,pageComponents:u.pageComponents,objectKinds:u.objectKinds,scopes:u.scopes,commands:u.commands,...u.hooks!==void 0?{hooks:u.hooks}:{},...u.memory!==void 0?{memory:u.memory}:{}}}e.manifest.transport?.kind==="http"&&!i&&we(e.name);let o,r=!1;if(e.sourceMarketplace!==void 0){const u=await Se(e.sourceMarketplace,n,t);u!==null&&(o=u.manifest.plugins.find(p=>p.name===e.name)?.version,r=u.pull.updated)}const a=await Wn(e);await Ee(e.scope,e.name,o??a.manifest.version);const l=await X(e.name,e.scope),c=await Z(e.name,e.scope),s=[...ye(a.manifest),...await ne(a.manifest)];return{name:e.name,...e.manifest.transport!==void 0?{transport:e.manifest.transport.kind==="machine"?"http":e.manifest.transport.kind}:{},updated:r||a.updated,sha:a.sha,...l!==void 0?{commands:l}:{},...c!==void 0?{hooks:c}:{},...a.memory!==void 0?{memory:a.memory}:{},...s.length>0?{warnings:s}:{}}}d(Te,"updateOnePlugin");async function q(e){const n=await Le().documents.reconcilePackages().catch(i=>Be(i)),t=n.conflicts.find(i=>i.plugin===e);if(t)throw new De("conflict",`plugin "${e}" is installed but its documents are not on the canvas: ${t.message}`,jn.GENERAL,{plugin:e,next:"Uninstall the other package providing that plugin name, then run `crtr pkg plugin update --name "+e+"`."});return n}d(q,"reconcilePluginDocuments");function zn(e,n){const t=[...(e.kinds?.refused??[]).filter(o=>o.plugin===n).map(o=>`object kind ${o.kind} not registered: ${o.message}`),...(e.kinds?.invalid??[]).filter(o=>o.plugin===n).map(o=>`object kinds and scopes not applied; the plugin holds no app token until this is fixed: ${o.error}`)],i=e.tokens?.granted.find(o=>o.plugin===n);return{warnings:t,...i!==void 0?{appScopes:i.scopes}:{}}}d(zn,"pluginObjectReport");function U(e,n,t){const{warnings:i,appScopes:o}=zn(n,t),a=[...e.warnings??[],...i];return{...e,...a.length>0?{warnings:a}:{},...o!==void 0?{appScopes:o}:{}}}d(U,"withObjectReport");const Et=B({name:"install",description:"install from a ref or HTTP endpoint",whenToUse:"installing one plugin from a marketplace ref, git URL, local path, or an HTTP directory-archive endpoint",help:{name:"pkg plugin install",summary:"install a plugin from a ref or HTTP endpoint",params:[{kind:"positional",name:"install-ref",type:"string",required:!1,constraint:"Plugin install ref. Provide exactly one of INSTALL-REF or --endpoint. Accepted ref forms: marketplace/plugin; git URL starting https://, ssh://, git@, file://, or ending .git; local path starting ./, ../, or /."},{kind:"flag",name:"endpoint",type:"string",required:!1,constraint:"HTTP plugin directory-archive endpoint. Provide exactly one of --endpoint or INSTALL-REF. Must be an absolute https: URL; http: is permitted only for localhost, any *.localhost host, 127.0.0.1, [::1], ::1, or host.docker.internal. Credentials and fragments are rejected."},{kind:"flag",name:"name",type:"string",required:!1,constraint:"Required with --endpoint and rejected without it. Lowercase kebab-case plugin handle."},{kind:"flag",name:"auth-env",type:"string",required:!1,constraint:"Optional environment variable holding the HTTP bearer token. Accepted only with --endpoint; its value is never stored."},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Default: project if available, else user."},{kind:"flag",name:"ref",type:"string",required:!1,constraint:"Git ref (branch/tag) for git URL installs. Rejected with --endpoint; ignored for marketplace and local path refs."}],output:[{name:"name",type:"string",required:!0,constraint:"Plugin name as installed."},{name:"scope",type:"string",required:!0,constraint:"Scope the plugin was installed into."},{name:"path",type:"string",required:!0,constraint:"Absolute path to the installed plugin directory."},{name:"transport",type:"string",required:!1,constraint:"exec or http when the plugin declares commands. Always http for an --endpoint install."},{name:"version",type:"string",required:!1,constraint:"First 12 hex characters of the fetched archive SHA-256 for an --endpoint install."},{name:"docs",type:"integer",required:!1,constraint:"Memory document count written from an --endpoint archive."},{name:"kinds",type:"integer",required:!1,constraint:"Kind-registry entry count declared by an --endpoint archive\u2019s bundle.json."},{name:"pageComponents",type:"integer",required:!1,constraint:"Page-component registration count declared by an --endpoint archive\u2019s bundle.json."},{name:"commands",type:"object",required:!1,constraint:"Present only when the plugin declares a command manifest. {mounts: string[] (accepted command paths now live for the next invocation), issues: object[] (typed validation issues that rejected a contribution \u2014 {code, path?, message, received, expected, next})}. Validated statically; commands are never executed."},{name:"hooks",type:"object",required:!1,constraint:"Present only when the plugin declares hooks. {manifestPath?, executablePath?, declarations: {target, phase, op, description, effects}[], lifecycle?: {event, phase, op, description, effects}[], issues: object[], trust: string}. Command targets, lifecycle events, and replacement collisions are validated statically; hook executables are never run."},{name:"objectKinds",type:"integer",required:!1,constraint:"Canvas object kind count declared by an --endpoint archive\u2019s bundle.json `object_kinds` block."},{name:"scopes",type:"integer",required:!1,constraint:"Canvas scope count declared by an --endpoint archive\u2019s bundle.json `scopes` block."},{name:"appScopes",type:"string[]",required:!1,constraint:"Present when the plugin holds an app token after install: the canvas scopes that token carries (the manifest `scopes`; empty for a plugin that declares kinds or serves over HTTP but asks for none)."},{name:"warnings",type:"string[]",required:!1,constraint:"Advisory missing PATH executable requirements declared by the installed plugin, kinds another owner already holds (`object kind <kind> not registered`), and an invalid `object_kinds`/`scopes` block that leaves the plugin without an app token. The install still succeeds and leaves the plugin enabled."},{name:"memory",type:"object",required:!1,constraint:"Present only when the plugin ships documents (its `memory/` folder). {docs: integer (documents checked), linkedSource?: string (the caller-owned directory, present only when the install keeps that directory as a live link)}."}],outputKind:"object",effects:["A ref install clones, links, or copies the plugin into the scope plugins directory and registers it with enabled=true. Marketplace installs refresh the source marketplace before resolving the plugin entry.","An --endpoint install fetches and validates one authenticated uncompressed tar archive before writing. It replaces the complete plugin directory with synthesized provenance and invocation metadata, commands.json, memory docs, and, when declared, hooks.json plus the hooks/ tree; it also copies any kind-registry entries the bundle.json declares (they join the launch registry below this scope\u2019s own config.json kinds), and any page components it declares (they join the active page-component catalog alongside the user config entries); a fetch or validation failure preserves the prior package.","If the plugin declares a command manifest, its commands go live on the next crtr invocation. Exec commands run trusted local code only when explicitly invoked; HTTP commands call their declared endpoint only when explicitly invoked.","Plugin command hooks go live on the next crtr invocation. They run implicitly with caller authority, may receive normalized inputs and after results, may block or replace declared targets, and may transmit received data. Lifecycle hooks run unprompted at every declared event before node launch and may transmit node identity and resolved paths. Hook executables are never run during install or update validation.","A plugin manifest `requires` declaration is checked against the PATH a node bash receives after install. Missing executables emit a warning with the declared install hint but never fail the install, disable the plugin, or remove its bare-binary contributions.","Before activation the candidate\u2019s `memory/` documents are checked for identity findings and refused if it cannot mount; a local path or marketplace-relative source stays a live link, named as `memory.linkedSource`. A refused package installs nothing."]},run:d(async e=>{const n=e.installRef,t=e.endpoint,i=e.name,o=e.authEnv,r=e.scope,a=e.ref,l=Rn(r);if(n===void 0==(t===void 0))throw b("provide exactly one of INSTALL-REF or --endpoint");if(t!==void 0){if(i===void 0)throw b("--name is required with --endpoint");if(a!==void 0)throw b("--ref is only valid with a git INSTALL-REF, not --endpoint");const h=await Un(i,t,o,l);return U(h,await q(i),i)}if(i!==void 0)throw b("--name is only valid with --endpoint");if(o!==void 0)throw b("--auth-env is only valid with --endpoint");const c=Fn(n),s=c.kind==="marketplace"?await Kn(c.value,l):c.kind==="local"?await On(c.value,l):await Vn(c.value,a,l),u=A(s.name,s.scope),y=await X(s.name,s.scope),p=await Z(s.name,s.scope),k=u===null?[]:[...ye(u.manifest),...await ne(u.manifest)],f=await q(s.name);return U({...s,...u?.manifest.transport!==void 0?{transport:u.manifest.transport.kind}:{},...y!==void 0?{commands:y}:{},...p!==void 0?{hooks:p}:{},...k.length>0?{warnings:k}:{}},f,s.name)},"run")}),Tt=B({name:"remove",description:"remove plugin and directory",whenToUse:"uninstalling a plugin: deletes its directory and removes it from config",help:{name:"pkg plugin remove",summary:"remove a plugin and its directory from the given scope",params:[{kind:"positional",name:"name",type:"string",required:!0,constraint:"Plugin name to remove."},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Default: searches every scope."}],output:[{name:"scopes",type:"string[]",required:!0,constraint:"Scopes the plugin was removed from."}],outputKind:"object",effects:["Deletes the plugin directory. Removes the plugin entry from config.json."]},run:d(async e=>{const n=e.name,t=e.scope;if(n==="crtr")throw b('cannot remove builtin plugin "crtr" \u2014 it ships with the binary');let i;if(t!==void 0){const r=oe(t);if(r==="builtin")throw b("cannot remove plugins from builtin scope");i=r==="all"?["project","user"].filter(a=>a!=="project"||ae()!==null):[r]}else i=["project","user"].filter(r=>r!=="project"||ae()!==null);const o=[];for(const r of i){const a=C(r);if(a===null)continue;const l=v(a,n);$(l)&&(E(l),await H(r,c=>{delete c.plugins[n]}),await V(r,c=>{delete c.plugins[n]}),o.push(r))}if(o.length===0)throw g(`plugin not found: ${n}`);return await q(),{scopes:o}},"run")}),qt=B({name:"enable",description:"enable a plugin",whenToUse:"reactivating a plugin that was previously disabled so its memory docs resolve again",help:{name:"pkg plugin enable",summary:"enable a plugin in the given scope",params:[{kind:"positional",name:"name",type:"string",required:!0,constraint:"Plugin name to enable."},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Default: scope where the plugin is installed."}],output:[{name:"scope",type:"string",required:!0,constraint:"Scope the change was applied in."},{name:"memory",type:"object",required:!1,constraint:"Present only when the plugin ships documents (its `memory/` folder). {docs: integer (documents checked), linkedSource?: string (the caller-owned directory, present only for a symlinked install)}."},{name:"appScopes",type:"string[]",required:!1,constraint:"Present when the plugin holds an app token: the canvas scopes it carries."},{name:"warnings",type:"string[]",required:!1,constraint:"Kinds another owner holds, or an invalid `object_kinds`/`scopes` block. Enabling still succeeds."}],outputKind:"object",effects:["Validates the installed package before any config change: its `memory/` documents are checked for identity findings and refused if it cannot mount. A refusal leaves the plugin disabled.","Sets plugin enabled=true in config.json."]},run:d(async e=>{const n=e.name,t=Pn(n,e.scope);if(t===null)throw g(`plugin not found: ${n}`);const i=x(t.root);if(i===null)throw g(`plugin manifest not found at ${t.root}/.crouter-plugin/plugin.json`);const o=t.scope==="project"?M("project"):S(),r=await P(i,t.root,t.scope,o,`${t.root}/.crouter-plugin/plugin.json`,void 0,O(t.root)?"linked":"package"),a=await ge(e,!0),l=await q(n);return U({scope:a.scope,...r!==void 0?{memory:r}:{}},l,n)},"run")}),At=B({name:"disable",description:"disable without removing",whenToUse:"hiding a plugin from resolution without deleting it, so you can re-enable it later",help:{name:"pkg plugin disable",summary:"disable a plugin (keeps files, hides from resolution)",params:[{kind:"positional",name:"name",type:"string",required:!0,constraint:"Plugin name to disable."},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Default: scope where the plugin is installed."}],output:[{name:"scope",type:"string",required:!0,constraint:"Scope the change was applied in."}],outputKind:"object",effects:["Sets plugin enabled=false in config.json."]},run:d(async e=>{const n=await ge(e,!1);return await q(),{scope:n.scope}},"run")}),Ct=B({name:"update",description:"update installed plugin content",whenToUse:"refreshing one named plugin or all installed plugins: archive plugins replace their complete package, while source-installed plugins retain their source update behavior",help:{name:"pkg plugin update",summary:"refresh one or all installed plugins",params:[{kind:"flag",name:"name",type:"string",required:!1,constraint:"Plugin name to update. Omit to update all installed plugins."},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Narrows resolution."}],output:[{name:"updated",type:"object[]",required:!0,constraint:"One entry per plugin processed: {name, transport?, updated, sha?, version?, docs?, kinds?, pageComponents?, commands?, hooks?, memory?, warnings?, error?}. memory is present for a plugin shipping documents and reports the same memory check install performs: {docs, linkedSource?}. Archive plugins report transport=http and replace their complete directory after an authenticated refetch; version is the archive content identifier, docs is the written memory-document count, kinds is the declared kind-registry entry count, pageComponents is the declared page-component registration count, objectKinds is the declared canvas object kind count, and scopes is the declared canvas scope count. appScopes lists the scopes the plugin\u2019s app token carries after the update. sha is present for git updates. A bulk update reports and skips a failed archive plugin. commands is present for validated command plugins: {mounts: string[] (accepted command paths), issues: object[]}. hooks is present for plugins declaring hooks: {manifestPath?, executablePath?, declarations: {target, phase, op, description, effects}[], lifecycle?: {event, phase, op, description, effects}[], issues: object[], trust: string}; it is static and never executes hooks. warnings lists advisory PATH requirements that remain absent after update, kinds another owner holds, and an invalid object_kinds/scopes block."}],outputKind:"object",effects:["Archive plugins unconditionally re-fetch, validate, and replace their complete package; a named failure exits nonzero and preserves the prior package. Bulk update reports a failed archive plugin and continues. Source-installed plugins retain their source update, version, and last_updated behavior.","A capability provider bundle (installed by the runtime from the directory) is skipped with a warning: the runtime refreshes it on grant sync.","Each candidate passes the same pre-activation memory check install performs."]},run:d(async e=>{const n=e.name,t=e.scope,i=t===void 0?void 0:oe(t),o=new Map;if(n!==void 0){const c=i===void 0||i==="all"||i==="builtin"?A(n):A(n,i);if(c===null)throw g(`plugin not found: ${n}${i===void 0||i==="all"||i==="builtin"?"":` (scope: ${i})`}`);const s=await Te(c,o,{strict:!0}),u=await q(n);return{updated:[U(s,u,s.name)]}}const r=ie().filter(c=>c.scope!=="builtin"&&(i===void 0||i==="all"||c.scope===i)),a=[];for(const c of r)try{a.push(await Te(c,o,{strict:!1}))}catch(s){a.push({name:c.name,...c.manifest.transport!==void 0?{transport:c.manifest.transport.kind}:{},updated:!1,error:s instanceof Error?s.message:String(s)})}const l=await q();return{updated:a.map(c=>c.error===void 0?U(c,l,c.name):c)}},"run")});export{P as assertPluginCandidateValid,Kn as installFromMarketplace,Nn as installPluginArchive,xe as isMarketplaceRelativeSource,At as pluginDisable,qt as pluginEnable,Et as pluginInstall,Tt as pluginRemove,Ct as pluginUpdate,xt as revalidateBundlePlugin,St as validatePluginArchive};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var c=Object.defineProperty;var s=(e,o)=>c(e,"name",{value:o,configurable:!0});import{join as f}from"node:path";import{notFound as
|
|
1
|
+
var c=Object.defineProperty;var s=(e,o)=>c(e,"name",{value:o,configurable:!0});import{join as f}from"node:path";import{notFound as a,usage as u}from"../../core/errors.js";import{resolveScopeArg as p,pluginsDir as g,projectScopeRoot as l}from"../../core/scope.js";import{updateConfig as d}from"../../core/config.js";import{pathExists as m}from"../../core/fs-utils.js";const j=/^(https?:\/\/|git@|ssh:\/\/|file:\/\/)/;function R(e){return j.test(e)||e.endsWith(".git")}s(R,"isGitUrl");function S(e){if(e!==void 0){const o=p(e);if(o==="all"||o==="builtin")throw u('scope must be "user" or "project"');return o}return l()!==null?"project":"user"}s(S,"resolveInstallScope");function h(e,o){let n;if(o!==void 0){const t=p(o);if(t==="builtin")throw u("cannot enable/disable plugins in builtin scope");n=t==="all"?["project","user"].filter(r=>r!=="project"||l()!==null):[t]}else n=["project","user"].filter(t=>t!=="project"||l()!==null);for(const t of n){const r=g(t);if(r===null)continue;const i=f(r,e);if(m(i))return{scope:t,root:i}}return null}s(h,"resolvePluginConfigTarget");async function y(e,o){const n=e.name,t=h(n,e.scope);if(t===null)throw a(`plugin not found: ${n}`);return await d(t.scope,r=>{const i=r.plugins[n];i!==void 0?i.enabled=o:r.plugins[n]={enabled:o}}),{name:n,scope:t.scope,enabled:o}}s(y,"setPluginEnabled");export{j as GIT_URL_RE,R as isGitUrl,S as resolveInstallScope,h as resolvePluginConfigTarget,y as setPluginEnabled};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var c=Object.defineProperty;var o=(r,e)=>c(r,"name",{value:e,configurable:!0});import{defineLeaf as s,defineBranch as f}from"../../core/command.js";import{InputError as d}from"../../core/io.js";import{loadProfileManifest as l,resolveProfileOperand as u}from"../../core/profiles/manifest.js";import{profileCoversCwd as h}from"../../core/profiles/select.js";import{existsSync as m}from"node:fs";import{getDefaultProfileId as p,setDefaultProfileId as y,clearDefaultProfile as w,clearMissingDefaultDirs as g,listDefaultPins as v,resolveBindingCwd as a}from"../../core/profiles/default-binding.js";const x=s({name:"set",description:"pin a profile as the default for the current directory",whenToUse:"you want crtr to stop asking which profile to use here and always default to a chosen one \u2014 the command form of the startup menu\u2019s `d` action. The profile must already cover this directory (add its purview relationship with `profile project add --dir` first if not).",help:{name:"profile default set",summary:"pin a profile as the current directory's default, so the startup chooser stops asking",params:[{kind:"positional",name:"profile",required:!0,constraint:"Profile id or manifest name; a close-enough name resolves to the nearest profile, reported on stderr. Must already cover the current directory (be at/above/below it in its project purview); this pin does not change automatic document delivery limits."}],output:[{name:"dir",type:"string",required:!0,constraint:"The resolved directory the pin was set for."},{name:"profile_id",type:"string",required:!0,constraint:"The pinned profile id."},{name:"name",type:"string",required:!0,constraint:"The pinned profile name."},{name:"follow_up",type:"string",required:!0,constraint:"The resulting ambient effect."}],outputKind:"object",effects:["Writes this directory's pin into `~/.crouter/profile-defaults.json`. The next launch here auto-picks this profile with no prompt (override once with `crtr --pick-profile`)."]},run:o(async r=>{const e=process.cwd(),t=a(e),i=u(r.profile);if(!h(i,t))throw new d({error:"not_covered",message:`profile "${i.manifest.name}" does not cover ${t}, so a default pinned here would be ignored.`,next:`Widen its purview first: \`crtr profile project add ${i.profileId} --dir ${t}\`, then re-run this.`});return y(e,i.profileId),{dir:t,profile_id:i.profileId,name:i.manifest.name,follow_up:`Launches here now auto-pick "${i.manifest.name}".`}},"run")}),_=s({name:"clear",description:"remove the current directory's default-profile pin",whenToUse:"you no longer want a fixed default here \u2014 go back to the normal startup chooser (MRU / covering menu). No-op if nothing was pinned.",help:{name:"profile default clear",summary:"remove a directory's default-profile pin \u2014 the current directory's, or any path with --dir, or every pin whose directory is gone with --missing",params:[{kind:"flag",name:"dir",type:"string",required:!1,constraint:"Directory whose pin to clear instead of the current one. It need not exist any more \u2014 a pin for a deleted directory is addressed by the path it was set with (a symlinked path that still exists resolves to its real path, as `set` stored it)."},{kind:"flag",name:"missing",type:"bool",required:!1,constraint:"Clear every pin whose directory no longer exists on disk, in one write. Used alone."}],output:[{name:"dir",type:"string",required:!1,constraint:"The resolved directory the pin was cleared for; absent with --missing."},{name:"cleared",type:"boolean",required:!0,constraint:"True when a pin existed and was removed; false when nothing was pinned."},{name:"cleared_dirs",type:"array",required:!1,constraint:"With --missing: each removed pin as {dir, profile_id}."},{name:"follow_up",type:"string",required:!0,constraint:"Concrete next commands."}],outputKind:"object",effects:["Deletes the directory's pin from the user-root profile-defaults state, if present. `--missing` deletes every pin whose directory no longer exists."]},run:o(async r=>{if(r.missing===!0){if(r.dir!==void 0)throw new d({error:"missing_not_exclusive",message:"--missing cannot be combined with --dir",field:"missing",next:"Pass --missing alone."});const n=g();return{cleared:n.length>0,cleared_dirs:n,follow_up:n.length>0?`Cleared ${n.length} pin(s) whose directory no longer exists.`:"Every pinned directory still exists."}}const e=r.dir??process.cwd(),t=a(e),i=p(e)!==null;return w(e),{dir:t,cleared:i,follow_up:i?"The startup chooser will ask again here. Re-pin with `crtr profile default set <profile>`.":"Nothing was pinned here."}},"run")}),b=s({name:"show",description:"show the current directory's default-profile pin",whenToUse:"you want to know which profile (if any) is pinned as this directory's default.",help:{name:"profile default show",summary:"report the current directory's pinned default profile, or none; --dir asks about another path",params:[{kind:"flag",name:"dir",type:"string",required:!1,constraint:"Directory whose pin to report instead of the current one. It need not exist any more \u2014 a pin for a deleted directory is addressed by the path it was set with (a symlinked path that still exists resolves to its real path, as `set` stored it)."}],output:[{name:"dir",type:"string",required:!0,constraint:"The resolved directory queried."},{name:"pinned",type:"boolean",required:!0,constraint:"True when a default is pinned here."},{name:"profile_id",type:"string",required:!1,constraint:"The pinned profile id, when pinned."},{name:"name",type:"string",required:!1,constraint:"The pinned profile name, when it still resolves."},{name:"stale",type:"boolean",required:!1,constraint:"True when a pin exists but its profile no longer resolves (deleted); the selector will self-heal it on next launch."},{name:"follow_up",type:"string",required:!0,constraint:"Concrete next commands."}],outputKind:"object",effects:["Read-only."]},run:o(async r=>{const e=r.dir??process.cwd(),t=a(e),i=p(e);if(i===null)return{dir:t,pinned:!1,follow_up:"Pin one with `crtr profile default set <profile>`."};let n;try{n=l(i).manifest.name}catch{n=void 0}return{dir:t,pinned:!0,profile_id:i,...n!==void 0?{name:n}:{stale:!0},follow_up:n!==void 0?"Change it with `crtr profile default set <profile>`, or clear it with `crtr profile default clear`.":"This profile no longer exists; clear the stale pin with `crtr profile default clear`."}},"run")}),T=s({name:"list",description:"list every directory pinned to a default profile",whenToUse:"you want to see all default-profile pins at once \u2014 including pins for directories that no longer exist \u2014 before clearing stale ones with `profile default clear --dir <path>` or `--missing`.",help:{name:"profile default list",summary:"every directory \u2192 default profile pin, with whether the directory and the profile still exist",params:[],output:[{name:"pins",type:"array",required:!0,constraint:"Each pin as {dir, profile_id, name?, dir_exists, profile_exists}, sorted by dir."}],outputKind:"object",effects:["Read-only."]},run:o(async()=>({pins:v().map(r=>{let e;try{e=l(r.profileId).manifest.name}catch{e=void 0}return{dir:r.dir,profile_id:r.profileId,...e!==void 0?{name:e}:{},dir_exists:m(r.dir),profile_exists:e!==void 0}})}),"run"),render:o(r=>{const e=r.pins;return e.length===0?"No default-profile pins.":e.map(t=>`${t.dir} \u2192 ${t.name??t.profile_id}${t.dir_exists?"":" [directory missing]"}${t.profile_exists?"":" [profile missing]"}`).join(`
|
|
1
|
+
var c=Object.defineProperty;var o=(r,e)=>c(r,"name",{value:e,configurable:!0});import{defineLeaf as s,defineBranch as f}from"../../core/command.js";import{InputError as d}from"../../core/io.js";import{loadProfileManifest as l,resolveProfileOperand as u}from"../../core/profiles/manifest.js";import{profileCoversCwd as h}from"../../core/profiles/select.js";import{existsSync as m}from"node:fs";import{getDefaultProfileId as p,setDefaultProfileId as y,clearDefaultProfile as w,clearMissingDefaultDirs as g,listDefaultPins as v,resolveBindingCwd as a}from"../../core/profiles/default-binding.js";const x=s({name:"set",description:"pin a profile as the default for the current directory",whenToUse:"you want crtr to stop asking which profile to use here and always default to a chosen one \u2014 the command form of the startup menu\u2019s `d` action. The profile must already cover this directory (add its purview relationship with `profile project add --dir` first if not).",help:{name:"profile default set",summary:"pin a profile as the current directory's default, so the startup chooser stops asking",params:[{kind:"positional",name:"profile",required:!0,constraint:"Profile id or manifest name; a close-enough name resolves to the nearest profile, reported on stderr. Must already cover the current directory (be at/above/below it in its project purview); this pin does not change automatic document delivery limits."}],output:[{name:"dir",type:"string",required:!0,constraint:"The resolved directory the pin was set for."},{name:"profile_id",type:"string",required:!0,constraint:"The pinned profile id."},{name:"name",type:"string",required:!0,constraint:"The pinned profile name."},{name:"follow_up",type:"string",required:!0,constraint:"The resulting ambient effect."}],outputKind:"object",effects:["Writes this directory's pin into `~/.crouter/profile-defaults.json`. The next launch here auto-picks this profile with no prompt (override once with `crtr --pick-profile`)."]},run:o(async r=>{const e=process.cwd(),t=a(e),i=u(r.profile);if(!h(i,t))throw new d({error:"not_covered",message:`profile "${i.manifest.name}" does not cover ${t}, so a default pinned here would be ignored.`,next:`Widen its purview first: \`crtr profile project add ${i.profileId} --dir ${t}\`, then re-run this.`});return await y(e,i.profileId),{dir:t,profile_id:i.profileId,name:i.manifest.name,follow_up:`Launches here now auto-pick "${i.manifest.name}".`}},"run")}),_=s({name:"clear",description:"remove the current directory's default-profile pin",whenToUse:"you no longer want a fixed default here \u2014 go back to the normal startup chooser (MRU / covering menu). No-op if nothing was pinned.",help:{name:"profile default clear",summary:"remove a directory's default-profile pin \u2014 the current directory's, or any path with --dir, or every pin whose directory is gone with --missing",params:[{kind:"flag",name:"dir",type:"string",required:!1,constraint:"Directory whose pin to clear instead of the current one. It need not exist any more \u2014 a pin for a deleted directory is addressed by the path it was set with (a symlinked path that still exists resolves to its real path, as `set` stored it)."},{kind:"flag",name:"missing",type:"bool",required:!1,constraint:"Clear every pin whose directory no longer exists on disk, in one write. Used alone."}],output:[{name:"dir",type:"string",required:!1,constraint:"The resolved directory the pin was cleared for; absent with --missing."},{name:"cleared",type:"boolean",required:!0,constraint:"True when a pin existed and was removed; false when nothing was pinned."},{name:"cleared_dirs",type:"array",required:!1,constraint:"With --missing: each removed pin as {dir, profile_id}."},{name:"follow_up",type:"string",required:!0,constraint:"Concrete next commands."}],outputKind:"object",effects:["Deletes the directory's pin from the user-root profile-defaults state, if present. `--missing` deletes every pin whose directory no longer exists."]},run:o(async r=>{if(r.missing===!0){if(r.dir!==void 0)throw new d({error:"missing_not_exclusive",message:"--missing cannot be combined with --dir",field:"missing",next:"Pass --missing alone."});const n=await g();return{cleared:n.length>0,cleared_dirs:n,follow_up:n.length>0?`Cleared ${n.length} pin(s) whose directory no longer exists.`:"Every pinned directory still exists."}}const e=r.dir??process.cwd(),t=a(e),i=p(e)!==null;return await w(e),{dir:t,cleared:i,follow_up:i?"The startup chooser will ask again here. Re-pin with `crtr profile default set <profile>`.":"Nothing was pinned here."}},"run")}),b=s({name:"show",description:"show the current directory's default-profile pin",whenToUse:"you want to know which profile (if any) is pinned as this directory's default.",help:{name:"profile default show",summary:"report the current directory's pinned default profile, or none; --dir asks about another path",params:[{kind:"flag",name:"dir",type:"string",required:!1,constraint:"Directory whose pin to report instead of the current one. It need not exist any more \u2014 a pin for a deleted directory is addressed by the path it was set with (a symlinked path that still exists resolves to its real path, as `set` stored it)."}],output:[{name:"dir",type:"string",required:!0,constraint:"The resolved directory queried."},{name:"pinned",type:"boolean",required:!0,constraint:"True when a default is pinned here."},{name:"profile_id",type:"string",required:!1,constraint:"The pinned profile id, when pinned."},{name:"name",type:"string",required:!1,constraint:"The pinned profile name, when it still resolves."},{name:"stale",type:"boolean",required:!1,constraint:"True when a pin exists but its profile no longer resolves (deleted); the selector will self-heal it on next launch."},{name:"follow_up",type:"string",required:!0,constraint:"Concrete next commands."}],outputKind:"object",effects:["Read-only."]},run:o(async r=>{const e=r.dir??process.cwd(),t=a(e),i=p(e);if(i===null)return{dir:t,pinned:!1,follow_up:"Pin one with `crtr profile default set <profile>`."};let n;try{n=l(i).manifest.name}catch{n=void 0}return{dir:t,pinned:!0,profile_id:i,...n!==void 0?{name:n}:{stale:!0},follow_up:n!==void 0?"Change it with `crtr profile default set <profile>`, or clear it with `crtr profile default clear`.":"This profile no longer exists; clear the stale pin with `crtr profile default clear`."}},"run")}),T=s({name:"list",description:"list every directory pinned to a default profile",whenToUse:"you want to see all default-profile pins at once \u2014 including pins for directories that no longer exist \u2014 before clearing stale ones with `profile default clear --dir <path>` or `--missing`.",help:{name:"profile default list",summary:"every directory \u2192 default profile pin, with whether the directory and the profile still exist",params:[],output:[{name:"pins",type:"array",required:!0,constraint:"Each pin as {dir, profile_id, name?, dir_exists, profile_exists}, sorted by dir."}],outputKind:"object",effects:["Read-only."]},run:o(async()=>({pins:v().map(r=>{let e;try{e=l(r.profileId).manifest.name}catch{e=void 0}return{dir:r.dir,profile_id:r.profileId,...e!==void 0?{name:e}:{},dir_exists:m(r.dir),profile_exists:e!==void 0}})}),"run"),render:o(r=>{const e=r.pins;return e.length===0?"No default-profile pins.":e.map(t=>`${t.dir} \u2192 ${t.name??t.profile_id}${t.dir_exists?"":" [directory missing]"}${t.profile_exists?"":" [profile missing]"}`).join(`
|
|
2
2
|
`)},"render")}),P=f({name:"default",description:"manage this directory's default-profile pin",whenToUse:"setting, clearing, or inspecting which profile a directory defaults to at startup \u2014 so crtr stops asking. Directory-scoped, independent of project purview and automatic document delivery limits.",help:{name:"profile default",summary:"the per-directory default profile \u2014 pin one so the startup chooser stops asking",model:"A pin binds the CURRENT directory to a profile: launches here auto-pick it with no prompt (`crtr --pick-profile` reopens the chooser once). `set` pins a profile (which must already cover this dir), `clear` removes the pin (`--dir <path>` for another path, even a deleted one; `--missing` for every pin whose directory is gone), `show` reports it (`--dir` too), `list` shows every pin. This is directory-scoped selection, independent of `crtr profile project`: project `path` values govern purview and each `memory` value caps automatic disclosure. The startup menu's `d` action writes the same pin."},children:[x,_,b,T]});export{P as defaultBranch};
|
package/dist/commands/push.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
var y=Object.defineProperty;var i=(e,r)=>y(e,"name",{value:r,configurable:!0});import{envNodeId as b}from"../shared/env.js";import{defineBranch as k,defineLeaf as c}from"../core/command.js";import{InputError as d,readStdinRaw as h}from"../core/io.js";import{ApiError as q}from"../api/index.js";import{cliClient as p,rethrowAsCliError as u}from"./api-client.js";function f(){const e=b();if(e===void 0||e.trim()==="")throw new d({error:"no_node_context",message:"CRTR_NODE_ID is not set \u2014 push runs inside a canvas node.",next:"Run push from a node process spawned by the runtime."});return e.trim()}i(f,"requireCallerNode");const m={update:"report progress to subscribers",final:"finish: write the canonical result, mark the node done, close its window"},_={update:"you have progress worth surfacing to your managers while work remains in flight. Use normal delivery unless it can wait for their next real wake (--tier deferred) or needs immediate attention (--tier urgent); use push final only when the work is actually done.",final:"the work this node was spawned to do is complete and you are ready to hand back the canonical result \u2014 this writes that result, marks the node done, and closes its window, so it is the LAST thing you do here, not a progress note. Use push update while work is still in flight, and do not reach for final on a node working directly with the user: it has no manager to report up to and would close mid-conversation (the guard blocks it unless you pass --force after the user confirms)."};function v(){return c({name:"result",description:"answer a pending structured-output request with the required JSON result, or decline it",whenToUse:'your system prompt names a pending structured-output request you must answer. The value is validated against the required schema server-side; a mismatch rejects with field errors and records nothing, so fix and rerun. When the schema cannot be honestly satisfied (blocked, unavailable, bad input), pass `--decline "<reason>" --code <token>` (plus `--retryable` when the same request could succeed later) instead of inventing a value; your requester names the code tokens it accepts. For a terminal request either path IS how the node finishes \u2014 never call `crtr push final` alongside it.',help:{name:"push result",summary:"answer a pending structured-output request",params:[{kind:"stdin",name:"value",required:!1,constraint:"The JSON result. Pipe it from a single-quoted heredoc (`<<'EOF'`) to preserve literal bytes. Required unless `--decline` is passed."},{kind:"flag",name:"request",type:"string",required:!0,constraint:"The request id from the structured-output instruction. It binds this result to that exact request; crouter never selects a pending request implicitly."},{kind:"flag",name:"decline",type:"string",required:!1,constraint:"Decline instead of answering: one plain sentence on why the schema cannot be honestly satisfied (blocked, unavailable, bad input). Requires `--code`. Records a failure outcome with reason `declined` carrying the reason, code, and retryable flag, and clears the request; for a terminal request this finishes the node."},{kind:"flag",name:"code",type:"string",required:!1,constraint:"With `--decline`: one whitespace-free token (\u2264 64 chars) naming the decline class. crouter carries it verbatim; the requester validates it against the tokens it documented for you."},{kind:"flag",name:"retryable",type:"bool",required:!1,default:!1,constraint:"With `--decline`: the same request could succeed if issued again later (a transient block). Omit when the decline is final for this input."}],output:[{name:"mode",type:"string",required:!0,constraint:"Which request this answered: `terminal` finished the node; `oneoff` left it working."},{name:"
|
|
1
|
+
var y=Object.defineProperty;var i=(e,r)=>y(e,"name",{value:r,configurable:!0});import{envNodeId as b}from"../shared/env.js";import{defineBranch as k,defineLeaf as c}from"../core/command.js";import{InputError as d,readStdinRaw as h}from"../core/io.js";import{ApiError as q}from"../api/index.js";import{cliClient as p,rethrowAsCliError as u}from"./api-client.js";function f(){const e=b();if(e===void 0||e.trim()==="")throw new d({error:"no_node_context",message:"CRTR_NODE_ID is not set \u2014 push runs inside a canvas node.",next:"Run push from a node process spawned by the runtime."});return e.trim()}i(f,"requireCallerNode");const m={update:"report progress to subscribers",final:"finish: write the canonical result, mark the node done, close its window"},_={update:"you have progress worth surfacing to your managers while work remains in flight. Use normal delivery unless it can wait for their next real wake (--tier deferred) or needs immediate attention (--tier urgent); use push final only when the work is actually done.",final:"the work this node was spawned to do is complete and you are ready to hand back the canonical result \u2014 this writes that result, marks the node done, and closes its window, so it is the LAST thing you do here, not a progress note. Use push update while work is still in flight, and do not reach for final on a node working directly with the user: it has no manager to report up to and would close mid-conversation (the guard blocks it unless you pass --force after the user confirms)."};function v(){return c({name:"result",description:"answer a pending structured-output request with the required JSON result, or decline it",whenToUse:'your system prompt names a pending structured-output request you must answer. The value is validated against the required schema server-side; a mismatch rejects with field errors and records nothing, so fix and rerun. When the schema cannot be honestly satisfied (blocked, unavailable, bad input), pass `--decline "<reason>" --code <token>` (plus `--retryable` when the same request could succeed later) instead of inventing a value; your requester names the code tokens it accepts. For a terminal request either path IS how the node finishes \u2014 never call `crtr push final` alongside it.',help:{name:"push result",summary:"answer a pending structured-output request",params:[{kind:"stdin",name:"value",required:!1,constraint:"The JSON result. Pipe it from a single-quoted heredoc (`<<'EOF'`) to preserve literal bytes. Required unless `--decline` is passed."},{kind:"flag",name:"request",type:"string",required:!0,constraint:"The request id from the structured-output instruction. It binds this result to that exact request; crouter never selects a pending request implicitly."},{kind:"flag",name:"decline",type:"string",required:!1,constraint:"Decline instead of answering: one plain sentence on why the schema cannot be honestly satisfied (blocked, unavailable, bad input). Requires `--code`. Records a failure outcome with reason `declined` carrying the reason, code, and retryable flag, and clears the request; for a terminal request this finishes the node."},{kind:"flag",name:"code",type:"string",required:!1,constraint:"With `--decline`: one whitespace-free token (\u2264 64 chars) naming the decline class. crouter carries it verbatim; the requester validates it against the tokens it documented for you."},{kind:"flag",name:"retryable",type:"bool",required:!1,default:!1,constraint:"With `--decline`: the same request could succeed if issued again later (a transient block). Omit when the decline is final for this input."}],output:[{name:"mode",type:"string",required:!0,constraint:"Which request this answered: `terminal` finished the node; `oneoff` left it working."},{name:"declined",type:"object",required:!1,constraint:"Present only when the request was declined: { reason, code, retryable } as recorded."},{name:"report",type:"string",required:!0,constraint:"Name of the report document pushed alongside the result, `<node-id>/reports/<name>`."},{name:"notified",type:"string[]",required:!0,constraint:"Subscriber node ids that received an inbox pointer."},{name:"transitioned",type:"object",required:!1,constraint:"Present only for a terminal request that flipped the node \u2014 { from, to } lifecycle-status transition applied server-side."}],outputKind:"object",effects:["Validates the value against the pending schema server-side; a mismatch records nothing and the request stays pending.","Records the accepted result (or the decline) on the pending request and clears it.","A terminal decline records a `failure` outcome with reason `declined` whose `declined` field carries { reason, code, retryable }; the requester sees no value.","Pushes the mode-matched report: final for a terminal request (the node finishes \u2014 same effects as `push final`), update for a one-off request (the node keeps working)."]},run:i(async e=>{const r=f(),s=typeof e.request=="string"?e.request.trim():"";if(s==="")throw new d({error:"request_id_required",message:"a structured result needs its request id",field:"request",next:"Copy the request id named in the structured-output instruction and rerun with `--request <request-id>`."});const o=typeof e.decline=="string"?e.decline.trim():"",a=typeof e.code=="string"?e.code.trim():"";let n;if(o!==""){if(a==="")throw new d({error:"missing_decline_code",message:"a decline needs a code",field:"code",next:"Pass `--code <token>` \u2014 the whitespace-free token your requester documented for this decline class."});n={request_id:s,decline:o,code:a,retryable:e.retryable===!0}}else{if(a!==""||e.retryable===!0)throw new d({error:"decline_flags_without_decline",message:"--code and --retryable only apply with --decline",next:'Pass `--decline "<reason>"` alongside them, or drop them and submit the JSON result.'});let t=typeof e.value=="string"?e.value.trim():"";if(t===""&&(t=(await h()).trim()),t==="")throw new d({error:"missing_value",message:"no result value",field:"value",next:'Pass the JSON result as an argument or on stdin, or `--decline "<reason>" --code <token>` when the schema cannot be honestly satisfied.'});let l;try{l=JSON.parse(t)}catch(g){throw new d({error:"bad_result_json",message:`the result is not valid JSON: ${g.message}`,field:"value",next:"Pass one valid JSON value matching the requested schema."})}n={request_id:s,value:l}}try{const t=await p().submitResult(r,n);return{mode:t.mode,report:t.report,notified:t.notified,...t.declined===void 0?{}:{declined:t.declined},...t.transitioned!==void 0?{transitioned:t.transitioned}:{},...t.worktree_auto_dropped===!0?{worktree_auto_dropped:!0,worktree_auto_dropped_path:t.worktree_auto_dropped_path}:{}}}catch(t){u(t)}},"run"),render:i(e=>{const r=e.declined,s=e.mode==="terminal"?`${r?"Decline recorded":"Result recorded"} \u2014 node finished; its engine shuts down on next stop. Nothing more to do here: STOP your turn immediately. Reply with just "Done." and nothing else.`:`${r?"One-off request declined":"One-off result recorded"} and pushed \u2014 the structured-output gate is cleared; continue working normally.`,o=r===void 0?"":`
|
|
2
2
|
- code: ${r.code} (${r.retryable?"retryable":"not retryable"})`;return`${s}
|
|
3
3
|
|
|
4
|
-
- ${r?"
|
|
5
|
-
- report: ${e.report}`},"render")})}i(v,"makeResultLeaf");function w(e){return c({name:e,description:m[e],whenToUse:_[e],help:{name:`push ${e}`,summary:m[e],params:[{kind:"stdin",name:"body",required:!0,constraint:"Report body (markdown). Pipe it from a single-quoted heredoc (`<<'EOF'`) to preserve literal bytes."},...e==="update"?[{kind:"flag",name:"tier",type:"enum",choices:["deferred","normal","urgent"],required:!1,default:"normal",constraint:"Delivery urgency: deferred holds for the receiver\u2019s next non-deferred wake; normal wakes normally; urgent steers a live receiver and wakes an idle receiver."}]:[{kind:"flag",name:"force",type:"bool",required:!1,default:!1,constraint:"Override the guard that blocks `push final` on a node the user is attending (a resident with no one to report up to). Only pass this after the user explicitly confirms they want this node finished."}]],output:[{name:"report",type:"string",required:!0,constraint:"Name of the written report document, `<node-id>/reports/<name>`."},{name:"notified",type:"string[]",required:!0,constraint:"Subscriber node ids that received an inbox pointer."},...e==="final"?[{name:"transitioned",type:"object",required:!1,constraint:"Present only for a final that flipped the node \u2014 { from, to } lifecycle-status transition applied server-side."},{name:"worktree_auto_dropped",type:"boolean",required:!1,constraint:"Present only when the server closed this node\u2019s managed-worktree record without requiring `node worktree close`; cleanup of an existing checkout remains pending (see worktree_auto_dropped_path)."},{name:"worktree_auto_dropped_path",type:"string",required:!1,constraint:"Present only alongside worktree_auto_dropped: the closed worktree path; an existing checkout remains until pending cleanup."}]:[]],outputKind:"object",effects:["Creates the report document `<node-id>/reports/<compact-ts>-<uuid8>-<kind>` (server-side).","Appends one inbox pointer per subscriber.",...e==="final"?["Marks the node done (status + intent) server-side; its engine shuts down on next stop.","When this node owns a clean managed worktree already contained in its local base, the server closes its record with cleanup pending instead of blocking on `node worktree close`. A clean worktree whose exact tip exists on any branch on origin may also finalize while retaining its branch and checkout; uncommitted changes or a tip absent from origin still block with open_managed_worktree."]:[]]},run:i(async r=>{const s=f();let o=typeof r.body=="string"?r.body.trim():"";if(o===""&&(o=(await h()).trim()),o==="")throw new d({error:"missing_body",message:"no report body",field:"body",next:"Pass the body as an argument or on stdin."});const a=p();if(e==="final"&&r.force!==!0){let n=null;try{n=await a.getNode(s)}catch(t){t instanceof q&&t.status===404||u(t)}if(n!==null&&n.lifecycle==="resident"&&n.edges.subscribers.length===0)throw new d({error:"no_final_recipient",message:"This node is working directly with the user \u2014 it has no manager to submit a final result to. `push final` would end the conversation mid-stream.",next:'You almost certainly do NOT need to finish here \u2014 just keep working with the user. If the user has explicitly asked you to finish and close this node, confirm with them first, then rerun with `crtr push final --force "<result>"`.'})}try{const n=r.tier,t=await a.pushReport(s,{tier:e,body:o,...n===void 0?{}:{delivery_tier:n}});return{report:t.report,notified:t.notified,...t.transitioned!==void 0?{transitioned:t.transitioned}:{},...t.worktree_auto_dropped===!0?{worktree_auto_dropped:!0,worktree_auto_dropped_path:t.worktree_auto_dropped_path}:{}}}catch(n){u(n)}},"run"),render:i(r=>{const s=Array.isArray(r.notified)?r.notified.length:0,o=e==="final"?'Result recorded \u2014 node finished; its engine shuts down on next stop. Nothing more to do here: STOP your turn immediately. Reply with just "Done." and nothing else.':`Progress report fanned to ${s} subscriber(s).`,a=r.worktree_auto_dropped===!0?`
|
|
4
|
+
- report: ${e.report}${o}`},"render")})}i(v,"makeResultLeaf");function w(e){return c({name:e,description:m[e],whenToUse:_[e],help:{name:`push ${e}`,summary:m[e],params:[{kind:"stdin",name:"body",required:!0,constraint:"Report body (markdown). Pipe it from a single-quoted heredoc (`<<'EOF'`) to preserve literal bytes."},...e==="update"?[{kind:"flag",name:"tier",type:"enum",choices:["deferred","normal","urgent"],required:!1,default:"normal",constraint:"Delivery urgency: deferred holds for the receiver\u2019s next non-deferred wake; normal wakes normally; urgent steers a live receiver and wakes an idle receiver."}]:[{kind:"flag",name:"force",type:"bool",required:!1,default:!1,constraint:"Override the guard that blocks `push final` on a node the user is attending (a resident with no one to report up to). Only pass this after the user explicitly confirms they want this node finished."}]],output:[{name:"report",type:"string",required:!0,constraint:"Name of the written report document, `<node-id>/reports/<name>`."},{name:"notified",type:"string[]",required:!0,constraint:"Subscriber node ids that received an inbox pointer."},...e==="final"?[{name:"transitioned",type:"object",required:!1,constraint:"Present only for a final that flipped the node \u2014 { from, to } lifecycle-status transition applied server-side."},{name:"worktree_auto_dropped",type:"boolean",required:!1,constraint:"Present only when the server closed this node\u2019s managed-worktree record without requiring `node worktree close`; cleanup of an existing checkout remains pending (see worktree_auto_dropped_path)."},{name:"worktree_auto_dropped_path",type:"string",required:!1,constraint:"Present only alongside worktree_auto_dropped: the closed worktree path; an existing checkout remains until pending cleanup."}]:[]],outputKind:"object",effects:["Creates the report document `<node-id>/reports/<compact-ts>-<uuid8>-<kind>` (server-side).","Appends one inbox pointer per subscriber.",...e==="final"?["Marks the node done (status + intent) server-side; its engine shuts down on next stop.","When this node owns a clean managed worktree already contained in its local base, the server closes its record with cleanup pending instead of blocking on `node worktree close`. A clean worktree whose exact tip exists on any branch on origin may also finalize while retaining its branch and checkout; uncommitted changes or a tip absent from origin still block with open_managed_worktree."]:[]]},run:i(async r=>{const s=f();let o=typeof r.body=="string"?r.body.trim():"";if(o===""&&(o=(await h()).trim()),o==="")throw new d({error:"missing_body",message:"no report body",field:"body",next:"Pass the body as an argument or on stdin."});const a=p();if(e==="final"&&r.force!==!0){let n=null;try{n=await a.getNode(s)}catch(t){t instanceof q&&t.status===404||u(t)}if(n!==null&&n.lifecycle==="resident"&&n.edges.subscribers.length===0)throw new d({error:"no_final_recipient",message:"This node is working directly with the user \u2014 it has no manager to submit a final result to. `push final` would end the conversation mid-stream.",next:'You almost certainly do NOT need to finish here \u2014 just keep working with the user. If the user has explicitly asked you to finish and close this node, confirm with them first, then rerun with `crtr push final --force "<result>"`.'})}try{const n=r.tier,t=await a.pushReport(s,{tier:e,body:o,...n===void 0?{}:{delivery_tier:n}});return{report:t.report,notified:t.notified,...t.transitioned!==void 0?{transitioned:t.transitioned}:{},...t.worktree_auto_dropped===!0?{worktree_auto_dropped:!0,worktree_auto_dropped_path:t.worktree_auto_dropped_path}:{}}}catch(n){u(n)}},"run"),render:i(r=>{const s=Array.isArray(r.notified)?r.notified.length:0,o=e==="final"?'Result recorded \u2014 node finished; its engine shuts down on next stop. Nothing more to do here: STOP your turn immediately. Reply with just "Done." and nothing else.':`Progress report fanned to ${s} subscriber(s).`,a=r.worktree_auto_dropped===!0?`
|
|
6
5
|
|
|
7
6
|
Closed a clean managed-worktree record at ${String(r.worktree_auto_dropped_path)} \u2014 nothing to land; cleanup remains pending if the checkout still exists.`:"";return`${o}
|
|
8
7
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var S=Object.defineProperty;var i=(t,e)=>S(t,"name",{value:e,configurable:!0});import{defineBranch as j,defineLeaf as u}from"../../core/command.js";import{InvalidRawSettingsError as T,readConfig as f,readRawSettingsForTarget as q,replaceRawSettingsForTarget as L,updateConfig as R,persistModelLadders as P,configPath as N}from"../../core/config.js";import{usage as o,notFound as g}from"../../core/errors.js";import{requireScopeRoot as _}from"../../core/scope.js";import{resolveScope as h}from"./shared.js";import{resolveProfileOperand as O}from"../../core/profiles/manifest.js";import{SettingsRevisionConflictError as E}from"../../core/scoped-state/settings.js";import{InputError as l}from"../../core/io.js";import{SCOPE_CONFIG_KEYS as C,USER_SETTINGS as U,findUserSetting as m}from"../../core/user-settings.js";const $=C.join(", "),J=U.map(t=>`${t.key} (${t.valueConstraint})`).join(", "),M=new Set(["anthropic","openai"]),I=new Set(["ultra","strong","medium","light"]);function y(t){return M.has(t)}i(y,"isModelProvider");function x(t){return I.has(t)}i(x,"isModelStrength");function w(t,e){const n=e.split(".");let r=t;for(const s of n){if(r===null||typeof r!="object")return;r=r[s]}return r}i(w,"getNestedValue");function A(t){return t==="true"?!0:t==="false"?!1:/^-?\d+$/.test(t)?parseInt(t,10):t}i(A,"parseConfigValue");function b(t,e){if(t.split(".",1)[0]==="brokerThresholds"&&e!=="user")throw o("brokerThresholds are available only in user scope")}i(b,"assertUserScopeBrokerThresholds");function v(t,e){if(t.split(".",1)[0]==="lifecycle"&&e!=="user")throw o("lifecycle settings are available only in user scope")}i(v,"assertUserScopeLifecycle");function F(t,e){if(t==="working_gerunds"&&e!=="user")throw o("working_gerunds is available only in user scope")}i(F,"assertWorkingGerundsScope");function K(t,e){if(t==="whip_messages"&&e!=="user")throw o("whip_messages are available only in user scope")}i(K,"assertWhipMessagesScope");function D(t,e){if(m(t)!==void 0&&e!=="user")throw o(`${t} is available only in user scope`)}i(D,"assertUserSettingScope");function G(t,e){const n=t.split(".");if(n[0]!=="modelLadders")return null;if(n.length===2&&n[1]==="defaultProvider"){if(!y(e))throw o("modelLadders.defaultProvider must be anthropic or openai");return{defaultProvider:e}}if(n.length===3){const r=n[1],s=n[2];if(!y(r))throw o("modelLadders provider must be anthropic or openai");if(!x(s))throw o("modelLadders strength must be ultra, strong, medium, or light");if(e.trim()==="")throw o(`modelLadders.${r}.${s} cannot be empty`);return{[r]:{[s]:e}}}throw o(`unsupported key path for set: ${t}`)}i(G,"modelLadderPatch");function k(t){const e=t.scope;if(e==="project")throw o("project settings remain a JSON file; use `crtr sys config set` or `crtr sys config path --scope project`.");const n=t.profile;if(e==="user"){if(n!==void 0)throw o("--profile is available only with --scope profile.");return{scope:"user"}}if(n===void 0)throw o("--profile is required with --scope profile.");return{scope:"profile",profileId:O(n).profileId}}i(k,"rawSettingsTarget");function Q(t){let e;try{e=JSON.parse(t)}catch{throw new l({error:"invalid_request",message:"stdin must be valid JSON",field:"stdin",next:"Pipe one complete JSON object on stdin."})}if(e===null||typeof e!="object"||Array.isArray(e))throw new l({error:"invalid_request",message:"stdin must be a JSON object",field:"stdin",next:"Pipe one complete JSON object on stdin."});return e}i(Q,"parseRawSettings");function W(t,e,n,r){const s=e.split("."),c=s[0];if(e==="working_gerunds"||e==="whip_messages"){let a;try{a=JSON.parse(n)}catch{throw o(`${e} must be a JSON array of non-empty strings`)}if(!Array.isArray(a)||a.length===0||!a.every(d=>typeof d=="string"&&d.trim()!==""))throw o(`${e} must be a non-empty JSON array of non-empty strings`);t[e]=a.map(d=>d.trim());return}if(c==="keybindings")throw o("keybindings are edited only through `crtr sys settings`");if(c==="modelLadders")throw o("modelLadders keys are written through persistModelLadders, not this path");const p=m(e);if(p!==void 0){const a=p.setFromString(t,n);if(a!==null)throw o(a);return}if(c==="brokerThresholds"){if(s.length!==2||s[1]!=="warning"&&s[1]!=="automaticReviveCap")throw o("brokerThresholds key must be warning or automaticReviveCap");if(typeof r!="number"||!Number.isFinite(r)||r<1)throw o(`brokerThresholds.${s[1]} must be an integer >= 1`);const a=Math.floor(r);if(s[1]==="warning"&&a>t.brokerThresholds.automaticReviveCap)throw o("brokerThresholds.warning must be <= brokerThresholds.automaticReviveCap");if(s[1]==="automaticReviveCap"&&a<t.brokerThresholds.warning)throw o("brokerThresholds.automaticReviveCap must be >= brokerThresholds.warning");t.brokerThresholds[s[1]]=a;return}if(c==="lifecycle"){if(s.length!==2||s[1]!=="unattendedParkMs")throw o("lifecycle key must be unattendedParkMs");if(typeof r!="number"||!Number.isFinite(r)||r<1)throw o("lifecycle.unattendedParkMs must be an integer >= 1");t.lifecycle.unattendedParkMs=Math.floor(r);return}throw o(`unsupported key path for set: ${e}`)}i(W,"setNestedValue");const B=u({name:"get",description:"read a config value by key",whenToUse:"you want to inspect one config value \u2014 including the whole user keybindings object \u2014 optionally from a specific scope. Use sys settings to edit keybindings and sys config set for supported scalar settings.",help:{name:"sys config get",summary:"read a config value by dotted key",params:[{kind:"positional",name:"key",type:"string",required:!0,constraint:`Dotted key path. Top-level keys: ${$}. brokerThresholds and lifecycle are user-only; keybindings is readable only as the whole user-scope object and editable only through sys settings.`},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Scope to read from. Default: user."}],output:[{name:"key",type:"string",required:!0,constraint:"Echo of input key."},{name:"value",type:"unknown",required:!0,constraint:"The resolved value. Type depends on the key."},{name:"scope",type:"string",required:!0,constraint:"Scope the value was read from."}],outputKind:"object",effects:["None. Read-only."]},run:i(async t=>{const e=t.key,n=h(t.scope);if(b(e,n),v(e,n),e.startsWith("keybindings.")||e==="keybindings"&&n!=="user")throw g("keybindings are available only as the whole user-scope object");const r=f(n),s=w(r,e);if(s===void 0)throw g(`config key not found: ${e}`);return{key:e,value:s,scope:n}},"run")}),H=u({name:"set",description:"write a config value by key",whenToUse:"you want to change a supported crtr setting in user or project scope. Use sys settings instead for keybindings, and sys config get to inspect values.",help:{name:"sys config set",summary:"write a config value by dotted key",params:[{kind:"positional",name:"key",type:"string",required:!0,constraint:`Dotted key path. User-scope scalar settings: ${J}. Also supported: working_gerunds and whip_messages (non-empty JSON string arrays), brokerThresholds.warning and brokerThresholds.automaticReviveCap (user scope; integer >= 1), lifecycle.unattendedParkMs (user scope; integer ms >= 1), modelLadders.defaultProvider, and modelLadders.<anthropic|openai>.<ultra|strong|medium|light>. Keybindings are edited only through sys settings. For arbitrary raw user or profile documents, use sys config get-raw and set-raw.`},{kind:"flag",name:"value",type:"string",required:!0,constraint:"value VALUE \u2014 string, required. working_gerunds and whip_messages accept JSON arrays; other values are stored as-is if quoted and coerced to number or boolean when unambiguous."},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Scope to write to. Default: user. Project scope is supported only for modelLadders."}],output:[{name:"value",type:"unknown",required:!0,constraint:"Resolved value as written after parsing and setting-specific coercion."},{name:"scope",type:"string",required:!0,constraint:"Scope the value was written to."}],outputKind:"object",effects:["Writes the updated value through the target scope\u2019s configuration storage."]},run:i(async t=>{const e=t.key,n=t.value,r=h(t.scope);b(e,r),v(e,r),F(e,r),K(e,r),D(e,r);const s=A(n),c=G(e,n),p=c!==null?(P(_(r),c),f(r)):R(r,d=>W(d,e,n,s));return{value:w(p,e),scope:r}},"run")}),V=u({name:"get-raw",description:"read one raw SQL-backed settings document and revision",whenToUse:"you need the exact stored user or profile settings document before replacing it with set-raw.",help:{name:"sys config get-raw",summary:"read one raw user or profile settings document",params:[{kind:"flag",name:"scope",type:"enum",choices:["user","profile","project"],required:!0,constraint:"SQL-backed target: user or profile. project is rejected because its settings remain a JSON file."},{kind:"flag",name:"profile",type:"string",required:!1,constraint:"Profile id or name to target. Required with --scope profile; rejected with --scope user or project."}],output:[{name:"revision",type:"string",required:!0,constraint:"Opaque revision token for set-raw. absent means the settings row does not exist."},{name:"settings",type:"object | null",required:!0,constraint:"Exact stored settings document, or null when no row exists."}],outputKind:"object",effects:["None. Read-only."]},run:i(async t=>q(k(t)),"run")}),z=u({name:"set-raw",description:"replace one raw SQL-backed settings document at a revision",whenToUse:"you have a complete user or profile settings document from get-raw and must replace it without losing a concurrent change.",help:{name:"sys config set-raw",summary:"atomically replace one raw user or profile settings document",params:[{kind:"flag",name:"scope",type:"enum",choices:["user","profile","project"],required:!0,constraint:"SQL-backed target: user or profile. project is rejected because its settings remain a JSON file."},{kind:"flag",name:"profile",type:"string",required:!1,constraint:"Profile id or name to target. Required with --scope profile; rejected with --scope user or project."},{kind:"flag",name:"if-revision",type:"string",required:!0,constraint:"Revision returned by get-raw. Required; use absent only when get-raw reported no settings row."},{kind:"stdin",name:"settings",required:!0,allowPositional:!1,constraint:"One complete JSON object. It replaces the document exactly; values are not normalized or merged."}],output:[{name:"revision",type:"string",required:!0,constraint:"Revision token of the stored document after this operation."},{name:"changed",type:"boolean",required:!0,constraint:"Whether the stored document changed."}],outputKind:"object",effects:["Atomically replaces the SQL-backed settings document only when --if-revision matches its current revision."]},run:i(async t=>{const e=k(t),n=Q(t.settings);try{return L(e,n,t.ifRevision)}catch(r){throw r instanceof E?new l({error:"settings_revision_conflict",message:"settings changed since the supplied revision",field:"if_revision",next:"Run `crtr sys config get-raw` again, reapply the intended transformation, and retry with its revision."}):r instanceof T?new l({error:"invalid_settings",message:r.message,field:"stdin",next:"Correct the document so crouter can merge it into resolved settings, then retry with a fresh revision."}):r}},"run")}),Y=u({name:"path",description:"print the project config.json path",whenToUse:"you need the project config.json path for inspection or backup. User and profile settings use get-raw and set-raw instead.",help:{name:"sys config path",summary:"print the project config.json path",params:[{kind:"flag",name:"scope",type:"enum",choices:["project","user","profile"],required:!1,constraint:"Project is the only path-backed settings scope. user and profile are rejected because they use SQL-backed get-raw and set-raw. Default: project."}],output:[{name:"paths",type:"object[]",required:!0,constraint:'One {scope: "project", path} entry when the current project has a config file; otherwise empty.'}],outputKind:"object",effects:["None. Read-only."]},run:i(async t=>{const e=t.scope;if(e==="user"||e==="profile")throw o(`${e} settings are SQL-backed; use \`crtr sys config get-raw --scope ${e}\` instead.`);const n=N("project");return{paths:n===null?[]:[{scope:"project",path:n}]}},"run")}),ce=j({name:"config",description:"read and write configuration",whenToUse:"inspecting crtr settings, changing supported scalar values, replacing complete raw user or profile settings documents, or locating a project config.json. Keybinding changes belong in sys settings.",help:{name:"sys config",summary:"read and write crtr configuration, including model ladders and raw SQL-backed user/profile settings",model:"get and set resolve individual settings. get-raw and set-raw read and replace complete user or profile documents with a revision precondition. path applies only to project config.json."},children:[B,H,V,z,Y]});export{ce as configBranch};
|
|
1
|
+
var S=Object.defineProperty;var i=(t,e)=>S(t,"name",{value:e,configurable:!0});import{defineBranch as j,defineLeaf as u}from"../../core/command.js";import{InvalidRawSettingsError as T,readConfig as f,readRawSettingsForTarget as q,replaceRawSettingsForTarget as L,updateConfig as R,persistModelLadders as P,configPath as N}from"../../core/config.js";import{usage as o,notFound as g}from"../../core/errors.js";import{requireScopeRoot as _}from"../../core/scope.js";import{resolveScope as h}from"./shared.js";import{resolveProfileOperand as O}from"../../core/profiles/manifest.js";import{SettingsRevisionConflictError as E}from"../../core/scoped-state/person-store.js";import{InputError as l}from"../../core/io.js";import{SCOPE_CONFIG_KEYS as C,USER_SETTINGS as U,findUserSetting as m}from"../../core/user-settings.js";const $=C.join(", "),J=U.map(t=>`${t.key} (${t.valueConstraint})`).join(", "),M=new Set(["anthropic","openai"]),I=new Set(["ultra","strong","medium","light"]);function y(t){return M.has(t)}i(y,"isModelProvider");function x(t){return I.has(t)}i(x,"isModelStrength");function w(t,e){const n=e.split(".");let r=t;for(const s of n){if(r===null||typeof r!="object")return;r=r[s]}return r}i(w,"getNestedValue");function A(t){return t==="true"?!0:t==="false"?!1:/^-?\d+$/.test(t)?parseInt(t,10):t}i(A,"parseConfigValue");function b(t,e){if(t.split(".",1)[0]==="brokerThresholds"&&e!=="user")throw o("brokerThresholds are available only in user scope")}i(b,"assertUserScopeBrokerThresholds");function v(t,e){if(t.split(".",1)[0]==="lifecycle"&&e!=="user")throw o("lifecycle settings are available only in user scope")}i(v,"assertUserScopeLifecycle");function F(t,e){if(t==="working_gerunds"&&e!=="user")throw o("working_gerunds is available only in user scope")}i(F,"assertWorkingGerundsScope");function K(t,e){if(t==="whip_messages"&&e!=="user")throw o("whip_messages are available only in user scope")}i(K,"assertWhipMessagesScope");function D(t,e){if(m(t)!==void 0&&e!=="user")throw o(`${t} is available only in user scope`)}i(D,"assertUserSettingScope");function G(t,e){const n=t.split(".");if(n[0]!=="modelLadders")return null;if(n.length===2&&n[1]==="defaultProvider"){if(!y(e))throw o("modelLadders.defaultProvider must be anthropic or openai");return{defaultProvider:e}}if(n.length===3){const r=n[1],s=n[2];if(!y(r))throw o("modelLadders provider must be anthropic or openai");if(!x(s))throw o("modelLadders strength must be ultra, strong, medium, or light");if(e.trim()==="")throw o(`modelLadders.${r}.${s} cannot be empty`);return{[r]:{[s]:e}}}throw o(`unsupported key path for set: ${t}`)}i(G,"modelLadderPatch");function k(t){const e=t.scope;if(e==="project")throw o("project settings remain a JSON file; use `crtr sys config set` or `crtr sys config path --scope project`.");const n=t.profile;if(e==="user"){if(n!==void 0)throw o("--profile is available only with --scope profile.");return{scope:"user"}}if(n===void 0)throw o("--profile is required with --scope profile.");return{scope:"profile",profileId:O(n).profileId}}i(k,"rawSettingsTarget");function Q(t){let e;try{e=JSON.parse(t)}catch{throw new l({error:"invalid_request",message:"stdin must be valid JSON",field:"stdin",next:"Pipe one complete JSON object on stdin."})}if(e===null||typeof e!="object"||Array.isArray(e))throw new l({error:"invalid_request",message:"stdin must be a JSON object",field:"stdin",next:"Pipe one complete JSON object on stdin."});return e}i(Q,"parseRawSettings");function W(t,e,n,r){const s=e.split("."),c=s[0];if(e==="working_gerunds"||e==="whip_messages"){let a;try{a=JSON.parse(n)}catch{throw o(`${e} must be a JSON array of non-empty strings`)}if(!Array.isArray(a)||a.length===0||!a.every(d=>typeof d=="string"&&d.trim()!==""))throw o(`${e} must be a non-empty JSON array of non-empty strings`);t[e]=a.map(d=>d.trim());return}if(c==="keybindings")throw o("keybindings are edited only through `crtr sys settings`");if(c==="modelLadders")throw o("modelLadders keys are written through persistModelLadders, not this path");const p=m(e);if(p!==void 0){const a=p.setFromString(t,n);if(a!==null)throw o(a);return}if(c==="brokerThresholds"){if(s.length!==2||s[1]!=="warning"&&s[1]!=="automaticReviveCap")throw o("brokerThresholds key must be warning or automaticReviveCap");if(typeof r!="number"||!Number.isFinite(r)||r<1)throw o(`brokerThresholds.${s[1]} must be an integer >= 1`);const a=Math.floor(r);if(s[1]==="warning"&&a>t.brokerThresholds.automaticReviveCap)throw o("brokerThresholds.warning must be <= brokerThresholds.automaticReviveCap");if(s[1]==="automaticReviveCap"&&a<t.brokerThresholds.warning)throw o("brokerThresholds.automaticReviveCap must be >= brokerThresholds.warning");t.brokerThresholds[s[1]]=a;return}if(c==="lifecycle"){if(s.length!==2||s[1]!=="unattendedParkMs")throw o("lifecycle key must be unattendedParkMs");if(typeof r!="number"||!Number.isFinite(r)||r<1)throw o("lifecycle.unattendedParkMs must be an integer >= 1");t.lifecycle.unattendedParkMs=Math.floor(r);return}throw o(`unsupported key path for set: ${e}`)}i(W,"setNestedValue");const B=u({name:"get",description:"read a config value by key",whenToUse:"you want to inspect one config value \u2014 including the whole user keybindings object \u2014 optionally from a specific scope. Use sys settings to edit keybindings and sys config set for supported scalar settings.",help:{name:"sys config get",summary:"read a config value by dotted key",params:[{kind:"positional",name:"key",type:"string",required:!0,constraint:`Dotted key path. Top-level keys: ${$}. brokerThresholds and lifecycle are user-only; keybindings is readable only as the whole user-scope object and editable only through sys settings.`},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Scope to read from. Default: user."}],output:[{name:"key",type:"string",required:!0,constraint:"Echo of input key."},{name:"value",type:"unknown",required:!0,constraint:"The resolved value. Type depends on the key."},{name:"scope",type:"string",required:!0,constraint:"Scope the value was read from."}],outputKind:"object",effects:["None. Read-only."]},run:i(async t=>{const e=t.key,n=h(t.scope);if(b(e,n),v(e,n),e.startsWith("keybindings.")||e==="keybindings"&&n!=="user")throw g("keybindings are available only as the whole user-scope object");const r=f(n),s=w(r,e);if(s===void 0)throw g(`config key not found: ${e}`);return{key:e,value:s,scope:n}},"run")}),H=u({name:"set",description:"write a config value by key",whenToUse:"you want to change a supported crtr setting in user or project scope. Use sys settings instead for keybindings, and sys config get to inspect values.",help:{name:"sys config set",summary:"write a config value by dotted key",params:[{kind:"positional",name:"key",type:"string",required:!0,constraint:`Dotted key path. User-scope scalar settings: ${J}. Also supported: working_gerunds and whip_messages (non-empty JSON string arrays), brokerThresholds.warning and brokerThresholds.automaticReviveCap (user scope; integer >= 1), lifecycle.unattendedParkMs (user scope; integer ms >= 1), modelLadders.defaultProvider, and modelLadders.<anthropic|openai>.<ultra|strong|medium|light>. Keybindings are edited only through sys settings. For arbitrary raw user or profile documents, use sys config get-raw and set-raw.`},{kind:"flag",name:"value",type:"string",required:!0,constraint:"value VALUE \u2014 string, required. working_gerunds and whip_messages accept JSON arrays; other values are stored as-is if quoted and coerced to number or boolean when unambiguous."},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Scope to write to. Default: user. Project scope is supported only for modelLadders."}],output:[{name:"value",type:"unknown",required:!0,constraint:"Resolved value as written after parsing and setting-specific coercion."},{name:"scope",type:"string",required:!0,constraint:"Scope the value was written to."}],outputKind:"object",effects:["Writes the updated value through the target scope\u2019s configuration storage."]},run:i(async t=>{const e=t.key,n=t.value,r=h(t.scope);b(e,r),v(e,r),F(e,r),K(e,r),D(e,r);const s=A(n),c=G(e,n),p=c!==null?(await P(_(r),c),f(r)):await R(r,d=>W(d,e,n,s));return{value:w(p,e),scope:r}},"run")}),V=u({name:"get-raw",description:"read one raw SQL-backed settings document and revision",whenToUse:"you need the exact stored user or profile settings document before replacing it with set-raw.",help:{name:"sys config get-raw",summary:"read one raw user or profile settings document",params:[{kind:"flag",name:"scope",type:"enum",choices:["user","profile","project"],required:!0,constraint:"SQL-backed target: user or profile. project is rejected because its settings remain a JSON file."},{kind:"flag",name:"profile",type:"string",required:!1,constraint:"Profile id or name to target. Required with --scope profile; rejected with --scope user or project."}],output:[{name:"revision",type:"string",required:!0,constraint:"Opaque revision token for set-raw. absent means the settings row does not exist."},{name:"settings",type:"object | null",required:!0,constraint:"Exact stored settings document, or null when no row exists."}],outputKind:"object",effects:["None. Read-only."]},run:i(async t=>q(k(t)),"run")}),z=u({name:"set-raw",description:"replace one raw SQL-backed settings document at a revision",whenToUse:"you have a complete user or profile settings document from get-raw and must replace it without losing a concurrent change.",help:{name:"sys config set-raw",summary:"atomically replace one raw user or profile settings document",params:[{kind:"flag",name:"scope",type:"enum",choices:["user","profile","project"],required:!0,constraint:"SQL-backed target: user or profile. project is rejected because its settings remain a JSON file."},{kind:"flag",name:"profile",type:"string",required:!1,constraint:"Profile id or name to target. Required with --scope profile; rejected with --scope user or project."},{kind:"flag",name:"if-revision",type:"string",required:!0,constraint:"Revision returned by get-raw. Required; use absent only when get-raw reported no settings row."},{kind:"stdin",name:"settings",required:!0,allowPositional:!1,constraint:"One complete JSON object. It replaces the document exactly; values are not normalized or merged."}],output:[{name:"revision",type:"string",required:!0,constraint:"Revision token of the stored document after this operation."},{name:"changed",type:"boolean",required:!0,constraint:"Whether the stored document changed."}],outputKind:"object",effects:["Atomically replaces the SQL-backed settings document only when --if-revision matches its current revision."]},run:i(async t=>{const e=k(t),n=Q(t.settings);try{return L(e,n,t.ifRevision)}catch(r){throw r instanceof E?new l({error:"settings_revision_conflict",message:"settings changed since the supplied revision",field:"if_revision",next:"Run `crtr sys config get-raw` again, reapply the intended transformation, and retry with its revision."}):r instanceof T?new l({error:"invalid_settings",message:r.message,field:"stdin",next:"Correct the document so crouter can merge it into resolved settings, then retry with a fresh revision."}):r}},"run")}),Y=u({name:"path",description:"print the project config.json path",whenToUse:"you need the project config.json path for inspection or backup. User and profile settings use get-raw and set-raw instead.",help:{name:"sys config path",summary:"print the project config.json path",params:[{kind:"flag",name:"scope",type:"enum",choices:["project","user","profile"],required:!1,constraint:"Project is the only path-backed settings scope. user and profile are rejected because they use SQL-backed get-raw and set-raw. Default: project."}],output:[{name:"paths",type:"object[]",required:!0,constraint:'One {scope: "project", path} entry when the current project has a config file; otherwise empty.'}],outputKind:"object",effects:["None. Read-only."]},run:i(async t=>{const e=t.scope;if(e==="user"||e==="profile")throw o(`${e} settings are SQL-backed; use \`crtr sys config get-raw --scope ${e}\` instead.`);const n=N("project");return{paths:n===null?[]:[{scope:"project",path:n}]}},"run")}),ce=j({name:"config",description:"read and write configuration",whenToUse:"inspecting crtr settings, changing supported scalar values, replacing complete raw user or profile settings documents, or locating a project config.json. Keybinding changes belong in sys settings.",help:{name:"sys config",summary:"read and write crtr configuration, including model ladders and raw SQL-backed user/profile settings",model:"get and set resolve individual settings. get-raw and set-raw read and replace complete user or profile documents with a revision precondition. path applies only to project config.json."},children:[B,H,V,z,Y]});export{ce as configBranch};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
var x=Object.defineProperty;var i=(e,n)=>x(e,"name",{value:n,configurable:!0});import{randomBytes as P}from"node:crypto";import R from"node:path";import{defineLeaf as A}from"../../core/command.js";import{readConfig as k,updateConfig as y}from"../../core/config.js";import{emit as S,InputError as s,isJsonOutput as E}from"../../core/io.js";import{renderResult as L}from"../../core/render.js";import{addScopedApiToken as q,getApiToken as b,setApiToken as I}from"../../core/secrets.js";import{ENFORCED as c}from"@north-light/identity";import{envCrtrdTcp as D,envCrtrdToken as v,envNodeId as N}from"../../shared/env.js";import{shellQuote as p}from"../../shared/shell-quote.js";import{cliClient as T}from"../api-client.js";const O="127.0.0.1:8787",$=3e4,M=100;function C(){return P(32).toString("hex")}i(C,"token");function j(e){if(e===void 0)return;const n=String(e).split(",").map(t=>t.trim()).filter(t=>t!=="");if(n.length===0)throw new s({error:"empty_scopes",message:"--scopes names no scope",received:e,field:"scopes",next:`Pass a comma-separated list from ${[...c].join(", ")}; omit the flag for the owner token.`});for(const t of n)if(!c.has(t))throw new s({error:"invalid_scope",message:`invalid scope: ${t}`,field:"scopes",received:t,next:`Use one of ${[...c].join(", ")}.`});return n}i(j,"parseScopes");function U(e){E()?S(e):process.stdout.write(L(e,F.help)+`
|
|
2
2
|
`)}i(U,"printCredentials");function W(e){const n=e.lastIndexOf(":");return n===-1||Number(e.slice(n+1))!==0?e:`${e.slice(0,n+1)}8787`}i(W,"fixedTcpPort");async function z(){const e=T(),n=Date.now()+$;let t;for(;Date.now()<n;){try{const r=await e.status();if(r.listeners.tcp!==null)return r}catch(r){t=r}await new Promise(r=>setTimeout(r,M))}throw new s({error:"listener_unavailable",message:`the successor did not expose a TCP listener within ${$}ms${t instanceof Error?`: ${t.message}`:""}`,next:"Run `crtr sys daemon status` to inspect the daemon, then retry `crtr sys connect`."})}i(z,"awaitTcpListener");async function _(e,n){const t=await e.getModelAuthReadiness(n);if(t.credential==="ready")return;process.stderr.write(`Logging in to ${t.provider} for ${t.model}.
|
|
3
|
-
`);const{loginProvider:r,openProviderLoginRuntime:a,terminalAuthInteraction:m}=await import("./provider-login.js");await r(await a(),t.provider,m());const o=await e.getModelAuthReadiness(n);if(o.credential!=="ready")throw new s({error:"provider_login_incomplete",message:`provider ${o.provider} credential is ${o.credential} after login`,next:`Run \`${B(n)}\` again and complete the provider login.`})}i(_,"ensureProviderCredential");function B(e){return["crtr sys connect",e.profile===void 0?void 0:`--profile ${p(e.profile)}`,e.cwd===void 0?void 0:`--cwd ${p(e.cwd)}`,e.kind===void 0?void 0:`--kind ${p(e.kind)}`,e.model===void 0?void 0:`--model ${p(e.model)}`].filter(n=>n!==void 0).join(" ")}i(B,"connectCommand");const F=A({name:"connect",description:"enable browser access to this daemon",whenToUse:"an application needs a browser-reachable daemon URL and bearer token; this enables the local TCP listener and reports the credentials to paste into that application. Add --app and --scopes to mint an app token instead of the owner token.",help:{name:"sys connect",summary:"enable authenticated browser access and log in to the selected model provider when needed; a handover reports browser credentials before it begins",params:[{kind:"flag",name:"app",type:"string",required:!1,constraint:"App id for the new scoped token (without the app: prefix). Required with --scopes; omit both for the owner token."},{kind:"flag",name:"scopes",type:"string",required:!1,constraint:`Comma-separated list from ${[...c].join(", ")}. Requires --app; mints a NEW app bearer with this resolved scope set. Omit both flags for the owner token.`},{kind:"flag",name:"profile",type:"string",required:!1,constraint:"Profile setting selecting the provider a root launch with these settings would use."},{kind:"flag",name:"cwd",type:"string",required:!1,constraint:"Directory setting selecting the provider a root launch with these settings would use. Default: this directory."},{kind:"flag",name:"kind",type:"string",required:!1,constraint:"Node kind setting selecting the provider a root launch with these settings would use."},{kind:"flag",name:"model",type:"string",required:!1,constraint:"Model setting selecting the provider a root launch with these settings would use."}],output:[{name:"base_url",type:"string",required:!0,constraint:"The HTTP URL configured for the TCP listener."},{name:"token",type:"string",required:!0,constraint:"The bearer token accepted by that listener: the owner token, or with --scopes the newly minted scoped token. Paste it only into the application that needs daemon access."}],outputKind:"object",effects:["Stores a missing listener address in user settings and a missing owner bearer token in the 0600 user secrets store.","With --scopes, appends a new scoped token to that secrets store; there is no revoke verb yet, so removing one means editing the store by hand.","When the listener is not already up with both settings present, or a scoped token was minted (the daemon reads tokens only at boot), asks the daemon to hand over to a successor.","After the listener is available, resolves the provider selected by these params (default: this directory) and runs its existing OAuth login flow when that provider has no usable credential."]},run:i(async e=>{const n={profile:e.profile,cwd:R.resolve(e.cwd??process.cwd()),kind:e.kind,model:e.model},t=j(e.scopes),r=e.app;if(t===void 0!=(r===void 0)||r!==void 0&&!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(String(r)))throw new s({error:"invalid_app",message:"--app must name an app id and is required exactly when --scopes is set",field:"app",received:r,next:"Pass --app with an app id and --scopes together, or omit both for the owner token."});const a=N(),o=k("user").api.tcp,l=b("user"),d=T(),w=await d.status();o===""?y("user",h=>{h.api.tcp=O}):Number(o.slice(o.lastIndexOf(":")+1))===0&&y("user",h=>{h.api.tcp=W(o)});const f=D()??k("user").api.tcp;if(Number(f.slice(f.lastIndexOf(":")+1))===0)throw new s({error:"dynamic_tcp_port",message:"CRTRD_TCP must use a fixed port for `crtr sys connect`",next:"Set CRTRD_TCP to a host and fixed port, then run `crtr sys connect` again."});if(t===void 0&&o!==""&&l!==void 0&&w.listeners.tcp!==null)return await _(d,n),{base_url:`http://${w.listeners.tcp}`,token:v()??l};l===void 0&&I(C(),"user");const g=v()??b("user");if(g===void 0)throw new Error("TCP listener cannot start without a bearer token");let u=g;t!==void 0&&(u=C(),q({token:u,grantee:`app:${String(r)}`,scopes:t,created:new Date().toISOString()},"user")),U({base_url:`http://${f}`,token:u}),await d.restartDaemon(),await z(),await _(d,n),a!==void 0&&await d.sendMessage(a,{body:"Browser access is ready.",tier:"urgent",from:a})},"run")});export{F as sysConnectLeaf};
|
|
3
|
+
`);const{loginProvider:r,openProviderLoginRuntime:a,terminalAuthInteraction:m}=await import("./provider-login.js");await r(await a(),t.provider,m());const o=await e.getModelAuthReadiness(n);if(o.credential!=="ready")throw new s({error:"provider_login_incomplete",message:`provider ${o.provider} credential is ${o.credential} after login`,next:`Run \`${B(n)}\` again and complete the provider login.`})}i(_,"ensureProviderCredential");function B(e){return["crtr sys connect",e.profile===void 0?void 0:`--profile ${p(e.profile)}`,e.cwd===void 0?void 0:`--cwd ${p(e.cwd)}`,e.kind===void 0?void 0:`--kind ${p(e.kind)}`,e.model===void 0?void 0:`--model ${p(e.model)}`].filter(n=>n!==void 0).join(" ")}i(B,"connectCommand");const F=A({name:"connect",description:"enable browser access to this daemon",whenToUse:"an application needs a browser-reachable daemon URL and bearer token; this enables the local TCP listener and reports the credentials to paste into that application. Add --app and --scopes to mint an app token instead of the owner token.",help:{name:"sys connect",summary:"enable authenticated browser access and log in to the selected model provider when needed; a handover reports browser credentials before it begins",params:[{kind:"flag",name:"app",type:"string",required:!1,constraint:"App id for the new scoped token (without the app: prefix). Required with --scopes; omit both for the owner token."},{kind:"flag",name:"scopes",type:"string",required:!1,constraint:`Comma-separated list from ${[...c].join(", ")}. Requires --app; mints a NEW app bearer with this resolved scope set. Omit both flags for the owner token.`},{kind:"flag",name:"profile",type:"string",required:!1,constraint:"Profile setting selecting the provider a root launch with these settings would use."},{kind:"flag",name:"cwd",type:"string",required:!1,constraint:"Directory setting selecting the provider a root launch with these settings would use. Default: this directory."},{kind:"flag",name:"kind",type:"string",required:!1,constraint:"Node kind setting selecting the provider a root launch with these settings would use."},{kind:"flag",name:"model",type:"string",required:!1,constraint:"Model setting selecting the provider a root launch with these settings would use."}],output:[{name:"base_url",type:"string",required:!0,constraint:"The HTTP URL configured for the TCP listener."},{name:"token",type:"string",required:!0,constraint:"The bearer token accepted by that listener: the owner token, or with --scopes the newly minted scoped token. Paste it only into the application that needs daemon access."}],outputKind:"object",effects:["Stores a missing listener address in user settings and a missing owner bearer token in the 0600 user secrets store.","With --scopes, appends a new scoped token to that secrets store; there is no revoke verb yet, so removing one means editing the store by hand.","When the listener is not already up with both settings present, or a scoped token was minted (the daemon reads tokens only at boot), asks the daemon to hand over to a successor.","After the listener is available, resolves the provider selected by these params (default: this directory) and runs its existing OAuth login flow when that provider has no usable credential."]},run:i(async e=>{const n={profile:e.profile,cwd:R.resolve(e.cwd??process.cwd()),kind:e.kind,model:e.model},t=j(e.scopes),r=e.app;if(t===void 0!=(r===void 0)||r!==void 0&&!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(String(r)))throw new s({error:"invalid_app",message:"--app must name an app id and is required exactly when --scopes is set",field:"app",received:r,next:"Pass --app with an app id and --scopes together, or omit both for the owner token."});const a=N(),o=k("user").api.tcp,l=b("user"),d=T(),w=await d.status();o===""?await y("user",h=>{h.api.tcp=O}):Number(o.slice(o.lastIndexOf(":")+1))===0&&await y("user",h=>{h.api.tcp=W(o)});const f=D()??k("user").api.tcp;if(Number(f.slice(f.lastIndexOf(":")+1))===0)throw new s({error:"dynamic_tcp_port",message:"CRTRD_TCP must use a fixed port for `crtr sys connect`",next:"Set CRTRD_TCP to a host and fixed port, then run `crtr sys connect` again."});if(t===void 0&&o!==""&&l!==void 0&&w.listeners.tcp!==null)return await _(d,n),{base_url:`http://${w.listeners.tcp}`,token:v()??l};l===void 0&&I(C(),"user");const g=v()??b("user");if(g===void 0)throw new Error("TCP listener cannot start without a bearer token");let u=g;t!==void 0&&(u=C(),q({token:u,grantee:`app:${String(r)}`,scopes:t,created:new Date().toISOString()},"user")),U({base_url:`http://${f}`,token:u}),await d.restartDaemon(),await z(),await _(d,n),a!==void 0&&await d.sendMessage(a,{body:"Browser access is ready.",tier:"urgent",from:a})},"run")});export{F as sysConnectLeaf};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
var
|
|
1
|
+
var w=Object.defineProperty;var r=(t,e)=>w(t,"name",{value:e,configurable:!0});import{envNodeId as l}from"../../../shared/env.js";import{writeFileSync as h}from"node:fs";import{tmpdir as f}from"node:os";import{join as y}from"node:path";import{defineLeaf as g}from"../../../core/command.js";import{InputError as o}from"../../../core/io.js";import{openNodeWindow as x}from"../../../core/runtime/placement-tmux.js";import{ApiError as _}from"../../../api/index.js";import{cliClient as i}from"../../api-client.js";import{shellQuote as $}from"../../../shared/shell-quote.js";const S=g({name:"sysprompt",description:"print a node's assembled system prompt",whenToUse:"you want to inspect a node's assembled system prompt headlessly, without paying conversation/context cost \u2014 this command prints the text from the node's latest launch recipe as markdown.",help:{name:"sys context sysprompt",summary:"print a node's assembled system prompt",params:[{kind:"positional",name:"node",required:!1,constraint:"Node id. Defaults to the calling node (CRTR_NODE_ID)."},{kind:"flag",name:"window",type:"bool",required:!1,constraint:"Open the assembled prompt in a NEW tmux window in the session currently showing that node instead of printing to stdout."}],output:[{name:"node_id",type:"string",required:!0,constraint:"The node whose prompt was read."},{name:"captured_at",type:"string",required:!0,constraint:"Time of the read in ISO-8601 UTC."},{name:"chars",type:"number",required:!0,constraint:"Character count of the stored prompt."},{name:"prompt",type:"string",required:!0,constraint:"The system prompt text the latest launch recipe passes to pi."},{name:"session",type:"string",required:!1,constraint:"tmux session showing the node (only when --window is used)."},{name:"window",type:"string",required:!1,constraint:"tmux window opened for the prompt (only when --window is used)."}],outputKind:"object",effects:["Read-only: reads the system prompt from the node's latest launch recipe, or opens it in a tmux window."],preview:{suppressOutput:!0}},run:r(async t=>{const e=t.node?.trim()||l();if(e===void 0||e==="")throw new o({error:"empty_node",message:"a node id is required",field:"node",next:"Pass a node id or run from inside a node."});try{await i().getNode(e)}catch(n){throw n instanceof _&&n.status===404?new o({error:"not_found",message:`no node: ${e}`,field:"node",next:"List nodes with `crtr node inspect list`."}):n}const d=await i().getSession(e),s=d.system_prompt;if(s===null)throw new o({error:"not_found",message:`node ${e} has no launch recipe yet`,field:"node",next:"Revive the node once, then rerun `crtr sys context sysprompt <node>`."});const c=d.captured_at;if(t.window===!0){const n=await i().focusOf(e);if(n===null||n.session===null||n.session==="")throw new o({error:"not_focused",message:`node ${e} is not currently shown in tmux`,field:"node",next:`Focus the node first with \`crtr surface node focus ${e}\`, then rerun \`crtr sys context sysprompt --window ${e}\`.`});const a=y(f(),`crtr-sysprompt-${e}.md`);h(a,s,"utf8");const p=$(a),u=`if command -v bat >/dev/null 2>&1; then bat --language=markdown --color=always --paging=always --style=plain ${p}; else less -R ${p}; fi`,m=x({session:n.session,name:`sysprompt:${e}`,cwd:process.cwd(),env:{},command:u});if(m===null)throw new o({error:"window_open_failed",message:`tmux could not open a window for node ${e}`,field:"node",next:"Check the tmux server is reachable, then retry."});return{node_id:e,session:n.session,window:m.window}}return{node_id:e,captured_at:c,chars:s.length,prompt:s}},"run"),render:r(t=>"window"in t?`Opened system prompt for node ${t.node_id} in tmux session ${t.session} \u2014 window ${t.window}.`:`- node_id: ${t.node_id}
|
|
2
2
|
- captured_at: ${t.captured_at}
|
|
3
3
|
- chars: ${t.chars}
|
|
4
4
|
|
|
5
|
-
${t.prompt}`,"render")});export{
|
|
5
|
+
${t.prompt}`,"render")});export{S as sysSyspromptLeaf};
|