@north-light/crouter 0.3.233 → 0.3.235
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.js +16 -15
- package/dist/api/dto/nodes.d.ts +11 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +1 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +14 -17
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/crtr-commands/index.ts +7 -11
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/index.ts +8 -8
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +10 -11
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/pi-shell-runner.ts +2 -2
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +3 -3
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +7 -7
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +8 -8
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +6 -6
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/sysprompt-window.ts +3 -3
- package/dist/builtin-pi-packages/pi-crtr-extensions/lib/subscription-state.ts +1 -1
- package/dist/clients/attach/chrome/ticket-panel.js +15 -2
- package/dist/clients/attach/overlays/graph.js +0 -3
- package/dist/clients/attach/overlays/mcp.js +1 -2
- package/dist/clients/attach/render/chat-view.js +0 -12
- package/dist/clients/attach/render/crtr-output.js +0 -2
- package/dist/clients/attach/render/tool-calls.js +0 -6
- package/dist/clients/attach/slash/dispatch.js +8 -11
- package/dist/clients/attach/viewer.js +535 -537
- package/dist/clients/conversation/projection.js +0 -2
- package/dist/clients/inbox/controller.js +22 -3
- package/dist/clients/inbox/review/companion-pane.js +0 -4
- package/dist/clients/inbox/review-adapter.js +0 -7
- package/dist/clients/inbox/tui/slots.d.ts +3 -3
- package/dist/clients/inbox/tui/types.d.ts +2 -2
- package/dist/commands/api-client.js +0 -8
- package/dist/commands/attention.js +1 -9
- package/dist/commands/canvas-browse.js +2 -1
- package/dist/commands/canvas-config.js +0 -10
- package/dist/commands/canvas-history.js +2 -1
- package/dist/commands/cron.js +10 -23
- package/dist/commands/dashboard.js +0 -2
- package/dist/commands/human/feedback.js +2 -1
- package/dist/commands/human/prompts.js +2 -5
- package/dist/commands/human/queue.js +2 -7
- package/dist/commands/human/request.js +0 -14
- package/dist/commands/human/review.js +2 -1
- package/dist/commands/human.js +1 -1
- package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +4 -4
- package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.d.ts +1 -0
- package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.js +96 -0
- package/dist/commands/memory/delete.js +1 -1
- package/dist/commands/memory/edit.js +6 -3
- package/dist/commands/memory/find.js +2 -2
- package/dist/commands/memory/lint.js +2 -1
- package/dist/commands/memory/list.d.ts +4 -0
- package/dist/commands/memory/list.js +20 -14
- package/dist/commands/memory/move.js +1 -1
- package/dist/commands/memory/read.d.ts +2 -7
- package/dist/commands/memory/read.js +5 -16
- package/dist/commands/memory/shared.d.ts +1 -0
- package/dist/commands/memory/shared.js +17 -8
- package/dist/commands/memory/write.js +8 -4
- package/dist/commands/node/bash.js +2 -1
- package/dist/commands/node/create.js +2 -1
- package/dist/commands/node/inspect.js +11 -10
- package/dist/commands/node/lifecycle.js +5 -13
- package/dist/commands/node/message.js +11 -6
- package/dist/commands/node/subscription.js +7 -2
- package/dist/commands/node/wait.js +9 -4
- package/dist/commands/node-context.js +2 -1
- package/dist/commands/node-lifecycle-revive.js +0 -2
- package/dist/commands/node-worktree.js +2 -1
- package/dist/commands/pkg/browse/actions.d.ts +1 -1
- package/dist/commands/pkg/browse/actions.js +4 -4
- package/dist/commands/pkg/browse/catalog.d.ts +1 -1
- package/dist/commands/pkg/browse/catalog.js +15 -15
- package/dist/commands/pkg/browse/command-view.d.ts +1 -1
- package/dist/commands/pkg/browse/command-view.js +3 -3
- package/dist/commands/pkg/browse/detail-panel.d.ts +1 -1
- package/dist/commands/pkg/browse/detail-panel.js +8 -8
- package/dist/commands/pkg/browse/doc-view.d.ts +1 -1
- package/dist/commands/pkg/browse/doc-view.js +3 -3
- package/dist/commands/pkg/browse/list-panel.d.ts +1 -1
- package/dist/commands/pkg/browse/list-panel.js +3 -3
- package/dist/commands/pkg/browse/model.d.ts +3 -3
- package/dist/commands/pkg/browse/shell.d.ts +2 -2
- package/dist/commands/pkg/browse/shell.js +13 -13
- package/dist/commands/pkg/plugin-manage.js +3 -2
- package/dist/commands/pkg/shared.js +0 -2
- package/dist/commands/pkg.js +1 -0
- package/dist/commands/profile/delete.js +2 -1
- package/dist/commands/profile/rename.js +1 -1
- package/dist/commands/push.js +2 -3
- package/dist/commands/revive.js +0 -2
- package/dist/commands/surface/node/placement.js +2 -1
- package/dist/commands/surface-edit.js +2 -1
- package/dist/commands/sys/config.js +1 -4
- package/dist/commands/sys/daemon.js +0 -10
- package/dist/commands/sys/doctor.js +3 -2
- package/dist/commands/sys/panels/broker-limits-panel.d.ts +2 -2
- package/dist/commands/sys/panels/broker-limits-panel.js +4 -4
- package/dist/commands/sys/panels/dependencies-panel.d.ts +2 -2
- package/dist/commands/sys/panels/dependencies-panel.js +2 -2
- package/dist/commands/sys/panels/keybindings-panel.d.ts +1 -1
- package/dist/commands/sys/panels/keybindings-panel.js +5 -5
- package/dist/commands/sys/panels/models-panel.d.ts +4 -4
- package/dist/commands/sys/panels/models-panel.js +11 -10
- package/dist/commands/sys/panels/plugins-panel.d.ts +2 -2
- package/dist/commands/sys/panels/plugins-panel.js +2 -2
- package/dist/commands/sys/panels/prefs-panel.d.ts +2 -2
- package/dist/commands/sys/panels/prefs-panel.js +4 -4
- package/dist/commands/sys/panels/profiles-panel.d.ts +1 -1
- package/dist/commands/sys/panels/profiles-panel.js +14 -13
- package/dist/commands/sys/panels/provider-panel.d.ts +3 -3
- package/dist/commands/sys/panels/provider-panel.js +8 -8
- package/dist/commands/sys/settings-shell.d.ts +3 -3
- package/dist/commands/sys/settings-shell.js +15 -15
- package/dist/commands/sys/setup-settings-runner.d.ts +3 -3
- package/dist/commands/sys/setup-settings-runner.js +5 -5
- package/dist/commands/sys/setup-wizard.d.ts +4 -4
- package/dist/commands/sys/setup-wizard.js +8 -8
- package/dist/commands/sys/support/prepare.js +4 -4
- package/dist/commands/sys/support/submit.js +2 -2
- package/dist/commands/sys/sync-deps.js +0 -2
- package/dist/commands/sys/sync-project-guidance.js +2 -1
- package/dist/commands/sys/sysprompt.js +2 -1
- package/dist/commands/sys.js +1 -0
- package/dist/core/__tests__/boot.test.js +0 -8
- package/dist/core/__tests__/broker-extension-canvas-db-boundary.test.js +23 -1
- package/dist/core/__tests__/canvas-db-boundary.test.d.ts +1 -0
- package/dist/core/__tests__/canvas-db-boundary.test.js +46 -0
- package/dist/core/__tests__/canvas.test.js +1 -1
- package/dist/core/__tests__/child-death-wake.test.js +0 -2
- package/dist/core/__tests__/cli-help-contract.test.d.ts +1 -0
- package/dist/core/__tests__/cli-help-contract.test.js +150 -0
- package/dist/core/__tests__/cron-armed-context-failure.test.d.ts +1 -0
- package/dist/core/__tests__/cron-armed-context-failure.test.js +145 -0
- package/dist/core/__tests__/daemon-wedge.test.js +0 -4
- package/dist/core/__tests__/dead-node-policy-table.test.js +0 -4
- package/dist/core/__tests__/fixtures/fake-engine.js +4 -14
- package/dist/core/__tests__/fixtures/fake-pi-host.js +5 -5
- package/dist/core/__tests__/focuses.test.js +0 -6
- package/dist/core/__tests__/fs-utils.test.d.ts +1 -0
- package/dist/core/__tests__/fs-utils.test.js +50 -0
- package/dist/core/__tests__/helpers/harness.js +1 -1
- package/dist/core/__tests__/inline-memory-refs.test.js +0 -2
- package/dist/core/__tests__/integration/broker-fork-seam.test.js +0 -2
- package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +3 -16
- package/dist/core/__tests__/integration/command-plugins.test.js +21 -24
- package/dist/core/__tests__/integration/deferred-no-wake.test.js +0 -6
- package/dist/core/__tests__/integration/flagship-lifecycle.test.js +0 -26
- package/dist/core/__tests__/integration/live-mutation-verbs.test.js +0 -4
- package/dist/core/__tests__/integration/live-mutation.test.js +1 -5
- package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +1 -5
- package/dist/core/__tests__/integration/revive.test.js +0 -12
- package/dist/core/__tests__/integration/subscription-delivery.test.js +0 -6
- package/dist/core/__tests__/integration/tmux-surface.test.js +24 -8
- package/dist/core/__tests__/integration/worktree-reap.test.js +0 -6
- package/dist/core/__tests__/lifecycle.test.js +0 -18
- package/dist/core/__tests__/memory-resolver-precedence.test.js +1 -1
- package/dist/core/__tests__/migration.test.js +2 -2
- package/dist/core/__tests__/on-read-dedup-resume.test.js +3 -3
- package/dist/core/__tests__/pid-identity-match.test.js +1 -1
- package/dist/core/__tests__/plugin-kinds.test.js +1 -1
- package/dist/core/__tests__/plugin-page-components.test.js +1 -1
- package/dist/core/__tests__/preview-registry-sync.test.js +42 -1
- package/dist/core/__tests__/respawn-throttle.test.js +0 -4
- package/dist/core/__tests__/revive-all.test.js +5 -5
- package/dist/core/__tests__/revive-parked-fresh.test.js +62 -11
- package/dist/core/__tests__/seam/broker-attach-multiclient.test.js +0 -8
- package/dist/core/__tests__/seam/broker-attach-stream.test.js +0 -8
- package/dist/core/__tests__/seam/broker-crash-teardown.test.js +0 -2
- package/dist/core/__tests__/tmux-driver-boundary.test.d.ts +1 -0
- package/dist/core/__tests__/tmux-driver-boundary.test.js +50 -0
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +11 -6
- package/dist/core/activity-signal.d.ts +7 -0
- package/dist/core/activity-signal.js +38 -0
- package/dist/core/auto-update.js +2 -1
- package/dist/core/bootstrap.js +2 -1
- package/dist/core/canvas/__tests__/remote-canvas-source.test.js +1 -1
- package/dist/core/canvas/__tests__/remote-transport.test.js +1 -1
- package/dist/core/canvas/__tests__/render-remote.test.js +1 -1
- package/dist/core/canvas/browse/app.js +3 -2
- package/dist/core/canvas/browse/model.d.ts +1 -1
- package/dist/core/canvas/browse/model.js +0 -4
- package/dist/core/canvas/canvas.d.ts +22 -0
- package/dist/core/canvas/canvas.js +61 -19
- package/dist/core/canvas/crons.js +0 -6
- package/dist/core/canvas/db.d.ts +14 -20
- package/dist/core/canvas/db.js +30 -1332
- package/dist/core/canvas/focuses.js +0 -4
- package/dist/core/canvas/history.js +2 -1
- package/dist/core/canvas/meta-file.js +18 -27
- package/dist/core/canvas/migrations.d.ts +20 -0
- package/dist/core/canvas/migrations.js +1339 -0
- package/dist/core/canvas/nav-model.js +1 -11
- package/dist/core/canvas/nav-render.js +0 -8
- package/dist/core/canvas/remote-canvas-source.d.ts +8 -0
- package/dist/core/canvas/remote-canvas-source.js +9 -3
- package/dist/core/canvas/render-source.js +31 -13
- package/dist/core/command-manifests/manifest.js +0 -10
- package/dist/core/command-manifests/registry.d.ts +2 -0
- package/dist/core/command-manifests/schema.js +0 -4
- package/dist/core/command-plugins/compose.js +4 -2
- package/dist/core/command-plugins/discovery.d.ts +1 -0
- package/dist/core/command-plugins/discovery.js +1 -1
- package/dist/core/command-plugins/transport/http-invoke.js +0 -14
- package/dist/core/command.js +2 -6
- package/dist/core/config.js +2 -1
- package/dist/core/fault-classifier.js +8 -0
- package/dist/core/feed/inbox.d.ts +10 -0
- package/dist/core/feed/inbox.js +18 -12
- package/dist/core/fs-utils.d.ts +9 -2
- package/dist/core/fs-utils.js +7 -15
- package/dist/core/help.js +0 -8
- package/dist/core/host-exports/export.d.ts +2 -2
- package/dist/core/host-exports/export.js +9 -12
- package/dist/core/human/answer.d.ts +2 -2
- package/dist/core/human/convention.d.ts +2 -5
- package/dist/core/human/convention.js +3 -13
- package/dist/core/human/page-schema.d.ts +2 -2
- package/dist/core/human/page-schema.js +2 -2
- package/dist/core/human/root.js +6 -23
- package/dist/core/human/scan.js +24 -7
- package/dist/core/human/tickets.d.ts +4 -1
- package/dist/core/human/tickets.js +20 -6
- package/dist/core/io.js +0 -12
- package/dist/core/memory/identity.js +0 -4
- package/dist/core/memory/inline-ref-inventory.js +3 -2
- package/dist/core/memory/lint.js +3 -6
- package/dist/core/memory-resolver.d.ts +5 -0
- package/dist/core/memory-resolver.js +14 -12
- package/dist/core/pagination.d.ts +2 -0
- package/dist/core/pagination.js +2 -3
- package/dist/core/preview-registry.d.ts +14 -0
- package/dist/core/preview-registry.js +2 -4
- package/dist/core/preview-result-path.js +2 -1
- package/dist/core/profiles/manifest.d.ts +37 -5
- package/dist/core/profiles/manifest.js +44 -24
- package/dist/core/profiles/select.js +0 -4
- package/dist/core/review/signal.js +4 -23
- package/dist/core/review/ticket-filter.d.ts +3 -3
- package/dist/core/review/ticket-filter.js +4 -9
- package/dist/core/runtime/__tests__/engine-route.test.js +1 -1
- package/dist/core/runtime/__tests__/spawn-env.test.js +0 -8
- package/dist/core/runtime/bearings-render.d.ts +56 -0
- package/dist/core/runtime/bearings-render.js +241 -0
- package/dist/core/runtime/bearings.d.ts +2 -17
- package/dist/core/runtime/bearings.js +12 -198
- package/dist/core/runtime/broker/auth-reload.d.ts +39 -0
- package/dist/core/runtime/broker/auth-reload.js +149 -0
- package/dist/core/runtime/broker/engine-drive.d.ts +26 -0
- package/dist/core/runtime/broker/engine-drive.js +257 -0
- package/dist/core/runtime/broker/engine-routing.d.ts +143 -0
- package/dist/core/runtime/broker/engine-routing.js +211 -0
- package/dist/core/runtime/broker/event-projection.js +3 -2
- package/dist/core/runtime/broker/fault-retry.js +11 -4
- package/dist/core/runtime/broker/frame-client.d.ts +38 -0
- package/dist/core/runtime/broker/frame-client.js +129 -0
- package/dist/core/runtime/broker/frame-dispatch.d.ts +12 -189
- package/dist/core/runtime/broker/frame-dispatch.js +89 -1476
- package/dist/core/runtime/broker/frame-engine-control.d.ts +20 -0
- package/dist/core/runtime/broker/frame-engine-control.js +231 -0
- package/dist/core/runtime/broker/frame-memory-refs.d.ts +19 -0
- package/dist/core/runtime/broker/frame-memory-refs.js +41 -0
- package/dist/core/runtime/broker/frame-model-query.d.ts +13 -0
- package/dist/core/runtime/broker/frame-model-query.js +69 -0
- package/dist/core/runtime/broker/frame-read.d.ts +19 -0
- package/dist/core/runtime/broker/frame-read.js +116 -0
- package/dist/core/runtime/broker/frame-replies.d.ts +24 -0
- package/dist/core/runtime/broker/frame-replies.js +64 -0
- package/dist/core/runtime/broker/frame-session.d.ts +34 -0
- package/dist/core/runtime/broker/frame-session.js +203 -0
- package/dist/core/runtime/broker/rebind.js +50 -0
- package/dist/core/runtime/broker/turn-ignition.d.ts +42 -0
- package/dist/core/runtime/broker/turn-ignition.js +74 -0
- package/dist/core/runtime/broker-extension-render.js +9 -85
- package/dist/core/runtime/broker-protocol.js +0 -4
- package/dist/core/runtime/broker-sdk.js +2 -1
- package/dist/core/runtime/broker.d.ts +1 -1
- package/dist/core/runtime/broker.js +5 -23
- package/dist/core/runtime/fault.js +3 -2
- package/dist/core/runtime/headless-pi.js +3 -2
- package/dist/core/runtime/host.js +2 -3
- package/dist/core/runtime/kickoff.js +0 -4
- package/dist/core/runtime/launch-target.js +2 -1
- package/dist/core/runtime/launch.d.ts +2 -2
- package/dist/core/runtime/launch.js +20 -10
- package/dist/core/runtime/lifecycle.js +17 -26
- package/dist/core/runtime/managed-provider-cooling.d.ts +1 -1
- package/dist/core/runtime/naming.js +0 -2
- package/dist/core/runtime/nodes.js +2 -1
- package/dist/core/runtime/persona.js +0 -6
- package/dist/core/runtime/placement-tmux.js +2 -5
- package/dist/core/runtime/placement.js +4 -11
- package/dist/core/runtime/recap.js +4 -3
- package/dist/core/runtime/reopen.js +4 -7
- package/dist/core/runtime/reset.js +0 -4
- package/dist/core/runtime/resume-root.js +0 -2
- package/dist/core/runtime/revive.js +17 -13
- package/dist/core/runtime/session-list-cache.js +2 -2
- package/dist/core/runtime/shell-expansion.js +0 -2
- package/dist/core/runtime/spawn.js +0 -2
- package/dist/core/runtime/stop-guard.js +28 -16
- package/dist/core/runtime/stream-watchdog.d.ts +0 -1
- package/dist/core/runtime/stream-watchdog.js +13 -18
- package/dist/core/runtime/tmux-bindings.js +0 -2
- package/dist/core/runtime/tmux-driver.d.ts +12 -0
- package/dist/core/runtime/tmux-driver.js +18 -13
- package/dist/core/runtime/warm-pool.js +0 -4
- package/dist/core/scope.js +4 -3
- package/dist/core/spawn.js +2 -3
- package/dist/core/subscription-state.js +10 -17
- package/dist/core/substrate/__tests__/surface-match-pre-command.test.js +3 -3
- package/dist/core/substrate/frontmatter-validation.d.ts +1 -0
- package/dist/core/substrate/frontmatter-validation.js +1 -1
- package/dist/core/substrate/render.js +0 -12
- package/dist/core/substrate/schema.js +0 -12
- package/dist/core/substrate/surface-match.js +0 -2
- package/dist/core/termrender/display.js +2 -1
- package/dist/core/tui/page-host.d.ts +3 -3
- package/dist/core/tui/page-host.js +4 -4
- package/dist/core/tui/panel.js +3 -3
- package/dist/core/wake.js +0 -12
- package/dist/core/worktree.js +0 -2
- package/dist/daemon/__tests__/reconciler-signature.test.d.ts +1 -0
- package/dist/daemon/__tests__/reconciler-signature.test.js +36 -0
- package/dist/daemon/api/__tests__/error-seam.test.js +27 -0
- package/dist/daemon/api/__tests__/seam/api-server.test.js +2 -16
- package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +3 -11
- package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +0 -6
- package/dist/daemon/api/handlers/attach.js +2 -1
- package/dist/daemon/api/handlers/broker-ops.js +3 -6
- package/dist/daemon/api/handlers/canvas.js +12 -18
- package/dist/daemon/api/handlers/feedback-comments.js +0 -8
- package/dist/daemon/api/handlers/health.js +3 -2
- package/dist/daemon/api/handlers/human-requests.js +0 -10
- package/dist/daemon/api/handlers/human.js +1 -5
- package/dist/daemon/api/handlers/inbox.js +0 -18
- package/dist/daemon/api/handlers/memory.js +1 -1
- package/dist/daemon/api/handlers/messages.js +16 -20
- package/dist/daemon/api/handlers/nodes.js +23 -22
- package/dist/daemon/api/handlers/reports.js +1 -1
- package/dist/daemon/api/handlers/reviews.js +1 -6
- package/dist/daemon/api/handlers/worktree.js +6 -22
- package/dist/daemon/api/map.d.ts +4 -2
- package/dist/daemon/api/map.js +22 -8
- package/dist/daemon/api/router.js +0 -4
- package/dist/daemon/api/server.js +2 -5
- package/dist/daemon/boot-migrations.d.ts +14 -0
- package/dist/daemon/boot-migrations.js +31 -0
- package/dist/daemon/cron/armed-context.d.ts +21 -0
- package/dist/daemon/cron/armed-context.js +100 -0
- package/dist/daemon/cron/capture.d.ts +20 -0
- package/dist/daemon/cron/capture.js +45 -0
- package/dist/daemon/cron/disposition.d.ts +19 -0
- package/dist/daemon/cron/disposition.js +52 -0
- package/dist/daemon/cron/escalation.d.ts +12 -0
- package/dist/daemon/cron/escalation.js +124 -0
- package/dist/daemon/cron/held.d.ts +4 -0
- package/dist/daemon/cron/held.js +20 -0
- package/dist/daemon/cron/lease-recovery.d.ts +3 -0
- package/dist/daemon/cron/lease-recovery.js +119 -0
- package/dist/daemon/cron/live-runs.d.ts +11 -0
- package/dist/daemon/cron/live-runs.js +23 -0
- package/dist/daemon/cron/passes.d.ts +11 -0
- package/dist/daemon/cron/passes.js +78 -0
- package/dist/daemon/cron/settle.d.ts +28 -0
- package/dist/daemon/cron/settle.js +37 -0
- package/dist/daemon/cron/sinks.d.ts +2 -0
- package/dist/daemon/cron/sinks.js +100 -0
- package/dist/daemon/cron-run.d.ts +5 -41
- package/dist/daemon/cron-run.js +193 -882
- package/dist/daemon/crtrd-cli.js +2 -1
- package/dist/daemon/crtrd.js +22 -22
- package/dist/daemon/fleet.js +0 -4
- package/dist/daemon/human/deliver-action.js +2 -1
- package/dist/daemon/human/sweep.js +15 -4
- package/dist/daemon/manage.d.ts +2 -2
- package/dist/daemon/manage.js +4 -13
- package/dist/daemon/pidfile.js +2 -2
- package/dist/daemon/reconcilers/broker-supervision.js +27 -30
- package/dist/daemon/reconcilers/dormant-inbox.d.ts +1 -1
- package/dist/daemon/reconcilers/dormant-inbox.js +2 -1
- package/dist/daemon/reconcilers/live-obligation.js +2 -2
- package/dist/daemon/reconcilers/pending-review-submit.d.ts +1 -1
- package/dist/daemon/reconcilers/pending-review-submit.js +2 -1
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -1
- package/dist/daemon/reconcilers/storage-maintenance.js +2 -1
- package/dist/daemon/review/companion.js +2 -2
- package/dist/daemon/review/sweep.js +8 -3
- package/dist/migrations/001-surfaces-frontmatter.js +0 -6
- package/dist/migrations/corpus.js +2 -5
- package/dist/migrations/registry.js +15 -2
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +0 -4
- package/dist/pi-extensions/broker-local.js +2 -1
- package/dist/pi-extensions/canvas-bash-valve.js +7 -20
- package/dist/pi-extensions/canvas-context-intro.js +2 -7
- package/dist/pi-extensions/canvas-doc-substrate.js +2 -3
- package/dist/pi-extensions/canvas-goal-capture.js +2 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +5 -12
- package/dist/pi-extensions/canvas-passive-context.js +2 -5
- package/dist/pi-extensions/canvas-preview-result.js +2 -1
- package/dist/pi-extensions/canvas-prompt-scrub.js +2 -1
- package/dist/pi-extensions/canvas-recap.js +3 -16
- package/dist/pi-extensions/canvas-review-boundary.js +2 -5
- package/dist/pi-extensions/canvas-stophook.js +2 -26
- package/dist/pi-extensions/canvas-structured-output.js +2 -1
- package/dist/pi-extensions/canvas-tool-guide.js +2 -1
- package/dist/shared/__tests__/env-boundary.test.d.ts +1 -0
- package/dist/shared/__tests__/env-boundary.test.js +93 -0
- package/dist/shared/env.d.ts +68 -0
- package/dist/shared/env.js +171 -0
- package/package.json +3 -1
- package/runtime.lock.json +2 -2
- package/dist/core/canvas/render.d.ts +0 -47
- package/dist/core/canvas/render.js +0 -245
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { envNodeId, envProfileId } from '../shared/env.js';
|
|
1
2
|
import { dirname, join, relative, sep } from 'node:path';
|
|
2
3
|
import { readdirSync } from 'node:fs';
|
|
3
4
|
import { CRTR_DIR_NAME } from '../types.js';
|
|
4
5
|
import { pathExists, readText, realpathOrSelf, walkFiles } from './fs-utils.js';
|
|
5
6
|
import { parseFrontmatterGeneric } from './frontmatter.js';
|
|
7
|
+
import { interpolateNodePaths } from './canvas/paths.js';
|
|
6
8
|
import { listInstalledPlugins, listInstalledPluginsInRoot } from './resolver.js';
|
|
7
9
|
import { notFound, usage } from './errors.js';
|
|
8
10
|
import { warn } from './output.js';
|
|
@@ -19,18 +21,16 @@ import { associateRepository } from './memory/repository-association.js';
|
|
|
19
21
|
function ambientTarget() {
|
|
20
22
|
return {
|
|
21
23
|
cwd: process.cwd(),
|
|
22
|
-
profileId:
|
|
23
|
-
nodeId:
|
|
24
|
+
profileId: envProfileId() || null,
|
|
25
|
+
nodeId: envNodeId() || null,
|
|
24
26
|
};
|
|
25
27
|
}
|
|
26
28
|
/** The selected profile id from the process env, or '' when none. */
|
|
27
29
|
function selectedProfileId() {
|
|
28
30
|
return ambientTarget().profileId ?? '';
|
|
29
31
|
}
|
|
30
|
-
// ---------------------------------------------------------------------------
|
|
31
32
|
// Store discovery: which physical stores a target sees, in what order, and
|
|
32
33
|
// whether each one's namespace lets it mount.
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
34
|
/** The memory scopes in resolution precedence: node > project stack > profile >
|
|
35
35
|
* user > builtin. Node is included only when the target names one and ranks
|
|
36
36
|
* NEAREST — a node doc overrides any wider scope. Project is included only when
|
|
@@ -291,10 +291,8 @@ export function nativeMemoryStoresInPrecedence(scope, includeDescendants = false
|
|
|
291
291
|
.filter((store) => store.mountStatus === 'ready' && store.scope !== 'builtin' && store.plugin === undefined)
|
|
292
292
|
.map((store) => ({ scope: store.scope, memoryDir: store.storeRoot, store }));
|
|
293
293
|
}
|
|
294
|
-
// ---------------------------------------------------------------------------
|
|
295
294
|
// Document loading: one store's markdown files become canonically-identified
|
|
296
295
|
// documents.
|
|
297
|
-
// ---------------------------------------------------------------------------
|
|
298
296
|
function firstLine(e) {
|
|
299
297
|
return (e instanceof Error ? e.message : String(e)).split('\n')[0] ?? '';
|
|
300
298
|
}
|
|
@@ -375,9 +373,7 @@ export function loadStoreMemoryDocs(store, quiet = false) {
|
|
|
375
373
|
export function listPluginMemoryDocs(plugin, scope, quiet = false, projectMemory = NEUTRAL_PROJECT_MEMORY) {
|
|
376
374
|
return loadStoreMemoryDocs(pluginStoreDescriptor(plugin, scope, projectMemory), quiet);
|
|
377
375
|
}
|
|
378
|
-
// ---------------------------------------------------------------------------
|
|
379
376
|
// Views: exact canonical resolution over a loaded corpus.
|
|
380
|
-
// ---------------------------------------------------------------------------
|
|
381
377
|
/** The canonical form of a query: empty segments dropped. An `NN-` ordering
|
|
382
378
|
* prefix is physical-path-only and is NOT stripped here — a canonical name
|
|
383
379
|
* never carries one, so `04-base` is simply no document's address. */
|
|
@@ -462,9 +458,7 @@ export function loadMemoryTargetView(target, opts = {}) {
|
|
|
462
458
|
export function loadMemoryStoreView(store, quiet = false) {
|
|
463
459
|
return { store, ...makeView([store], loadStoreMemoryDocs(store, quiet)) };
|
|
464
460
|
}
|
|
465
|
-
// ---------------------------------------------------------------------------
|
|
466
461
|
// Corpus listing.
|
|
467
|
-
// ---------------------------------------------------------------------------
|
|
468
462
|
/** All project-scoped docs visible from an explicit node workspace/profile — the
|
|
469
463
|
* project-only slice of a `MemoryTarget` view, used where only workspace docs
|
|
470
464
|
* are wanted (a workspace-open render). For a full-precedence target-addressed
|
|
@@ -507,6 +501,16 @@ export function createMemoryDocSnapshot(target = ambientTarget()) {
|
|
|
507
501
|
export function resolveMemoryDocs(names) {
|
|
508
502
|
return createMemoryDocSnapshot().resolve(names);
|
|
509
503
|
}
|
|
504
|
+
/** Load the body at an already-resolved memory path with the same frontmatter
|
|
505
|
+
* stripping and in-node path interpolation as `memory read`. Callers that
|
|
506
|
+
* already have the resolved path (such as slash-command discovery) avoid
|
|
507
|
+
* re-walking every memory store for each document. */
|
|
508
|
+
export function readMemoryDocContent(path, includeFrontmatter = false) {
|
|
509
|
+
const raw = readText(path);
|
|
510
|
+
const content = includeFrontmatter ? raw : parseFrontmatterGeneric(raw).body;
|
|
511
|
+
const nodeId = envNodeId();
|
|
512
|
+
return nodeId ? interpolateNodePaths(content, nodeId) : content;
|
|
513
|
+
}
|
|
510
514
|
/** The address winner for an exact canonical name in the ambient target. */
|
|
511
515
|
export function resolveMemoryDoc(rawName, opts = {}) {
|
|
512
516
|
return resolveMemoryDocForTarget(rawName, ambientTarget(), opts);
|
|
@@ -541,10 +545,8 @@ export function resolveMemoryCandidatesForTarget(rawName, target, opts = {}) {
|
|
|
541
545
|
export function resolveMemoryDocInStore(rawName, store, opts = {}) {
|
|
542
546
|
return loadMemoryStoreView(store, true).resolve(rawName, opts);
|
|
543
547
|
}
|
|
544
|
-
// ---------------------------------------------------------------------------
|
|
545
548
|
// Physical sidecar lookup: the revision log mirrors the doc tree, so it is
|
|
546
549
|
// addressed by PHYSICAL path segments, not by canonical identity.
|
|
547
|
-
// ---------------------------------------------------------------------------
|
|
548
550
|
/** Find the direct child of `dir` — an `ext` file (matched on name minus
|
|
549
551
|
* extension) or a directory — whose NORMALIZED display name equals
|
|
550
552
|
* `segment`. An exact literal match (no prefix to strip) wins over a
|
|
@@ -16,6 +16,8 @@ export interface PaginateOpts<T> {
|
|
|
16
16
|
/** Returns the stable sort key for an item. Must match the sort order of the
|
|
17
17
|
* input array — ascending by this key. */
|
|
18
18
|
keyOf: (item: T) => string;
|
|
19
|
+
/** Compares sort keys when their order is not raw code-unit order. */
|
|
20
|
+
compareKeys?: (left: string, right: string) => number;
|
|
19
21
|
/** 'count' → compute and return `total`; 'omit' → return `null`. */
|
|
20
22
|
total: 'count' | 'omit';
|
|
21
23
|
}
|
package/dist/core/pagination.js
CHANGED
|
@@ -11,9 +11,7 @@
|
|
|
11
11
|
// item after it is returned correctly).
|
|
12
12
|
import { CrtrError } from './errors.js';
|
|
13
13
|
import { ExitCode } from '../types.js';
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
14
|
// Cursor encoding / decoding
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
15
|
/** Encodes a stable sort key into an opaque base64url cursor token. */
|
|
18
16
|
export function encodeCursor(key) {
|
|
19
17
|
const json = JSON.stringify({ k: key });
|
|
@@ -69,9 +67,10 @@ export function paginate(allItemsSortedAscByKey, params, opts) {
|
|
|
69
67
|
let startIndex = 0;
|
|
70
68
|
if (params.cursor !== undefined) {
|
|
71
69
|
const cursorKey = decodeCursor(params.cursor); // throws CrtrError on bad cursor
|
|
70
|
+
const compareKeys = opts.compareKeys ?? ((left, right) => left < right ? -1 : left > right ? 1 : 0);
|
|
72
71
|
// Find the first item whose key is strictly greater than cursorKey.
|
|
73
72
|
// Linear scan; callers with large datasets should pre-filter upstream.
|
|
74
|
-
startIndex = allItemsSortedAscByKey.findIndex((item) => opts.keyOf(item) >
|
|
73
|
+
startIndex = allItemsSortedAscByKey.findIndex((item) => compareKeys(opts.keyOf(item), cursorKey) > 0);
|
|
75
74
|
if (startIndex === -1) {
|
|
76
75
|
// All items are at or before the cursor key — list is exhausted.
|
|
77
76
|
startIndex = allItemsSortedAscByKey.length;
|
|
@@ -14,6 +14,9 @@ export declare const HELP_ICON: string;
|
|
|
14
14
|
* paints lives in one file: terminal for `bash`, file-text for `read`, floppy for
|
|
15
15
|
* `write` (content committed to disk), pencil-square for `edit`. */
|
|
16
16
|
export declare const TOOL_ICON: Readonly<Record<'bash' | 'read' | 'write' | 'edit', string>>;
|
|
17
|
+
/** Per-leaf overrides, keyed by full leaf help-name path (e.g. "memory
|
|
18
|
+
* lint"), same shape as SUPPRESS_OUTPUT_LEAVES. */
|
|
19
|
+
export declare const LEAF_ICON_CP: Record<string, number>;
|
|
17
20
|
/** Resolve the Nerd Font glyph for a command's argv tokens: the longest
|
|
18
21
|
* matching LEAF_ICON_CP prefix, else the tokens[0] family glyph, else the
|
|
19
22
|
* generic ◆ fallback for an unmapped family. */
|
|
@@ -29,7 +32,18 @@ export interface CrtrPreview {
|
|
|
29
32
|
jsonl?: Record<string, unknown>[];
|
|
30
33
|
error?: Record<string, unknown>;
|
|
31
34
|
}
|
|
35
|
+
type SummaryInput = {
|
|
36
|
+
result?: Record<string, unknown>;
|
|
37
|
+
jsonl?: Record<string, unknown>[];
|
|
38
|
+
error?: Record<string, unknown>;
|
|
39
|
+
};
|
|
40
|
+
type Summarizer = (input: SummaryInput, tokens: readonly string[]) => SummaryLine[] | null;
|
|
41
|
+
export declare const SUMMARIZERS: ReadonlyArray<{
|
|
42
|
+
path: string;
|
|
43
|
+
run: Summarizer;
|
|
44
|
+
}>;
|
|
32
45
|
/** Summarize an exact CLI result record. The recorded path is authoritative:
|
|
33
46
|
* shell tokenization is used only for an invocation's static icon/help chrome,
|
|
34
47
|
* never to identify or decode the returned leaf data. */
|
|
35
48
|
export declare function summarizePath(preview: CrtrPreview, tokens?: readonly string[]): SummaryLine[] | null;
|
|
49
|
+
export {};
|
|
@@ -42,12 +42,10 @@ export function suppressOutputForPath(tokens) {
|
|
|
42
42
|
}
|
|
43
43
|
return false;
|
|
44
44
|
}
|
|
45
|
-
// ---------------------------------------------------------------------------
|
|
46
45
|
// Icon registry (rule 12, inline-ui-placement: real Nerd Font glyphs, not the
|
|
47
46
|
// generic ◆ diamond). Every leaf's glyph is looked up first in LEAF_ICON_CP
|
|
48
47
|
// (longest-prefix match, same shape as SUPPRESS_OUTPUT_LEAVES); an unmapped
|
|
49
48
|
// leaf falls back to its root family's glyph in FAMILY_ICON_CP.
|
|
50
|
-
// ---------------------------------------------------------------------------
|
|
51
49
|
/** question-circle — the header glyph for a `-h`/`--help` invocation,
|
|
52
50
|
* regardless of which command's help was requested. */
|
|
53
51
|
const HELP_ICON_CP = 0xf059;
|
|
@@ -83,7 +81,7 @@ const FAMILY_ICON_CP = {
|
|
|
83
81
|
};
|
|
84
82
|
/** Per-leaf overrides, keyed by full leaf help-name path (e.g. "memory
|
|
85
83
|
* lint"), same shape as SUPPRESS_OUTPUT_LEAVES. */
|
|
86
|
-
const LEAF_ICON_CP = {
|
|
84
|
+
export const LEAF_ICON_CP = {
|
|
87
85
|
'canvas dashboard': 0xf0e4,
|
|
88
86
|
'canvas snapshot': 0xf030,
|
|
89
87
|
'canvas browse': 0xf14e,
|
|
@@ -345,7 +343,7 @@ function summarizeProfileList(input) {
|
|
|
345
343
|
...profiles.slice(0, 5).map((profile) => ({ text: `${stringField(profile, 'name')} · ${numberField(profile, 'projects_count')} projects`, tone: 'muted' })),
|
|
346
344
|
];
|
|
347
345
|
}
|
|
348
|
-
const SUMMARIZERS = [
|
|
346
|
+
export const SUMMARIZERS = [
|
|
349
347
|
{ path: 'memory read', run: summarizeMemoryRead },
|
|
350
348
|
{ path: 'memory list', run: summarizeArray('docs') },
|
|
351
349
|
{ path: 'memory find', run: summarizeArray('hits', 'hits') },
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// into the command text — the executed script has to stay exactly what the
|
|
8
8
|
// agent wrote, because `cmd.sh`, job inspection, and the doc substrate's
|
|
9
9
|
// `command` surfaces all read that text as the agent's own words.
|
|
10
|
+
import { envNodeId } from '../shared/env.js';
|
|
10
11
|
import { tmpdir } from 'node:os';
|
|
11
12
|
import { join } from 'node:path';
|
|
12
13
|
export const PREVIEW_RESULT_PATH_ENV = 'CRTR_PREVIEW_RESULT_PATH';
|
|
@@ -16,7 +17,7 @@ export const PREVIEW_RESULT_PATH_ENV = 'CRTR_PREVIEW_RESULT_PATH';
|
|
|
16
17
|
* Node id and pid are equal across both sides of the transport (they run in
|
|
17
18
|
* the same broker process) without either side sharing state. */
|
|
18
19
|
function brokerToken() {
|
|
19
|
-
return `${encodeURIComponent(
|
|
20
|
+
return `${encodeURIComponent(envNodeId() ?? 'no-node')}-${process.pid}`;
|
|
20
21
|
}
|
|
21
22
|
/** Deterministic from the tool call id, so the spawning side and the result
|
|
22
23
|
* side derive the same path without sharing state. */
|
|
@@ -24,12 +24,44 @@ export interface ProfileEntry {
|
|
|
24
24
|
profileId: string;
|
|
25
25
|
manifest: ProfileManifest;
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
export interface ProfileEnumeration {
|
|
28
|
+
/** Every profile with a readable manifest, in directory-listing order. */
|
|
29
|
+
entries: ProfileEntry[];
|
|
30
|
+
/** Ids whose directory is present under the profiles root but whose manifest
|
|
31
|
+
* did not read — corrupt JSON, a pre-object project shape, an unreadable or
|
|
32
|
+
* missing `profile.json`. These are NOT deleted profiles, and a caller that
|
|
33
|
+
* cannot tell the two apart silently substitutes another identity. */
|
|
34
|
+
unreadableIds: string[];
|
|
35
|
+
}
|
|
36
|
+
/** Every profile with a readable manifest, in directory-listing order. A
|
|
37
|
+
* profile whose manifest is missing or corrupt is skipped rather than
|
|
38
|
+
* crashing the whole listing — `lookupProfile` is how a caller that must not
|
|
39
|
+
* confuse "skipped" with "gone" asks. */
|
|
32
40
|
export declare function listProfiles(): ProfileEntry[];
|
|
41
|
+
/** What a stored profile id resolves to — including the case every
|
|
42
|
+
* null-returning resolver here erases: the profile is THERE and could not be
|
|
43
|
+
* read. A caller that treats that as "deleted" substitutes another identity
|
|
44
|
+
* (root) for the one its work was pinned to. */
|
|
45
|
+
export type ProfileLookup = {
|
|
46
|
+
kind: 'resolved';
|
|
47
|
+
entry: ProfileEntry;
|
|
48
|
+
}
|
|
49
|
+
/** Nothing on this host answers to the id or name — a deleted profile. */
|
|
50
|
+
| {
|
|
51
|
+
kind: 'absent';
|
|
52
|
+
}
|
|
53
|
+
/** The id's directory is present; its manifest did not read. */
|
|
54
|
+
| {
|
|
55
|
+
kind: 'unreadable';
|
|
56
|
+
profileId: string;
|
|
57
|
+
manifestPath: string;
|
|
58
|
+
};
|
|
59
|
+
/** Exact resolution (generated id, else a unique manifest `name`) that reports
|
|
60
|
+
* WHY it failed. Only an ID can come back `unreadable`: a name lives inside
|
|
61
|
+
* the manifest that could not be read, so an unreadable profile has no name to
|
|
62
|
+
* match on. Throws on an ambiguous name, exactly as `loadProfileManifest`
|
|
63
|
+
* does. */
|
|
64
|
+
export declare function lookupProfile(profileIdOrName: string): ProfileLookup;
|
|
33
65
|
/** Read one exact profile id without falling back to manifest-name matching.
|
|
34
66
|
* Used at persistence gates that already hold a resolved durable identity. */
|
|
35
67
|
export declare function loadExactProfileManifest(profileId: string): ProfileEntry;
|
|
@@ -15,10 +15,8 @@ import { ensureDir, nowIso } from '../fs-utils.js';
|
|
|
15
15
|
import { usage, notFound, ambiguous, general } from '../errors.js';
|
|
16
16
|
import { withExclusiveDirectoryLock } from '../exclusive-lock.js';
|
|
17
17
|
import { fuzzyMatchProfile } from './fuzzy-match.js';
|
|
18
|
-
// ---------------------------------------------------------------------------
|
|
19
18
|
// Path safety — the only code in the tree that builds a path under the
|
|
20
19
|
// profiles root. Every other module reaches profile paths through this file.
|
|
21
|
-
// ---------------------------------------------------------------------------
|
|
22
20
|
/** `<slug>-<shortid>`: slug is lower-case, non-alphanumeric collapsed to `-`,
|
|
23
21
|
* trimmed to 40 chars (defaulting to `profile`); shortid is 8 lowercase hex
|
|
24
22
|
* chars. The char class alone rules out `/`, `\`, `.`, and `..` segments —
|
|
@@ -71,11 +69,9 @@ export function profileManifestPath(profileId) {
|
|
|
71
69
|
export function profileMemoryDir(profileId) {
|
|
72
70
|
return join(profileRoot(profileId), 'memory');
|
|
73
71
|
}
|
|
74
|
-
// ---------------------------------------------------------------------------
|
|
75
72
|
// Enumeration + resolution — the ONLY functions that turn a CLI operand into
|
|
76
73
|
// a profile id. Both walk immediate children of the canonical root; neither
|
|
77
74
|
// ever joins an unvalidated operand into a path.
|
|
78
|
-
// ---------------------------------------------------------------------------
|
|
79
75
|
/** A profile's `home` DEFAULTS to its first project dir. Normalizing here (the
|
|
80
76
|
* single read path) rather than at write time means a manifest written before
|
|
81
77
|
* homes existed, and one whose explicit home was later removed from purview,
|
|
@@ -175,16 +171,15 @@ export function profileHome(profileId) {
|
|
|
175
171
|
return null;
|
|
176
172
|
}
|
|
177
173
|
}
|
|
178
|
-
/**
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
|
|
182
|
-
* rather than crashing the whole listing. */
|
|
183
|
-
export function listProfiles() {
|
|
174
|
+
/** The one walk of the profiles root: immediate children only — never
|
|
175
|
+
* recurses, never trusts a caller-supplied id. A dir whose name doesn't match
|
|
176
|
+
* the generated id shape is not a profile at all and is ignored. */
|
|
177
|
+
function enumerateProfiles() {
|
|
184
178
|
const root = profilesRoot();
|
|
185
179
|
if (!existsSync(root))
|
|
186
|
-
return [];
|
|
187
|
-
const
|
|
180
|
+
return { entries: [], unreadableIds: [] };
|
|
181
|
+
const entries = [];
|
|
182
|
+
const unreadableIds = [];
|
|
188
183
|
for (const dirent of readdirSync(root, { withFileTypes: true })) {
|
|
189
184
|
if (!dirent.isDirectory())
|
|
190
185
|
continue;
|
|
@@ -193,10 +188,37 @@ export function listProfiles() {
|
|
|
193
188
|
continue;
|
|
194
189
|
const manifest = readManifestFile(join(root, profileId, 'profile.json'), profileId);
|
|
195
190
|
if (manifest === null)
|
|
196
|
-
|
|
197
|
-
|
|
191
|
+
unreadableIds.push(profileId);
|
|
192
|
+
else
|
|
193
|
+
entries.push({ profileId, manifest });
|
|
198
194
|
}
|
|
199
|
-
return
|
|
195
|
+
return { entries, unreadableIds };
|
|
196
|
+
}
|
|
197
|
+
/** Every profile with a readable manifest, in directory-listing order. A
|
|
198
|
+
* profile whose manifest is missing or corrupt is skipped rather than
|
|
199
|
+
* crashing the whole listing — `lookupProfile` is how a caller that must not
|
|
200
|
+
* confuse "skipped" with "gone" asks. */
|
|
201
|
+
export function listProfiles() {
|
|
202
|
+
return enumerateProfiles().entries;
|
|
203
|
+
}
|
|
204
|
+
/** Exact resolution (generated id, else a unique manifest `name`) that reports
|
|
205
|
+
* WHY it failed. Only an ID can come back `unreadable`: a name lives inside
|
|
206
|
+
* the manifest that could not be read, so an unreadable profile has no name to
|
|
207
|
+
* match on. Throws on an ambiguous name, exactly as `loadProfileManifest`
|
|
208
|
+
* does. */
|
|
209
|
+
export function lookupProfile(profileIdOrName) {
|
|
210
|
+
const { entries, unreadableIds } = enumerateProfiles();
|
|
211
|
+
const exact = findExactProfile(entries, profileIdOrName);
|
|
212
|
+
if (exact !== null)
|
|
213
|
+
return { kind: 'resolved', entry: exact };
|
|
214
|
+
if (unreadableIds.includes(profileIdOrName)) {
|
|
215
|
+
return {
|
|
216
|
+
kind: 'unreadable',
|
|
217
|
+
profileId: profileIdOrName,
|
|
218
|
+
manifestPath: join(profilesRoot(), profileIdOrName, 'profile.json'),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
return { kind: 'absent' };
|
|
200
222
|
}
|
|
201
223
|
// Three resolvers, in descending tolerance. `resolveProfileOperand` is what a
|
|
202
224
|
// command leaf calls for a value the USER TYPED: exact id, exact name, then a
|
|
@@ -255,11 +277,13 @@ function profileNotFound(all, profileIdOrName) {
|
|
|
255
277
|
});
|
|
256
278
|
}
|
|
257
279
|
export function loadProfileManifest(profileIdOrName) {
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
280
|
+
const lookup = lookupProfile(profileIdOrName);
|
|
281
|
+
if (lookup.kind === 'resolved')
|
|
282
|
+
return lookup.entry;
|
|
283
|
+
// Unreadable and absent both answer not-found here: this is the tolerant
|
|
284
|
+
// resolver every runtime consumer already handles that way. A caller that
|
|
285
|
+
// must NOT substitute another identity calls `lookupProfile` directly.
|
|
286
|
+
throw profileNotFound(listProfiles(), profileIdOrName);
|
|
263
287
|
}
|
|
264
288
|
/** Resolve a profile the USER TYPED — a `--profile` flag or a `<profile>`
|
|
265
289
|
* operand. Exact id or name wins outright; only when nothing matches exactly
|
|
@@ -316,10 +340,8 @@ function writeManifestAtomic(path, manifest) {
|
|
|
316
340
|
writeFileSync(tmp, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
|
|
317
341
|
renameSync(tmp, path);
|
|
318
342
|
}
|
|
319
|
-
// ---------------------------------------------------------------------------
|
|
320
343
|
// Project dirs — resolved to absolute real paths, must exist + be a directory
|
|
321
344
|
// on add/create, deduped by real path, stored in manifest order.
|
|
322
|
-
// ---------------------------------------------------------------------------
|
|
323
345
|
function resolveExistingProjectDir(dir) {
|
|
324
346
|
const abs = resolvePath(dir);
|
|
325
347
|
if (!existsSync(abs) || !statSync(abs).isDirectory()) {
|
|
@@ -364,11 +386,9 @@ function generateProfileId(name) {
|
|
|
364
386
|
}
|
|
365
387
|
throw general(`failed to generate a unique profile id for "${name}" after 20 attempts`);
|
|
366
388
|
}
|
|
367
|
-
// ---------------------------------------------------------------------------
|
|
368
389
|
// Mutations — all under withProfileManifestLock, all atomic writes, all call
|
|
369
390
|
// resetScopeCache() when they can change project dirs or the profile name
|
|
370
391
|
// (never for a bare last-used-at touch).
|
|
371
|
-
// ---------------------------------------------------------------------------
|
|
372
392
|
export function ensureRootProfile() {
|
|
373
393
|
return withProfileManifestLock(ROOT_PROFILE_ID, () => {
|
|
374
394
|
const manifestPath = profileManifestPath(ROOT_PROFILE_ID);
|
|
@@ -120,7 +120,6 @@ export function selectProfileForCwdReadOnly(cwd) {
|
|
|
120
120
|
function isInteractive() {
|
|
121
121
|
return Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY);
|
|
122
122
|
}
|
|
123
|
-
// ---------------------------------------------------------------------------
|
|
124
123
|
// Pre-boot prompt presentation. These prompts print to the raw controlling
|
|
125
124
|
// terminal BEFORE pi takes it over (not the attach viewer), so styling is
|
|
126
125
|
// plain ANSI via the house `stdoutColor` helper (NO_COLOR / non-TTY aware) and
|
|
@@ -129,7 +128,6 @@ function isInteractive() {
|
|
|
129
128
|
// dim subtitle, then accent-keyed option rows. We deliberately do NOT echo the
|
|
130
129
|
// user's own cwd back at them (they know where they are) — the only paths
|
|
131
130
|
// worth showing are OTHER dirs: which project root a covering profile owns.
|
|
132
|
-
// ---------------------------------------------------------------------------
|
|
133
131
|
const dim = stdoutColor.dim;
|
|
134
132
|
const bold = stdoutColor.bold;
|
|
135
133
|
const accent = stdoutColor.cyan;
|
|
@@ -310,7 +308,6 @@ function runMenu(bindings, title, subtitle, rows, opts = {}) {
|
|
|
310
308
|
draw();
|
|
311
309
|
});
|
|
312
310
|
}
|
|
313
|
-
// ---------------------------------------------------------------------------
|
|
314
311
|
// The profile manager. `v` on either selection gate opens the Profiles page of
|
|
315
312
|
// `crtr sys settings` in a tmux popup: this menu is a CHOOSER filtered to cwd,
|
|
316
313
|
// while that page is the whole map — every profile, every directory each one
|
|
@@ -318,7 +315,6 @@ function runMenu(bindings, title, subtitle, rows, opts = {}) {
|
|
|
318
315
|
// torn down (runMenu cleans up before resolving an action), and the caller then
|
|
319
316
|
// re-runs the whole selector, so a directory just adopted or a default just
|
|
320
317
|
// pinned decides the menu you come back to.
|
|
321
|
-
// ---------------------------------------------------------------------------
|
|
322
318
|
/** Open the profiles page in a tmux popup and block until it closes. False when
|
|
323
319
|
* there is no tmux to host it — possible only on the `crtr node new` path, as
|
|
324
320
|
* the front door requires tmux before it ever selects — after printing the
|
|
@@ -1,31 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { mkdirSync, watch, writeFileSync } from 'node:fs';
|
|
3
|
-
import { crtrHome } from '../canvas/paths.js';
|
|
1
|
+
import { activityPath, signalActivity, watchActivity } from '../activity-signal.js';
|
|
4
2
|
/** Signal one durable review mutation to every open viewer without watching every review directory. */
|
|
5
3
|
export function reviewActivityPath() {
|
|
6
|
-
return
|
|
4
|
+
return activityPath('review-activity');
|
|
7
5
|
}
|
|
8
6
|
/** Signal one review mutation (comment create/edit/resolve/delete/reanchor/delivery) to every open review surface. */
|
|
9
7
|
export function signalReviewActivity() {
|
|
10
|
-
|
|
11
|
-
mkdirSync(dirname(reviewActivityPath()), { recursive: true, mode: 0o700 });
|
|
12
|
-
writeFileSync(reviewActivityPath(), `${Date.now()}\n`, { mode: 0o600 });
|
|
13
|
-
}
|
|
14
|
-
catch {
|
|
15
|
-
// A later review read is still authoritative.
|
|
16
|
-
}
|
|
8
|
+
signalActivity('review-activity');
|
|
17
9
|
}
|
|
18
10
|
export function watchReviewActivity(onChange) {
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
mkdirSync(dirname(activityPath), { recursive: true, mode: 0o700 });
|
|
22
|
-
const watcher = watch(dirname(activityPath), (_event, filename) => {
|
|
23
|
-
if (String(filename) === basename(activityPath))
|
|
24
|
-
onChange();
|
|
25
|
-
});
|
|
26
|
-
return () => watcher.close();
|
|
27
|
-
}
|
|
28
|
-
catch {
|
|
29
|
-
return () => { };
|
|
30
|
-
}
|
|
11
|
+
return watchActivity('review-activity', onChange);
|
|
31
12
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Terminal-review ticket visibility filter.
|
|
3
|
-
* Hides
|
|
3
|
+
* Hides review tickets by canonical state.
|
|
4
4
|
* This module never imports canvas DB directly; daemon call sites apply the filter.
|
|
5
5
|
*/
|
|
6
6
|
import type { TicketSummary } from '../human/types.js';
|
|
7
7
|
/**
|
|
8
8
|
* Determines if a review ticket should be visible based on its canonical review state.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* Only an open row is visible: 'binding', 'approved', and 'canceled' are hidden, and so is a
|
|
10
|
+
* ticket with no row at all — a row is committed before its ticket is ever published.
|
|
11
11
|
*/
|
|
12
12
|
export declare function isReviewTicketVisible(bridgeNodeId: string): boolean;
|
|
13
13
|
/**
|
|
@@ -1,21 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Terminal-review ticket visibility filter.
|
|
3
|
-
* Hides
|
|
3
|
+
* Hides review tickets by canonical state.
|
|
4
4
|
* This module never imports canvas DB directly; daemon call sites apply the filter.
|
|
5
5
|
*/
|
|
6
6
|
import { getReviewByBridge } from './store.js';
|
|
7
7
|
/**
|
|
8
8
|
* Determines if a review ticket should be visible based on its canonical review state.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* Only an open row is visible: 'binding', 'approved', and 'canceled' are hidden, and so is a
|
|
10
|
+
* ticket with no row at all — a row is committed before its ticket is ever published.
|
|
11
11
|
*/
|
|
12
12
|
export function isReviewTicketVisible(bridgeNodeId) {
|
|
13
|
-
|
|
14
|
-
// Pre-cutover ticket with no record: visible
|
|
15
|
-
if (review === null)
|
|
16
|
-
return true;
|
|
17
|
-
// Canonical review exists: hide terminal states, show open
|
|
18
|
-
return review.state === 'open';
|
|
13
|
+
return getReviewByBridge(bridgeNodeId)?.state === 'open';
|
|
19
14
|
}
|
|
20
15
|
/**
|
|
21
16
|
* Filters a ticket summary array to remove hidden terminal-review tickets.
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// session). An idle follow_up must run as a prompt.
|
|
10
10
|
import { test } from 'node:test';
|
|
11
11
|
import assert from 'node:assert/strict';
|
|
12
|
-
import { resolveEngineRoute } from '../broker/
|
|
12
|
+
import { resolveEngineRoute } from '../broker/engine-routing.js';
|
|
13
13
|
const IMAGES = [{ type: 'image', data: 'aGk=', mimeType: 'image/png' }];
|
|
14
14
|
test('m-C: follow_up on an IDLE session escalates to prompt (no streamingBehavior)', () => {
|
|
15
15
|
const route = resolveEngineRoute({ type: 'follow_up' }, false);
|
|
@@ -102,12 +102,10 @@ test('B: configured model-provider keys cross by exact name', () => {
|
|
|
102
102
|
assert.equal(env.ANTHROPIC_API_KEY, 'fake-anthropic');
|
|
103
103
|
assert.equal(env.OPENAI_API_KEY, 'fake-openai');
|
|
104
104
|
});
|
|
105
|
-
// ---------------------------------------------------------------------------
|
|
106
105
|
// A2 — proxy userinfo guard (Major 1 fix): must reject username-only,
|
|
107
106
|
// password-only, and scheme-less userinfo, for BOTH uppercase and lowercase
|
|
108
107
|
// var names; must keep a plain proxy URL, for both cases; NO_PROXY always
|
|
109
108
|
// keeps.
|
|
110
|
-
// ---------------------------------------------------------------------------
|
|
111
109
|
test('A2: a credentialed proxy URL is dropped, a plain one crosses (uppercase)', () => {
|
|
112
110
|
const env = base(LEAK_CLASS_HOST_ENV);
|
|
113
111
|
assert.equal(env.HTTP_PROXY, undefined, 'userinfo-bearing proxy must not cross');
|
|
@@ -142,10 +140,8 @@ test('A2: a non-http(s) scheme or hostless value is dropped, never admitted', ()
|
|
|
142
140
|
const env = base({ HTTP_PROXY: 'not a url at all' });
|
|
143
141
|
assert.equal(env.HTTP_PROXY, undefined);
|
|
144
142
|
});
|
|
145
|
-
// ---------------------------------------------------------------------------
|
|
146
143
|
// buildBrokerEnv: overlay + drop the leak class through the real process.env
|
|
147
144
|
// path.
|
|
148
|
-
// ---------------------------------------------------------------------------
|
|
149
145
|
test('buildBrokerEnv overlays inv.env + FRONT_DOOR_ENV on top of the sanitized base, and drops the leak class', () => {
|
|
150
146
|
const inv = {
|
|
151
147
|
argv: [],
|
|
@@ -170,9 +166,7 @@ test('buildBrokerEnv overlays inv.env + FRONT_DOOR_ENV on top of the sanitized b
|
|
|
170
166
|
delete process.env.GIT_ASKPASS;
|
|
171
167
|
}
|
|
172
168
|
});
|
|
173
|
-
// ---------------------------------------------------------------------------
|
|
174
169
|
// C — explicit spawnEnv.allow escape hatch: literal names + globs.
|
|
175
|
-
// ---------------------------------------------------------------------------
|
|
176
170
|
test('C: an explicit spawnEnv.allow literal name admits a var that would otherwise be dropped', () => {
|
|
177
171
|
mkdirSync(join(isolatedHome, '.crouter'), { recursive: true });
|
|
178
172
|
writeFileSync(join(isolatedHome, '.crouter', 'config.json'), JSON.stringify({ spawnEnv: { allow: ['GOOGLE_GENERATIVE_AI_API_KEY'] } }));
|
|
@@ -198,10 +192,8 @@ test('C (glob, Minor fix): a bare "*" (inherit-all) is rejected loud at config r
|
|
|
198
192
|
resetScopeCache();
|
|
199
193
|
assert.throws(() => readMergedLaunchConfig(isolatedCwd, null), /matches every env var name/, 'a bare "*" must fail loud at config read, per cto-rejects-fallback-hedges — never silently literal, never silently dropped');
|
|
200
194
|
});
|
|
201
|
-
// ---------------------------------------------------------------------------
|
|
202
195
|
// Major 2 fix — spawnEnv.allow resolves from the TARGET's own cwd/profile,
|
|
203
196
|
// never the calling/launcher process's ambient scope.
|
|
204
|
-
// ---------------------------------------------------------------------------
|
|
205
197
|
test('target-scope: spawnEnv.allow is read from the TARGET cwd, not process.cwd() (the ambient/launcher cwd)', () => {
|
|
206
198
|
const launcherCwd = realpathSync(mkdtempSync(join(tmpdir(), 'crtr-spawn-env-launcher-')));
|
|
207
199
|
const targetCwd = realpathSync(mkdtempSync(join(tmpdir(), 'crtr-spawn-env-target-')));
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type NamedNode } from '../canvas/labels.js';
|
|
2
|
+
export declare function escapeAttribute(value: string): string;
|
|
3
|
+
/** The `<project_context>` block — the `<environment>` snapshot only: a
|
|
4
|
+
* host/runtime line (platform, hostname, node version, tmux-or-not — the
|
|
5
|
+
* headless engine's own process env, which its bash tools inherit), the cwd
|
|
6
|
+
* dir listing, and git status/worktrees. Project guidance lives in the
|
|
7
|
+
* document substrate, so this wrapper stays environment-only. It always emits
|
|
8
|
+
* because the environment snapshot is always present. */
|
|
9
|
+
export declare function buildProjectContextBlock(cwd: string): string;
|
|
10
|
+
/** The context-directory note — names the path INLINE (no XML attribute, so it
|
|
11
|
+
* never scopes a sibling block) and frames the dir as durable, shared scratch.
|
|
12
|
+
* Present for every node, rendered as the `## Your context directory`
|
|
13
|
+
* subsection of <crtr-bearings>. */
|
|
14
|
+
export declare function contextDirNote(nodeId: string): string;
|
|
15
|
+
/** The profile-purview note — rendered ONLY when the profile resolves to a
|
|
16
|
+
* manifest that names at least one project dir. Phrased as PURVIEW, not a cwd
|
|
17
|
+
* replacement: the node's cwd is still its one working dir (bash/edits run
|
|
18
|
+
* there), the profile just widens what it may ALSO read/act on. Omitted
|
|
19
|
+
* entirely for a profile with no project purview (including the stable root
|
|
20
|
+
* profile) or a deleted/unreadable manifest — never throws. This absolute-path
|
|
21
|
+
* disclosure is intentional (spec-approved): the agent must know its full
|
|
22
|
+
* purview, not a redacted count. */
|
|
23
|
+
export declare function profileNote(cwd: string, profileId: string | null | undefined): string;
|
|
24
|
+
/** Orchestrator-only framing: a resident orchestrator survives refresh cycles,
|
|
25
|
+
* so its context dir is also where a future cycle of itself resumes the work.
|
|
26
|
+
* Used inside the bearings block AND in the promotion guidance dump, so a
|
|
27
|
+
* promoted node gets the same note a born-orchestrator gets. */
|
|
28
|
+
export declare function orchestratorContextNote(nodeId: string): string;
|
|
29
|
+
export interface RelativeLabelNode extends NamedNode {
|
|
30
|
+
node_id: string;
|
|
31
|
+
kind: string;
|
|
32
|
+
status: string;
|
|
33
|
+
name: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
icon?: string;
|
|
36
|
+
}
|
|
37
|
+
/** One relative's line in the map: `<id> — <kind> · <status>`, plus the node's
|
|
38
|
+
* task description when it carries one (orientation: what that relative is for). */
|
|
39
|
+
export declare function relativeLabel(node: RelativeLabelNode): string;
|
|
40
|
+
/** The graph mini-map: the ancestry trunk (root first), then this node marked
|
|
41
|
+
* `● you`, then its immediate children. Returns '' for a lone root with no
|
|
42
|
+
* children (nothing to map). */
|
|
43
|
+
export declare function renderGraphMap(nodeId: string, kind: string, mode: string, trunk: readonly RelativeLabelNode[], children: readonly RelativeLabelNode[]): string;
|
|
44
|
+
/** The identity assertion injected at session start. A fork names its source
|
|
45
|
+
* while treating the copied first-person narrative as reference. The caller
|
|
46
|
+
* resolves `sourceLabel`: the bare `forkFrom` id when the source lookup
|
|
47
|
+
* fails/is unsafe, else `${forkFrom} ("${fullName(src)}")`. */
|
|
48
|
+
export declare function buildIdentityAssertion(nodeId: string, kind: string, mode: string, forkFrom: string | null | undefined, sourceLabel: string): string;
|
|
49
|
+
export interface ManagedWorktreeLike {
|
|
50
|
+
state: string;
|
|
51
|
+
path: string;
|
|
52
|
+
branch: string;
|
|
53
|
+
base_ref: string;
|
|
54
|
+
base_sha: string;
|
|
55
|
+
}
|
|
56
|
+
export declare function worktreeNote(worktree: ManagedWorktreeLike | null | undefined): string;
|