@north-light/crouter 0.3.349 → 0.3.350
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/bin/crtr-launcher +4 -0
- package/bin/runtime-generation-manifest.mjs +12 -2
- package/dist/api/client.d.ts +50 -7
- package/dist/api/client.js +2 -2
- package/dist/api/dto/analytics.d.ts +184 -0
- package/dist/api/dto/analytics.js +0 -0
- package/dist/api/dto/broker-ops.d.ts +43 -1
- package/dist/api/dto/config.d.ts +11 -0
- package/dist/api/dto/grants.d.ts +14 -0
- package/dist/api/dto/grants.js +0 -0
- package/dist/api/dto/human-requests.d.ts +14 -0
- package/dist/api/dto/memory.d.ts +6 -0
- package/dist/api/dto/modelauth.d.ts +35 -0
- package/dist/api/dto/node-records.d.ts +35 -0
- package/dist/api/dto/node-records.js +0 -0
- package/dist/api/dto/nodes.d.ts +5 -0
- package/dist/api/dto/profiles.d.ts +38 -3
- package/dist/api/dto/worktree.d.ts +11 -0
- package/dist/api/errors.d.ts +23 -1
- package/dist/api/errors.js +1 -1
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +1 -1
- package/dist/api/node-transport.js +1 -1
- package/dist/api/routes.d.ts +22 -0
- package/dist/api/routes.js +1 -1
- package/dist/build-root.d.ts +6 -1
- package/dist/build-root.js +1 -1
- package/dist/builtin-memory/crouter-sdk/client.md +34 -0
- package/dist/builtin-memory/crouter-sdk/errors.md +2 -0
- package/dist/builtin-memory/crouter-sdk/memory.md +2 -2
- package/dist/builtin-memory/crouter-sdk/streaming.md +21 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +8 -4
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +39 -118
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +6 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +41 -27
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +52 -29
- package/dist/cli.js +9 -8
- package/dist/clients/attach/chrome/inbox-strip.js +1 -1
- package/dist/clients/attach/chrome/roster.js +1 -1
- package/dist/clients/attach/config.js +1 -1
- package/dist/clients/attach/overlays/auth.js +2 -2
- package/dist/clients/attach/overlays/graph.js +1 -1
- package/dist/clients/attach/render/tool-calls.js +3 -3
- package/dist/clients/attach/session/connection.js +1 -1
- package/dist/clients/attach/session/profile-files.js +1 -1
- package/dist/clients/attach/viewer.js +1569 -816
- package/dist/commands/api-client.js +3 -3
- package/dist/commands/broker-permissions.d.ts +2 -0
- package/dist/commands/broker-permissions.js +1 -0
- package/dist/commands/canvas-analytics/chart.d.ts +52 -0
- package/dist/commands/canvas-analytics/chart.js +1 -0
- package/dist/commands/canvas-analytics/drilldown.d.ts +34 -0
- package/dist/commands/canvas-analytics/drilldown.js +1 -0
- package/dist/commands/canvas-analytics/format.d.ts +29 -0
- package/dist/commands/canvas-analytics/format.js +1 -0
- package/dist/commands/canvas-analytics/graph-detail.d.ts +2 -0
- package/dist/commands/canvas-analytics/graph-detail.js +2 -0
- package/dist/commands/canvas-analytics/graphs.d.ts +9 -0
- package/dist/commands/canvas-analytics/graphs.js +1 -0
- package/dist/commands/canvas-analytics/memory.d.ts +2 -0
- package/dist/commands/canvas-analytics/memory.js +1 -0
- package/dist/commands/canvas-analytics/overview.d.ts +2 -0
- package/dist/commands/canvas-analytics/overview.js +1 -0
- package/dist/commands/canvas-analytics/shell.d.ts +60 -0
- package/dist/commands/canvas-analytics/shell.js +2 -0
- package/dist/commands/canvas-analytics/time.d.ts +2 -0
- package/dist/commands/canvas-analytics/time.js +1 -0
- package/dist/commands/canvas-analytics/usage.d.ts +2 -0
- package/dist/commands/canvas-analytics/usage.js +1 -0
- package/dist/commands/canvas-analytics/view.d.ts +85 -0
- package/dist/commands/canvas-analytics/view.js +1 -0
- package/dist/commands/canvas-analytics.d.ts +2 -0
- package/dist/commands/canvas-analytics.js +1 -0
- package/dist/commands/canvas-prune.js +1 -1
- package/dist/commands/canvas.js +1 -1
- package/dist/commands/cron.js +5 -5
- package/dist/commands/human/components.d.ts +2 -0
- package/dist/commands/human/components.js +2 -2
- package/dist/commands/human/prompts.js +1 -1
- package/dist/commands/human/queue.js +1 -1
- package/dist/commands/memory/client.d.ts +11 -0
- package/dist/commands/memory/client.js +1 -0
- package/dist/commands/memory/delete.js +1 -1
- package/dist/commands/memory/edit.js +3 -3
- package/dist/commands/memory/find.js +1 -1
- package/dist/commands/memory/history.js +4 -4
- package/dist/commands/memory/lint.js +1 -1
- package/dist/commands/memory/list.d.ts +0 -2
- package/dist/commands/memory/list.js +1 -1
- package/dist/commands/memory/move.js +1 -1
- package/dist/commands/memory/origin.js +1 -1
- package/dist/commands/memory/read.d.ts +0 -5
- package/dist/commands/memory/read.js +3 -3
- package/dist/commands/memory/shared.d.ts +0 -178
- package/dist/commands/memory/shared.js +1 -12
- package/dist/commands/memory/write.js +5 -5
- package/dist/commands/node/bash.js +5 -5
- package/dist/commands/node/create.d.ts +0 -17
- package/dist/commands/node/create.js +2 -3
- package/dist/commands/node/inspect.js +6 -6
- package/dist/commands/node/lifecycle.js +2 -2
- package/dist/commands/node-context.js +2 -2
- package/dist/commands/node-inspect-artifacts.js +6 -6
- package/dist/commands/pkg/browse/catalog.js +1 -1
- package/dist/commands/pkg/browse/model.d.ts +1 -1
- package/dist/commands/pkg/market-manage.js +1 -1
- package/dist/commands/pkg/plugin-manage.js +10 -10
- package/dist/commands/profile/daemon-profiles.d.ts +13 -0
- package/dist/commands/profile/daemon-profiles.js +4 -0
- package/dist/commands/profile/delete.js +1 -1
- package/dist/commands/profile/env.d.ts +6 -0
- package/dist/commands/profile/env.js +2 -2
- package/dist/commands/profile/kind.js +1 -2
- package/dist/commands/profile/list.js +1 -1
- package/dist/commands/profile/meta.js +1 -1
- package/dist/commands/profile/new.js +1 -1
- package/dist/commands/profile/pause.js +1 -1
- package/dist/commands/profile/project.js +1 -1
- package/dist/commands/profile/rename.js +1 -1
- package/dist/commands/profile/show.js +1 -1
- package/dist/commands/profile.js +1 -1
- package/dist/commands/push.js +3 -3
- package/dist/commands/surface-inspect.js +1 -1
- package/dist/commands/sys/branch.js +1 -1
- package/dist/commands/sys/config.js +1 -1
- package/dist/commands/sys/connect.js +3 -3
- package/dist/commands/sys/context/admin/actions.js +1 -1
- package/dist/commands/sys/context/admin/model.d.ts +1 -0
- package/dist/commands/sys/context/admin/model.js +1 -1
- package/dist/commands/sys/context/admin.js +1 -1
- package/dist/commands/sys/context/expose.js +2 -1
- package/dist/commands/sys/context/prompt-review.js +2 -2
- package/dist/commands/sys/context/resolve.js +7 -7
- package/dist/commands/sys/context/sysprompt.js +1 -1
- package/dist/commands/sys/join.d.ts +1 -0
- package/dist/commands/sys/join.js +1 -0
- package/dist/commands/sys/migrate.js +1 -1
- package/dist/commands/sys/panels/models-panel.js +1 -1
- package/dist/commands/sys/panels/profiles-panel.d.ts +0 -1
- package/dist/commands/sys/panels/profiles-panel.js +1 -1
- package/dist/commands/sys/provider-login.js +6 -6
- package/dist/commands/sys/setup-core.d.ts +1 -1
- package/dist/commands/sys/setup-core.js +6 -6
- package/dist/commands/sys/setup-settings-runner.js +1 -1
- package/dist/commands/sys/setup.js +1 -1
- package/dist/commands/sys/spaces.d.ts +1 -0
- package/dist/commands/sys/spaces.js +2 -0
- package/dist/commands/sys/sync-deps.js +2 -2
- package/dist/commands/sys/sync-project-guidance.js +4 -4
- package/dist/commands/sys/sync-skills.js +2 -2
- package/dist/commands/sys/worktrees.d.ts +1 -0
- package/dist/commands/sys/worktrees.js +1 -1
- package/dist/commands/sys.js +1 -1
- package/dist/core/auth-file.js +2 -2
- package/dist/core/bash-job-supervisor.d.ts +6 -0
- package/dist/core/bash-job-supervisor.js +4 -0
- package/dist/core/bash-jobs.d.ts +13 -6
- package/dist/core/bash-jobs.js +8 -7
- package/dist/core/broker-client/transport-relay.d.ts +6 -3
- package/dist/core/broker-client/transport-relay.js +1 -1
- package/dist/core/broker-client/transport-socket.d.ts +6 -1
- package/dist/core/broker-client/transport-socket.js +1 -1
- package/dist/core/canvas/canvas.d.ts +39 -18
- package/dist/core/canvas/canvas.js +21 -20
- package/dist/core/canvas/context-strip.d.ts +20 -0
- package/dist/core/canvas/context-strip.js +5 -0
- package/dist/core/canvas/crons.d.ts +12 -20
- package/dist/core/canvas/crons.js +15 -13
- package/dist/core/canvas/db.js +2 -2
- package/dist/core/canvas/deliveries.d.ts +4 -1
- package/dist/core/canvas/deliveries.js +1 -1
- package/dist/core/canvas/executions.js +1 -1
- package/dist/core/canvas/history.d.ts +2 -1
- package/dist/core/canvas/history.js +17 -18
- package/dist/core/canvas/memory-reads.d.ts +19 -0
- package/dist/core/canvas/memory-reads.js +1 -0
- package/dist/core/canvas/migrations.d.ts +0 -4
- package/dist/core/canvas/migrations.js +99 -32
- package/dist/core/canvas/nav-render.js +1 -1
- package/dist/core/canvas/node-agent-paths.d.ts +8 -0
- package/dist/core/canvas/node-agent-paths.js +1 -0
- package/dist/core/canvas/node-recap.d.ts +2 -2
- package/dist/core/canvas/node-recap.js +2 -2
- package/dist/core/canvas/node-tokens.d.ts +24 -0
- package/dist/core/canvas/node-tokens.js +5 -0
- package/dist/core/canvas/paths.d.ts +16 -19
- package/dist/core/canvas/paths.js +1 -1
- package/dist/core/canvas/render-source.d.ts +2 -2
- package/dist/core/canvas/render-source.js +6 -9
- package/dist/core/canvas/sessions.d.ts +18 -0
- package/dist/core/canvas/sessions.js +4 -1
- package/dist/core/canvas/types.d.ts +22 -6
- package/dist/core/command-hooks/compose.js +1 -1
- package/dist/core/command-hooks/discovery.d.ts +15 -1
- package/dist/core/command-hooks/discovery.js +1 -1
- package/dist/core/command-hooks/help.d.ts +2 -2
- package/dist/core/command-hooks/lifecycle-create.d.ts +1 -1
- package/dist/core/command-hooks/lifecycle-create.js +1 -1
- package/dist/core/command-hooks/transport/exec-invoke.d.ts +2 -0
- package/dist/core/command-hooks/transport/exec-invoke.js +1 -1
- package/dist/core/command-hooks/transport/exec-lifecycle.d.ts +1 -0
- package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
- package/dist/core/command-hooks/transport/plan.d.ts +3 -0
- package/dist/core/command-hooks/transport/plan.js +1 -0
- package/dist/core/command-plugins/discovery.js +1 -1
- package/dist/core/command.d.ts +6 -2
- package/dist/core/command.js +6 -6
- package/dist/core/config.d.ts +8 -5
- package/dist/core/config.js +1 -1
- package/dist/core/conversation-store/client-worker.d.ts +1 -0
- package/dist/core/conversation-store/client-worker.js +1 -0
- package/dist/core/conversation-store/client.d.ts +2 -0
- package/dist/core/conversation-store/client.js +2 -0
- package/dist/core/conversation-store/file-store.d.ts +37 -0
- package/dist/core/conversation-store/file-store.js +9 -0
- package/dist/core/conversation-store/index.d.ts +50 -0
- package/dist/core/conversation-store/index.js +1 -0
- package/dist/core/conversation-store/listener.d.ts +4 -0
- package/dist/core/conversation-store/listener.js +3 -0
- package/dist/core/conversation-store/patch.d.ts +1 -0
- package/dist/core/conversation-store/patch.js +1 -0
- package/dist/core/directory/join.d.ts +27 -0
- package/dist/core/directory/join.js +1 -0
- package/dist/core/disk-usage.d.ts +4 -0
- package/dist/core/disk-usage.js +1 -0
- package/dist/core/events/emit.d.ts +2 -0
- package/dist/core/events/emit.js +3 -1
- package/dist/core/feed/feed.js +4 -4
- package/dist/core/feed/messages.d.ts +3 -0
- package/dist/core/feed/messages.js +6 -6
- package/dist/core/fs-utils.d.ts +2 -0
- package/dist/core/fs-utils.js +3 -3
- package/dist/core/grants/local.d.ts +4 -0
- package/dist/core/grants/local.js +1 -0
- package/dist/core/grants/mirror.d.ts +44 -0
- package/dist/core/grants/mirror.js +4 -0
- package/dist/core/grants/on-sync.d.ts +22 -0
- package/dist/core/grants/on-sync.js +1 -0
- package/dist/core/grants/remove.d.ts +7 -0
- package/dist/core/grants/remove.js +1 -0
- package/dist/core/grants/sandboxes.d.ts +7 -0
- package/dist/core/grants/sandboxes.js +1 -0
- package/dist/core/grants/sync.d.ts +12 -0
- package/dist/core/grants/sync.js +1 -0
- package/dist/core/help/memory-extensions.d.ts +3 -0
- package/dist/core/help/memory-extensions.js +2 -0
- package/dist/core/help.d.ts +14 -0
- package/dist/core/help.js +7 -7
- package/dist/core/host-exports/builtins.js +3 -3
- package/dist/core/host-exports/export.js +3 -3
- package/dist/core/human/action-binding.d.ts +2 -0
- package/dist/core/human/action-binding.js +1 -1
- package/dist/core/human/feedback-companion.d.ts +0 -1
- package/dist/core/human/feedback-companion.js +1 -1
- package/dist/core/human/page-schema.d.ts +1 -1
- package/dist/core/inspector/core.d.ts +2 -0
- package/dist/core/inspector/core.js +1 -1
- package/dist/core/inspector/tui.js +2 -2
- package/dist/core/installed-plugins.js +1 -1
- package/dist/core/io.js +6 -6
- package/dist/core/keybindings/catalog.d.ts +1 -1
- package/dist/core/keybindings/catalog.js +1 -1
- package/dist/core/layout-migrate/index.d.ts +15 -0
- package/dist/core/layout-migrate/index.js +4 -0
- package/dist/core/layout-migrate/paths.d.ts +26 -0
- package/dist/core/layout-migrate/paths.js +1 -0
- package/dist/core/layout-migrate/stored-paths.d.ts +2 -0
- package/dist/core/layout-migrate/stored-paths.js +11 -0
- package/dist/core/layout-migrate/stores.d.ts +17 -0
- package/dist/core/layout-migrate/stores.js +4 -0
- package/dist/core/layout.d.ts +26 -0
- package/dist/core/layout.js +2 -0
- package/dist/core/llm/run.d.ts +60 -0
- package/dist/core/llm/run.js +4 -0
- package/dist/core/memory/cli-selector.d.ts +13 -0
- package/dist/core/memory/cli-selector.js +1 -0
- package/dist/core/memory/history.d.ts +5 -4
- package/dist/core/memory/history.js +6 -6
- package/dist/core/memory/inline-ref-inventory.d.ts +2 -1
- package/dist/core/memory/inline-ref-inventory.js +1 -1
- package/dist/core/memory/lint.js +2 -2
- package/dist/core/memory/mutation-domain.d.ts +2 -2
- package/dist/core/memory/mutation-domain.js +8 -7
- package/dist/core/memory/mutations.js +1 -1
- package/dist/core/memory/service.d.ts +5 -0
- package/dist/core/memory/service.js +2 -2
- package/dist/core/memory-resolver.d.ts +11 -7
- package/dist/core/memory-resolver.js +2 -2
- package/dist/core/model-auth/daemon-login.d.ts +13 -0
- package/dist/core/model-auth/daemon-login.js +1 -0
- package/dist/core/model-auth/flows.d.ts +45 -0
- package/dist/core/model-auth/flows.js +1 -0
- package/dist/core/model-auth/handoff-jti.d.ts +4 -0
- package/dist/core/model-auth/handoff-jti.js +1 -0
- package/dist/core/model-routes.js +1 -1
- package/dist/core/nested-stores.d.ts +2 -1
- package/dist/core/nested-stores.js +1 -2
- package/dist/core/preview-registry.js +2 -2
- package/dist/core/profiles/env-store.js +2 -2
- package/dist/core/profiles/manifest.d.ts +16 -5
- package/dist/core/profiles/manifest.js +1 -1
- package/dist/core/provider-management.js +1 -1
- package/dist/core/review/birth.js +1 -1
- package/dist/core/review/companion.d.ts +0 -2
- package/dist/core/review/companion.js +1 -1
- package/dist/core/review/fork.js +2 -2
- package/dist/core/review/realize.js +1 -1
- package/dist/core/review/stage.d.ts +1 -1
- package/dist/core/review/stage.js +1 -1
- package/dist/core/review/types.d.ts +1 -1
- package/dist/core/runs/events.d.ts +34 -0
- package/dist/core/runs/events.js +1 -0
- package/dist/core/runs/operations.d.ts +43 -0
- package/dist/core/runs/operations.js +12 -0
- package/dist/core/runtime/bearings-render.d.ts +2 -2
- package/dist/core/runtime/bearings-render.js +11 -11
- package/dist/core/runtime/bearings.js +2 -2
- package/dist/core/runtime/broker/cli-relay.d.ts +5 -0
- package/dist/core/runtime/broker/cli-relay.js +1 -0
- package/dist/core/runtime/broker/client-registry.d.ts +0 -5
- package/dist/core/runtime/broker/client-registry.js +1 -1
- package/dist/core/runtime/broker/daemon-ops.d.ts +28 -1
- package/dist/core/runtime/broker/daemon-ops.js +1 -1
- package/dist/core/runtime/broker/engine-drive.d.ts +0 -2
- package/dist/core/runtime/broker/engine-drive.js +1 -1
- package/dist/core/runtime/broker/fault-retry.d.ts +9 -0
- package/dist/core/runtime/broker/fault-retry.js +1 -1
- package/dist/core/runtime/broker/frame-dispatch.d.ts +5 -9
- package/dist/core/runtime/broker/frame-dispatch.js +1 -1
- package/dist/core/runtime/broker/frame-engine-control.d.ts +3 -2
- package/dist/core/runtime/broker/frame-engine-control.js +1 -1
- package/dist/core/runtime/broker/frame-memory-refs.d.ts +4 -3
- package/dist/core/runtime/broker/frame-memory-refs.js +1 -1
- package/dist/core/runtime/broker/frame-read.js +1 -1
- package/dist/core/runtime/broker/frame-session.js +1 -1
- package/dist/core/runtime/broker/held-deferred-inbox.d.ts +3 -1
- package/dist/core/runtime/broker/held-deferred-inbox.js +1 -1
- package/dist/core/runtime/broker/inbox.d.ts +1 -2
- package/dist/core/runtime/broker/inbox.js +7 -10
- package/dist/core/runtime/broker/model-adapter.d.ts +9 -0
- package/dist/core/runtime/broker/model-adapter.js +2 -0
- package/dist/core/runtime/broker/node-token.d.ts +3 -0
- package/dist/core/runtime/broker/node-token.js +1 -0
- package/dist/core/runtime/broker/read-ops.js +1 -1
- package/dist/core/runtime/broker/rebind.d.ts +2 -0
- package/dist/core/runtime/broker/rebind.js +1 -1
- package/dist/core/runtime/broker/tool-groups.js +1 -1
- package/dist/core/runtime/broker/turn-ignition.d.ts +3 -3
- package/dist/core/runtime/broker/turn-ignition.js +1 -1
- package/dist/core/runtime/broker-cli.js +3 -3
- package/dist/core/runtime/broker-extension-render.d.ts +2 -5
- package/dist/core/runtime/broker-extension-render.js +4 -4
- package/dist/core/runtime/broker-persona-guidance.js +3 -3
- package/dist/core/runtime/broker-protocol.d.ts +7 -8
- package/dist/core/runtime/broker.js +1 -1
- package/dist/core/runtime/canvas-extensions.d.ts +1 -0
- package/dist/core/runtime/canvas-extensions.js +1 -1
- package/dist/core/runtime/close.d.ts +9 -0
- package/dist/core/runtime/close.js +1 -1
- package/dist/core/runtime/deliver-live.js +1 -1
- package/dist/core/runtime/fleet.d.ts +1 -1
- package/dist/core/runtime/front-door-login.js +1 -1
- package/dist/core/runtime/front-door.js +2 -2
- package/dist/core/runtime/headless-pi.d.ts +1 -1
- package/dist/core/runtime/headless-pi.js +1 -1
- package/dist/core/runtime/host.d.ts +1 -1
- package/dist/core/runtime/host.js +3 -1
- package/dist/core/runtime/invocation.d.ts +3 -0
- package/dist/core/runtime/kickoff.d.ts +1 -0
- package/dist/core/runtime/kickoff.js +16 -16
- package/dist/core/runtime/launch-target.d.ts +1 -1
- package/dist/core/runtime/launch-target.js +1 -1
- package/dist/core/runtime/launch.d.ts +10 -35
- package/dist/core/runtime/launch.js +1 -1
- package/dist/core/runtime/lifecycle.js +2 -2
- package/dist/core/runtime/memory.d.ts +1 -1
- package/dist/core/runtime/memory.js +1 -1
- package/dist/core/runtime/model-registry.js +1 -1
- package/dist/core/runtime/model-swap.d.ts +17 -19
- package/dist/core/runtime/model-swap.js +1 -1
- package/dist/core/runtime/node-read.js +3 -2
- package/dist/core/runtime/nodes.d.ts +7 -0
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/core/runtime/outcome-document.js +1 -1
- package/dist/core/runtime/package-health.js +2 -2
- package/dist/core/runtime/persona.js +2 -2
- package/dist/core/runtime/pi-vendored.js +1 -1
- package/dist/core/runtime/placement-tmux.d.ts +1 -1
- package/dist/core/runtime/placement-tmux.js +1 -1
- package/dist/core/runtime/placement.js +1 -1
- package/dist/core/runtime/promote.js +1 -1
- package/dist/core/runtime/provider-credential-gate.js +2 -2
- package/dist/core/runtime/recovery-hold.d.ts +2 -0
- package/dist/core/runtime/recovery-hold.js +1 -0
- package/dist/core/runtime/recycle.js +1 -1
- package/dist/core/runtime/reopen.js +1 -1
- package/dist/core/runtime/reset.js +1 -1
- package/dist/core/runtime/revive.d.ts +1 -1
- package/dist/core/runtime/revive.js +2 -3
- package/dist/core/runtime/roadmap.js +4 -4
- package/dist/core/runtime/run-command.d.ts +6 -0
- package/dist/core/runtime/run-command.js +1 -1
- package/dist/core/runtime/session-branch.d.ts +2 -8
- package/dist/core/runtime/session-branch.js +1 -1
- package/dist/core/runtime/session-list-cache.d.ts +6 -22
- package/dist/core/runtime/session-list-cache.js +1 -1
- package/dist/core/runtime/situational-context.js +2 -2
- package/dist/core/runtime/spawn-env.d.ts +6 -6
- package/dist/core/runtime/spawn-env.js +1 -1
- package/dist/core/runtime/spawn.d.ts +5 -0
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/core/runtime/stop-guard.js +2 -2
- package/dist/core/runtime/stop-signals.d.ts +2 -2
- package/dist/core/runtime/stop-signals.js +1 -1
- package/dist/core/runtime/structured-output.d.ts +10 -4
- package/dist/core/runtime/structured-output.js +4 -4
- package/dist/core/runtime/tmux-bindings.js +3 -3
- package/dist/core/runtime/tmux-driver.d.ts +4 -0
- package/dist/core/runtime/tmux-driver.js +7 -7
- package/dist/core/runtime/view-socket.d.ts +9 -2
- package/dist/core/runtime/view-socket.js +1 -1
- package/dist/core/runtime/warm-pool.js +1 -1
- package/dist/core/scope.d.ts +3 -2
- package/dist/core/scope.js +1 -1
- package/dist/core/scoped-state/db.js +1 -1
- package/dist/core/scoped-state/migrate.js +3 -3
- package/dist/core/scoped-state/profiles.d.ts +2 -1
- package/dist/core/scoped-state/profiles.js +1 -1
- package/dist/core/scoped-state/schema.d.ts +2 -1
- package/dist/core/scoped-state/schema.js +4 -4
- package/dist/core/scopes.d.ts +2 -2
- package/dist/core/scopes.js +1 -1
- package/dist/core/secrets.d.ts +1 -0
- package/dist/core/secrets.js +2 -2
- package/dist/core/spaces/mounts.d.ts +32 -0
- package/dist/core/spaces/mounts.js +1 -0
- package/dist/core/spaces/open-beneath.d.ts +71 -0
- package/dist/core/spaces/open-beneath.js +1 -0
- package/dist/core/spaces/permissions.d.ts +46 -0
- package/dist/core/spaces/permissions.js +1 -0
- package/dist/core/spaces/process.d.ts +27 -0
- package/dist/core/spaces/process.js +1 -0
- package/dist/core/spaces/space.d.ts +8 -0
- package/dist/core/spaces/space.js +2 -0
- package/dist/core/spaces/stop.d.ts +8 -0
- package/dist/core/spaces/stop.js +2 -0
- package/dist/core/spaces/users.d.ts +19 -0
- package/dist/core/spaces/users.js +1 -0
- package/dist/core/subscription-state.d.ts +2 -0
- package/dist/core/subscription-state.js +3 -3
- package/dist/core/substrate/frontmatter-validation.js +1 -1
- package/dist/core/substrate/injected-store.d.ts +28 -3
- package/dist/core/substrate/injected-store.js +2 -1
- package/dist/core/substrate/listings.js +1 -1
- package/dist/core/substrate/memory-events.d.ts +6 -0
- package/dist/core/substrate/memory-events.js +1 -0
- package/dist/core/substrate/on-read-node.js +1 -1
- package/dist/core/substrate/on-read.d.ts +6 -6
- package/dist/core/substrate/on-read.js +5 -5
- package/dist/core/substrate/plan.js +1 -1
- package/dist/core/substrate/render-node.js +1 -1
- package/dist/core/substrate/render.d.ts +4 -3
- package/dist/core/substrate/render.js +38 -38
- package/dist/core/substrate/schema.d.ts +6 -0
- package/dist/core/substrate/schema.js +1 -1
- package/dist/core/tui/panel.js +1 -1
- package/dist/core/user-settings.d.ts +12 -0
- package/dist/core/user-settings.js +1 -1
- package/dist/core/worktree-mutation-async.js +5 -5
- package/dist/core/worktree-quarantine.js +1 -1
- package/dist/core/worktree-remove.d.ts +15 -0
- package/dist/core/worktree-remove.js +1 -0
- package/dist/core/worktree-sweep.js +6 -6
- package/dist/daemon/analytics/compute.d.ts +37 -0
- package/dist/daemon/analytics/compute.js +1 -0
- package/dist/daemon/analytics/scan-worker.d.ts +1 -0
- package/dist/daemon/analytics/scan-worker.js +2 -0
- package/dist/daemon/analytics/scan.d.ts +37 -0
- package/dist/daemon/analytics/scan.js +1 -0
- package/dist/daemon/api/app-listener.d.ts +11 -0
- package/dist/daemon/api/app-listener.js +21 -0
- package/dist/daemon/api/bridge.js +5 -5
- package/dist/daemon/api/handlers/analytics.d.ts +2 -0
- package/dist/daemon/api/handlers/analytics.js +1 -0
- package/dist/daemon/api/handlers/attach.js +1 -1
- package/dist/daemon/api/handlers/bash-jobs.js +2 -2
- package/dist/daemon/api/handlers/bash.js +1 -1
- package/dist/daemon/api/handlers/broker-ops.js +1 -1
- package/dist/daemon/api/handlers/canvas.d.ts +1 -1
- package/dist/daemon/api/handlers/canvas.js +6 -6
- package/dist/daemon/api/handlers/crons.js +1 -1
- package/dist/daemon/api/handlers/files.d.ts +1 -1
- package/dist/daemon/api/handlers/files.js +1 -1
- package/dist/daemon/api/handlers/health.js +2 -2
- package/dist/daemon/api/handlers/hook-exec.d.ts +2 -0
- package/dist/daemon/api/handlers/hook-exec.js +1 -0
- package/dist/daemon/api/handlers/human-requests.js +1 -1
- package/dist/daemon/api/handlers/inbox.js +1 -1
- package/dist/daemon/api/handlers/llm.d.ts +2 -0
- package/dist/daemon/api/handlers/llm.js +3 -0
- package/dist/daemon/api/handlers/memory-reads.d.ts +4 -0
- package/dist/daemon/api/handlers/memory-reads.js +1 -0
- package/dist/daemon/api/handlers/memory.js +5 -1
- package/dist/daemon/api/handlers/messages.js +2 -2
- package/dist/daemon/api/handlers/modelauth.js +1 -1
- package/dist/daemon/api/handlers/node-outcomes.js +1 -1
- package/dist/daemon/api/handlers/node-records.d.ts +2 -0
- package/dist/daemon/api/handlers/node-records.js +3 -0
- package/dist/daemon/api/handlers/nodes.d.ts +1 -1
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/profiles.d.ts +4 -1
- package/dist/daemon/api/handlers/profiles.js +1 -1
- package/dist/daemon/api/handlers/reports.js +5 -3
- package/dist/daemon/api/handlers/reviews.d.ts +1 -1
- package/dist/daemon/api/handlers/reviews.js +1 -1
- package/dist/daemon/api/handlers/run-routes.d.ts +2 -0
- package/dist/daemon/api/handlers/run-routes.js +1 -0
- package/dist/daemon/api/handlers/runs.d.ts +9 -0
- package/dist/daemon/api/handlers/runs.js +1 -0
- package/dist/daemon/api/handlers/subscriptions.js +1 -1
- package/dist/daemon/api/handlers/worktree.js +1 -1
- package/dist/daemon/api/map.d.ts +10 -4
- package/dist/daemon/api/map.js +2 -2
- package/dist/daemon/api/operations.d.ts +18 -0
- package/dist/daemon/api/operations.js +1 -0
- package/dist/daemon/api/principal.d.ts +42 -0
- package/dist/daemon/api/principal.js +1 -0
- package/dist/daemon/api/router.d.ts +27 -3
- package/dist/daemon/api/router.js +1 -1
- package/dist/daemon/api/server.d.ts +4 -0
- package/dist/daemon/api/server.js +1 -1
- package/dist/daemon/api/vendor-signin.d.ts +7 -0
- package/dist/daemon/api/vendor-signin.js +77 -0
- package/dist/daemon/api/viewer-presence.d.ts +3 -0
- package/dist/daemon/api/viewer-presence.js +1 -0
- package/dist/daemon/cron/armed-context.d.ts +4 -0
- package/dist/daemon/cron/armed-context.js +1 -1
- package/dist/daemon/cron/escalation.js +3 -3
- package/dist/daemon/cron/lease-recovery.js +1 -1
- package/dist/daemon/cron/sinks.js +2 -2
- package/dist/daemon/cron-run.d.ts +5 -5
- package/dist/daemon/cron-run.js +1 -1
- package/dist/daemon/crtrd.js +8 -7
- package/dist/daemon/delivery/run-delivery.d.ts +4 -0
- package/dist/daemon/delivery/run-delivery.js +1 -1
- package/dist/daemon/fleet.d.ts +1 -1
- package/dist/daemon/fleet.js +6 -6
- package/dist/daemon/human/finish.js +7 -7
- package/dist/daemon/joined-owner.d.ts +5 -0
- package/dist/daemon/joined-owner.js +1 -0
- package/dist/daemon/manage.js +2 -2
- package/dist/daemon/messaging/node-message.js +1 -1
- package/dist/daemon/park-activity.js +1 -1
- package/dist/daemon/reconcilers/bash-deadline.js +1 -1
- package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
- package/dist/daemon/reconcilers/broker-supervision.js +4 -4
- package/dist/daemon/reconcilers/delivery-lane.js +1 -1
- package/dist/daemon/reconcilers/live-obligation.d.ts +7 -0
- package/dist/daemon/reconcilers/live-obligation.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +20 -1
- package/dist/daemon/reconcilers/storage-maintenance.js +1 -1
- package/dist/daemon/runs/append-section.d.ts +6 -0
- package/dist/daemon/runs/append-section.js +2 -0
- package/dist/daemon/runs/observer.d.ts +5 -0
- package/dist/daemon/runs/observer.js +4 -0
- package/dist/launcher/bwrap.d.ts +4 -0
- package/dist/launcher/bwrap.js +2 -0
- package/dist/launcher/client.d.ts +2 -0
- package/dist/launcher/client.js +3 -0
- package/dist/launcher/main.d.ts +1 -0
- package/dist/launcher/main.js +3 -0
- package/dist/launcher/netrule.d.ts +1 -0
- package/dist/launcher/netrule.js +1 -0
- package/dist/launcher/seccomp.d.ts +1 -0
- package/dist/launcher/seccomp.js +1 -0
- package/dist/launcher/spec.d.ts +88 -0
- package/dist/launcher/spec.js +1 -0
- package/dist/launcher/users.d.ts +18 -0
- package/dist/launcher/users.js +7 -0
- package/dist/launcher/validate.d.ts +22 -0
- package/dist/launcher/validate.js +1 -0
- package/dist/migrations/corpus.js +3 -3
- package/dist/migrations/runner.js +1 -1
- package/dist/native/linux/addon.node +0 -0
- package/dist/native/linux.d.ts +29 -0
- package/dist/native/linux.js +1 -0
- package/dist/pi-extensions/broker-local.js +2 -2
- package/dist/pi-extensions/canvas-bash-valve.d.ts +1 -3
- package/dist/pi-extensions/canvas-bash-valve.js +4 -7
- package/dist/pi-extensions/canvas-context-intro.d.ts +1 -2
- package/dist/pi-extensions/canvas-context-intro.js +2 -2
- package/dist/pi-extensions/canvas-doc-substrate.js +6 -6
- package/dist/pi-extensions/canvas-inbox-watcher.d.ts +2 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +2 -1
- package/dist/pi-extensions/canvas-passive-context.d.ts +1 -1
- package/dist/pi-extensions/canvas-passive-context.js +11 -11
- package/dist/pi-extensions/canvas-recap.js +6 -6
- package/dist/pi-extensions/canvas-stophook.js +1 -1
- package/dist/pi-extensions/canvas-structured-output.js +4 -4
- package/dist/pi-extensions/canvas-tool-guide.js +1 -1
- package/dist/pi-extensions/system-prompt-entry.d.ts +15 -0
- package/dist/pi-extensions/system-prompt-entry.js +1 -0
- package/dist/shared/env.d.ts +5 -1
- package/dist/shared/env.js +1 -1
- package/dist/shared/strip-cd-prefix.d.ts +1 -0
- package/dist/shared/strip-cd-prefix.js +1 -0
- package/dist/types.d.ts +31 -15
- package/docs/cli/memory-and-preferences.md +3 -1
- package/docs/sdk/client.md +34 -0
- package/docs/sdk/errors.md +2 -0
- package/docs/sdk/memory.md +2 -2
- package/docs/sdk/streaming.md +21 -0
- package/package.json +18 -4
- package/packages/crouter-identity/dist/index.d.ts +54 -0
- package/packages/crouter-identity/dist/index.js +166 -0
- package/packages/crouter-identity/package.json +33 -0
- package/runtime.lock.json +34 -8
- package/scripts/build-native-linux.mjs +16 -0
- package/scripts/install-runtime.mjs +9 -7
- package/scripts/lib/isolation-env.mjs +42 -0
- package/scripts/runtime-smoke.mjs +49 -0
- package/src/native/linux/addon.c +249 -0
- package/dist/core/profiles/state-block.d.ts +0 -4
- package/dist/core/profiles/state-block.js +0 -3
- package/dist/core/runtime/broker/auth-reload.d.ts +0 -41
- package/dist/core/runtime/broker/auth-reload.js +0 -1
- package/dist/core/substrate/cli-context-delivery.d.ts +0 -22
- package/dist/core/substrate/cli-context-delivery.js +0 -1
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
var J=Object.defineProperty;var o=(e,t)=>J(e,"name",{value:t,configurable:!0});import{envNodeId as W,envProfileId as K}from"../../shared/env.js";import{defineLeaf as Y}from"../../core/command.js";import{InputError as r}from"../../core/io.js";import{requireScope as G}from"../../core/errors.js";import{mark as O}from"../../core/timing.js";import{OUTPUT_SCHEMA_CONSTRAINTS as V,OUTPUT_SCHEMA_TRANSPORT as X,parseOutputSchemaValue as Q}from"../../core/runtime/structured-output.js";import{MODEL_SPEC_FORMS as Z,MODEL_SPEC_NEXT as ee}from"../../core/runtime/model-selection.js";import{readMergedLaunchConfig as R}from"../../core/config.js";import{parseDurationMs as te}from"../../core/wake.js";import{profilesStateBlock as ne}from"../../core/profiles/state-block.js";import{resolveProfileOperand as oe}from"../../core/profiles/manifest.js";import{stateBlock as re}from"../../core/help.js";import{cliClient as ie,getNodeOrNull as I,rethrowAsCliError as ae}from"../api-client.js";import{inTmux as $}from"../../core/runtime/placement-tmux.js";import{openSpawnViewer as se}from"../surface/node/placement.js";import{resolve as de}from"node:path";const le=1e5,F='--output-schema writes the accepted result to the node\u2019s context/result.json and pushes it as the node\u2019s final report; a node that cannot honestly satisfy the schema declines with `crtr push result --decline "<reason>" --code <token>`, which finishes it with a failure outcome (reason `declined`) whose `declined` field carries { reason, code, retryable } and no result. Name the code tokens you accept in the prompt; crouter carries the code verbatim and you validate it.',N="Do not wait, poll, or duplicate this child's assignment in your own context \u2014 there is no result to await, stopping will not strand you, and duplicated work wastes the delegated context. You're auto-subscribed, so its finish wakes you on its own. Two moves only: do other independent work right now, or stop and end your turn \u2014 the wake brings you back.";async function ce(e){if(e===void 0||e==="")return N;const t=await I(e);if(t===null||t.mode!=="orchestrator")return N;const n=t.context_tokens??null;return n===null||n<le?N:`Child spawned \u2014 you're auto-subscribed, so its finish wakes you on its own; never wait, poll, or duplicate the child's assignment in your own context. But you're an orchestrator already carrying ~${Math.round(n/1e3)}k of context: rather than hold this window open for the result, checkpoint context/roadmap.md and \`crtr node yield\` now. Yielding ends this turn, and the child's completion then revives you fresh against your roadmap \u2014 let that clean revive absorb the result instead of this bloated context.`}o(ce,"childFollowUp");function je(e){const t=Object.keys(R().kinds).sort();if(!t.includes(e))throw new r({error:"unknown_kind",message:`unknown kind: ${e}`,field:"kind",next:`Valid kinds: ${t.join(", ")}.`})}o(je,"assertKind");function ue(){const e=R().kinds,t=Object.keys(e).filter(i=>{const s=i.indexOf("/");return s===-1?!0:(e[i]?.availableTo??[i.slice(0,s)]).includes("*")}).sort(),n=t.map(i=>{const s=e[i]?.whenToUse??"";return s?`${i} \u2014 ${s}`:i}).join(`
|
|
2
|
-
`);return re("kinds",{count:t.length},n)}o(ue,"kindsStateBlock");function fe(){return[{kind:"stdin",name:"prompt",required:!1,constraint:"First user message."},{kind:"flag",name:"kind",type:"string",required:!1,constraint:"Persona kind. Defaults to the profile's default kind; `general` when the profile has none. The <kinds> list below names every top-level installable kind."},{kind:"flag",name:"mode",type:"enum",choices:["base","orchestrator"],required:!1,default:"base",constraint:"Persona mode. base for one hands-on unit; orchestrator when the unit itself needs decomposition across children. When you hold several parallel units of one kind, spawn ONE orchestrator child of that kind to own the fan-out rather than spawning the units yourself \u2014 unless you are already an orchestrator of that kind, whose job is exactly that fan-out."},{kind:"flag",name:"cwd",type:"path",required:!1,constraint:"Pin the node to this directory. Defaults to the spawner\u2019s directory for a managed child, and to the directory this command runs in for a root."},{kind:"flag",name:"name",type:"string",required:!1,constraint:"Display name."},{kind:"flag",name:"parent",type:"string",required:!1,constraint:"Parent node id. Defaults to the calling node."},{kind:"flag",name:"node-id",type:"string",required:!1,constraint:"Exact id for the new node; lowercase letters, digits, and hyphens only, at most 128 characters. Rejected if already present."},{kind:"flag",name:"root",type:"bool",required:!1,constraint:"Spawn an independent root with no parent or subscription. Mutually exclusive with --worktree."},{kind:"flag",name:"resident",type:"bool",required:!1,constraint:"Birth the node as resident: it parks and stays wakeable without being forced to submit a final. Pass it ONLY when the user will open this node\u2019s viewer pane and work with it back and forth; a child that only other nodes message stays terminal. Applies to managed children and roots; roots default to resident."},{kind:"flag",name:"terminal",type:"bool",required:!1,constraint:"Birth the node as terminal: it finalizes when its work is done and leaves nothing wakeable behind. Only meaningful with --root, whose default is resident; managed children are already terminal. Pass it for bounded programmatic work no one will open a viewer on. Mutually exclusive with --resident."},{kind:"flag",name:"worktree",type:"string",required:!1,constraint:"Local base branch for a crouter-managed worktree for this child. Mutually exclusive with --root."},{kind:"flag",name:"fork-from",type:"string",required:!1,constraint:"Fork the new node from an existing node id, absolute session path, or partial pi session uuid."},{kind:"flag",name:"model",type:"string",required:!1,constraint:"Durable model override. Omit unless the task or governing guidance requires a specific model.",focusedHelp:{whenToUse:"Use only when the user, task, or governing agent guidance already requires a specific provider, model, capability tier, or family. Omit it for routine delegation: the selected persona kind and profile own normal model selection, and review personas may enforce a quality floor.",value:`Accepted forms: ${Z}. Concrete provider/id requests must be registered. Portable provider/tier, bare-tier, and family-alias requests resolve through the configured model ladders.`,effects:["The resolved concrete override is stored on the node and in its launch recipe, so every launch and revive uses that exact provider/model.","Portable tiers and aliases resolve through the configured ladders; a persona quality floor may raise a weaker request before its resolved model is stored."]}},{kind:"flag",name:"profile",type:"string",required:!1,constraint:"Profile override. Use only when the task needs different project purview, memory, or environment; otherwise omit for normal inheritance or selection.",focusedHelp:{whenToUse:"Use only when the work must run under a different profile because it needs that profile\u2019s project purview, memory store, stored environment, or defaults. Do not use it merely to change the working directory, persona kind, model, or graph ownership; those have separate parameters.",value:"Pass a profile id or name from the <profiles> list below; a close-enough name resolves to the nearest profile and the choice is reported on stderr. Omit it inside a node to inherit the caller\u2019s profile; outside a node, omission runs normal cwd-based profile selection.",effects:["The selected profile id is stored on the node and supplies its profile-scoped config, memory, environment, and injected bearings.","It does not change the parent or subscription; --cwd separately pins the working directory."],dynamicState:o(()=>ne(),"dynamicState")}},{kind:"flag",name:"situational-context",type:"string",required:!1,constraint:"Hidden ambient context appended to injected bearings, never visible chat."},{kind:"flag",name:"no-kickoff",type:"bool",required:!1,hidden:!0,constraint:"With --root, start the broker and session idle without a first message or model turn. Mutually exclusive with a prompt and --mode orchestrator."},{kind:"flag",name:"deadline",type:"string",required:!1,constraint:"Positive, representable wall-clock duration from spawn. Grammar: one or more positive integer-unit parts; units: s, m, h, d; adjacent parts are summed. Omit for no deadline."},{kind:"flag",name:"outcome-action",type:"string",required:!1,constraint:"Declared human-action name that receives the node outcome. Grammar: 1\u2013128 ASCII letters, digits, dots, underscores, or hyphens; starts with a letter or digit. Omit when no external delivery target is needed."},{kind:"flag",name:"outcome-payload",type:"string",required:!1,constraint:"JSON value, serialized at most 64 KiB, frozen and echoed to --outcome-action. Requires --outcome-action."},{kind:"flag",name:"output-schema",type:"string",required:!1,constraint:"Replace prose completion with a schema-constrained final result. Use only when its consumer requires fixed fields.",focusedHelp:{whenToUse:"Use only when the node\u2019s consumer needs a machine-checkable final object with fixed fields. Omit it for ordinary delegation or when a prose report is enough; structured output replaces the completion protocol, and an over-constrained schema can force retries.",value:`Pass the JSON Schema the result must satisfy. ${X} ${V}`,effects:["The node must answer with `crtr push result` and cannot finish until the result is accepted; a plain `crtr push final` is blocked while the request is pending.",F,"The managed parent wakes through its existing subscription when the final report arrives; an independent root has no subscriber to wake.","An accepted result, or a decline, removes the request and terminates the node."]}}]}o(fe,"nodeNewParams");function he(){return[{name:"node_id",type:"string",required:!0,constraint:"New node id."},{name:"name",type:"string",required:!0,constraint:"Display name."},{name:"frozen_at",type:"string",required:!1,constraint:"Present when a managed child exists but capacity deferred its broker start."},...$()?[{name:"window",type:"string",required:!1,constraint:"tmux window id when a viewer opens."},{name:"session",type:"string",required:!1,constraint:"tmux session when a viewer opens."}]:[],{name:"follow_up",type:"string",required:!0,constraint:"Managed child: continue unrelated work or stop; its final report wakes you. Root: hand it off; no report wakes you."}]}o(he,"nodeNewOutput");function me(){return["Creates nodes/<id>/ in the canvas home, indexes the node in canvas.db, and starts its detached broker engine.","A managed child creates an active parent subscription; its pushes wake the parent. --root creates an independent node with spawned_by provenance and no parent subscription.","--worktree creates a managed worktree at ~/.crouter/canvas/worktrees/<node-id>/ on a new crtr/<node-id> branch.",F,"--deadline persists a wall-clock deadline from spawn; expiry cancels the node and records a failure outcome with reason deadline_exceeded.","--outcome-action registers one resolved local human-action target. When the node settles, crouter retries delivery of its outcome document until the target accepts it or permanently rejects it; --outcome-payload is frozen and echoed in that document.",...$()?["--root opens a viewer for the new node in the current tmux session."]:[]]}o(me,"nodeNewEffects");async function pe(e){G("act","crtr node new");const t=e.prompt??"",n=e.noKickoff===!0;if(!n&&t.trim()==="")throw new r({error:"empty_prompt",message:"a prompt is required (stdin or positional)",next:"Pipe a task on stdin or pass it as an argument, or pass --no-kickoff to spawn an idle node with none."});if(n&&t.trim()!=="")throw new r({error:"no_kickoff_with_prompt",message:"--no-kickoff cannot be combined with a prompt",field:"no-kickoff",next:"Drop --no-kickoff, or drop the prompt."});const i=e.kind,s=e.mode??"base",f=e.cwd?.trim(),m=f!==void 0&&f!==""?de(f):void 0,S=e.name,L=e.parent,a=e.root===!0,T=e.resident===!0,C=e.terminal===!0;if(T&&C)throw new r({error:"lifecycle_conflict",message:"--resident and --terminal cannot both be passed",field:"terminal",next:"Pass the one birth lifecycle you want, or neither to take the default (resident for --root, terminal for a managed child)."});const p=e.worktree;if(p!==void 0&&p.trim()==="")throw new r({error:"worktree_base_required",message:"--worktree requires a base branch",field:"worktree",next:"Pass an existing local branch that landing can fast-forward."});const w=p?.trim(),D=e.forkFrom,y=e.model?.trim();if(y==="")throw new r({error:"empty_spec",message:"a model spec is required",field:"model",next:`Run \`crtr node new --model -h\` and read the focused contract. ${ee}`});const E=e.profile,k=E===void 0?void 0:oe(E).profileId,g=e.situationalContext?.trim(),U=g!==void 0&&g!==""?g:void 0,j=Q(e.outputSchema),M=j!==null?JSON.stringify(j):null,h=e.deadline;if(h!==void 0){const l=te(h),B=l===null?Number.NaN:new Date(Date.now()+l).getTime();if(l===null||!Number.isFinite(l)||l<=0||!Number.isFinite(B))throw new r({error:"invalid_deadline",message:"--deadline must be a positive representable duration",field:"deadline",next:"Pass positive integer-unit parts using s, m, h, or d."})}const b=e.outcomeAction,v=e.outcomePayload;if(v!==void 0&&b===void 0)throw new r({error:"outcome_payload_requires_action",message:"--outcome-payload requires --outcome-action",field:"outcome-payload",next:"Pass the declared delivery action with --outcome-action."});let _;if(v!==void 0)try{_=JSON.parse(v)}catch{throw new r({error:"invalid_outcome_payload",message:"--outcome-payload must be valid JSON",field:"outcome-payload",next:"Pass one valid JSON value."})}const x=e.nodeId?.trim();if(a&&w!==void 0)throw new r({error:"worktree_root_conflict",message:"--worktree is mutually exclusive with --root",field:"worktree",next:"Drop either --root or --worktree."});if(n&&!a)throw new r({error:"no_kickoff_requires_root",message:"--no-kickoff is only valid with --root",field:"no-kickoff",next:"Add --root, or drop --no-kickoff and provide a prompt."});if(n&&s==="orchestrator")throw new r({error:"no_kickoff_orchestrator_unsupported",message:"--no-kickoff cannot be combined with --mode orchestrator",field:"no-kickoff",next:"Drop --no-kickoff and provide a prompt, or spawn in base mode."});const q=W(),c=L??q;let u=(k??K())||null;if(u===null&&c!==void 0&&(u=(await I(c))?.profile_id??null),u===null&&c===void 0){const{selectProfileForCwdReadOnly:l}=await import("../../core/profiles/select.js");u=l(process.cwd())}const{exitForMissingProviderCredential:z,hasConfiguredProviderCredential:H}=await import("../../core/runtime/provider-credential-gate.js");await H(u)||z(),O("node_new.create_start",{root:a});const d=await ie().createNode({...i!==void 0?{kind:i}:{},mode:s,cwd:process.cwd(),...m!==void 0&&m!==""?{pin_cwd:m}:{},...S!==void 0?{name:S}:{},prompt:t,...a?{root:!0}:{parent:c??null},...q!==void 0?{creator:q}:{},...T?{root_lifecycle:"resident"}:{},...C?{root_lifecycle:"terminal"}:{},...w!==void 0?{worktree:w}:{},...D!==void 0?{fork_from:D}:{},...y!==void 0?{model:y}:{},...k!==void 0?{profile:k}:{},...U!==void 0?{situational_context:U}:{},...n?{no_kickoff:!0}:{},...M!==null?{output_schema:M}:{},...h!==void 0?{deadline:h}:{},...b!==void 0?{outcome_delivery:{action:b,..._===void 0?{}:{payload:_}}}:{},...x!==void 0&&x!==""?{node_id:x}:{},...a?{prefer_warm:!0}:{}}).catch(ae);O("node_new.node_created",{node:d.node_id});let P={};a&&(P=se(d.node_id,d.cwd,d.name)),a&&O("node_new.viewer_window_opened");const A=!a&&d.frozen_at!==null;return{node_id:d.node_id,name:d.name,...A?{frozen_at:d.frozen_at}:{},window:P.window,session:P.session,follow_up:a?n?"Independent root spawned idle. No kickoff turn ran; hand it off or attach and prompt it. No report wakes you.":"Independent root spawned. You are not subscribed, so its finish does not wake you; hand it off and move on.":A?"Child row exists, but no broker started because capacity is full. It is frozen and will launch when a broker slot frees; its final report wakes you then.":await ce(c)}}o(pe,"runNodeCreation");const Me=Y({name:"new",description:"create and start a node immediately",whenToUse:"a unit of work is genuinely separable from what you are doing: a bounded subtask you would otherwise grind out inline, several independent units worth running in parallel (usually via one orchestrator child of the matching kind rather than a flat fan-out from you), a scouting pass over unfamiliar code, a change that wants its own git worktree, or an answer you need in a fixed shape rather than as prose",tier:"important",help:{name:"node new",summary:"create a node immediately and start its detached broker",guide:"The prompt is the child\u2019s entire brief: it wakes with this prompt, its persona, and ambient bearings \u2014 none of your conversation carries over. State the outcome and constraints. Pass an implementation plan only when it is already settled or necessary to preserve an approved decision; otherwise, let the child investigate and choose how. Give the reason along with the request: the larger goal this serves and what the child's output enables, so the child resolves ambiguity toward your intent instead of guessing. Name by absolute path every artifact the task depends on (a spec, an explore report, an earlier child's findings); the child inherits only the files the prompt names. When the report must carry something specific\u2014findings inline, or paths to artifacts it wrote\u2014say so in the prompt.",params:fe(),output:he(),dynamicState:o(()=>ue(),"dynamicState"),outputKind:"object",effects:me()},run:o(e=>pe(e),"run"),render:o(e=>{const t=e.window?` in window ${e.window}`:"",n=[`Spawned "${e.name}" (${e.node_id})${t}.`];return e.session&&n.push(`- session: ${e.session}`),n.push("",String(e.follow_up)),n.join(`
|
|
3
|
-
`)},"render")});export{je as assertKind,ce as childFollowUp,ue as kindsStateBlock,Me as nodeNew};
|
|
1
|
+
var $=Object.defineProperty;var a=(e,n)=>$(e,"name",{value:n,configurable:!0});import{envNodeId as z}from"../../shared/env.js";import{defineLeaf as B}from"../../core/command.js";import{InputError as o}from"../../core/io.js";import{requireScope as W}from"../../core/errors.js";import{mark as x}from"../../core/timing.js";import{OUTPUT_SCHEMA_CONSTRAINTS as J,OUTPUT_SCHEMA_TRANSPORT as Y,parseOutputSchemaValue as G}from"../../core/runtime/structured-output.js";import{MODEL_SPEC_FORMS as K,MODEL_SPEC_NEXT as V}from"../../core/runtime/model-selection.js";import{parseDurationMs as X}from"../../core/wake.js";import{kindsStateBlock as Q,profilesStateBlock as Z,resolveProfileViaDaemon as ee}from"../profile/daemon-profiles.js";import{cliClient as te,getNodeOrNull as oe,rethrowAsCliError as ne}from"../api-client.js";import{inTmux as R}from"../../core/runtime/placement-tmux.js";import{openSpawnViewer as re}from"../surface/node/placement.js";import{resolve as ie}from"node:path";const ae=1e5,M='--output-schema writes the accepted result to the node\u2019s context/result.json and pushes it as the node\u2019s final report; a node that cannot honestly satisfy the schema declines with `crtr push result --decline "<reason>" --code <token>`, which finishes it with a failure outcome (reason `declined`) whose `declined` field carries { reason, code, retryable } and no result. Name the code tokens you accept in the prompt; crouter carries the code verbatim and you validate it.',j=["A resident is told never to push a final, so the spawner gets no report wake when the work is done.","If it stops mid-task, nothing prompts it to continue.","After 15 unattended minutes it is concluded with only a deferred update, which does not wake the spawner."],L="To re-task a terminal child after its final, use `crtr node message send --reopen`; to make an existing node resident later, use `crtr node config --lifecycle resident`.",q="Do not wait, poll, or duplicate this child's assignment in your own context \u2014 there is no result to await, stopping will not strand you, and duplicated work wastes the delegated context. You're auto-subscribed, so its finish wakes you on its own. Two moves only: do other independent work right now, or stop and end your turn \u2014 the wake brings you back.";async function se(e){if(e===void 0||e==="")return q;const n=await oe(e);if(n===null||n.mode!=="orchestrator")return q;const t=n.context_tokens??null;return t===null||t<ae?q:`Child spawned \u2014 you're auto-subscribed, so its finish wakes you on its own; never wait, poll, or duplicate the child's assignment in your own context. But you're an orchestrator already carrying ~${Math.round(t/1e3)}k of context: rather than hold this window open for the result, checkpoint context/roadmap.md and \`crtr node yield\` now. Yielding ends this turn, and the child's completion then revives you fresh against your roadmap \u2014 let that clean revive absorb the result instead of this bloated context.`}a(se,"childFollowUp");function de(){return[{kind:"stdin",name:"prompt",required:!1,constraint:"First user message."},{kind:"flag",name:"kind",type:"string",required:!1,constraint:"Persona kind. Defaults to the profile's default kind; `general` when the profile has none. The <kinds> list below names every top-level installable kind."},{kind:"flag",name:"mode",type:"enum",choices:["base","orchestrator"],required:!1,default:"base",constraint:"Persona mode. base for one hands-on unit; orchestrator when the unit itself needs decomposition across children. When you hold several parallel units of one kind, spawn ONE orchestrator child of that kind to own the fan-out rather than spawning the units yourself \u2014 unless you are already an orchestrator of that kind, whose job is exactly that fan-out."},{kind:"flag",name:"cwd",type:"path",required:!1,constraint:"Pin the node to this directory. Defaults to the spawner\u2019s directory for a managed child, and to the directory this command runs in for a root."},{kind:"flag",name:"name",type:"string",required:!1,constraint:"Display name."},{kind:"flag",name:"parent",type:"string",required:!1,constraint:"Parent node id. Defaults to the calling node."},{kind:"flag",name:"node-id",type:"string",required:!1,constraint:"Exact id for the new node; lowercase letters, digits, and hyphens only, at most 128 characters. Rejected if already present."},{kind:"flag",name:"root",type:"bool",required:!1,constraint:"Spawn an independent root with no parent or subscription. Mutually exclusive with --worktree."},{kind:"flag",name:"resident",type:"bool",required:!1,constraint:"Birth the node as resident, a conversation partner for a person rather than a worker. Omit unless the user explicitly asks for a node they can talk with back and forth.",focusedHelp:{whenToUse:"Pass it ONLY when the user explicitly asks for a node they can talk with back and forth. Never infer it from task size, from expecting the user to look at the node, or from wanting to follow up later. "+L,value:"Boolean. Roots default to resident, so with --root it changes nothing. Managed children default to terminal; for a managed child the command first refuses, explains the cost, and says how to confirm.",effects:[...j,"It ends by going dormant or by being closed."]}},{kind:"flag",name:"terminal",type:"bool",required:!1,constraint:"Birth the node as terminal: it finalizes when its work is done and leaves nothing wakeable behind. Only meaningful with --root, whose default is resident; managed children are already terminal. Pass it for bounded programmatic work no one will open a viewer on. Mutually exclusive with --resident."},{kind:"flag",name:"force",type:"bool",required:!1,default:!1,hidden:!0,constraint:"Confirm a resident managed child (--resident without --root) after the user explicitly asked for one."},{kind:"flag",name:"worktree",type:"string",required:!1,constraint:"Local base branch for a crouter-managed worktree for this child. Mutually exclusive with --root."},{kind:"flag",name:"fork-from",type:"string",required:!1,constraint:"Fork the new node from an existing node id, absolute session path, or partial pi session uuid."},{kind:"flag",name:"model",type:"string",required:!1,constraint:"Durable model override. Omit unless the task or governing guidance requires a specific model.",focusedHelp:{whenToUse:"Use only when the user, task, or governing agent guidance already requires a specific provider, model, capability tier, or family. Omit it for routine delegation: the selected persona kind and profile own normal model selection, and review personas may enforce a quality floor.",value:`Accepted forms: ${K}. Concrete provider/id requests must be registered. Portable provider/tier, bare-tier, and family-alias requests resolve through the configured model ladders.`,effects:["The resolved concrete model is stored on the node and in its launch recipe.","A concrete provider/id runs exactly that model on every launch and revive. A portable provider/tier, bare tier, or family alias keeps its tier: when that model's provider is rate-limited or rejects its credential, the node moves to the next model in its route: another provider's model at the same tier first, then the configured fallback tier (strong by default).","A persona quality floor may raise a weaker request before its resolved model is stored."]}},{kind:"flag",name:"profile",type:"string",required:!1,constraint:"Profile override. Use only when the task needs different project purview, memory, or environment; otherwise omit for normal inheritance or selection.",focusedHelp:{whenToUse:"Use only when the work must run under a different profile because it needs that profile\u2019s project purview, memory store, stored environment, or defaults. Do not use it merely to change the working directory, persona kind, model, or graph ownership; those have separate parameters.",value:"Pass a profile id or name from the <profiles> list below; a close-enough name resolves to the nearest profile and the choice is reported on stderr. Omit it inside a node to inherit the caller\u2019s profile; outside a node, omission runs normal cwd-based profile selection.",effects:["The selected profile id is stored on the node and supplies its profile-scoped config, memory, environment, and injected bearings.","It does not change the parent or subscription; --cwd separately pins the working directory."]}},{kind:"flag",name:"situational-context",type:"string",required:!1,constraint:"Hidden ambient context appended to injected bearings, never visible chat."},{kind:"flag",name:"no-kickoff",type:"bool",required:!1,hidden:!0,constraint:"With --root, start the broker and session idle without a first message or model turn. Mutually exclusive with a prompt and --mode orchestrator."},{kind:"flag",name:"deadline",type:"string",required:!1,constraint:"Positive, representable wall-clock duration from spawn. Grammar: one or more positive integer-unit parts; units: s, m, h, d; adjacent parts are summed. Omit for no deadline."},{kind:"flag",name:"outcome-action",type:"string",required:!1,constraint:"Declared human-action name that receives the node outcome. Grammar: 1\u2013128 ASCII letters, digits, dots, underscores, or hyphens; starts with a letter or digit. Omit when no external delivery target is needed."},{kind:"flag",name:"outcome-payload",type:"string",required:!1,constraint:"JSON value, serialized at most 64 KiB, frozen and echoed to --outcome-action. Requires --outcome-action."},{kind:"flag",name:"output-schema",type:"string",required:!1,constraint:"Replace prose completion with a schema-constrained final result. Use only when its consumer requires fixed fields.",focusedHelp:{whenToUse:"Use only when the node\u2019s consumer needs a machine-checkable final object with fixed fields. Omit it for ordinary delegation or when a prose report is enough; structured output replaces the completion protocol, and an over-constrained schema can force retries.",value:`Pass the JSON Schema the result must satisfy. ${Y} ${J}`,effects:["The node must answer with `crtr push result` and cannot finish until the result is accepted; a plain `crtr push final` is blocked while the request is pending.",M,"The managed parent wakes through its existing subscription when the final report arrives; an independent root has no subscriber to wake.","An accepted result, or a decline, removes the request and terminates the node."]}}]}a(de,"nodeNewParams");function le(){return[{name:"node_id",type:"string",required:!0,constraint:"New node id."},{name:"name",type:"string",required:!0,constraint:"Display name."},{name:"frozen_at",type:"string",required:!1,constraint:"Present when a managed child exists but capacity deferred its broker start."},...R()?[{name:"window",type:"string",required:!1,constraint:"tmux window id when a viewer opens."},{name:"session",type:"string",required:!1,constraint:"tmux session when a viewer opens."}]:[],{name:"follow_up",type:"string",required:!0,constraint:"Managed child: continue unrelated work or stop; its final report wakes you. Root: hand it off; no report wakes you."}]}a(le,"nodeNewOutput");function ce(){return["Creates nodes/<id>/ in the canvas home, indexes the node in canvas.db, and starts its detached broker engine.","A managed child creates an active parent subscription; its pushes wake the parent. --root creates an independent node with spawned_by provenance and no parent subscription.","--worktree creates a managed worktree at ~/.crouter/canvas/worktrees/<node-id>/ on a new crtr/<node-id> branch.",M,"--deadline persists a wall-clock deadline from spawn; expiry cancels the node and records a failure outcome with reason deadline_exceeded.","--outcome-action registers one resolved local human-action target. When the node settles, crouter retries delivery of its outcome document until the target accepts it or permanently rejects it; --outcome-payload is frozen and echoed in that document.",...R()?["--root opens a viewer for the new node in the current tmux session."]:[]]}a(ce,"nodeNewEffects");async function ue(e){W("act","crtr node new");const n=e.prompt??"",t=e.noKickoff===!0;if(!t&&n.trim()==="")throw new o({error:"empty_prompt",message:"a prompt is required (stdin or positional)",next:"Pipe a task on stdin or pass it as an argument, or pass --no-kickoff to spawn an idle node with none."});if(t&&n.trim()!=="")throw new o({error:"no_kickoff_with_prompt",message:"--no-kickoff cannot be combined with a prompt",field:"no-kickoff",next:"Drop --no-kickoff, or drop the prompt."});const l=e.kind,N=e.mode??"base",c=e.cwd?.trim(),u=c!==void 0&&c!==""?ie(c):void 0,S=e.name,F=e.parent,r=e.root===!0,h=e.resident===!0,O=e.terminal===!0;if(h&&O)throw new o({error:"lifecycle_conflict",message:"--resident and --terminal cannot both be passed",field:"terminal",next:"Pass the one birth lifecycle you want, or neither to take the default (resident for --root, terminal for a managed child)."});if(h&&!r&&e.force!==!0)throw new o({error:"resident_child_requires_force",message:`--resident on a managed child makes it a conversation partner for a person, not a worker that reports back. ${j.join(" ")}`,field:"resident",next:`If the user did not explicitly ask for a node they can talk with back and forth, drop --resident; a terminal child's final report wakes you. ${L} If the user did explicitly ask for one, re-run with --force.`});const f=e.worktree;if(f!==void 0&&f.trim()==="")throw new o({error:"worktree_base_required",message:"--worktree requires a base branch",field:"worktree",next:"Pass an existing local branch that landing can fast-forward."});const m=f?.trim(),T=e.forkFrom,p=e.model?.trim();if(p==="")throw new o({error:"empty_spec",message:"a model spec is required",field:"model",next:`Run \`crtr node new --model -h\` and read the focused contract. ${V}`});const P=e.profile,D=P===void 0?void 0:(await ee(P)).id,w=e.situationalContext?.trim(),E=w!==void 0&&w!==""?w:void 0,C=G(e.outputSchema),A=C!==null?JSON.stringify(C):null,d=e.deadline;if(d!==void 0){const s=X(d),H=s===null?Number.NaN:new Date(Date.now()+s).getTime();if(s===null||!Number.isFinite(s)||s<=0||!Number.isFinite(H))throw new o({error:"invalid_deadline",message:"--deadline must be a positive representable duration",field:"deadline",next:"Pass positive integer-unit parts using s, m, h, or d."})}const k=e.outcomeAction,y=e.outcomePayload;if(y!==void 0&&k===void 0)throw new o({error:"outcome_payload_requires_action",message:"--outcome-payload requires --outcome-action",field:"outcome-payload",next:"Pass the declared delivery action with --outcome-action."});let g;if(y!==void 0)try{g=JSON.parse(y)}catch{throw new o({error:"invalid_outcome_payload",message:"--outcome-payload must be valid JSON",field:"outcome-payload",next:"Pass one valid JSON value."})}const b=e.nodeId?.trim();if(r&&m!==void 0)throw new o({error:"worktree_root_conflict",message:"--worktree is mutually exclusive with --root",field:"worktree",next:"Drop either --root or --worktree."});if(t&&!r)throw new o({error:"no_kickoff_requires_root",message:"--no-kickoff is only valid with --root",field:"no-kickoff",next:"Add --root, or drop --no-kickoff and provide a prompt."});if(t&&N==="orchestrator")throw new o({error:"no_kickoff_orchestrator_unsupported",message:"--no-kickoff cannot be combined with --mode orchestrator",field:"no-kickoff",next:"Drop --no-kickoff and provide a prompt, or spawn in base mode."});const v=z(),I=F??v;x("node_new.create_start",{root:r});const i=await te().createNode({...l!==void 0?{kind:l}:{},mode:N,cwd:process.cwd(),...u!==void 0&&u!==""?{pin_cwd:u}:{},...S!==void 0?{name:S}:{},prompt:n,...r?{root:!0}:{parent:I??null},...v!==void 0?{creator:v}:{},...h?{root_lifecycle:"resident"}:{},...O?{root_lifecycle:"terminal"}:{},...m!==void 0?{worktree:m}:{},...T!==void 0?{fork_from:T}:{},...p!==void 0?{model:p}:{},...D!==void 0?{profile:D}:{},...E!==void 0?{situational_context:E}:{},...t?{no_kickoff:!0}:{},...A!==null?{output_schema:A}:{},...d!==void 0?{deadline:d}:{},...k!==void 0?{outcome_delivery:{action:k,...g===void 0?{}:{payload:g}}}:{},...b!==void 0&&b!==""?{node_id:b}:{},...r?{prefer_warm:!0}:{}}).catch(ne);x("node_new.node_created",{node:i.node_id});let _={};r&&(_=re(i.node_id,i.cwd,i.name)),r&&x("node_new.viewer_window_opened");const U=!r&&i.frozen_at!==null;return{node_id:i.node_id,name:i.name,...U?{frozen_at:i.frozen_at}:{},window:_.window,session:_.session,follow_up:r?t?"Independent root spawned idle. No kickoff turn ran; hand it off or attach and prompt it. No report wakes you.":"Independent root spawned. You are not subscribed, so its finish does not wake you; hand it off and move on.":U?"Child row exists, but no broker started because capacity is full. It is frozen and will launch when a broker slot frees; its final report wakes you then.":await se(I)}}a(ue,"runNodeCreation");const Oe=B({name:"new",description:"create and start a node immediately",whenToUse:"a unit of work is genuinely separable from what you are doing: a bounded subtask you would otherwise grind out inline, several independent units worth running in parallel (usually via one orchestrator child of the matching kind rather than a flat fan-out from you), a scouting pass over unfamiliar code, a change that wants its own git worktree, or an answer you need in a fixed shape rather than as prose",tier:"important",help:{name:"node new",summary:"create a node immediately and start its detached broker",guide:"The prompt is the child\u2019s entire brief: it wakes with this prompt, its persona, and ambient bearings \u2014 none of your conversation carries over. State the outcome and constraints. Pass an implementation plan only when it is already settled or necessary to preserve an approved decision; otherwise, let the child investigate and choose how. Give the reason along with the request: the larger goal this serves and what the child's output enables, so the child resolves ambiguity toward your intent instead of guessing. Name by absolute path every artifact the task depends on (a spec, an explore report, an earlier child's findings); the child inherits only the files the prompt names. When the report must carry something specific\u2014findings inline, or paths to artifacts it wrote\u2014say so in the prompt.",params:de(),output:le(),outputKind:"object",effects:ce()},helpState:{leaf:Q,flags:{profile:Z}},run:a(e=>ue(e),"run"),render:a(e=>{const n=e.window?` in window ${e.window}`:"",t=[`Spawned "${e.name}" (${e.node_id})${n}.`];return e.session&&t.push(`- session: ${e.session}`),t.push("",String(e.follow_up)),t.join(`
|
|
2
|
+
`)},"render")});export{se as childFollowUp,Oe as nodeNew};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
var R=Object.defineProperty;var h=(t,e)=>R(t,"name",{value:e,configurable:!0});import{defineBranch as
|
|
2
|
-
`),"
|
|
3
|
-
`)}},"run"),render:h(t=>{const e=t.node,o=String(e.node_id),s=e.pi_pid,r=S.has(t)?"remote (liveness not checked locally)":
|
|
4
|
-
`));const l=h((u,c)=>{if(c.length===0)return`${u}: none`;const g=["node_id","name","kind","status","active"],n=`| ${g.join(" | ")} |`,w=`| ${g.map(()=>"---").join(" | ")} |`,
|
|
1
|
+
var R=Object.defineProperty;var h=(t,e)=>R(t,"name",{value:e,configurable:!0});import{defineBranch as P,defineLeaf as k}from"../../core/command.js";import{InputError as v}from"../../core/io.js";import{requireScope as A}from"../../core/errors.js";import{isPidAlive as I}from"../../core/canvas/pid.js";import{fullName as $}from"../../core/canvas/labels.js";import{fuzzyMatch as O}from"../../core/tui/fuzzy.js";import{nodeSnapshotLeaf as C}from"../node-snapshot.js";import{nodeTranscriptLeaf as F}from"../node-transcript.js";import{nodeContextLeaf as L}from"../node-context.js";import{nodeArtifactsLeaf as U}from"../node-inspect-artifacts.js";import{cliClient as _,cliCanvasSource as x,rethrowAsCliError as y}from"../api-client.js";import{RemoteCanvasSource as q}from"../../core/canvas/remote-canvas-source.js";import{kindsStateBlock as D,profilesStateBlock as E,resolveProfileViaDaemon as z}from"../profile/daemon-profiles.js";import{focusViewer as B,nodeInPane as W}from"../surface/node/placement.js";const K=k({name:"list",description:"list nodes on the canvas",whenToUse:"you want a flat roster of the nodes on the canvas, sliced by displayed name, status, kind, mode, lifecycle, profile, cwd, and graph scope (--under a node, for that node plus its subscription descendants). The filters AND together. Use `node inspect show` instead to drill into one node and its spine neighbors, `canvas dashboard` for the tree shape, and `canvas attention` to find nodes blocked on the user",help:{name:"node inspect list",summary:"list nodes on the canvas, filtered by any combination of attribute slices and a graph-scope (--under) that AND together",params:[{kind:"flag",name:"status",type:"string",required:!1,constraint:"Filter status (comma-separated for several; accepted values: active, idle, done, dead, canceled). NOTE: `active` means the engine process is live (never closed), NOT that the node is generating right now \u2014 an active node is usually dormant between turns. To tell working-vs-idle, check the pi session-file mtime or CPU, not status."},{kind:"flag",name:"kind",type:"string",required:!1,constraint:"Filter by persona kind (comma-separated for several). The <kinds> list below names every top-level installable kind; a registered sub-kind filters too by exact path even though it is not listed."},{kind:"flag",name:"mode",type:"string",required:!1,constraint:"Filter by mode (comma-separated for several; accepted values: base, orchestrator)."},{kind:"flag",name:"lifecycle",type:"string",required:!1,constraint:"Filter by lifecycle (comma-separated for several; accepted values: terminal, resident)."},{kind:"flag",name:"profile",type:"string",required:!1,constraint:"Filter by profile. On the local canvas, accepts a profile id or manifest name from the <profiles> list below, or a close-enough name that resolves to the nearest profile. Against a remote canvas, pass the exact profile id carried by its node rows."},{kind:"flag",name:"name",type:"string",required:!1,constraint:"Filter by the displayed node label (handle plus generated description) with the canvas browser\u2019s case-insensitive fuzzy subsequence match."},{kind:"flag",name:"cwd",type:"string",required:!1,constraint:"Filter to nodes pinned to this exact cwd (absolute path). Roster is canvas-wide (all cwds) by default."},{kind:"flag",name:"under",type:"string",required:!1,constraint:'Graph scope: restrict to this node and its subscription descendants (the sub-DAG reachable downward \u2014 its reports, theirs, \u2026). This is "one initiative / my subtree". ANDs with every attribute filter above, narrowing any of them to this subtree.'},{kind:"flag",name:"canvas",type:"string",required:!1,constraint:"Read from the named remote canvas target (see `crtr canvas config list`) instead of the local canvas. Overrides `crtr canvas use`."}],output:[{name:"nodes",type:"object[]",required:!0,constraint:"Rows include {node_id, name, kind, mode, lifecycle, status, cwd, profile_id, parent, created}. `name` is the displayed node label searched by --name and shown in canvas views. `profile_id` is the stable profile-directory id (null only for historical no-profile nodes)."}],outputKind:"object",effects:["Read-only: lists nodes through the daemon API."]},helpState:{leaf:h(async()=>(await Promise.all([D(),E()])).join(`
|
|
2
|
+
`),"leaf")},run:h(async t=>{const e=h(n=>{const w=t[n];return w!==void 0&&w!==""?w.split(",").map(b=>b.trim()).filter(b=>b!==""):void 0},"csv"),o=e("status"),s=e("kind"),p=e("mode"),r=e("lifecycle"),m=t.profile,a=t.name,d=t.cwd,i=t.under,l=x({canvasName:t.canvas}),f=l instanceof q?m:m===void 0?void 0:(await z(m)).id;let u;if(i!==void 0&&i!==""){if(await l.getNode(i).catch(y)===null)throw new v({error:"not_found",message:`no node: ${i}`,next:"List nodes with `crtr node inspect list`, then pass a real id to --under."});u=new Set([i,...await l.view(i)])}return{nodes:(await l.listNodes(o!==void 0?{status:o}:void 0).catch(y)).filter(n=>!(u!==void 0&&!u.has(n.node_id)||s!==void 0&&!s.includes(n.kind)||p!==void 0&&!p.includes(n.mode)||r!==void 0&&!r.includes(n.lifecycle)||f!==void 0&&n.profile_id!==f||d!==void 0&&d!==""&&n.cwd!==d)).map(n=>({...n,name:$(n)})).filter(n=>a===void 0||a===""||O(a,n.name))}},"run")}),S=new WeakSet;async function j(t,e){const o=await t.getNode(e.node_id).catch(y);return{node_id:e.node_id,name:o?$(o):"(missing)",kind:o?.kind??"?",status:o?o.intent?`${o.status}/${o.intent}`:o.status:"?",active:e.active}}h(j,"enrichNeighbor");const M=k({name:"show",description:"show a node + its spine neighbors, artifacts, and drill-in pointers",whenToUse:"you want one node in depth \u2014 the debugging entrypoint: a glanceable meta slice, named spine neighbors, artifact and pending-cron counts, and exact drill-in paths. Use `node inspect list` for the flat roster or `canvas dashboard` for the whole-tree shape",help:{name:"node inspect show",summary:"show a node in depth \u2014 meta slice, named neighbors, artifact/pending-cron counts, and drill-in pointers",params:[{kind:"positional",name:"node",required:!0,constraint:"Node id."},{kind:"flag",name:"canvas",type:"string",required:!1,constraint:"Read from the named remote canvas target (see `crtr canvas config list`) instead of the local canvas. Overrides `crtr canvas use`."}],output:[{name:"node",type:"object",required:!0,constraint:"The full node meta (system prompt + every telemetry field). The render surfaces a glanceable slice; `--json` carries the complete dump."},{name:"fault",type:"object",required:!0,constraint:"The active runtime fault projection, or null: {link, kind, retry: {disposition}, since}."},{name:"reports",type:"object[]",required:!0,constraint:"Who this node subscribes to (its reports/down), each enriched with {node_id, name, kind, status, active} \u2014 these are typically its spawned children."},{name:"managers",type:"object[]",required:!0,constraint:"Who subscribes to this node (its managers/up), same enriched shape."},{name:"artifacts",type:"object",required:!0,constraint:"Counts of what the node left on disk by corpus: {report, doc, roadmap}. Enumerate them with `node inspect artifacts <id>`."},{name:"pending_crons",type:"number",required:!0,constraint:"How many pending crons were created by this node. Inspect with `crtr cron list`."},{name:"paths",type:"object",required:!0,constraint:"Resolved on-disk locations: {context_dir, reports_dir, session_file} \u2014 read these directly to debug."},{name:"follow_up",type:"string",required:!0,constraint:"The concrete next commands to drill deeper."}],outputKind:"object",effects:["Read-only: reads the node, its edges and artifacts, and pending crons through crtrd."],preview:{suppressOutput:!0}},run:h(async t=>{const e=t.node,o=t.canvas,s=x({canvasName:o});if(s instanceof q){const n=await s.rawShow(e);if(n===null)throw new v({error:"not_found",message:`no node: ${e}`,next:"List nodes with `crtr node inspect list --canvas <name>`."});const w={...n};return S.add(w),w}const p=await s.getNode(e).catch(n=>y(n,"List nodes with `crtr node inspect list`."));if(p===null)throw new v({error:"not_found",message:`no node: ${e}`,next:"List nodes with `crtr node inspect list`."});const r=p,m=_(),a=await Promise.all((await s.subscriptionsOf(e)).map(n=>j(s,n))),d=await Promise.all((await s.subscribersOf(e)).map(n=>j(s,n))),i=await m.getArtifacts(e),l={report:i.artifacts.filter(n=>n.source.startsWith("report")).length,doc:i.artifacts.filter(n=>n.source==="doc").length,roadmap:i.artifacts.filter(n=>n.source==="roadmap").length},f=(await m.listCrons().catch(y)).filter(n=>n.created_by===e).length,u={context_dir:r.paths.context_dir,reports_dir:r.paths.reports_dir,...r.pi_session_file!==void 0?{session_file:r.pi_session_file}:{}},c=[],g=l.report+l.doc+l.roadmap;return g>0&&c.push(`Read its ${g} artifact(s): \`crtr node inspect artifacts ${e}\` \u2192 each ref feeds \`crtr canvas history read <ref>\`.`),c.push(`Browse its context + reports dirs (and its subscriptions') in nvim: \`crtr node inspect context ${e}\`.`),u.session_file&&c.push(`Read the raw conversation transcript: ${u.session_file}`),c.push(`On-disk context dir (ls/read directly): ${u.context_dir}`),f>0&&c.push(`It created ${f} pending cron(s): \`crtr cron list\`.`),a.length>0&&c.push(`Drill into a child/report: \`crtr node inspect show <node_id>\` (${a.map(n=>n.node_id).join(", ")}).`),c.push(`Full machine dump (system prompt + all telemetry): \`crtr --json node inspect show ${e}\`.`),{node:r,fault:r.fault??null,reports:a,managers:d,artifacts:l,pending_crons:f,paths:u,follow_up:c.join(`
|
|
3
|
+
`)}},"run"),render:h(t=>{const e=t.node,o=String(e.node_id),s=e.pi_pid,r=S.has(t)?"remote (liveness not checked locally)":I(s)?"alive":"dead",m=e.intent?`/${String(e.intent)}`:"",a=t.fault,d=[];d.push(`# ${$(e)} (${o})`);const i=[`- kind/mode/lifecycle: ${e.kind} / ${e.mode} / ${e.lifecycle}`,`- status: ${e.status}${m}`,...a==null?[]:[`- fault: ${String(a.kind)} / ${String(a.retry?.disposition)} since ${String(a.since)}`],`- broker pid: ${s??"(none)"} \u2014 ${r}`,`- cwd: ${e.cwd}`,`- host: ${e.host_kind}`+(e.profile_id?` \xB7 profile ${e.profile_id}`:""),`- cycles: ${e.cycles} \xB7 created ${e.created}`];e.parent&&i.push(`- parent: ${e.parent}`),i.push(`- creator: ${e.creator??"an external process"}`),e.waiting_for&&i.push(`- waiting for message: ${e.waiting_for}`),d.push(i.join(`
|
|
4
|
+
`));const l=h((u,c)=>{if(c.length===0)return`${u}: none`;const g=["node_id","name","kind","status","active"],n=`| ${g.join(" | ")} |`,w=`| ${g.map(()=>"---").join(" | ")} |`,b=c.map(T=>`| ${g.map(N=>String(T[N]??"").replace(/\|/g,"\\|").replace(/\n/g," ")).join(" | ")} |`).join(`
|
|
5
5
|
`);return`${c.length} ${u}:
|
|
6
6
|
|
|
7
7
|
${n}
|
|
8
8
|
${w}
|
|
9
|
-
${
|
|
9
|
+
${b}`},"table");d.push(l("reports (down \u2014 subscriptions, usually children)",t.reports)),d.push(l("managers (up \u2014 subscribers)",t.managers));const f=t.artifacts;return d.push(`artifacts: ${f.report} report(s), ${f.doc} doc(s), ${f.roadmap} roadmap \xB7 ${t.pending_crons} pending cron(s)`),d.push(`Drill deeper:
|
|
10
10
|
${String(t.follow_up)}`),d.join(`
|
|
11
11
|
|
|
12
|
-
`)},"render")}),
|
|
12
|
+
`)},"render")}),ae=k({name:"fork",description:"fork a node into an independent idle root with the same conversation and durable context",whenToUse:"a conversation has already accumulated the context you want, and you want a new user-driven branch beside it without sending a prompt or inheriting any graph-management responsibility. This copies the conversation and durable context, then waits for the fork\u2019s first real user message to supply its mandate. Use `node new --fork-from` instead when spawning a managed worker with an immediate task",help:{name:"node fork",summary:"create an independent resident root from a node\u2019s conversation and durable context, with no kickoff prompt or model turn",params:[{kind:"flag",name:"node",type:"string",required:!1,constraint:"Source node id. Mutually exclusive with --pane; one of them is required."},{kind:"flag",name:"pane",type:"string",required:!1,constraint:"tmux pane showing the source node. Mutually exclusive with --node; one of them is required. The prefix menu passes this for you and the new viewer splits beside this pane."}],output:[{name:"node_id",type:"string",required:!0,constraint:"The new independent root id."},{name:"focused",type:"boolean",required:!0,constraint:"True when a new viewer pane opened beside the caller; false outside tmux."},{name:"session",type:"string",required:!1,constraint:"The tmux session containing the new viewer, when one opened."}],outputKind:"object",effects:["Creates a resident base-mode root with the source node\u2019s copied pi conversation, cwd, profile, kind, model override, and durable context files. Top-level initial-prompt.md, yield-message.md, result.json, and the jobs/ folder of background bash jobs are omitted.","Copies no parent, subscriptions, subscribers, children, crons, worktree, situational context, or lifecycle responsibility. Sends no prompt and consumes no model turn; the first real user message becomes the fork\u2019s mandate.","Inside tmux, opens and focuses a surface-attach viewer as an even-horizontal split in the source pane\u2019s window. Outside tmux, the root is still created but no interactive fallback opens."]},run:h(async t=>{A("act","crtr node fork");const e=t.pane,o=t.node;if(o!==void 0&&e!==void 0)throw new v({error:"conflicting_target",message:"--node and --pane are mutually exclusive",next:"Pass the source node id or its viewer pane, not both."});let s=o;if(s===void 0&&e!==void 0&&(s=W(e)),s===void 0||s==="")throw new v({error:"no_node",message:"no source node was provided or found in the pane",next:"Pass --node <id>, or --pane <pane-id> for a pane showing a node."});const p=await _().forkNode(s).catch(y),r=await B(p.node_id,{cwd:p.cwd,name:p.name,...e!==void 0?{pane:e}:{},newPane:!0});return{node_id:p.node_id,focused:r.focused,session:r.session}},"run"),render:h(t=>{const e=t.focused===!0?` Viewer opened beside the source${t.session?` in session ${t.session}`:""}.`:" No viewer opened because no tmux pane was available.";return`Forked independent idle root ${t.node_id}.${e} It will make no model call until its first real user message.`},"render")}),de=P({name:"inspect",description:"read one node \u2014 its graph position, context, and artifacts",whenToUse:"reading everything about ONE node you can name: enumerate the roster (`list`), inspect a node and its spine neighbors (`show`), browse its on-disk context dir (`context`), or list its reports/docs as refs (`artifacts`). Use `canvas dashboard` instead to render the whole tree SHAPE, or `canvas attention` to find which nodes are blocked on the user",help:{name:"node inspect",summary:"read one node (or the roster) \u2014 topology, context dir, and artifacts",model:"Inspection is read-only and never revives a node. The roster is the selection surface; one-node metadata points to progressively heavier views: a parsed broker snapshot, rendered conversation, context browser, or artifact references."},children:[K,M,C,F,L,U]});export{ae as nodeFork,de as nodeInspect};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var E=Object.defineProperty;var
|
|
2
|
-
`)},"render")}),F=y({name:"close",description:"close a node + cascade-cancel its exclusive subtree",whenToUse:"you want to tear a node down WITHOUT finishing it, cascade-cancelling every descendant it exclusively owns: abandoning a line of work, killing a stuck or wrong-turn subtree, clearing a branch you no longer need. A node that never produced substantive assistant output is deleted and cannot be revived; streaming nodes and nodes with an open managed worktree are retained. Other closed nodes keep their pi session and can be revived later (`node lifecycle revive`). Use `node lifecycle recycle` instead to FINISH the agent in your pane with a final report, and `push final` when a worker should end its own work normally (Alt+C \u2192 x)",help:{name:"node lifecycle close",summary:"close a node and cascade-cancel its subtree \u2014 kill its tmux window plus those of every descendant it EXCLUSIVELY owns (down the subscribes_to spine), mark retained nodes canceled, and leave them a notice they read on resume. A descendant still subscribed to by a manager outside the subtree is left running. A node that never produced substantive assistant output is deleted and cannot be revived; streaming nodes and nodes with an open managed worktree are retained. Other closed nodes keep their pi session and can be revived later (`crtr node lifecycle revive`)",params:[{kind:"flag",name:"node",type:"string",required:!1,constraint:"Node to close. Defaults to the node occupying --pane (or your current pane)."},{kind:"flag",name:"pane",type:"string",required:!1,constraint:"tmux pane id whose node to close. Defaults to $TMUX_PANE / your current pane. The Alt+C menu passes this for you."}],output:[{name:"node_id",type:"string",required:!1,constraint:"The node that was closed \u2014 the cascade root."},{name:"count",type:"number",required:!1,constraint:"How many nodes were closed (root + cascaded descendants)."},{name:"closed_ids",type:"string[]",required:!1,constraint:"All closed node ids, kill order (leaves first, root last)."},{name:"spared",type:"string[]",required:!1,constraint:"Descendants left alive because a manager outside the subtree still subscribes to them."}],outputKind:"object",effects:["Marks retained nodes and their exclusive descendants `canceled` and clears intent (the daemon never revives a canceled node).","Deletes a non-streaming node with no substantive assistant output unless it has an open managed worktree; a deleted node cannot be revived.","Kills each closed node's tmux window; retained nodes keep their pi sessions and canvas edges for a later revive.","Appends a cancellation notice to each retained node's inbox, surfaced on its next resume."]},run:s(async e=>{const t=e.pane??process.env.TMUX_PANE;let n=e.node;if((n===void 0||n==="")&&(n=T(t)),n===void 0||n==="")throw new l({error:"no_node",message:"no node found in this pane to close",next:"Pass --node <id>, or run from inside the agent's pane."});const i=await p().closeNode(n,process.ppid>0?{caller_pid:process.ppid}:{}).catch(d=>f(d,"List nodes with `crtr node inspect list`."));return{node_id:i.root,count:i.closed.length,closed_ids:i.closed,spared:i.spared}},"run"),render:s(e=>{const t=e.spared?.length??0;return`Closed ${e.node_id} and its exclusive subtree \u2014 ${e.count} node(s) closed${t>0?`, ${t} spared (still managed from outside the subtree)`:""}.`},"render")}),A="Model change first: a live broker switches immediately over its socket; a dormant node persists the durable model override and launch recipe for its next revive.",ee=y({name:"config",description:"reconfigure a node's settings headlessly \u2014 model, lifecycle (terminal/resident), kind, mode, name; repair a missing cwd",whenToUse:"you want to reconfigure a node's settings headlessly after spawn \u2014 swap its model/provider, flip it terminal\u2194resident (interactable), respecialize its kind, switch base\u2194orchestrator mode, or rename it \u2014 without opening its viewer. It also repairs a dormant node whose recorded cwd is gone, starting its next revive in a fresh conversation. The durable attribute setter; reuses the same recipes a revive reads. Use `node promote` for the opinionated self-promotion path, and `node lifecycle` for teardown actions (recycle/close/demote).",help:{name:"node config",summary:"reconfigure a node's settings headlessly \u2014 model, lifecycle, kind, mode, name; repair a missing cwd",params:[{kind:"flag",name:"node",type:"string",required:!1,constraint:"Target node id. Defaults to the node in --pane, else CRTR_NODE_ID."},{kind:"flag",name:"pane",type:"string",required:!1,constraint:"tmux pane id to resolve the node from. Defaults to $TMUX_PANE."},{kind:"flag",name:"model",type:"string",required:!1,constraint:"Durable model change. Omit unless the task or governing guidance requires a different model.",focusedHelp:{whenToUse:"Use only when intentionally changing this node\u2019s durable model because the user, task, or governing agent guidance requires a specific provider, model, capability tier, or family. Omit it to keep the current model; do not use it merely to inspect available models or experiment with a live node.",value:`Accepted durable forms: ${I}. A live broker also accepts a free-text substring matched against its loaded model registry; a dormant node cannot resolve a substring and requires a durable form.`,effects:[A,"A concrete provider/id pins that provider. Portable tiers and aliases preserve logical intent for runtime routing; a persona quality floor may raise a weaker request."]}},{kind:"flag",name:"lifecycle",type:"enum",choices:["terminal","resident"],required:!1,constraint:"Set lifecycle headlessly without closing the viewer. terminal owes a final and reaps when done; resident stays interactable while attached or awaiting something live."},{kind:"flag",name:"kind",type:"string",required:!1,constraint:"Persona kind. The <kinds> list below names every top-level installable kind and when to use each; a registered sub-kind is valid too by exact path but not listed here."},{kind:"flag",name:"mode",type:"enum",choices:["base","orchestrator"],required:!1,constraint:"Set persona mode headlessly. base is hands-on; orchestrator holds a roadmap and delegates. orchestrator seeds a roadmap scaffold if absent."},{kind:"flag",name:"name",type:"string",required:!1,constraint:"Rename the node; if the node has a live window, also rename that viewer window."},{kind:"flag",name:"nice",type:"int",required:!1,constraint:`Scheduler niceness every command this node's bash tool starts at, 0\u2013${w} (default ${q}). ${q} keeps the node's builds and test suites below the daemon, the brokers, the viewers, and the person's own shell; 0 lets them compete on equal terms with everything else on the host; ${w} makes them yield to it. Applies to the node's very next command, foreground and background alike.`},{kind:"flag",name:"cwd",type:"string",required:!1,constraint:"Repair-only replacement launch directory. Must be a non-empty absolute existing directory and used alone; the daemon accepts it only for a dormant, non-forked node with no open managed worktree whose recorded cwd is gone. Clears the saved Pi session, so the next revive starts fresh while durable node work remains."}],output:[{name:"node_id",type:"string",required:!1,constraint:"The reconfigured node, present for ordinary config changes."},{name:"model",type:"string",required:!1,constraint:"The resolved model, present only when --model changed it."},{name:"lifecycle",type:"string",required:!1,constraint:"The new lifecycle, present only when --lifecycle changed it."},{name:"kind",type:"string",required:!1,constraint:"The new kind, present only when --kind changed it."},{name:"mode",type:"string",required:!1,constraint:"The new mode, present only when --mode changed it."},{name:"name",type:"string",required:!1,constraint:"The new name, present only when --name changed it."},{name:"nice",type:"number",required:!1,constraint:"The new bash niceness, present only when --nice changed it."},{name:"cwd",type:"string",required:!1,constraint:"The lexically resolved replacement directory, present only after a cwd repair."}],outputKind:"object",effects:[A,"Kind, mode, and lifecycle changes rebuild the launch spec from the fresh node meta; setting mode to orchestrator seeds a roadmap scaffold if absent.","Name changes update the row and, when the node already has a live window, rename that viewer window to the new full name.","A cwd repair writes only the lexically resolved cwd and clears saved Pi session pointers; the old transcript and durable node work remain untouched.","A niceness change is stored with the node's own bash-job state, so it takes effect on the next command without a revive and survives one."],dynamicState:s(()=>_(),"dynamicState")},run:s(async e=>{const t=e.pane??process.env.TMUX_PANE,n=await N(e,t),i=e.cwd;if(i!==void 0&&["model","kind","lifecycle","mode","name","nice"].some(v=>e[v]!==void 0))throw new l({error:"cwd_not_exclusive",message:"cwd repair cannot be combined with another config flag",field:"cwd",next:"Pass --cwd alone."});const d=e.model?.trim();if(d==="")throw new l({error:"empty_spec",message:"a model spec is required",field:"model",next:"Run `crtr node config --model -h` and read the focused contract before retrying."});const o=e.kind?.trim(),r=e.lifecycle?.trim(),c=e.mode?.trim(),x=e.name,h=e.nice;if(h!==void 0&&(h<0||h>w))throw new l({error:"bad_nice",message:`niceness must be between 0 and ${w}: ${h}`,field:"nice",next:`A negative niceness needs root, so pass 0\u2013${w}.`});if(o!==void 0&&k(o),r!==void 0&&r.toLowerCase()!=="terminal"&&r.toLowerCase()!=="resident")throw new l({error:"bad_lifecycle",message:`invalid lifecycle: ${r}`,field:"lifecycle",next:"Pass `terminal` or `resident`."});if(c!==void 0&&c.toLowerCase()!=="base"&&c.toLowerCase()!=="orchestrator")throw new l({error:"bad_mode",message:`invalid mode: ${c}`,field:"mode",next:"Pass `base` or `orchestrator`."});const a=[],u={};if(d!==void 0&&(u.model=d,a.push("model")),o!==void 0&&(u.kind=o,a.push("kind")),r!==void 0&&(u.lifecycle=r.toLowerCase(),a.push("lifecycle")),c!==void 0&&(u.mode=c.toLowerCase(),a.push("mode")),x!==void 0&&(u.name=x,a.push("name")),i!==void 0&&(u.cwd=i,a.push("cwd")),h!==void 0&&($(P(n),h),a.push("nice"),a.length===1))return{node_id:n,nice:h};if(a.length===0)throw new l({error:"no_change",message:"no config changes requested",next:"Pass at least one of --model, --lifecycle, --kind, --mode, --name, --nice, --cwd."});const g=await p().patchConfig(n,u).catch(v=>f(v,"List nodes with `crtr node inspect list`."));if(i!==void 0)return{cwd:g.cwd};const m={node_id:n};return a.includes("model")&&(m.model=g.model_override??d),a.includes("lifecycle")&&(m.lifecycle=g.lifecycle),a.includes("kind")&&(m.kind=g.kind),a.includes("mode")&&(m.mode=g.mode),a.includes("name")&&(m.name=g.name),a.includes("nice")&&(m.nice=h),m},"run"),render:s(e=>{if(e.cwd!==void 0)return`Repaired cwd: ${e.cwd}.`;const t=[];return e.model!==void 0&&t.push(`model=${e.model}`),e.lifecycle!==void 0&&t.push(`lifecycle=${e.lifecycle}`),e.kind!==void 0&&t.push(`kind=${e.kind}`),e.mode!==void 0&&t.push(`mode=${e.mode}`),e.name!==void 0&&t.push(`name=${e.name}`),e.nice!==void 0&&t.push(`nice=${e.nice}`),`Configured ${e.node_id} \u2014 ${t.join(", ")}`},"render")}),ne=y({name:"promote",description:"become an orchestrator of a chosen kind",whenToUse:"the remaining work contains independent units that can run in parallel, and the task is large enough that coordinating and integrating them will materially improve intelligence, productivity, or elapsed throughput. Become a long-lived, roadmap-holding orchestrator whose primary job is steering those children across refreshes (`node yield`). Keep sequential or tightly coupled work in base mode even when it spans phases or context windows; spawning one helper does not itself require promotion",tier:"important",help:{name:"node promote",summary:"promote yourself to an orchestrator when worthwhile parallel delegation should make coordination your primary job; task duration, sequential phases, or one helper do not qualify. Mode only \u2014 lifecycle stays as-is unless you pass --resident",params:[{kind:"flag",name:"kind",type:"string",required:!1,constraint:"Specialize as this kind of orchestrator. The <kinds> list below names every top-level installable kind and when to use each; a registered sub-kind is valid too by exact path but not listed here. For an exact composed persona list, use `crtr sys context prompt-review --list --kind <kind>` with the target kind. Defaults to your current kind. Promoting from a generic kind? CHOOSE a concrete one \u2014 it sets the orchestrator persona you revive into."},{kind:"flag",name:"resident",type:"bool",required:!1,constraint:"ALSO flip lifecycle\u2192resident: make the node interactable \u2014 it is never forced to submit a final, and unattended grace parks it after a summary turn instead, leaving it revivable fresh against its goal and roadmap. Omit to stay terminal/orchestrator (delegates + holds a roadmap, but still owes a final up the spine and reaps when done)."},{kind:"flag",name:"model",type:"enum",choices:["ultra","strong"],required:!1,constraint:"Change the model you run on, by capability tier: `ultra` (frontier \u2014 reserve for high-taste judgment or enormous work: speccing, planning something large, e2e-testing something hard to test) or `strong` (opus \u2014 regular dev work). Omit to keep your current model. An orchestrator steering work is never weaker than opus, so these are the only two choices; the change is durable across future revives."},{kind:"flag",name:"node",type:"string",required:!1,constraint:"Node to promote. Defaults to the caller (CRTR_NODE_ID)."}],output:[{name:"node_id",type:"string",required:!0,constraint:"The promoted node."},{name:"kind",type:"string",required:!0,constraint:"The kind it now orchestrates as."},{name:"model",type:"string",required:!1,constraint:"The model tier it now runs on, present only when you changed it with --model."},{name:"lifecycle",type:"string",required:!0,constraint:'"resident" if you passed --resident, else unchanged (typically "terminal").'},{name:"roadmap_written",type:"boolean",required:!0,constraint:"True if a roadmap scaffold was seeded by this call."},{name:"roadmap_path",type:"string",required:!0,constraint:"Absolute path to your roadmap doc (context/roadmap.md) \u2014 edit it to author your plan."},{name:"goal_path",type:"string",required:!0,constraint:"Absolute path to your goal doc (context/initial-prompt.md) \u2014 the mandate you were spawned with."}],dynamicState:s(()=>_(),"dynamicState"),outputKind:"object",effects:["Flips mode\u2192orchestrator + kind\u2192chosen (lifecycle unchanged unless --resident, which also flips lifecycle\u2192resident); --model durably pins the model tier; rewrites the launch spec to that kind's orchestrator persona; seeds context/roadmap.md scaffold if absent.","The next model request is gated on appending and persisting your new-role guidance. If a fresh context starts first, its rebuilt baseline carries the new role."]},run:s(async e=>{const t=e.node??b();if(t===void 0||t==="")throw new l({error:"no_node",message:"no node to promote (set CRTR_NODE_ID or pass --node)",next:"Run from inside a node, or pass --node <id>."});const n=e.kind;n!==void 0&&k(n);const i=e.model,d=e.resident===!0,o=await p().promoteNode(t,{...n!==void 0?{kind:n}:{},...d?{resident:!0}:{},...i!==void 0?{model:i}:{}}).catch(r=>f(r));return{node_id:o.node_id,kind:o.kind,lifecycle:o.lifecycle,...i!==void 0&&o.model_override!=null?{model:o.model_override}:{},roadmap_written:o.roadmap_written??!1,roadmap_path:o.roadmap_path??"",goal_path:o.goal_path??""}},"run")});async function N(e,t){let n=e.node;if((n===void 0||n==="")&&(n=T(t)),(n===void 0||n==="")&&(n=b()),n===void 0||n==="")throw new l({error:"no_node",message:"no node (set CRTR_NODE_ID, pass --node, or run from the agent's pane)",next:"Run from inside a node, pass --node <id>, or --pane <pane>."});if(await D(n)===null)throw new l({error:"not_found",message:`no node: ${n}`,next:"List nodes with `crtr node inspect list`."});return n}s(N,"resolveLifecycleNode");const H=y({name:"demote",description:"demote a node to terminal in place; it stays focused and running but now owes a final; --detach also closes its viewer (broker keeps running off-screen)",whenToUse:"you are watching a resident/interactive node and want to put it on a finishing track WITHOUT disturbing it: flip it terminal IN PLACE \u2014 it keeps its viewer and your focus, keeps running, but now owes a final report up the spine and reaps when done. The friendly counterpart to `node promote`. You can also let go entirely and close its viewer so the agent finishes off-screen on its broker. Use `node lifecycle recycle` instead to FINISH it now and reboot a fresh root in its pane, and `node config --lifecycle` for the orthogonal low-level flip (incl. terminal\u2192resident)",help:{name:"node lifecycle demote",summary:"demote a node to terminal IN PLACE \u2014 it stays focused and running but now owes a final up the spine and reaps when done. Pairs with `node promote` (mode\u2191); `--detach` also closes its viewer (the broker engine keeps running off-screen)",params:[{kind:"flag",name:"node",type:"string",required:!1,constraint:"Node to demote. Defaults to the node in --pane, else the caller (CRTR_NODE_ID)."},{kind:"flag",name:"pane",type:"string",required:!1,constraint:"tmux pane id whose node to demote, when --node is omitted. Defaults to $TMUX_PANE. The Alt+C menu passes this for you."},{kind:"flag",name:"detach",type:"bool",required:!1,constraint:"After flipping terminal, stop foregrounding the agent by closing its viewer pane. The broker engine keeps generating off-screen and \u2014 now terminal \u2014 pushes a final up the spine when done; a later `focus` reattaches a viewer. The Alt+C \u2192 D move."}],output:[{name:"node_id",type:"string",required:!0,constraint:"The demoted node."},{name:"detached",type:"boolean",required:!1,constraint:"True when --detach closed the agent's viewer pane (broker keeps running)."}],outputKind:"object",effects:["Flips the node's lifecycle\u2192terminal and rebuilds its launch spec so a future revive boots terminal \u2014 it stays focused and running, now owing a final up the spine.","The next model request is gated on appending and persisting the role transition. If a fresh context starts first, its rebuilt baseline carries the new lifecycle.","With --detach: closes the agent's viewer pane WITHOUT touching the broker engine \u2014 it keeps generating off-screen, reconnectable by a later `focus`."]},run:s(async e=>{const t=e.pane??process.env.TMUX_PANE,n=await N(e,t),i=await p().patchConfig(n,{lifecycle:"terminal"}).catch(o=>f(o));let d=!1;if(e.detach===!0){const o=M(n)??t;o!==void 0&&o!==""&&O(o)&&(d=R(o))}return{node_id:i.node_id,detached:d}},"run"),render:s(e=>`Demoted ${e.node_id} \u2014 lifecycle now terminal (in place)${e.detached===!0?", viewer closed (broker still running off-screen)":""}.`,"render")}),te=C({name:"lifecycle",description:"lifecycle actions \u2014 recycle, close, demote, or revive a node",whenToUse:"you are ending, transitioning, or bringing back one node you can name: finish the agent in your pane and reboot a fresh root (`recycle`), tear a node + its exclusive subtree down without finishing (`close`), flip a node onto a finishing track in place (`demote`), or bring a dormant node back (`revive`). To merely SET the terminal/resident attribute headlessly use `node config --lifecycle`; to FINISH from inside a node's own turn use `crtr push final`; to mass-reconnect EVERY disconnected node at once use `canvas revive --all`.",help:{name:"node lifecycle",summary:"end, transition, or revive a node \u2014 recycle the pane, close + cascade-cancel a subtree, demote to terminal in place, or revive a dormant node",model:"Lifecycle actions preserve or replace an existing node identity. Finishing is permanent, closing is revivable, demotion changes the completion obligation in place, and revival relaunches a dormant broker. Teardown cascades only through descendants exclusively managed by the affected subtree."},children:[j,F,H,S]}),oe=y({name:"yield",description:"refresh your context, same mode, against your roadmap or goal",whenToUse:"your context is filling but the mandate remains; refresh in the same mode, or combine the refresh with promotion when meaningful independent work can run in parallel and coordinating it should become your primary job",help:{name:"node yield",summary:"request a fresh context window against your roadmap or original goal; mode stays unchanged unless --promote is passed",guide:"The yield aborts your turn the instant this command returns: no text or tool call you planned after it will run. So anything the user is owed \u2014 an answer, a status \u2014 must already be a visible message in the conversation before you call it; never plan to reply after yielding. Before invoking: (1) Bring `$CRTR_CONTEXT_DIR/roadmap.md` current \u2014 it, not the yield note, carries the goal into the fresh window. Keep its seeded sections (Goal, Exit criteria, Phases) and keep it short: strategy and present state only \u2014 what is settled, what remains, the current phase\u2019s one-line status, plus dead ends worth not repeating. Delete completed items instead of marking them done; the roadmap should shrink as work completes. (2) Move anything worth remembering but not needed next window into memory (`crtr memory write -h`): node-local for lessons specific to this node\u2019s task, the workspace store for lessons that would benefit other agents working here. (3) Send any pending human question; in-flight asks survive the refresh.",params:[{kind:"flag",name:"promote",type:"bool",required:!1,constraint:"Also become an orchestrator as you refresh. Pass only when (1) the remaining work contains independent units that can run in parallel and (2) the task is large enough that parallel execution will materially improve intelligence, productivity, or elapsed throughput after coordination and synthesis. Task length, context exhaustion, sequential phases, or one helper are not enough; keep hands-on work in base mode and yield again as needed. Promote when coordinating and integrating children becomes your primary job. Already an orchestrator? This is not an error: your mode stays orchestrator and a missing roadmap is seeded."},{kind:"flag",name:"kind",type:"string",required:!1,constraint:"Respecialize as you refresh. The <kinds> list below names every top-level available kind and when to choose it; a registered sub-kind is valid too by exact path but not listed here. Defaults to your current kind. With --promote it sets the orchestrator kind you become; without --promote it changes the kind while preserving your current mode."},{kind:"flag",name:"model",type:"enum",choices:["ultra","strong"],required:!1,constraint:"Change the model your fresh revive runs on, by capability tier: `ultra` (frontier \u2014 reserve for high-taste judgment or enormous work: speccing, planning something large, e2e-testing something hard to test) or `strong` (opus \u2014 regular dev work). Omit to keep your current model. A node steering work is never weaker than opus, so these are the only two choices; the change is durable across future revives."},{kind:"stdin",name:"message",required:!0,constraint:"A note to your future self \u2014 what you just tried, where things stand, and the first move on waking: enough to continue efficiently, no more. If the user asked something you have not answered in a visible message, say so and quote the question. Never describe a reply as sent unless it is visible in the conversation above this call. Durable strategy belongs in the roadmap, not here. Surfaced as <yield-message> in the next revive. Pass as a positional or pipe via heredoc."}],output:[{name:"node_id",type:"string",required:!0,constraint:"The yielding node."},{name:"model",type:"string",required:!1,constraint:"The model tier your fresh revive will run on, present only when you changed it with --model."}],dynamicState:s(()=>_(),"dynamicState"),outputKind:"object",effects:["Aborts your current turn as soon as this command returns \u2014 nothing after it runs \u2014 then the daemon revives the node fresh.","--kind and/or --model durably reshape the node (kind respecialization, model-tier pin) before the refresh-revive; --promote additionally flips mode\u2192orchestrator and seeds a roadmap scaffold \u2014 mode is otherwise left exactly as it was."]},run:s(async e=>{const t=b();if(t===void 0||t==="")throw new l({error:"no_node",message:"no node to yield (CRTR_NODE_ID unset)",next:"Run from inside a node."});const n=e.kind;n!==void 0&&k(n);const i=e.model,d=e.promote===!0,o=typeof e.message=="string"?e.message.trim():"";if(o==="")throw new l({error:"empty_message",message:"a yield message is required (stdin or positional)",next:"Pass a note to your future self as an argument or pipe it on stdin."});const r=await p().yieldNode(t,{note:o,...n!==void 0?{kind:n}:{},...i!==void 0?{model:i}:{},...d?{promote:!0}:{}}).catch(c=>f(c));return{node_id:r.node_id,...i!==void 0&&r.model_override!=null?{model:r.model_override}:{}}},"run")});export{ee as nodeConfig,te as nodeLifecycle,ne as nodePromote,oe as nodeYield};
|
|
1
|
+
var E=Object.defineProperty;var l=(e,t)=>E(e,"name",{value:t,configurable:!0});import{envNodeId as b}from"../../shared/env.js";import{defineBranch as C,defineLeaf as y}from"../../core/command.js";import{InputError as d}from"../../core/io.js";import{cliClient as u,getNodeOrNull as D,rethrowAsCliError as m}from"../api-client.js";import{DEFAULT_BASH_NICENESS as T,MAX_BASH_NICENESS as v,writeBashNiceness as $}from"../../core/bash-jobs.js";import{nodeReviveLeaf as P}from"../node-lifecycle-revive.js";import{kindsStateBlock as k}from"../profile/daemon-profiles.js";import{MODEL_SPEC_FORMS as S}from"../../core/runtime/model-selection.js";import{closePane as I,paneExists as R,respawnPaneSync as O,viewerEnv as U,viewerPaneOf as L,nodeInPane as _}from"../surface/node/placement.js";const j=y({name:"recycle",description:"finish the agent in your pane + recycle it into a fresh root",whenToUse:"you are at an agent's pane and done with it: finish it cleanly and recycle the pane in one move \u2014 push its last message as a final report to everyone waiting on it, mark it done, then boot a fresh crtr root in the same pane to keep working. The hands-on way to end an agent and immediately start over in place. Use `node lifecycle demote` instead to put it on a finishing track IN PLACE (flip terminal, keep it running) without ending it now, `node lifecycle close` to tear a node and its subtree down WITHOUT finishing (no report, revivable), and `push final` when the agent should finish ITSELF from inside its own turn",help:{name:"node lifecycle recycle",summary:"finish the agent in your current pane and recycle the pane \u2014 push its last message as a final report to everyone waiting on it, mark it done, then boot a fresh crtr root in the same pane",params:[{kind:"flag",name:"node",type:"string",required:!1,constraint:"Node to finish. Defaults to the node occupying --pane (or your current pane)."},{kind:"flag",name:"pane",type:"string",required:!1,constraint:"tmux pane id to recycle. Defaults to $TMUX_PANE / your current pane. The Alt+C menu passes this for you."}],output:[{name:"recycled",type:"boolean",required:!0,constraint:"True when the pane was recycled into a fresh root."},{name:"node_id",type:"string",required:!1,constraint:"The finished node."},{name:"new_root",type:"string",required:!1,constraint:"The fresh root node booted into the pane."}],outputKind:"object",effects:["Pushes a final report from the node (fans out to all subscribers) and marks it done.","Kills the agent's pi and respawns a fresh resident root in the same tmux pane."]},run:l(async e=>{const t=e.pane??process.env.TMUX_PANE;let n=e.node;if((n===void 0||n==="")&&(n=_(t)),n===void 0||n==="")throw new d({error:"no_node",message:"no node found in this pane to finish",next:"Pass --node <id>, or run from inside the agent's pane."});const i=await u().getNode(n).catch(c=>m(c,"List nodes with `crtr node inspect list`.")),o=(await u().recycleNode(n).catch(m)).node_id;let r=!1;return t!==void 0&&t!==""&&(r=O({pane:t,cwd:i.cwd,env:U(),command:"crtr"})),{recycled:r,node_id:n,new_root:o}},"run"),render:l(e=>{if(e.recycled!==!0)return e.new_root?`Finished ${e.node_id} and spawned a fresh broker root (${e.new_root}), but its viewer did not attach \u2014 the new broker did not come up. Re-focus the root to view it.`:`Recycle failed for ${e.node_id??"?"} \u2014 not in tmux, or no agent in this pane.`;const t=[`Recycled the pane \u2014 finished ${e.node_id}.`];return e.new_root&&t.push(`- new root: ${e.new_root}`),t.join(`
|
|
2
|
+
`)},"render")}),M=y({name:"close",description:"close a node + cascade-cancel its exclusive subtree",whenToUse:"you want to tear a node down WITHOUT finishing it, cascade-cancelling every descendant it exclusively owns: abandoning a line of work, killing a stuck or wrong-turn subtree, clearing a branch you no longer need. A node that never produced substantive assistant output is deleted and cannot be revived; streaming nodes and nodes with an open managed worktree are retained. Other closed nodes keep their pi session and can be revived later (`node lifecycle revive`). Use `node lifecycle recycle` instead to FINISH the agent in your pane with a final report, and `push final` when a worker should end its own work normally (Alt+C \u2192 x)",help:{name:"node lifecycle close",summary:"close a node and cascade-cancel its subtree \u2014 kill its tmux window plus those of every descendant it EXCLUSIVELY owns (down the subscribes_to spine), mark retained nodes canceled, and leave them a notice they read on resume. A descendant still subscribed to by a manager outside the subtree is left running. A node that never produced substantive assistant output is deleted and cannot be revived; streaming nodes and nodes with an open managed worktree are retained. Other closed nodes keep their pi session and can be revived later (`crtr node lifecycle revive`)",params:[{kind:"flag",name:"node",type:"string",required:!1,constraint:"Node to close. Defaults to the node occupying --pane (or your current pane)."},{kind:"flag",name:"pane",type:"string",required:!1,constraint:"tmux pane id whose node to close. Defaults to $TMUX_PANE / your current pane. The Alt+C menu passes this for you."}],output:[{name:"node_id",type:"string",required:!1,constraint:"The node that was closed \u2014 the cascade root."},{name:"count",type:"number",required:!1,constraint:"How many nodes were closed (root + cascaded descendants)."},{name:"closed_ids",type:"string[]",required:!1,constraint:"All closed node ids, kill order (leaves first, root last)."},{name:"spared",type:"string[]",required:!1,constraint:"Descendants left alive because a manager outside the subtree still subscribes to them."}],outputKind:"object",effects:["Marks retained nodes and their exclusive descendants `canceled` and clears intent (the daemon never revives a canceled node).","Deletes a non-streaming node with no substantive assistant output unless it has an open managed worktree; a deleted node cannot be revived.","Kills each closed node's tmux window; retained nodes keep their pi sessions and canvas edges for a later revive.","Appends a cancellation notice to each retained node's inbox, surfaced on its next resume."]},run:l(async e=>{const t=e.pane??process.env.TMUX_PANE;let n=e.node;if((n===void 0||n==="")&&(n=_(t)),n===void 0||n==="")throw new d({error:"no_node",message:"no node found in this pane to close",next:"Pass --node <id>, or run from inside the agent's pane."});const i=await u().closeNode(n,process.ppid>0?{caller_pid:process.ppid}:{}).catch(s=>m(s,"List nodes with `crtr node inspect list`."));return{node_id:i.root,count:i.closed.length,closed_ids:i.closed,spared:i.spared}},"run"),render:l(e=>{const t=e.spared?.length??0;return`Closed ${e.node_id} and its exclusive subtree \u2014 ${e.count} node(s) closed${t>0?`, ${t} spared (still managed from outside the subtree)`:""}.`},"render")}),q="Model change first: a running broker, including one still starting right after `node new`, switches over its socket; a dormant node persists the durable model override and launch recipe for its next revive.",Q=y({name:"config",description:"reconfigure a node's settings headlessly \u2014 model, lifecycle (terminal/resident), kind, mode, name; repair a missing cwd",whenToUse:"you want to reconfigure a node's settings headlessly after spawn \u2014 swap its model/provider, flip it terminal\u2194resident (interactable), respecialize its kind, switch base\u2194orchestrator mode, or rename it \u2014 without opening its viewer. It also repairs a dormant node whose recorded cwd is gone, starting its next revive in a fresh conversation. The durable attribute setter; reuses the same recipes a revive reads. Use `node promote` for the opinionated self-promotion path, and `node lifecycle` for teardown actions (recycle/close/demote).",help:{name:"node config",summary:"reconfigure a node's settings headlessly \u2014 model, lifecycle, kind, mode, name; repair a missing cwd",params:[{kind:"flag",name:"node",type:"string",required:!1,constraint:"Target node id. Defaults to the node in --pane, else CRTR_NODE_ID."},{kind:"flag",name:"pane",type:"string",required:!1,constraint:"tmux pane id to resolve the node from. Defaults to $TMUX_PANE."},{kind:"flag",name:"model",type:"string",required:!1,constraint:"Durable model change. Omit unless the task or governing guidance requires a different model.",focusedHelp:{whenToUse:"Use only when intentionally changing this node\u2019s durable model because the user, task, or governing agent guidance requires a specific provider, model, capability tier, or family. Omit it to keep the current model; do not use it merely to inspect available models or experiment with a live node.",value:`Accepted durable forms: ${S}. A live broker also accepts a free-text substring matched against its loaded model registry; a dormant node cannot resolve a substring and requires a durable form.`,effects:[q,"A concrete provider/id runs exactly that model on every launch and revive. A portable provider/tier, bare tier, or family alias keeps its tier: when that model's provider is rate-limited or rejects its credential, the node moves to the next model in its route: another provider's model at the same tier first, then the configured fallback tier (strong by default)."]}},{kind:"flag",name:"lifecycle",type:"enum",choices:["terminal","resident"],required:!1,constraint:"Set lifecycle headlessly without closing the viewer. terminal owes a final and reaps when done; resident stays interactable while attached or awaiting something live."},{kind:"flag",name:"kind",type:"string",required:!1,constraint:"Persona kind. The <kinds> list below names every top-level installable kind and when to use each; a registered sub-kind is valid too by exact path but not listed here."},{kind:"flag",name:"mode",type:"enum",choices:["base","orchestrator"],required:!1,constraint:"Set persona mode headlessly. base is hands-on; orchestrator holds a roadmap and delegates. orchestrator seeds a roadmap scaffold if absent."},{kind:"flag",name:"name",type:"string",required:!1,constraint:"Rename the node; if the node has a live window, also rename that viewer window."},{kind:"flag",name:"nice",type:"int",required:!1,constraint:`Scheduler niceness every command this node's bash tool starts at, 0\u2013${v} (default ${T}). ${T} keeps the node's builds and test suites below the daemon, the brokers, the viewers, and the person's own shell; 0 lets them compete on equal terms with everything else on the host; ${v} makes them yield to it. Applies to the node's very next command, foreground and background alike.`},{kind:"flag",name:"cwd",type:"string",required:!1,constraint:"Repair-only replacement launch directory. Must be a non-empty absolute existing directory and used alone; the daemon accepts it only for a dormant, non-forked node with no open managed worktree whose recorded cwd is gone. Clears the saved Pi session, so the next revive starts fresh while durable node work remains."}],output:[{name:"node_id",type:"string",required:!1,constraint:"The reconfigured node, present for ordinary config changes."},{name:"model",type:"string",required:!1,constraint:"The resolved model, present only when --model changed it."},{name:"lifecycle",type:"string",required:!1,constraint:"The new lifecycle, present only when --lifecycle changed it."},{name:"kind",type:"string",required:!1,constraint:"The new kind, present only when --kind changed it."},{name:"mode",type:"string",required:!1,constraint:"The new mode, present only when --mode changed it."},{name:"name",type:"string",required:!1,constraint:"The new name, present only when --name changed it."},{name:"nice",type:"number",required:!1,constraint:"The new bash niceness, present only when --nice changed it."},{name:"cwd",type:"string",required:!1,constraint:"The lexically resolved replacement directory, present only after a cwd repair."}],outputKind:"object",effects:[q,"Kind, mode, and lifecycle changes rebuild the launch spec from the fresh node meta; setting mode to orchestrator seeds a roadmap scaffold if absent.","Name changes update the row and, when the node already has a live window, rename that viewer window to the new full name.","A cwd repair writes only the lexically resolved cwd and clears saved Pi session pointers; the old transcript and durable node work remain untouched.","A niceness change is stored with the node's own bash-job state, so it takes effect on the next command without a revive and survives one."]},helpState:{leaf:k},run:l(async e=>{const t=e.pane??process.env.TMUX_PANE,n=await A(e,t),i=e.cwd;if(i!==void 0&&["model","kind","lifecycle","mode","name","nice"].some(w=>e[w]!==void 0))throw new d({error:"cwd_not_exclusive",message:"cwd repair cannot be combined with another config flag",field:"cwd",next:"Pass --cwd alone."});const s=e.model?.trim();if(s==="")throw new d({error:"empty_spec",message:"a model spec is required",field:"model",next:"Run `crtr node config --model -h` and read the focused contract before retrying."});const o=e.kind?.trim(),r=e.lifecycle?.trim(),c=e.mode?.trim(),x=e.name,h=e.nice;if(h!==void 0&&(h<0||h>v))throw new d({error:"bad_nice",message:`niceness must be between 0 and ${v}: ${h}`,field:"nice",next:`A negative niceness needs root, so pass 0\u2013${v}.`});if(r!==void 0&&r.toLowerCase()!=="terminal"&&r.toLowerCase()!=="resident")throw new d({error:"bad_lifecycle",message:`invalid lifecycle: ${r}`,field:"lifecycle",next:"Pass `terminal` or `resident`."});if(c!==void 0&&c.toLowerCase()!=="base"&&c.toLowerCase()!=="orchestrator")throw new d({error:"bad_mode",message:`invalid mode: ${c}`,field:"mode",next:"Pass `base` or `orchestrator`."});const a=[],p={};if(s!==void 0&&(p.model=s,a.push("model")),o!==void 0&&(p.kind=o,a.push("kind")),r!==void 0&&(p.lifecycle=r.toLowerCase(),a.push("lifecycle")),c!==void 0&&(p.mode=c.toLowerCase(),a.push("mode")),x!==void 0&&(p.name=x,a.push("name")),i!==void 0&&(p.cwd=i,a.push("cwd")),h!==void 0){const w=await u().getNode(n).catch(N=>m(N));if($(w.paths.context_dir,h),a.push("nice"),a.length===1)return{node_id:n,nice:h}}if(a.length===0)throw new d({error:"no_change",message:"no config changes requested",next:"Pass at least one of --model, --lifecycle, --kind, --mode, --name, --nice, --cwd."});const g=await u().patchConfig(n,p).catch(w=>m(w,"List nodes with `crtr node inspect list`."));if(i!==void 0)return{cwd:g.cwd};const f={node_id:n};return a.includes("model")&&(f.model=g.model_override??s),a.includes("lifecycle")&&(f.lifecycle=g.lifecycle),a.includes("kind")&&(f.kind=g.kind),a.includes("mode")&&(f.mode=g.mode),a.includes("name")&&(f.name=g.name),a.includes("nice")&&(f.nice=h),f},"run"),render:l(e=>{if(e.cwd!==void 0)return`Repaired cwd: ${e.cwd}.`;const t=[];return e.model!==void 0&&t.push(`model=${e.model}`),e.lifecycle!==void 0&&t.push(`lifecycle=${e.lifecycle}`),e.kind!==void 0&&t.push(`kind=${e.kind}`),e.mode!==void 0&&t.push(`mode=${e.mode}`),e.name!==void 0&&t.push(`name=${e.name}`),e.nice!==void 0&&t.push(`nice=${e.nice}`),`Configured ${e.node_id} \u2014 ${t.join(", ")}`},"render")}),Z=y({name:"promote",description:"become an orchestrator of a chosen kind",whenToUse:"the remaining work contains independent units that can run in parallel, and the task is large enough that coordinating and integrating them will materially improve intelligence, productivity, or elapsed throughput. Become a long-lived, roadmap-holding orchestrator whose primary job is steering those children across refreshes (`node yield`). Keep sequential or tightly coupled work in base mode even when it spans phases or context windows; spawning one helper does not itself require promotion",tier:"important",help:{name:"node promote",summary:"promote yourself to an orchestrator when worthwhile parallel delegation should make coordination your primary job; task duration, sequential phases, or one helper do not qualify. Mode only \u2014 lifecycle stays as-is unless you pass --resident",params:[{kind:"flag",name:"kind",type:"string",required:!1,constraint:"Specialize as this kind of orchestrator. The <kinds> list below names every top-level installable kind and when to use each; a registered sub-kind is valid too by exact path but not listed here. For an exact composed persona list, use `crtr sys context prompt-review --list --kind <kind>` with the target kind. Defaults to your current kind. Promoting from a generic kind? CHOOSE a concrete one \u2014 it sets the orchestrator persona you revive into."},{kind:"flag",name:"resident",type:"bool",required:!1,constraint:"ALSO flip lifecycle\u2192resident: make the node interactable \u2014 it is never forced to submit a final, and unattended grace parks it after a summary turn instead, leaving it revivable fresh against its goal and roadmap. Omit to stay terminal/orchestrator (delegates + holds a roadmap, but still owes a final up the spine and reaps when done)."},{kind:"flag",name:"model",type:"enum",choices:["ultra","strong"],required:!1,constraint:"Change the model you run on, by capability tier: `ultra` (frontier \u2014 reserve for high-taste judgment or enormous work: speccing, planning something large, e2e-testing something hard to test) or `strong` (opus \u2014 regular dev work). Omit to keep your current model. An orchestrator steering work is never weaker than opus, so these are the only two choices; the change is durable across future revives."},{kind:"flag",name:"node",type:"string",required:!1,constraint:"Node to promote. Defaults to the caller (CRTR_NODE_ID)."}],output:[{name:"node_id",type:"string",required:!0,constraint:"The promoted node."},{name:"kind",type:"string",required:!0,constraint:"The kind it now orchestrates as."},{name:"model",type:"string",required:!1,constraint:"The model tier it now runs on, present only when you changed it with --model."},{name:"lifecycle",type:"string",required:!0,constraint:'"resident" if you passed --resident, else unchanged (typically "terminal").'},{name:"roadmap_written",type:"boolean",required:!0,constraint:"True if a roadmap scaffold was seeded by this call."},{name:"roadmap_path",type:"string",required:!0,constraint:"Absolute path to your roadmap doc (context/roadmap.md) \u2014 edit it to author your plan."},{name:"goal_path",type:"string",required:!0,constraint:"Absolute path to your goal doc (context/initial-prompt.md) \u2014 the mandate you were spawned with."}],outputKind:"object",effects:["Flips mode\u2192orchestrator + kind\u2192chosen (lifecycle unchanged unless --resident, which also flips lifecycle\u2192resident); --model durably sets the model; rewrites the launch spec to that kind's orchestrator persona; seeds context/roadmap.md scaffold if absent.","The next model request is gated on appending and persisting your new-role guidance. If a fresh context starts first, its rebuilt baseline carries the new role."]},helpState:{leaf:k},run:l(async e=>{const t=e.node??b();if(t===void 0||t==="")throw new d({error:"no_node",message:"no node to promote (set CRTR_NODE_ID or pass --node)",next:"Run from inside a node, or pass --node <id>."});const n=e.kind,i=e.model,s=e.resident===!0,o=await u().promoteNode(t,{...n!==void 0?{kind:n}:{},...s?{resident:!0}:{},...i!==void 0?{model:i}:{}}).catch(r=>m(r));return{node_id:o.node_id,kind:o.kind,lifecycle:o.lifecycle,...i!==void 0&&o.model_override!=null?{model:o.model_override}:{},roadmap_written:o.roadmap_written??!1,roadmap_path:o.roadmap_path??"",goal_path:o.goal_path??""}},"run")});async function A(e,t){let n=e.node;if((n===void 0||n==="")&&(n=_(t)),(n===void 0||n==="")&&(n=b()),n===void 0||n==="")throw new d({error:"no_node",message:"no node (set CRTR_NODE_ID, pass --node, or run from the agent's pane)",next:"Run from inside a node, pass --node <id>, or --pane <pane>."});if(await D(n)===null)throw new d({error:"not_found",message:`no node: ${n}`,next:"List nodes with `crtr node inspect list`."});return n}l(A,"resolveLifecycleNode");const F=y({name:"demote",description:"demote a node to terminal in place; it stays focused and running but now owes a final; --detach also closes its viewer (broker keeps running off-screen)",whenToUse:"you are watching a resident/interactive node and want to put it on a finishing track WITHOUT disturbing it: flip it terminal IN PLACE \u2014 it keeps its viewer and your focus, keeps running, but now owes a final report up the spine and reaps when done. The friendly counterpart to `node promote`. You can also let go entirely and close its viewer so the agent finishes off-screen on its broker. Use `node lifecycle recycle` instead to FINISH it now and reboot a fresh root in its pane, and `node config --lifecycle` for the orthogonal low-level flip (incl. terminal\u2192resident)",help:{name:"node lifecycle demote",summary:"demote a node to terminal IN PLACE \u2014 it stays focused and running but now owes a final up the spine and reaps when done. Pairs with `node promote` (mode\u2191); `--detach` also closes its viewer (the broker engine keeps running off-screen)",params:[{kind:"flag",name:"node",type:"string",required:!1,constraint:"Node to demote. Defaults to the node in --pane, else the caller (CRTR_NODE_ID)."},{kind:"flag",name:"pane",type:"string",required:!1,constraint:"tmux pane id whose node to demote, when --node is omitted. Defaults to $TMUX_PANE. The Alt+C menu passes this for you."},{kind:"flag",name:"detach",type:"bool",required:!1,constraint:"After flipping terminal, stop foregrounding the agent by closing its viewer pane. The broker engine keeps generating off-screen and \u2014 now terminal \u2014 pushes a final up the spine when done; a later `focus` reattaches a viewer. The Alt+C \u2192 D move."}],output:[{name:"node_id",type:"string",required:!0,constraint:"The demoted node."},{name:"detached",type:"boolean",required:!1,constraint:"True when --detach closed the agent's viewer pane (broker keeps running)."}],outputKind:"object",effects:["Flips the node's lifecycle\u2192terminal and rebuilds its launch spec so a future revive boots terminal \u2014 it stays focused and running, now owing a final up the spine.","The next model request is gated on appending and persisting the role transition. If a fresh context starts first, its rebuilt baseline carries the new lifecycle.","With --detach: closes the agent's viewer pane WITHOUT touching the broker engine \u2014 it keeps generating off-screen, reconnectable by a later `focus`."]},run:l(async e=>{const t=e.pane??process.env.TMUX_PANE,n=await A(e,t),i=await u().patchConfig(n,{lifecycle:"terminal"}).catch(o=>m(o));let s=!1;if(e.detach===!0){const o=L(n)??t;o!==void 0&&o!==""&&R(o)&&(s=I(o))}return{node_id:i.node_id,detached:s}},"run"),render:l(e=>`Demoted ${e.node_id} \u2014 lifecycle now terminal (in place)${e.detached===!0?", viewer closed (broker still running off-screen)":""}.`,"render")}),ee=C({name:"lifecycle",description:"lifecycle actions \u2014 recycle, close, demote, or revive a node",whenToUse:"you are ending, transitioning, or bringing back one node you can name: finish the agent in your pane and reboot a fresh root (`recycle`), tear a node + its exclusive subtree down without finishing (`close`), flip a node onto a finishing track in place (`demote`), or bring a dormant node back (`revive`). To merely SET the terminal/resident attribute headlessly use `node config --lifecycle`; to FINISH from inside a node's own turn use `crtr push final`; to mass-reconnect EVERY disconnected node at once use `canvas revive --all`.",help:{name:"node lifecycle",summary:"end, transition, or revive a node \u2014 recycle the pane, close + cascade-cancel a subtree, demote to terminal in place, or revive a dormant node",model:"Lifecycle actions preserve or replace an existing node identity. Finishing is permanent, closing is revivable, demotion changes the completion obligation in place, and revival relaunches a dormant broker. Teardown cascades only through descendants exclusively managed by the affected subtree."},children:[j,M,F,P]}),ne=y({name:"yield",description:"refresh your context, same mode, against your roadmap or goal",whenToUse:"your context is filling but the mandate remains; refresh in the same mode, or combine the refresh with promotion when meaningful independent work can run in parallel and coordinating it should become your primary job",help:{name:"node yield",summary:"request a fresh context window against your roadmap or original goal; mode stays unchanged unless --promote is passed",guide:"The yield aborts your turn the instant this command returns: no text or tool call you planned after it will run. So anything the user is owed \u2014 an answer, a status \u2014 must already be a visible message in the conversation before you call it; never plan to reply after yielding. Before invoking: (1) Bring `$CRTR_CONTEXT_DIR/roadmap.md` current \u2014 it, not the yield note, carries the goal into the fresh window. Keep its seeded sections (Goal, Exit criteria, Phases) and keep it short: strategy and present state only \u2014 what is settled, what remains, the current phase\u2019s one-line status, plus dead ends worth not repeating. Delete completed items instead of marking them done; the roadmap should shrink as work completes. (2) Move anything worth remembering but not needed next window into memory (`crtr memory write -h`): node-local for lessons specific to this node\u2019s task, the workspace store for lessons that would benefit other agents working here. (3) Send any pending human question; in-flight asks survive the refresh.",params:[{kind:"flag",name:"promote",type:"bool",required:!1,constraint:"Also become an orchestrator as you refresh. Pass only when (1) the remaining work contains independent units that can run in parallel and (2) the task is large enough that parallel execution will materially improve intelligence, productivity, or elapsed throughput after coordination and synthesis. Task length, context exhaustion, sequential phases, or one helper are not enough; keep hands-on work in base mode and yield again as needed. Promote when coordinating and integrating children becomes your primary job. Already an orchestrator? This is not an error: your mode stays orchestrator and a missing roadmap is seeded."},{kind:"flag",name:"kind",type:"string",required:!1,constraint:"Respecialize as you refresh. The <kinds> list below names every top-level available kind and when to choose it; a registered sub-kind is valid too by exact path but not listed here. Defaults to your current kind. With --promote it sets the orchestrator kind you become; without --promote it changes the kind while preserving your current mode."},{kind:"flag",name:"model",type:"enum",choices:["ultra","strong"],required:!1,constraint:"Change the model your fresh revive runs on, by capability tier: `ultra` (frontier \u2014 reserve for high-taste judgment or enormous work: speccing, planning something large, e2e-testing something hard to test) or `strong` (opus \u2014 regular dev work). Omit to keep your current model. A node steering work is never weaker than opus, so these are the only two choices; the change is durable across future revives."},{kind:"stdin",name:"message",required:!0,constraint:"A note to your future self \u2014 what you just tried, where things stand, and the first move on waking: enough to continue efficiently, no more. If the user asked something you have not answered in a visible message, say so and quote the question. Never describe a reply as sent unless it is visible in the conversation above this call. Durable strategy belongs in the roadmap, not here. Surfaced as <yield-message> in the next revive. Pass as a positional or pipe via heredoc."}],output:[{name:"node_id",type:"string",required:!0,constraint:"The yielding node."},{name:"model",type:"string",required:!1,constraint:"The model tier your fresh revive will run on, present only when you changed it with --model."}],outputKind:"object",effects:["Aborts your current turn as soon as this command returns \u2014 nothing after it runs \u2014 then the daemon revives the node fresh.","--kind and/or --model durably reshape the node (kind respecialization, model change) before the refresh-revive; --promote additionally flips mode\u2192orchestrator and seeds a roadmap scaffold \u2014 mode is otherwise left exactly as it was."]},helpState:{leaf:k},run:l(async e=>{const t=b();if(t===void 0||t==="")throw new d({error:"no_node",message:"no node to yield (CRTR_NODE_ID unset)",next:"Run from inside a node."});const n=e.kind,i=e.model,s=e.promote===!0,o=typeof e.message=="string"?e.message.trim():"";if(o==="")throw new d({error:"empty_message",message:"a yield message is required (stdin or positional)",next:"Pass a note to your future self as an argument or pipe it on stdin."});const r=await u().yieldNode(t,{note:o,...n!==void 0?{kind:n}:{},...i!==void 0?{model:i}:{},...s?{promote:!0}:{}}).catch(c=>m(c));return{node_id:r.node_id,...i!==void 0&&r.model_override!=null?{model:r.model_override}:{}}},"run")});export{Q as nodeConfig,ee as nodeLifecycle,Z as nodePromote,ne as nodeYield};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var h=Object.defineProperty;var s=(n,o)=>h(n,"name",{value:o,configurable:!0});import{envNodeId as
|
|
2
|
-
`)},"render")});export{
|
|
1
|
+
var h=Object.defineProperty;var s=(n,o)=>h(n,"name",{value:o,configurable:!0});import{envNodeId as v}from"../shared/env.js";import{spawnSync as a}from"node:child_process";import{existsSync as l,mkdirSync as x,mkdtempSync as b,rmSync as y,symlinkSync as c}from"node:fs";import{tmpdir as g}from"node:os";import{dirname as w,join as d}from"node:path";import{defineLeaf as T}from"../core/command.js";import{InputError as p}from"../core/io.js";import{cliClient as D,rethrowAsCliError as R}from"./api-client.js";function u(n){return n.replace(/[^A-Za-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"node"}s(u,"sanitize");async function S(n){const o=await D().getContext(n),t=[];for(const e of o.roots){const r=e.dir,i=e.reports_dir,m=e.node_id.slice(0,8),f=e.self?`self-${u(e.label)}`:`${u(e.label)}-${m}`;t.push({nodeId:e.node_id,label:f,dir:w(r),self:e.self,fileCount:e.files,contextDir:r,reportsDir:i})}return t}s(S,"resolveRoots");function _(){const n=a("nvim",["--version"],{stdio:"ignore"});return n.error===void 0&&(n.status===0||n.status===null)}s(_,"nvimAvailable");function $(n){const o=b(d(g(),"crtr-context-"));for(const t of n){const e=t.self?`0-${t.label}`:t.label,r=d(o,e);x(r,{recursive:!0});try{l(t.contextDir)&&c(t.contextDir,d(r,"context"),"dir"),l(t.reportsDir)&&c(t.reportsDir,d(r,"reports"),"dir")}catch{}}return o}s($,"buildSymlinkTree");const q=T({name:"context",description:"browse this node + its subscriptions\u2019 context and reports dirs in an nvim popup",whenToUse:"you want to SEE what the nodes you subscribe to have written \u2014 open a read-only nvim file explorer over this node\u2019s context and reports dirs and every subscribed node\u2019s context and reports dirs at once. The /context popup shells this. Piped it prints the roster instead",help:{name:"node inspect context",summary:"open a read-only nvim file explorer over this node\u2019s context and reports dirs and those of every node it subscribes to",params:[{kind:"flag",name:"node",type:"string",required:!1,constraint:"Node id to root on. Defaults to $CRTR_NODE_ID (the calling node)."}],output:[{name:"roots",type:"object[]",required:!0,constraint:"Resolved browse roots: {node_id, label, dir, self, files}. Returned on the piped/non-TTY path."}],outputKind:"object",effects:["TTY: builds a temp dir of labelled node dirs, symlinking each available `context`/`reports` dir inside it, then execs `nvim -R` on the tree; the temp links are removed on exit (real dirs untouched).","Requires nvim on PATH (a crtr strong dependency). Missing nvim -> error with an install hint.","Non-TTY / piped: prints the resolved roster and exits 0; opens nothing."]},run:s(async n=>{const o=n.node?.trim()||v();if(o===void 0||o==="")throw new p({error:"no_node",message:"no current node: $CRTR_NODE_ID is unset and --node was not given",field:"node",next:"Run this from inside a canvas node (the /context popup does), or pass --node <id>."});let t;try{t=await S(o)}catch(i){R(i)}const e=t.map(i=>({node_id:i.nodeId,label:i.label,dir:i.dir,self:i.self,files:i.fileCount}));if(!process.stdout.isTTY)return{roots:e};if(!_())throw new p({error:"nvim_missing",message:"nvim is not on PATH \u2014 `crtr node inspect context` opens the context explorer in nvim",next:"Install Neovim (macOS: `brew install neovim`; Debian/Ubuntu: `apt install neovim`), then retry."});const r=$(t);try{a("nvim",["-R","."],{cwd:r,stdio:"inherit"})}finally{y(r,{recursive:!0,force:!0})}return{roots:e}},"run"),render:s(n=>{const o=n.roots??[];if(o.length===0)return"No node dirs to show (no subscriptions with written context or reports, and this node\u2019s own context/reports dirs are empty/absent).";const t=o.map(e=>{const r=e.self===!0?" (self)":"";return` ${String(e.label)}${r} ${String(e.files)} files ${String(e.dir)}`});return[`Context roots (${o.length}):`,...t].join(`
|
|
2
|
+
`)},"render")});export{q as nodeContextLeaf};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var
|
|
2
|
-
`);
|
|
1
|
+
var p=Object.defineProperty;var f=(o,t)=>p(o,"name",{value:t,configurable:!0});import{defineLeaf as u}from"../core/command.js";import{cliClient as m,rethrowAsCliError as h}from"./api-client.js";const y=["report","doc","roadmap","inbox"],$=u({name:"artifacts",description:"enumerate one node's artifacts as refs",whenToUse:'you have a node id and want to see everything it left behind \u2014 its reports and context docs as refs ready for `canvas history read`. The bridge from "found the node" to "read its artifacts". Use `node inspect show` instead for the node\'s topology/neighbors, not its content.',help:{name:"node inspect artifacts",summary:"list one node's artifacts (reports + context docs) as refs ready for `canvas history read`",params:[{kind:"positional",name:"node-id",required:!0,constraint:"The node whose artifacts to list."},{kind:"flag",name:"type",type:"enum",choices:[...y],required:!1,constraint:"Narrow to one corpus: report | doc | roadmap | inbox. Default: report, doc, roadmap (inbox is opt-in only \u2014 the node's inbox history including full un-clipped direct-message bodies; a diagnostic surface, not curated past work)."},{kind:"flag",name:"sort",type:"enum",choices:["recency","oldest"],required:!1,constraint:"Order by artifact timestamp. Default recency."}],output:[{name:"node",type:"string",required:!0,constraint:"Node name + id."},{name:"artifacts",type:"object[]",required:!0,constraint:"Each: {ref, source, ts, detail}. source = report:<kind> | doc | roadmap | inbox. detail = report title / doc heading + size (inbox: `[kind] label`, no size). ref passes verbatim to `canvas history read`."},{name:"follow_up",type:"string",required:!0,constraint:"Concrete next commands."}],outputKind:"object",effects:["None. Read-only."]},run:f(async o=>{const t=o.nodeId.trim(),r=o.type,s=o.sort??"recency",c=m();let d,a;try{const[e,i]=await Promise.all([c.getNode(t),c.getArtifacts(t,r!==void 0?{type:r}:void 0)]);d=e.name,a=i.artifacts}catch(e){h(e,"List nodes with `crtr node inspect list`, or find one with `crtr canvas history search`.")}const n=f(e=>Date.parse(e)||0,"ms");a.sort((e,i)=>(s==="oldest"?n(e.ts)-n(i.ts):n(i.ts)-n(e.ts))||e.ref.localeCompare(i.ref));const l=a.map(e=>({ref:e.ref,source:e.source,ts:e.ts,detail:e.title+(e.size>0?` (${e.size}B)`:"")}));return{node:`${d} (${t})`,artifacts:l,follow_up:"Read one with `crtr canvas history read <ref>`; reopen the node with `crtr node lifecycle revive "+t+"`."}},"run"),render:f(o=>{const t=o.artifacts,r=[`node: ${o.node}`];if(t.length===0)r.push("0 artifacts.");else{const s=Object.keys(t[0]),c=`| ${s.join(" | ")} |`,d=`| ${s.map(()=>"---").join(" | ")} |`,a=t.map(n=>`| ${s.map(l=>String(n[l]??"").replace(/\|/g,"\\|").replace(/\n/g," ")).join(" | ")} |`).join(`
|
|
2
|
+
`);r.push(`${t.length} artifacts:
|
|
3
3
|
|
|
4
|
-
${
|
|
5
|
-
${
|
|
6
|
-
${
|
|
4
|
+
${c}
|
|
5
|
+
${d}
|
|
6
|
+
${a}`)}return r.push(String(o.follow_up)),r.join(`
|
|
7
7
|
|
|
8
|
-
`)},"render")});export{
|
|
8
|
+
`)},"render")});export{$ as nodeArtifactsLeaf};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var D=Object.defineProperty;var l=(e,n)=>D(e,"name",{value:n,configurable:!0});import{statSync as C}from"node:fs";import{isAbsolute as z,join as k}from"node:path";import{SUBTREE_NAMES as U,coreCommandPaths as B,extensibleCoreBranches as _}from"../../../build-root.js";import{discoverPluginCommandCandidates as F,validateEffectiveCommandPlugins as L,validatePluginCommands as W}from"../../../core/command-plugins/discovery.js";import{qualifiedTopLevelCommandName as w}from"../../../core/command-manifests/registry.js";import{listDirs as x,pathExists as A,walkFiles as q}from"../../../core/fs-utils.js";import{currentSha as Z,gitSync as G}from"../../../core/git.js";import{listPluginMemoryDocs as H}from"../../../core/memory-resolver.js";import{memoryExtensionEffectiveCatalog as K,projectEffectiveMemoryExtensions as O}from"../../../core/memory/extensions.js";import{readMarketplaceManifest as J,readPluginManifest as E}from"../../../core/manifest.js";import{readConfig as Q}from"../../../core/config.js";import{parseSubstrateDoc as V}from"../../../core/substrate/schema.js";import{projectScopeRoot as y,userScopeRoot as S}from"../../../core/scope.js";import{isGitUrl as X}from"../shared.js";import{INSTALLED_SOURCE_ID as $,marketplaceSourceId as M}from"./model.js";function P(e){const n=/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z.-]+)?$/.exec(e);return n===null?null:{core:[Number(n[1]),Number(n[2]),Number(n[3])],prerelease:n[4]?.split(".")??[]}}l(P,"parseSemver");function Y(e,n){for(let t=0;t<e.core.length;t+=1){const o=e.core[t]-n.core[t];if(o!==0)return o}if(e.prerelease.length===0||n.prerelease.length===0)return e.prerelease.length===n.prerelease.length?0:e.prerelease.length===0?1:-1;for(let t=0;t<Math.max(e.prerelease.length,n.prerelease.length);t+=1){const o=e.prerelease[t],a=n.prerelease[t];if(o===void 0||a===void 0)return o===void 0?-1:1;const i=/^\d+$/.test(o),r=/^\d+$/.test(a);if(i&&r){const s=Number(o)-Number(a);if(s!==0)return s}else{if(i!==r)return i?-1:1;if(o!==a)return o<a?-1:1}}return 0}l(Y,"compareSemver");function j(e,n){if(e===void 0||n===void 0)return!1;const t=P(e),o=P(n);return t!==null&&o!==null&&Y(o,t)>0}l(j,"offeredVersionIsNewer");function ee(e){return e.startsWith("./")||e.startsWith("../")||!z(e)&&!X(e)}l(ee,"isMarketplaceRelativeSource");function I(e,n){return{kind:"installed",scope:e.scope,enabled:e.enabled,version:e.version,path:e.root,updateAvailable:j(e.version,n)}}l(I,"pluginInstallState");function ne(e,n){return{key:`${$}:${e.scope}:${e.name}`,name:e.name,ref:e.name,sourceId:$,...e.sourceMarketplace!==void 0?{marketplace:e.sourceMarketplace}:{},...n===void 0?{}:{version:n},description:e.manifest.description,keywords:[],owner:e.manifest.owner,source:e.manifest.source,install:I(e,n),root:e.root}}l(ne,"installedEntry");function v(e,n){return`${e}:${n}`}l(v,"marketplacePluginKey");function te(e,n){const t=Z(e.root)??void 0,o=G(["show","-s","--format=%cI","HEAD"],e.root),a=o.status===0&&o.stdout.trim()||void 0,i=e.manifest.plugins;return{name:e.name,scope:e.scope,url:e.url,ref:e.ref,path:e.root,owner:e.manifest.owner,version:e.manifest.version,pluginCount:i.length,installedCount:i.filter(r=>n.has(v(e.name,r.name))).length,updatableCount:i.filter(r=>{const s=n.get(v(e.name,r.name));return s!==void 0&&j(s.version,r.version)}).length,revision:t,revisionDate:a}}l(te,"marketplaceDetail");function re(e,n,t){const o=t.get(v(e.name,n.name)),a=ee(n.source)?k(e.root,n.source):void 0;return{key:`${M(e.name,e.scope)}:${n.name}`,name:n.name,ref:`${e.name}/${n.name}`,sourceId:M(e.name,e.scope),marketplace:e.name,version:n.version,description:n.description,keywords:n.keywords??[],owner:e.manifest.owner,source:n.source,install:o===void 0?{kind:"absent"}:I(o,n.version),...o!==void 0?{root:o.root}:a!==void 0&&A(a)?{root:a}:{}}}l(re,"marketplaceEntry");function R(e,n){try{return Q(e)}catch(t){return n.push(`Could not read ${e} config: ${b(t)}`),null}}l(R,"readableConfig");function oe(e){const n=[...y()===null?[]:[{scope:"project",root:y()}],{scope:"user",root:S()}],t=[];for(const{scope:o,root:a}of n){const i=R(o,e);for(const r of x(k(a,"plugins"))){const s=k(a,"plugins",r);try{const c=E(s);if(c===null){e.push(`Plugin "${r}" has no readable manifest: ${s}`);continue}const u=i?.plugins[r];t.push({name:r,scope:o,root:s,manifest:c,enabled:typeof u?.enabled=="boolean"?u.enabled:!0,sourceMarketplace:typeof u?.source_marketplace=="string"?u.source_marketplace:void 0,version:typeof u?.version=="string"?u.version:c.version})}catch(c){e.push(`Could not read plugin "${r}": ${b(c)}`)}}}return t}l(oe,"readInstalledPlugins");function se(e,n,t){if(!Array.isArray(e))return t.push(`Marketplace "${n}" has an invalid plugins list.`),[];const o=[];for(const[a,i]of e.entries()){if(typeof i!="object"||i===null||Array.isArray(i)){t.push(`Marketplace "${n}" has an invalid plugin entry at index ${a}.`);continue}const r=i;if(typeof r.name!="string"||r.name===""||typeof r.source!="string"||r.source===""){t.push(`Marketplace "${n}" has a plugin entry without a name and source at index ${a}.`);continue}o.push({name:r.name,source:r.source,...typeof r.version=="string"?{version:r.version}:{},...typeof r.description=="string"?{description:r.description}:{},...Array.isArray(r.keywords)&&r.keywords.every(s=>typeof s=="string")?{keywords:r.keywords}:{}})}return o}l(se,"marketplaceEntries");function ae(e,n,t){if(typeof e!="object"||e===null||Array.isArray(e))return t.push(`Marketplace "${n}" has an invalid manifest.`),null;const o=e;if(typeof o.name!="string"||o.name==="")return t.push(`Marketplace "${n}" has a manifest without a name.`),null;const a=o.owner,i=typeof a=="object"&&a!==null&&!Array.isArray(a)?{...typeof a.name=="string"?{name:a.name}:{},...typeof a.email=="string"?{email:a.email}:{}}:void 0;return{name:o.name,plugins:se(o.plugins,o.name,t),...typeof o.version=="string"?{version:o.version}:{},...i!==void 0?{owner:i}:{}}}l(ae,"readableMarketplaceManifest");function ie(e){const n=[...y()===null?[]:[{scope:"project",root:y()}],{scope:"user",root:S()}],t=[];for(const{scope:o,root:a}of n){const i=R(o,e);for(const r of x(k(a,"marketplaces"))){const s=k(a,"marketplaces",r);try{const c=J(s);if(c===null){e.push(`Marketplace "${r}" has no readable manifest: ${s}`);continue}const u=ae(c,r,e);if(u===null)continue;const d=i?.marketplaces[r];t.push({name:r,scope:o,root:s,manifest:u,url:d?.url??"",ref:d?.ref??"main"})}catch(c){e.push(`Could not read marketplace "${r}": ${b(c)}`)}}}return t}l(ie,"readMarketplaces");function Ae(){const e=[],n=oe(e),t=ie(e),o=new Map(n.filter(r=>r.sourceMarketplace!==void 0).map(r=>[v(r.sourceMarketplace,r.name),r])),a=new Map(t.flatMap(r=>r.manifest.plugins.map(s=>[v(r.name,s.name),s.version]))),i=[{id:$,kind:"installed",label:"Installed",entries:n.map(r=>ne(r,r.sourceMarketplace===void 0?void 0:a.get(v(r.sourceMarketplace,r.name)))).sort((r,s)=>r.name.localeCompare(s.name))}];for(const r of t.sort((s,c)=>s.name.localeCompare(c.name)))try{i.push({id:M(r.name,r.scope),kind:"marketplace",label:r.name,marketplace:te(r,o),entries:r.manifest.plugins.map(s=>re(r,s,o)).sort((s,c)=>s.name.localeCompare(c.name))})}catch(s){e.push(`Could not load marketplace "${r.name}": ${b(s)}`)}return{sources:i,installScopes:["user",...y()===null?[]:["project"]],warnings:e}}l(Ae,"loadCatalog");function T(e,n=[]){const t=[...n,e.name];return e.kind==="branch"?{path:t,kind:"branch",description:e.description,whenToUse:e.whenToUse,summary:e.summary,...e.tier!==void 0?{tier:e.tier}:{},...e.passthrough!==void 0?{passthrough:e.passthrough}:{},...e.rootEntry!==void 0?{rootEntry:e.rootEntry}:{},children:e.children.map(o=>T(o,t)),params:[],output:[],effects:[]}:{path:t,kind:"leaf",description:e.description,whenToUse:e.whenToUse,summary:e.summary,...e.tier!==void 0?{tier:e.tier}:{},children:[],params:e.params,output:e.output,effects:[...e.effects],..."rest"in e?{rest:{method:e.rest.method,path:e.rest.path,streaming:e.rest.streaming===!0}}:{}}}l(T,"commandNode");function le(e){return H(e,e.scope,!0).flatMap(n=>{const t=V(n);if(t===null)return[];let o;try{o=C(t.path).size}catch{}return[{name:t.name,kind:t.kind,...t.shortForm!==""?{shortForm:t.shortForm}:{},...t.whenAndWhyToRead!==""?{routingLine:t.whenAndWhyToRead}:{},path:t.path,...o!==void 0?{sizeBytes:o}:{},surfaces:t.surfaces,unlisted:t.unlisted,slash:t.slash,...t.gate!==void 0?{gate:t.gate}:{},...t.rationale!==void 0?{rationale:t.rationale}:{},extensions:O(n.frontmatter?.extensions,K(n)),body:t.body}]})}l(le,"docDetails");function ce(e){try{return q(e).reduce((n,t)=>n+C(t).size,0)}catch{return}}l(ce,"directorySize");async function Ee(e){if(e.root===void 0||!A(e.root))return null;try{const n=E(e.root);if(n===null)return null;const t=e.install.kind==="installed"?e.install.scope:"user",o={name:e.name,scope:t,root:e.root,manifest:n,enabled:e.install.kind!=="installed"||e.install.enabled},a=new Set(U),[i,r]=await Promise.all([B(),_()]);let s=W(o,a,i,r);const c=[];if(e.install.kind==="installed"&&e.install.enabled)try{s=L(a,void 0,void 0,i,r).find(p=>p.plugin.root===e.root)??s}catch(d){c.push({message:`Could not resolve the effective command registry: ${b(d)}`,next:"Repair the unreadable installed plugin manifest, then reopen the dossier."})}if(e.install.kind!=="installed"||!e.install.enabled){const d=new Map;for(const m of F())if(m.plugin.root!==e.root)for(const f of m.contributions){const h=d.get(f.node.name)??[];h.push(m.plugin),d.set(f.node.name,h)}const p=e.install.kind==="installed"?"enabling":"installing";s.contributions=s.contributions.map(m=>{const f=d.get(m.node.name);if(f===void 0||f.length===0)return m;const h=w({name:e.name,sourceMarketplace:e.marketplace},m.node.name),N=f.map(g=>`moves ${g.name}'s to "${w(g,m.node.name)}"`);return s.issues.push({code:"command_collision",plugin:o.name,path:m.node.name,message:`top-level command "${m.node.name}" is already claimed by ${f.map(g=>g.name).join(", ")} \u2014 ${p} mounts this one as "${h}" and ${N.join(" and ")}`,received:[...f.map(g=>g.name),o.name].join(", "),expected:"an origin-qualified top-level command for each claimant",next:`After ${p}, invoke "${h}".`}),{...m,node:{...m.node,name:h}}})}const u=n.transport;return{root:e.root,transport:u?.kind??null,...u?.kind==="exec"&&u.executable!==void 0?{transportTarget:u.executable}:{},...u?.kind==="http"?{transportTarget:u.endpoint}:{},commands:s.contributions.map(d=>T(d.node)),commandIssues:[...s.issues.map(({message:d,next:p})=>({message:d,...p!==void 0?{next:p}:{}})),...c],docs:le(o),sizeBytes:ce(e.root)}}catch{return null}}l(Ee,"loadCapability");function b(e){return e instanceof Error?e.message:String(e)}l(b,"errorMessage");export{Ee as loadCapability,Ae as loadCatalog};
|
|
1
|
+
var D=Object.defineProperty;var l=(e,n)=>D(e,"name",{value:n,configurable:!0});import{statSync as C}from"node:fs";import{isAbsolute as z,join as k}from"node:path";import{SUBTREE_NAMES as U,coreCommandPaths as B,extensibleCoreBranches as _}from"../../../build-root.js";import{discoverPluginCommandCandidates as F,validateEffectiveCommandPlugins as L,validatePluginCommands as W}from"../../../core/command-plugins/discovery.js";import{qualifiedTopLevelCommandName as w}from"../../../core/command-manifests/registry.js";import{listDirs as x,pathExists as A,walkFiles as q}from"../../../core/fs-utils.js";import{currentSha as Z,gitSync as G}from"../../../core/git.js";import{listPluginMemoryDocs as H}from"../../../core/memory-resolver.js";import{memoryExtensionEffectiveCatalog as K,projectEffectiveMemoryExtensions as O}from"../../../core/memory/extensions.js";import{readMarketplaceManifest as J,readPluginManifest as E}from"../../../core/manifest.js";import{readConfig as Q}from"../../../core/config.js";import{parseSubstrateDoc as V}from"../../../core/substrate/schema.js";import{projectScopeRoot as y}from"../../../core/scope.js";import{runtimeRoot as S}from"../../../core/layout.js";import{isGitUrl as X}from"../shared.js";import{INSTALLED_SOURCE_ID as $,marketplaceSourceId as M}from"./model.js";function P(e){const n=/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z.-]+)?$/.exec(e);return n===null?null:{core:[Number(n[1]),Number(n[2]),Number(n[3])],prerelease:n[4]?.split(".")??[]}}l(P,"parseSemver");function Y(e,n){for(let t=0;t<e.core.length;t+=1){const o=e.core[t]-n.core[t];if(o!==0)return o}if(e.prerelease.length===0||n.prerelease.length===0)return e.prerelease.length===n.prerelease.length?0:e.prerelease.length===0?1:-1;for(let t=0;t<Math.max(e.prerelease.length,n.prerelease.length);t+=1){const o=e.prerelease[t],a=n.prerelease[t];if(o===void 0||a===void 0)return o===void 0?-1:1;const i=/^\d+$/.test(o),r=/^\d+$/.test(a);if(i&&r){const s=Number(o)-Number(a);if(s!==0)return s}else{if(i!==r)return i?-1:1;if(o!==a)return o<a?-1:1}}return 0}l(Y,"compareSemver");function j(e,n){if(e===void 0||n===void 0)return!1;const t=P(e),o=P(n);return t!==null&&o!==null&&Y(o,t)>0}l(j,"offeredVersionIsNewer");function ee(e){return e.startsWith("./")||e.startsWith("../")||!z(e)&&!X(e)}l(ee,"isMarketplaceRelativeSource");function I(e,n){return{kind:"installed",scope:e.scope,enabled:e.enabled,version:e.version,path:e.root,updateAvailable:j(e.version,n)}}l(I,"pluginInstallState");function ne(e,n){return{key:`${$}:${e.scope}:${e.name}`,name:e.name,ref:e.name,sourceId:$,...e.sourceMarketplace!==void 0?{marketplace:e.sourceMarketplace}:{},...n===void 0?{}:{version:n},description:e.manifest.description,keywords:[],owner:e.manifest.owner,source:e.manifest.source,install:I(e,n),root:e.root}}l(ne,"installedEntry");function v(e,n){return`${e}:${n}`}l(v,"marketplacePluginKey");function te(e,n){const t=Z(e.root)??void 0,o=G(["show","-s","--format=%cI","HEAD"],e.root),a=o.status===0&&o.stdout.trim()||void 0,i=e.manifest.plugins;return{name:e.name,scope:e.scope,url:e.url,ref:e.ref,path:e.root,owner:e.manifest.owner,version:e.manifest.version,pluginCount:i.length,installedCount:i.filter(r=>n.has(v(e.name,r.name))).length,updatableCount:i.filter(r=>{const s=n.get(v(e.name,r.name));return s!==void 0&&j(s.version,r.version)}).length,revision:t,revisionDate:a}}l(te,"marketplaceDetail");function re(e,n,t){const o=t.get(v(e.name,n.name)),a=ee(n.source)?k(e.root,n.source):void 0;return{key:`${M(e.name,e.scope)}:${n.name}`,name:n.name,ref:`${e.name}/${n.name}`,sourceId:M(e.name,e.scope),marketplace:e.name,version:n.version,description:n.description,keywords:n.keywords??[],owner:e.manifest.owner,source:n.source,install:o===void 0?{kind:"absent"}:I(o,n.version),...o!==void 0?{root:o.root}:a!==void 0&&A(a)?{root:a}:{}}}l(re,"marketplaceEntry");function R(e,n){try{return Q(e)}catch(t){return n.push(`Could not read ${e} config: ${b(t)}`),null}}l(R,"readableConfig");function oe(e){const n=[...y()===null?[]:[{scope:"project",root:y()}],{scope:"user",root:S()}],t=[];for(const{scope:o,root:a}of n){const i=R(o,e);for(const r of x(k(a,"plugins"))){const s=k(a,"plugins",r);try{const c=E(s);if(c===null){e.push(`Plugin "${r}" has no readable manifest: ${s}`);continue}const u=i?.plugins[r];t.push({name:r,scope:o,root:s,manifest:c,enabled:typeof u?.enabled=="boolean"?u.enabled:!0,sourceMarketplace:typeof u?.source_marketplace=="string"?u.source_marketplace:void 0,version:typeof u?.version=="string"?u.version:c.version})}catch(c){e.push(`Could not read plugin "${r}": ${b(c)}`)}}}return t}l(oe,"readInstalledPlugins");function se(e,n,t){if(!Array.isArray(e))return t.push(`Marketplace "${n}" has an invalid plugins list.`),[];const o=[];for(const[a,i]of e.entries()){if(typeof i!="object"||i===null||Array.isArray(i)){t.push(`Marketplace "${n}" has an invalid plugin entry at index ${a}.`);continue}const r=i;if(typeof r.name!="string"||r.name===""||typeof r.source!="string"||r.source===""){t.push(`Marketplace "${n}" has a plugin entry without a name and source at index ${a}.`);continue}o.push({name:r.name,source:r.source,...typeof r.version=="string"?{version:r.version}:{},...typeof r.description=="string"?{description:r.description}:{},...Array.isArray(r.keywords)&&r.keywords.every(s=>typeof s=="string")?{keywords:r.keywords}:{}})}return o}l(se,"marketplaceEntries");function ae(e,n,t){if(typeof e!="object"||e===null||Array.isArray(e))return t.push(`Marketplace "${n}" has an invalid manifest.`),null;const o=e;if(typeof o.name!="string"||o.name==="")return t.push(`Marketplace "${n}" has a manifest without a name.`),null;const a=o.owner,i=typeof a=="object"&&a!==null&&!Array.isArray(a)?{...typeof a.name=="string"?{name:a.name}:{},...typeof a.email=="string"?{email:a.email}:{}}:void 0;return{name:o.name,plugins:se(o.plugins,o.name,t),...typeof o.version=="string"?{version:o.version}:{},...i!==void 0?{owner:i}:{}}}l(ae,"readableMarketplaceManifest");function ie(e){const n=[...y()===null?[]:[{scope:"project",root:y()}],{scope:"user",root:S()}],t=[];for(const{scope:o,root:a}of n){const i=R(o,e);for(const r of x(k(a,"marketplaces"))){const s=k(a,"marketplaces",r);try{const c=J(s);if(c===null){e.push(`Marketplace "${r}" has no readable manifest: ${s}`);continue}const u=ae(c,r,e);if(u===null)continue;const d=i?.marketplaces[r];t.push({name:r,scope:o,root:s,manifest:u,url:d?.url??"",ref:d?.ref??"main"})}catch(c){e.push(`Could not read marketplace "${r}": ${b(c)}`)}}}return t}l(ie,"readMarketplaces");function Ee(){const e=[],n=oe(e),t=ie(e),o=new Map(n.filter(r=>r.sourceMarketplace!==void 0).map(r=>[v(r.sourceMarketplace,r.name),r])),a=new Map(t.flatMap(r=>r.manifest.plugins.map(s=>[v(r.name,s.name),s.version]))),i=[{id:$,kind:"installed",label:"Installed",entries:n.map(r=>ne(r,r.sourceMarketplace===void 0?void 0:a.get(v(r.sourceMarketplace,r.name)))).sort((r,s)=>r.name.localeCompare(s.name))}];for(const r of t.sort((s,c)=>s.name.localeCompare(c.name)))try{i.push({id:M(r.name,r.scope),kind:"marketplace",label:r.name,marketplace:te(r,o),entries:r.manifest.plugins.map(s=>re(r,s,o)).sort((s,c)=>s.name.localeCompare(c.name))})}catch(s){e.push(`Could not load marketplace "${r.name}": ${b(s)}`)}return{sources:i,installScopes:["user",...y()===null?[]:["project"]],warnings:e}}l(Ee,"loadCatalog");function T(e,n=[]){const t=[...n,e.name];return e.kind==="branch"?{path:t,kind:"branch",description:e.description,whenToUse:e.whenToUse,summary:e.summary,...e.tier!==void 0?{tier:e.tier}:{},...e.passthrough!==void 0?{passthrough:e.passthrough}:{},...e.rootEntry!==void 0?{rootEntry:e.rootEntry}:{},children:e.children.map(o=>T(o,t)),params:[],output:[],effects:[]}:{path:t,kind:"leaf",description:e.description,whenToUse:e.whenToUse,summary:e.summary,...e.tier!==void 0?{tier:e.tier}:{},children:[],params:e.params,output:e.output,effects:[...e.effects],..."rest"in e?{rest:{method:e.rest.method,path:e.rest.path,streaming:e.rest.streaming===!0}}:{}}}l(T,"commandNode");function le(e){return H(e,e.scope,!0).flatMap(n=>{const t=V(n);if(t===null)return[];let o;try{o=C(t.path).size}catch{}return[{name:t.name,kind:t.kind,...t.shortForm!==""?{shortForm:t.shortForm}:{},...t.whenAndWhyToRead!==""?{routingLine:t.whenAndWhyToRead}:{},path:t.path,...o!==void 0?{sizeBytes:o}:{},surfaces:t.surfaces,unlisted:t.unlisted,slash:t.slash,...t.gate!==void 0?{gate:t.gate}:{},...t.rationale!==void 0?{rationale:t.rationale}:{},extensions:O(n.frontmatter?.extensions,K(n)),body:t.body}]})}l(le,"docDetails");function ce(e){try{return q(e).reduce((n,t)=>n+C(t).size,0)}catch{return}}l(ce,"directorySize");async function Se(e){if(e.root===void 0||!A(e.root))return null;try{const n=E(e.root);if(n===null)return null;const t=e.install.kind==="installed"?e.install.scope:"user",o={name:e.name,scope:t,root:e.root,manifest:n,enabled:e.install.kind!=="installed"||e.install.enabled},a=new Set(U),[i,r]=await Promise.all([B(),_()]);let s=W(o,a,i,r);const c=[];if(e.install.kind==="installed"&&e.install.enabled)try{s=L(a,void 0,void 0,i,r).find(p=>p.plugin.root===e.root)??s}catch(d){c.push({message:`Could not resolve the effective command registry: ${b(d)}`,next:"Repair the unreadable installed plugin manifest, then reopen the dossier."})}if(e.install.kind!=="installed"||!e.install.enabled){const d=new Map;for(const m of F())if(m.plugin.root!==e.root)for(const f of m.contributions){const h=d.get(f.node.name)??[];h.push(m.plugin),d.set(f.node.name,h)}const p=e.install.kind==="installed"?"enabling":"installing";s.contributions=s.contributions.map(m=>{const f=d.get(m.node.name);if(f===void 0||f.length===0)return m;const h=w({name:e.name,sourceMarketplace:e.marketplace},m.node.name),N=f.map(g=>`moves ${g.name}'s to "${w(g,m.node.name)}"`);return s.issues.push({code:"command_collision",plugin:o.name,path:m.node.name,message:`top-level command "${m.node.name}" is already claimed by ${f.map(g=>g.name).join(", ")} \u2014 ${p} mounts this one as "${h}" and ${N.join(" and ")}`,received:[...f.map(g=>g.name),o.name].join(", "),expected:"an origin-qualified top-level command for each claimant",next:`After ${p}, invoke "${h}".`}),{...m,node:{...m.node,name:h}}})}const u=n.transport;return{root:e.root,transport:u?.kind??null,...u?.kind==="exec"&&u.executable!==void 0?{transportTarget:u.executable}:{},...u?.kind==="http"?{transportTarget:u.endpoint}:{},commands:s.contributions.map(d=>T(d.node)),commandIssues:[...s.issues.map(({message:d,next:p})=>({message:d,...p!==void 0?{next:p}:{}})),...c],docs:le(o),sizeBytes:ce(e.root)}}catch{return null}}l(Se,"loadCapability");function b(e){return e instanceof Error?e.message:String(e)}l(b,"errorMessage");export{Se as loadCapability,Ee as loadCatalog};
|
|
@@ -64,7 +64,7 @@ export interface CommandNode {
|
|
|
64
64
|
streaming: boolean;
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
|
-
/** `crtr search web` — how a user types the command a node names. The one place
|
|
67
|
+
/** `crtr exa-search web` — how a user types the command a node names. The one place
|
|
68
68
|
* a command path becomes a label, so no corner of the page invents its own. */
|
|
69
69
|
export declare function commandLabel(node: CommandNode): string;
|
|
70
70
|
/** Every node in a command forest, parents before their children. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var J=Object.defineProperty;var m=(o,n)=>J(o,"name",{value:n,configurable:!0});import{dirname as R,join as
|
|
1
|
+
var J=Object.defineProperty;var m=(o,n)=>J(o,"name",{value:n,configurable:!0});import{dirname as R,join as g,relative as Q,resolve as M}from"node:path";import{renameSync as y}from"node:fs";import{defineLeaf as D}from"../../core/command.js";import{general as j,notFound as d}from"../../core/errors.js";import{listAllMarketplaces as I,listAllPlugins as W,findMarketplaceByName as w}from"../../core/resolver.js";import{resolveScopeArg as C,requireScopeRoot as S,marketplacesDir as X,pluginsDir as Y}from"../../core/scope.js";import{updateConfig as q,updateState as G,ensureScopeInitialized as Z,readConfig as ee}from"../../core/config.js";import{pathExists as $,ensureDir as L,removePath as f,isSymlink as te,nowIso as N,readSymlinkTarget as oe}from"../../core/fs-utils.js";import{clone as _,deriveNameFromUrl as ne,currentSha as K,gitSync as O,isGitRepo as E}from"../../core/git.js";import{readMarketplaceManifest as U,readPluginManifest as F}from"../../core/manifest.js";import{assertPluginCandidateValid as re,isMarketplaceRelativeSource as ae}from"./plugin-manage.js";import{resolveInstallScope as se}from"./shared.js";function ie(o){const{url:n,ref:s,scope:t}=o,i=S(t);Z(t,i);const p=ne(n),c=X(t);L(c);const l=g(c,p);$(l)&&f(l),_(n,l,{depth:1,ref:s!==void 0?s:void 0});const u=U(l);if(!u)throw f(l),d(`marketplace manifest not found at ${l}/.crouter-marketplace/marketplace.json \u2014 not a valid marketplace`);const e=u.name,r=g(c,e);e!==p&&($(r)&&f(r),y(l,r));const a=s!==void 0?s:"main";return q(t,k=>{k.marketplaces[e]={url:n,ref:a,installed_at:N()}}),{name:e,scope:t,path:r}}m(ie,"addMarketplace");const Re=D({name:"add",description:"add a marketplace by git URL",whenToUse:"registering a new marketplace source repo so its plugins appear in marketplace browse output and become installable by marketplace/plugin ref",help:{name:"pkg market add",summary:"add a marketplace by git URL",params:[{kind:"positional",name:"url",type:"string",required:!0,constraint:"Git URL of the marketplace repo."},{kind:"flag",name:"ref",type:"string",required:!1,constraint:"Git ref to track. Default: main."},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Default: project if available, else user."}],output:[{name:"name",type:"string",required:!0,constraint:"Marketplace name as declared in marketplace.json."},{name:"scope",type:"string",required:!0,constraint:"Scope the marketplace was added into."},{name:"path",type:"string",required:!0,constraint:"Absolute path to the cloned marketplace directory."}],outputKind:"object",effects:["Clones the marketplace repo. Registers the marketplace in config.json."]},run:m(async o=>{const n=o.url,s=o.ref,t=o.scope;return ie({url:n,ref:s,scope:se(t)})},"run")}),je=D({name:"remove",description:"remove a marketplace",whenToUse:"unregistering a marketplace source: deletes the source clone and any plugins installed from it in the same scope",help:{name:"pkg market remove",summary:"remove a marketplace and its directory",params:[{kind:"positional",name:"name",type:"string",required:!0,constraint:"Marketplace name to remove."},{kind:"flag",name:"scope",type:"enum",choices:["user","project"],required:!1,constraint:"Narrows resolution."}],output:[],outputKind:"object",effects:["Deletes the marketplace directory. Removes the entry from config.json. Removes plugin files and config entries sourced from that marketplace in the same scope."]},run:m(async o=>{const n=o.name,s=o.scope;let t,i;if(s!==void 0){const r=C(s);if(r!=="all"&&r!=="builtin"){const a=r,k=w(n,a);if(!k)throw d(`marketplace not found: ${n} (scope: ${a})`);t=a,i=k.root}else{const a=w(n);if(!a)throw d(`marketplace not found: ${n}`);t=a.scope,i=a.root}}else{const r=w(n);if(!r)throw d(`marketplace not found: ${n}`);t=r.scope,i=r.root}const p=t,c=S(p),l=Y(p),u=ee(p),e=[];for(const[r,a]of Object.entries(u.plugins))a.source_marketplace===n&&e.push(r);for(const r of e){const a=g(l,r);f(a)}return f(i),q(p,r=>{delete r.marketplaces[n];for(const a of e)delete r.plugins[a]}),{}},"run")});function z(o,n,s,t){try{_(o,t,{depth:1,ref:n})}catch(i){throw f(t),i}return{active:s,candidate:t,previous:`${t}.previous`}}m(z,"stageGitRoot");function ce(o){const n=[],s=[];try{for(const t of o){if($(t.previous))throw j(`prior staged backup remains at ${t.previous}`);y(t.active,t.previous),n.push(t)}for(const t of o)y(t.candidate,t.active),s.push(t)}catch(t){for(const i of[...s].reverse())y(i.active,i.candidate);for(const i of[...n].reverse())y(i.previous,i.active);throw t}for(const t of o)f(t.previous)}m(ce,"activateStagedRoots");function B(o,n,s){return{plugin:{...o,root:n,manifest:s},scopeRoot:R(R(o.root))}}m(B,"candidatePlugin");async function pe(o){const n=K(o.root)??"",s=W().filter(u=>u.scope===o.scope&&u.sourceMarketplace===o.name),t=[],i=[];let p,c;const l=[];try{if(E(o.root)){const e=g(R(o.root),`.${o.name}.${process.pid}.${Date.now()}.candidate`);c=z(o.url,o.ref,o.root,e),i.push(e);const r=U(e);if(r===null)throw d(`marketplace manifest not found in candidate checkout: ${e}/.crouter-marketplace/marketplace.json`);p=r,t.push(c)}else{const e=U(o.root);if(e===null)throw d(`marketplace manifest not found after refresh: ${o.root}/.crouter-marketplace/marketplace.json`);p=e}for(const e of s){if(te(e.root)){if(c===void 0)continue;const b=p.plugins.find(V=>V.name===e.name);if(b===void 0||!ae(b.source))throw j(`marketplace candidate removes relative-source plugin "${e.name}" while it is installed`);const T=oe(e.root);if(T===null)throw j(`installed marketplace plugin "${e.name}" has no readable symlink target`);const x=Q(o.root,M(R(e.root),T)),h=M(c.candidate,b.source);if(h!==M(c.candidate,x))throw j(`marketplace candidate moves installed relative-source plugin "${e.name}" from ${x} to ${b.source}`);if(!$(h))throw d(`marketplace candidate source path does not exist for plugin "${e.name}": ${h}`);const A=F(h);if(A===null)throw d(`plugin manifest not found in marketplace candidate: ${h}/.crouter-plugin/plugin.json`);l.push(B(e,h,A));continue}if(!$(e.root)||!E(e.root))continue;const r=O(["config","--get","remote.origin.url"],e.root).stdout.trim(),a=O(["symbolic-ref","--short","HEAD"],e.root).stdout.trim();if(r===""||a==="")continue;const k=e.scope==="project"?S("project"):S("user"),v=g(k,"tmp",`${e.name}.${process.pid}.${Date.now()}.candidate`);L(g(k,"tmp"));const H=z(r,a,e.root,v);i.push(v);const P=F(v);if(P===null)throw d(`plugin manifest not found in update candidate: ${v}/.crouter-plugin/plugin.json`);l.push(B(e,v,P)),t.push(H)}for(const e of l)await re(e.plugin.manifest,e.plugin.root,e.plugin.scope,e.scopeRoot,`${e.plugin.root}/.crouter-plugin/plugin.json`,l);ce(t),G(o.scope,e=>{e.marketplaces[o.name]===void 0&&(e.marketplaces[o.name]={}),e.marketplaces[o.name].last_updated=N()});for(const e of s){const r=p.plugins.find(a=>a.name===e.name);r?.version!==void 0&&q(e.scope,a=>{a.plugins[e.name]!==void 0&&(a.plugins[e.name].version=r.version)}),G(e.scope,a=>{a.plugins[e.name]===void 0&&(a.plugins[e.name]={}),a.plugins[e.name].last_updated=N()})}const u=K(o.root)??"";return{name:o.name,updated:n!==u,sha:u}}finally{for(const u of i)f(u)}}m(pe,"updateMarketplaceTarget");const Se=D({name:"update",description:"replace marketplace source with its latest revision",whenToUse:"refreshing one named marketplace source from git, or all registered marketplace sources when no name is given; also updates installed plugins sourced from refreshed marketplaces",help:{name:"pkg market update",summary:"refresh one or all registered marketplaces",params:[{kind:"flag",name:"name",type:"string",required:!1,constraint:"Marketplace name to update. Omit to update all registered marketplaces."},{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 marketplace processed: {name, updated, sha}."}],outputKind:"object",effects:["Stages and validates marketplace and sourced-plugin revisions before atomically activating them, replacing each checkout even at an unchanged revision \u2014 local modifications inside those directories are discarded. `updated` reports whether the revision moved, not whether the checkout was replaced. Updates installed plugin content/version for plugins sourced from refreshed marketplaces."]},run:m(async o=>{const n=o.name,s=o.scope,t=s===void 0?void 0:C(s),i=n===void 0?t===void 0||t==="all"?I():t==="builtin"?[]:I().filter(c=>c.scope===t):(()=>{const c=t===void 0||t==="all"||t==="builtin"?w(n):w(n,t);if(c===null)throw d(`marketplace not found: ${n}${t===void 0||t==="all"||t==="builtin"?"":` (scope: ${t})`}`);return[c]})(),p=[];for(const c of i)p.push(await pe(c));return{updated:p}},"run")});export{ie as addMarketplace,Re as marketAdd,je as marketRemove,Se as marketUpdate};
|