@north-light/crouter 0.3.232 → 0.3.234
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/builtin-memory/internal/memory-loading.md +4 -3
- 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 +532 -534
- 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 +0 -8
- 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 +5 -18
- 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/memory/__tests__/command-selector-and-mutation-guards.test.js +4 -4
- package/dist/commands/memory/find.js +2 -2
- package/dist/commands/memory/lint.js +2 -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 -1
- package/dist/commands/memory/shared.js +7 -10
- package/dist/commands/memory/write.js +4 -3
- package/dist/commands/node/bash.js +2 -1
- package/dist/commands/node/create.js +2 -1
- package/dist/commands/node/inspect.js +0 -6
- package/dist/commands/node/lifecycle.js +4 -13
- package/dist/commands/node/message.js +3 -2
- package/dist/commands/node/subscription.js +2 -1
- package/dist/commands/node/wait.js +4 -3
- 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 +2 -1
- package/dist/commands/pkg/shared.js +0 -2
- package/dist/commands/profile/delete.js +2 -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 +0 -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/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__/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 +0 -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/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 +50 -18
- 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/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.js +0 -2
- package/dist/core/canvas/render-source.js +31 -13
- package/dist/core/command-manifests/manifest.js +0 -10
- package/dist/core/command-manifests/schema.js +0 -4
- package/dist/core/command-plugins/transport/http-invoke.js +0 -14
- package/dist/core/command.js +0 -4
- package/dist/core/config.js +2 -1
- 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.js +0 -2
- 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 +5 -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/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.js +3 -6
- 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/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.d.ts +1 -0
- package/dist/core/substrate/__tests__/surface-match-pre-command.test.js +92 -0
- package/dist/core/substrate/frontmatter-validation.js +1 -1
- package/dist/core/substrate/injected-store.d.ts +6 -0
- package/dist/core/substrate/injected-store.js +24 -0
- package/dist/core/substrate/on-read.d.ts +17 -1
- package/dist/core/substrate/on-read.js +36 -2
- package/dist/core/substrate/render.js +0 -12
- package/dist/core/substrate/schema.d.ts +3 -3
- package/dist/core/substrate/schema.js +4 -16
- package/dist/core/substrate/surface-match.d.ts +19 -0
- package/dist/core/substrate/surface-match.js +60 -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__/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 +4 -8
- package/dist/daemon/api/handlers/nodes.js +10 -21
- package/dist/daemon/api/handlers/reports.js +1 -1
- package/dist/daemon/api/handlers/reviews.js +1 -6
- package/dist/daemon/api/map.js +0 -6
- 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 +26 -29
- 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/__tests__/pre-command-gate.test.d.ts +1 -0
- package/dist/pi-extensions/__tests__/pre-command-gate.test.js +220 -0
- package/dist/pi-extensions/broker-local.js +2 -1
- package/dist/pi-extensions/canvas-bash-valve.js +3 -17
- package/dist/pi-extensions/canvas-context-intro.js +2 -7
- package/dist/pi-extensions/canvas-doc-substrate.d.ts +14 -0
- package/dist/pi-extensions/canvas-doc-substrate.js +77 -5
- 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
|
@@ -126,7 +126,7 @@ export const findLeaf = defineLeaf({
|
|
|
126
126
|
const units = selector.store !== null
|
|
127
127
|
? searchUnits(kindFilter, loadMemoryStoreView(requireMountedStore(selector.store), false).docs, false)
|
|
128
128
|
: searchUnits(kindFilter, listAllMemoryDocs(selector.scope, false, true), true);
|
|
129
|
-
//
|
|
129
|
+
// grep mode: regex over every unit's body, one row per matching line
|
|
130
130
|
if (grep) {
|
|
131
131
|
let regex;
|
|
132
132
|
try {
|
|
@@ -167,7 +167,7 @@ export const findLeaf = defineLeaf({
|
|
|
167
167
|
registerMemoryListingExposure(listingIdentity);
|
|
168
168
|
return output;
|
|
169
169
|
}
|
|
170
|
-
//
|
|
170
|
+
// ranked mode: weighted relevance over name/routing-line/short-form(+body)
|
|
171
171
|
const terms = query
|
|
172
172
|
.toLowerCase()
|
|
173
173
|
.split(/\s+/)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// verification, the plugin candidate gate, and the build's builtin gate consume
|
|
4
4
|
// too; this leaf only picks WHAT to lint (a target view, or one exact store
|
|
5
5
|
// with --dir) and shapes the findings for the CLI.
|
|
6
|
+
import { envProfileId } from '../../shared/env.js';
|
|
6
7
|
import { defineLeaf } from '../../core/command.js';
|
|
7
8
|
import { warn } from '../../core/output.js';
|
|
8
9
|
import { ExitCode } from '../../types.js';
|
|
@@ -26,7 +27,7 @@ function findingRow(finding) {
|
|
|
26
27
|
function resolvableNamesForStore(store) {
|
|
27
28
|
const view = loadMemoryTargetView({
|
|
28
29
|
cwd: store.ownerDir ?? store.storeRoot,
|
|
29
|
-
profileId:
|
|
30
|
+
profileId: envProfileId() || null,
|
|
30
31
|
nodeId: null,
|
|
31
32
|
}, { quiet: true, includeDescendants: true });
|
|
32
33
|
return resolvableCanonicalNames(view.docs);
|
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import { createMemoryDocSnapshot, resolveMemoryDocs } from '../../core/memory-resolver.js';
|
|
1
|
+
import { createMemoryDocSnapshot, readMemoryDocContent, resolveMemoryDocs } from '../../core/memory-resolver.js';
|
|
2
2
|
import type { MemoryDoc } from '../../core/memory-resolver.js';
|
|
3
|
-
export { createMemoryDocSnapshot, resolveMemoryDocs };
|
|
4
|
-
/** Load the body at an already-resolved memory path with the same frontmatter
|
|
5
|
-
* stripping and in-node path interpolation as `memory read`. Callers that
|
|
6
|
-
* already have the resolved path (such as slash-command discovery) avoid
|
|
7
|
-
* re-walking every memory store for each document. */
|
|
8
|
-
export declare function readMemoryDocContent(path: string, includeFrontmatter?: boolean): string;
|
|
3
|
+
export { createMemoryDocSnapshot, readMemoryDocContent, resolveMemoryDocs };
|
|
9
4
|
/** One physical document sharing a canonical identity, as the path-aware
|
|
10
5
|
* surfaces report it. `--dir <its project>` is how a non-winner is reached. */
|
|
11
6
|
export declare function candidateRow(doc: MemoryDoc, winner: MemoryDoc): Record<string, unknown>;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
+
import { envNodeId } from '../../shared/env.js';
|
|
1
2
|
import { CrtrClient } from '../../api/index.js';
|
|
2
|
-
import { interpolateNodePaths } from '../../core/canvas/paths.js';
|
|
3
3
|
import { defineLeaf } from '../../core/command.js';
|
|
4
4
|
import { CrtrError } from '../../core/errors.js';
|
|
5
5
|
import { memoryExtensionEffectiveCatalog, projectEffectiveMemoryExtensions } from '../../core/memory/extensions.js';
|
|
6
|
-
import {
|
|
7
|
-
import { parseFrontmatterGeneric } from '../../core/frontmatter.js';
|
|
6
|
+
import { realpathOrSelf } from '../../core/fs-utils.js';
|
|
8
7
|
import { docLinkNames } from '../../core/memory/doc-link-grammar.js';
|
|
9
|
-
import { createMemoryDocSnapshot, listAllMemoryDocs, loadMemoryStoreView, resolveMemoryCandidates, resolveMemoryDocs, } from '../../core/memory-resolver.js';
|
|
8
|
+
import { createMemoryDocSnapshot, listAllMemoryDocs, loadMemoryStoreView, readMemoryDocContent, resolveMemoryCandidates, resolveMemoryDocs, } from '../../core/memory-resolver.js';
|
|
10
9
|
import { expandShellBlocks, hasShellBlocks, makeNodeShellRunner } from '../../core/runtime/shell-expansion.js';
|
|
11
10
|
import { emptyContextExposureState, exposedAtOrAbove, exposureTarget, loadContextExposureState, registerDocumentExposure, registerExposure, saveContextExposureState, } from '../../core/substrate/injected-store.js';
|
|
12
11
|
import { dirDedupKey, docListingDirs, docsByName, isDirName, renderDirListing } from '../../core/substrate/listings.js';
|
|
@@ -15,17 +14,7 @@ import { renderResult } from '../../core/render.js';
|
|
|
15
14
|
import { effectiveDocKind } from '../../core/substrate/schema.js';
|
|
16
15
|
import { canonicalSegments } from '../../core/memory/identity.js';
|
|
17
16
|
import { MEMORY_KINDS, requireMountedStore, resolveReadSelector, selectorParam } from './shared.js';
|
|
18
|
-
export { createMemoryDocSnapshot, resolveMemoryDocs };
|
|
19
|
-
/** Load the body at an already-resolved memory path with the same frontmatter
|
|
20
|
-
* stripping and in-node path interpolation as `memory read`. Callers that
|
|
21
|
-
* already have the resolved path (such as slash-command discovery) avoid
|
|
22
|
-
* re-walking every memory store for each document. */
|
|
23
|
-
export function readMemoryDocContent(path, includeFrontmatter = false) {
|
|
24
|
-
const raw = readText(path);
|
|
25
|
-
const content = includeFrontmatter ? raw : parseFrontmatterGeneric(raw).body;
|
|
26
|
-
const nodeId = process.env['CRTR_NODE_ID'];
|
|
27
|
-
return nodeId ? interpolateNodePaths(content, nodeId) : content;
|
|
28
|
-
}
|
|
17
|
+
export { createMemoryDocSnapshot, readMemoryDocContent, resolveMemoryDocs };
|
|
29
18
|
/** The node-config subject for memory-read-event gate evaluation. A CLI
|
|
30
19
|
* process cannot take it from canvas-db (V-1); one `/v1` request supplies it.
|
|
31
20
|
* With no node identity or no reachable daemon the answer is null — gated
|
|
@@ -150,7 +139,7 @@ export const readLeaf = defineLeaf({
|
|
|
150
139
|
}
|
|
151
140
|
fail = () => resolveMemoryCandidates(nameRaw, resolveOpts);
|
|
152
141
|
}
|
|
153
|
-
const nodeId =
|
|
142
|
+
const nodeId = envNodeId() || undefined;
|
|
154
143
|
if (set === null) {
|
|
155
144
|
// No document answers this name — a directory with no document of its own
|
|
156
145
|
// still does, through its listing. An explicit dir read is a deliberate
|
|
@@ -194,7 +194,7 @@ export declare function overlayParam(name: string, overrides?: Partial<FlagParam
|
|
|
194
194
|
* `--doc-rationale`, because `--rationale` there means why THIS REVISION is
|
|
195
195
|
* happening. Same field, same prose, two flag names that cannot be confused. */
|
|
196
196
|
export declare const DOC_RATIONALE_CONSTRAINT = "Frontmatter rationale \u2014 the observed agent failure that made this doc necessary. Maintainer-facing only: never ships in any delivered surface (boot render, on-read injection, `memory read` content), visible only via `memory read --frontmatter`. Omitting the flag preserves an existing rationale unchanged.";
|
|
197
|
-
export declare const GUIDE_SURFACES = "Every doc appears in its directory\u2019s listing by default (suppress with --unlisted); everything beyond the listing is explicit `surfaces` routing \u2014 entries declaring WHEN the doc delivers and how much. Events: `boot` delivers in the boot catalog every agent sees; `workspace-open` delivers in first-message context when cwd/profile mounts the doc\u2019s project store (project stores only); `read` fires when the agent reads a matching file (globs vs the file\u2019s absolute path and basename, `./`-anchored globs vs its path relative to the store\u2019s owning repo dir, `match-frontmatter` predicates over the read file\u2019s own YAML frontmatter); `memory-read` fires when another memory doc is read (globs vs that doc\u2019s canonical name, `./` anchored to this doc\u2019s routing anchor \u2014 its own canonical name when it is its directory\u2019s document, otherwise the canonical directory it sits in); `command` fires when a matching shell command runs (globs vs each shell segment of the command line \u2014 split on `&&`/`||`/`;`/`|`/newlines outside quotes, leading `VAR=value` assignments dropped \u2014 where `*` spans whole whitespace-separated tokens and never part of one, `?` is one character inside a token, and quoted argument text is opaque, so `*git commit*` fires for `cd x && git commit -m \"\u2026\"` but not for `git commit-tree` or an `echo` that merely mentions it). An entry may also carry `gate`, a node-config predicate using the same vocabulary as the document-level `gate`: event constraints and entry gate both must match, then all participating entries fold to the highest `at` (`content` > `preview` > `name`), with no cross-entry deny precedence. The document-level `gate` remains the hard eligibility check: when it fails, no automatic surface can deliver the document. `at` sets how much delivers: `name` the bare tag, `preview` the routing line, `content` the whole body. Explicit `memory read` and listings remain deliberate access and ignore gates/rungs; only companion docs routed by their `memory-read` entries use entry gates. Each entry is paid by every future agent it fires on, so default down: no surfaces at all is correct for reference depth reached through listings and [[links]], and when a doc fits in a single sentence, deliver `content` directly \u2014 a `preview` routing line would run longer than the doc itself. Sentence-length `content` docs are correct; never pad a memory to be more verbose than the rule or fact it carries.";
|
|
197
|
+
export declare const GUIDE_SURFACES = "Every doc appears in its directory\u2019s listing by default (suppress with --unlisted); everything beyond the listing is explicit `surfaces` routing \u2014 entries declaring WHEN the doc delivers and how much. Events: `boot` delivers in the boot catalog every agent sees; `workspace-open` delivers in first-message context when cwd/profile mounts the doc\u2019s project store (project stores only); `read` fires when the agent reads a matching file (globs vs the file\u2019s absolute path and basename, `./`-anchored globs vs its path relative to the store\u2019s owning repo dir, `match-frontmatter` predicates over the read file\u2019s own YAML frontmatter); `memory-read` fires when another memory doc is read (globs vs that doc\u2019s canonical name, `./` anchored to this doc\u2019s routing anchor \u2014 its own canonical name when it is its directory\u2019s document, otherwise the canonical directory it sits in); `command` fires when a matching shell command runs (globs vs each shell segment of the command line \u2014 split on `&&`/`||`/`;`/`|`/newlines outside quotes, leading `VAR=value` assignments dropped \u2014 where `*` spans whole whitespace-separated tokens and never part of one, `?` is one character inside a token, and quoted argument text is opaque, so `*git commit*` fires for `cd x && git commit -m \"\u2026\"` but not for `git commit-tree` or an `echo` that merely mentions it); `pre-command` fires BEFORE a matching bash command runs (same matching): when the memory has not been read yet, the command does not execute \u2014 the memory comes back as the tool result instead, and the agent re-issues the command, which then runs. Use it to guarantee a memory is seen before a sensitive action is taken. Requires `match`. An entry may also carry `gate`, a node-config predicate using the same vocabulary as the document-level `gate`: event constraints and entry gate both must match, then all participating entries fold to the highest `at` (`content` > `preview` > `name`), with no cross-entry deny precedence. The document-level `gate` remains the hard eligibility check: when it fails, no automatic surface can deliver the document. `at` sets how much delivers: `name` the bare tag, `preview` the routing line, `content` the whole body. Explicit `memory read` and listings remain deliberate access and ignore gates/rungs; only companion docs routed by their `memory-read` entries use entry gates. Each entry is paid by every future agent it fires on, so default down: no surfaces at all is correct for reference depth reached through listings and [[links]], and when a doc fits in a single sentence, deliver `content` directly \u2014 a `preview` routing line would run longer than the doc itself. Sentence-length `content` docs are correct; never pad a memory to be more verbose than the rule or fact it carries.";
|
|
198
198
|
export declare const GUIDE_ROUTING_LINE = "The routing line (--when-and-why-to-read) is the only text an agent reads before deciding to load the doc. The test for its when-clause: it names an observable circumstance in the reader\u2019s current work, not the doc\u2019s topic reworded as an activity. If the WHEN can be inferred from the title alone, it is not a real trigger. Bad on a todo list: \"When planning or prioritizing work across this profile.\" Good: \"When the user mentions something from their todos, or asks what is still outstanding across this profile.\" The test for its because-clause: if it can be derived by paraphrasing the doc\u2019s advice, it is a restatement, not a payoff \u2014 a real payoff names a consequence in the reader\u2019s world that the document itself never asserts. Bad: \"because only genuine first principles belong in taste memory.\" Bad: \"because keeping the test loop fast and free of speculative tests protects the development pace\" \u2014 the doc\u2019s rule as an outcome, derivable straight from its advice. Good: \"because identifying throughlines in user taste lets future decisions be made faster and with less re-litigation.\" Someone mid-task who has not read the doc must be able to decide from this line alone whether the read is worth it. If you cannot name the concrete situation that triggers it, you do not yet understand the memory \u2014 ask the user one sharp question instead of improvising.";
|
|
199
199
|
export declare const GUIDE_PREDICATE_VOCABULARY = "Document gates, surface-entry gates, and match-frontmatter share the same predicate language: a field map is AND-ed across fields; dotted fields resolve nested values; field matchers may be scalar, array, or object. Scalar matchers do exact equality, with arrays matching any element. Array matchers do membership or intersection. Object matchers accept `eq`, `ne`, `in`, `nin`, `exists`, `contains`, `containsAll`, `containsAny`, `matches`, `imatches`, `gt`, `gte`, `lt`, and `lte`. Combinators are `all`, `any`, and `not`; sibling field matchers next to them are AND-ed in. An empty condition is inert. An unknown op never matches.";
|
|
200
200
|
export declare const GUIDE_DOC_LINKS = "Link related docs with `[[canonical/name]]`. A doc link in any body is a first-class cross-reference to another memory document by its exact canonical name \u2014 the same identifier `crtr memory read` takes, namespace included for a project document. A bare directory name is a valid link too: following it returns that directory\u2019s own document when it has one, plus the directory listing. Links are pointers, never transclusion: the linked body is loaded only when a reader follows it, so a link costs nothing until needed. `crtr memory lint` fails on a link that resolves to no document or directory, and `crtr memory read` lists a doc\u2019s resolvable links alongside its body. There is no alias, label, or old-name form \u2014 a renamed target needs its links rewritten.";
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// scope modules and build their documented output objects on top of the small
|
|
4
4
|
// helpers here. Nothing in this file forks on kind or re-implements the
|
|
5
5
|
// schema/gate/resolver — it only composes them.
|
|
6
|
+
import { envNodeId, envProfileId } from '../../shared/env.js';
|
|
6
7
|
import { existsSync, readdirSync, realpathSync, rmdirSync, statSync } from 'node:fs';
|
|
7
8
|
import { dirname, join, resolve as resolvePath } from 'node:path';
|
|
8
9
|
import { stringify as yamlStringify, parse as yamlParse } from 'yaml';
|
|
@@ -40,7 +41,7 @@ export function scopeRank(scope) {
|
|
|
40
41
|
return scope === 'node' ? -1 : scope === 'project' ? 0 : scope === 'profile' ? 1 : scope === 'user' ? 2 : 3;
|
|
41
42
|
}
|
|
42
43
|
export function registerMemoryListingExposure(identity) {
|
|
43
|
-
const nodeId =
|
|
44
|
+
const nodeId = envNodeId();
|
|
44
45
|
if (nodeId === undefined || nodeId === '')
|
|
45
46
|
return;
|
|
46
47
|
const state = loadContextExposureState(nodeId);
|
|
@@ -151,7 +152,7 @@ export function resolveWriteSelector(input) {
|
|
|
151
152
|
if (scope === 'node') {
|
|
152
153
|
// The this-node store: the same dir render.ts's nodeLocalDocs loads at
|
|
153
154
|
// boot, so a doc written here rides into this node's knowledge block.
|
|
154
|
-
const nodeId =
|
|
155
|
+
const nodeId = envNodeId() || '';
|
|
155
156
|
if (nodeId === '') {
|
|
156
157
|
throw usage('node scope requires a running node (CRTR_NODE_ID unset); rerun inside a node');
|
|
157
158
|
}
|
|
@@ -163,7 +164,7 @@ export function resolveWriteSelector(input) {
|
|
|
163
164
|
// is a durable id this process was launched under, so it resolves strictly
|
|
164
165
|
// — a stale one must fail rather than write into a neighbouring store.
|
|
165
166
|
const typed = input.profile !== undefined && input.profile !== '';
|
|
166
|
-
const profileIdOrName = typed ? input.profile :
|
|
167
|
+
const profileIdOrName = typed ? input.profile : envProfileId() || '';
|
|
167
168
|
if (profileIdOrName === '') {
|
|
168
169
|
throw usage('profile scope requires a selected profile; rerun inside a profiled node or pass --profile');
|
|
169
170
|
}
|
|
@@ -209,14 +210,12 @@ export function requireMountedStore(store) {
|
|
|
209
210
|
next: `Run \`crtr sys migrate --dir ${repositoryRoot}\`.`,
|
|
210
211
|
});
|
|
211
212
|
}
|
|
212
|
-
// ---------------------------------------------------------------------------
|
|
213
213
|
// Canonical name → physical placement
|
|
214
214
|
//
|
|
215
215
|
// Every surface takes the FULL canonical name. Placement strips the selected
|
|
216
216
|
// store's namespace off it, checks that neither the identity nor either
|
|
217
217
|
// physical representation of the local name is already taken, and picks the
|
|
218
218
|
// form the new file takes.
|
|
219
|
-
// ---------------------------------------------------------------------------
|
|
220
219
|
/** Normalize and validate a full canonical name: ordering prefixes are
|
|
221
220
|
* physical-path-only, a trailing `INDEX` is never an address, and the segment
|
|
222
221
|
* charset is fixed. */
|
|
@@ -436,7 +435,7 @@ export function coerceSurface(raw) {
|
|
|
436
435
|
throw usage(`--surface: invalid \`match-frontmatter\`: ${JSON.stringify(matchFrontmatter)} (expected a field→matcher object)`);
|
|
437
436
|
}
|
|
438
437
|
}
|
|
439
|
-
if ((on === 'read' || on === 'memory-read' || on === 'command') && match === undefined && matchFrontmatter === undefined) {
|
|
438
|
+
if ((on === 'read' || on === 'memory-read' || on === 'command' || on === 'pre-command') && match === undefined && matchFrontmatter === undefined) {
|
|
440
439
|
throw usage(`--surface: a \`${on}\` entry requires \`match\`${on === 'read' ? ' or `match-frontmatter`' : ''}`);
|
|
441
440
|
}
|
|
442
441
|
const gate = rec['gate'];
|
|
@@ -709,13 +708,11 @@ export function applyExtensionChanges(frontmatter, sets, unsets) {
|
|
|
709
708
|
else
|
|
710
709
|
frontmatter['extensions'] = extensions;
|
|
711
710
|
}
|
|
712
|
-
// ---------------------------------------------------------------------------
|
|
713
711
|
// Help material shared by `write` and `edit`
|
|
714
712
|
//
|
|
715
713
|
// Single-sourced: both leaves compose these, so a wording fix lands on both.
|
|
716
714
|
// Anything exclusive to one leaf (creation rules on `write`, the rationale
|
|
717
715
|
// contract on `edit`) stays owned by that leaf.
|
|
718
|
-
// ---------------------------------------------------------------------------
|
|
719
716
|
/** The frontmatter-overlay flags, keyed by flag name, carrying the prose true
|
|
720
717
|
* on BOTH leaves. `write` appends its creation clauses with `withConstraint`;
|
|
721
718
|
* neither leaf restates the other's rules. */
|
|
@@ -768,7 +765,7 @@ export const FRONTMATTER_OVERLAY_PARAMS = {
|
|
|
768
765
|
'when-and-why-to-read': { kind: 'flag', name: 'when-and-why-to-read', type: 'string', required: false, constraint: 'ONE routing sentence: "When <circumstance>, this <kind> should be read because <broader downstream payoff>." WHY is the reader\u2019s payoff \u2014 the consequence they secure for their task by reading \u2014 NEVER the doc summary, its rule, or that rule reworded as an outcome (a benefit-shaped restatement still fails). Rendered verbatim as the preview.' },
|
|
769
766
|
'short-form': { kind: 'flag', name: 'short-form', type: 'string', required: false, constraint: 'Frontmatter short-form \u2014 a very abbreviated version of the content, the hook shown in `crtr memory list`.' },
|
|
770
767
|
'unlisted': { kind: 'flag', name: 'unlisted', type: 'bool', required: false, default: false, constraint: 'Suppress this doc from directory listings. Suppression only — explicit reads, [[links]], and surfaces entries still work.' },
|
|
771
|
-
'surface': { kind: 'flag', name: 'surface', type: 'string', required: false, repeatable: true, constraint: 'One routing entry per occurrence, as a YAML/JSON object `{on, at, match?, match-frontmatter?, gate?}`; the flag set replaces the document’s whole surfaces list. `on` is boot|workspace-open|read|memory-read|command; `at` is name|preview|content. `match` holds the event’s globs — required on read/memory-read/command (a read entry may carry `match-frontmatter`, a predicate over the read file’s own frontmatter, instead), meaningless on boot/workspace-open. Optional entry `gate` is a node-config predicate using the same vocabulary as the document gate; its event constraints and gate both match before it participates. A `./`-anchored glob is relative: for `read` to the store’s owning repo dir, for `memory-read` to this doc’s routing anchor — its own canonical name when the doc is its directory’s document (`<dir>/INDEX.md`), otherwise the canonical directory it sits in. Participating entries fold to their highest `at`; there is no cross-entry deny precedence.' },
|
|
768
|
+
'surface': { kind: 'flag', name: 'surface', type: 'string', required: false, repeatable: true, constraint: 'One routing entry per occurrence, as a YAML/JSON object `{on, at, match?, match-frontmatter?, gate?}`; the flag set replaces the document’s whole surfaces list. `on` is boot|workspace-open|read|memory-read|command|pre-command; `at` is name|preview|content. `match` holds the event’s globs — required on read/memory-read/command/pre-command (a read entry may carry `match-frontmatter`, a predicate over the read file’s own frontmatter, instead), meaningless on boot/workspace-open. Optional entry `gate` is a node-config predicate using the same vocabulary as the document gate; its event constraints and gate both match before it participates. A `./`-anchored glob is relative: for `read` to the store’s owning repo dir, for `memory-read` to this doc’s routing anchor — its own canonical name when the doc is its directory’s document (`<dir>/INDEX.md`), otherwise the canonical directory it sits in. Participating entries fold to their highest `at`; there is no cross-entry deny precedence.' },
|
|
772
769
|
'gate': { kind: 'flag', name: 'gate', type: 'string', required: false, constraint: 'Frontmatter gate \u2014 YAML/JSON object predicate over node config using the same field/matcher vocabulary described in the guide.' },
|
|
773
770
|
'slash': { kind: 'flag', name: 'slash', type: 'bool', required: false, default: false, constraint: 'Presence flags this doc invocable as a pi slash command (`/<name>`, `/` in a nested name rendered as `:`) \u2014 the doc body becomes the command\u2019s injected prompt. Default false: most docs are consulted, not invoked.' },
|
|
774
771
|
};
|
|
@@ -786,7 +783,7 @@ export function overlayParam(name, overrides = {}, extraConstraint) {
|
|
|
786
783
|
* `--doc-rationale`, because `--rationale` there means why THIS REVISION is
|
|
787
784
|
* happening. Same field, same prose, two flag names that cannot be confused. */
|
|
788
785
|
export const DOC_RATIONALE_CONSTRAINT = 'Frontmatter rationale \u2014 the observed agent failure that made this doc necessary. Maintainer-facing only: never ships in any delivered surface (boot render, on-read injection, `memory read` content), visible only via `memory read --frontmatter`. Omitting the flag preserves an existing rationale unchanged.';
|
|
789
|
-
export const GUIDE_SURFACES = 'Every doc appears in its directory’s listing by default (suppress with --unlisted); everything beyond the listing is explicit `surfaces` routing — entries declaring WHEN the doc delivers and how much. Events: `boot` delivers in the boot catalog every agent sees; `workspace-open` delivers in first-message context when cwd/profile mounts the doc’s project store (project stores only); `read` fires when the agent reads a matching file (globs vs the file’s absolute path and basename, `./`-anchored globs vs its path relative to the store’s owning repo dir, `match-frontmatter` predicates over the read file’s own YAML frontmatter); `memory-read` fires when another memory doc is read (globs vs that doc’s canonical name, `./` anchored to this doc’s routing anchor — its own canonical name when it is its directory’s document, otherwise the canonical directory it sits in); `command` fires when a matching shell command runs (globs vs each shell segment of the command line — split on `&&`/`||`/`;`/`|`/newlines outside quotes, leading `VAR=value` assignments dropped — where `*` spans whole whitespace-separated tokens and never part of one, `?` is one character inside a token, and quoted argument text is opaque, so `*git commit*` fires for `cd x && git commit -m "…"` but not for `git commit-tree` or an `echo` that merely mentions it). An entry may also carry `gate`, a node-config predicate using the same vocabulary as the document-level `gate`: event constraints and entry gate both must match, then all participating entries fold to the highest `at` (`content` > `preview` > `name`), with no cross-entry deny precedence. The document-level `gate` remains the hard eligibility check: when it fails, no automatic surface can deliver the document. `at` sets how much delivers: `name` the bare tag, `preview` the routing line, `content` the whole body. Explicit `memory read` and listings remain deliberate access and ignore gates/rungs; only companion docs routed by their `memory-read` entries use entry gates. Each entry is paid by every future agent it fires on, so default down: no surfaces at all is correct for reference depth reached through listings and [[links]], and when a doc fits in a single sentence, deliver `content` directly — a `preview` routing line would run longer than the doc itself. Sentence-length `content` docs are correct; never pad a memory to be more verbose than the rule or fact it carries.';
|
|
786
|
+
export const GUIDE_SURFACES = 'Every doc appears in its directory’s listing by default (suppress with --unlisted); everything beyond the listing is explicit `surfaces` routing — entries declaring WHEN the doc delivers and how much. Events: `boot` delivers in the boot catalog every agent sees; `workspace-open` delivers in first-message context when cwd/profile mounts the doc’s project store (project stores only); `read` fires when the agent reads a matching file (globs vs the file’s absolute path and basename, `./`-anchored globs vs its path relative to the store’s owning repo dir, `match-frontmatter` predicates over the read file’s own YAML frontmatter); `memory-read` fires when another memory doc is read (globs vs that doc’s canonical name, `./` anchored to this doc’s routing anchor — its own canonical name when it is its directory’s document, otherwise the canonical directory it sits in); `command` fires when a matching shell command runs (globs vs each shell segment of the command line — split on `&&`/`||`/`;`/`|`/newlines outside quotes, leading `VAR=value` assignments dropped — where `*` spans whole whitespace-separated tokens and never part of one, `?` is one character inside a token, and quoted argument text is opaque, so `*git commit*` fires for `cd x && git commit -m "…"` but not for `git commit-tree` or an `echo` that merely mentions it); `pre-command` fires BEFORE a matching bash command runs (same matching): when the memory has not been read yet, the command does not execute — the memory comes back as the tool result instead, and the agent re-issues the command, which then runs. Use it to guarantee a memory is seen before a sensitive action is taken. Requires `match`. An entry may also carry `gate`, a node-config predicate using the same vocabulary as the document-level `gate`: event constraints and entry gate both must match, then all participating entries fold to the highest `at` (`content` > `preview` > `name`), with no cross-entry deny precedence. The document-level `gate` remains the hard eligibility check: when it fails, no automatic surface can deliver the document. `at` sets how much delivers: `name` the bare tag, `preview` the routing line, `content` the whole body. Explicit `memory read` and listings remain deliberate access and ignore gates/rungs; only companion docs routed by their `memory-read` entries use entry gates. Each entry is paid by every future agent it fires on, so default down: no surfaces at all is correct for reference depth reached through listings and [[links]], and when a doc fits in a single sentence, deliver `content` directly — a `preview` routing line would run longer than the doc itself. Sentence-length `content` docs are correct; never pad a memory to be more verbose than the rule or fact it carries.';
|
|
790
787
|
export const GUIDE_ROUTING_LINE = 'The routing line (--when-and-why-to-read) is the only text an agent reads before deciding to load the doc. The test for its when-clause: it names an observable circumstance in the reader\u2019s current work, not the doc\u2019s topic reworded as an activity. If the WHEN can be inferred from the title alone, it is not a real trigger. Bad on a todo list: "When planning or prioritizing work across this profile." Good: "When the user mentions something from their todos, or asks what is still outstanding across this profile." The test for its because-clause: if it can be derived by paraphrasing the doc\u2019s advice, it is a restatement, not a payoff \u2014 a real payoff names a consequence in the reader\u2019s world that the document itself never asserts. Bad: "because only genuine first principles belong in taste memory." Bad: "because keeping the test loop fast and free of speculative tests protects the development pace" \u2014 the doc\u2019s rule as an outcome, derivable straight from its advice. Good: "because identifying throughlines in user taste lets future decisions be made faster and with less re-litigation." Someone mid-task who has not read the doc must be able to decide from this line alone whether the read is worth it. If you cannot name the concrete situation that triggers it, you do not yet understand the memory \u2014 ask the user one sharp question instead of improvising.';
|
|
791
788
|
export const GUIDE_PREDICATE_VOCABULARY = 'Document gates, surface-entry gates, and match-frontmatter share the same predicate language: a field map is AND-ed across fields; dotted fields resolve nested values; field matchers may be scalar, array, or object. Scalar matchers do exact equality, with arrays matching any element. Array matchers do membership or intersection. Object matchers accept `eq`, `ne`, `in`, `nin`, `exists`, `contains`, `containsAll`, `containsAny`, `matches`, `imatches`, `gt`, `gte`, `lt`, and `lte`. Combinators are `all`, `any`, and `not`; sibling field matchers next to them are AND-ed in. An empty condition is inert. An unknown op never matches.';
|
|
792
789
|
export const GUIDE_DOC_LINKS = 'Link related docs with `[[canonical/name]]`. A doc link in any body is a first-class cross-reference to another memory document by its exact canonical name \u2014 the same identifier `crtr memory read` takes, namespace included for a project document. A bare directory name is a valid link too: following it returns that directory\u2019s own document when it has one, plus the directory listing. Links are pointers, never transclusion: the linked body is loaded only when a reader follows it, so a link costs nothing until needed. `crtr memory lint` fails on a link that resolves to no document or directory, and `crtr memory read` lists a doc\u2019s resolvable links alongside its body. There is no alias, label, or old-name form \u2014 a renamed target needs its links rewritten.';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { envNodeId, envProfileId } from '../../shared/env.js';
|
|
1
2
|
import { join } from 'node:path';
|
|
2
3
|
import { defineLeaf } from '../../core/command.js';
|
|
3
4
|
import { usage } from '../../core/errors.js';
|
|
@@ -188,14 +189,14 @@ export const writeLeaf = defineLeaf({
|
|
|
188
189
|
? {
|
|
189
190
|
resolvable: resolvableCanonicalNames(loadMemoryTargetView({
|
|
190
191
|
cwd: store.ownerDir ?? process.cwd(),
|
|
191
|
-
profileId:
|
|
192
|
-
nodeId:
|
|
192
|
+
profileId: envProfileId() || null,
|
|
193
|
+
nodeId: envNodeId() || null,
|
|
193
194
|
}, { quiet: true, includeDescendants: true }).docs),
|
|
194
195
|
}
|
|
195
196
|
: {}),
|
|
196
197
|
...(carriesBootEntry
|
|
197
198
|
? {
|
|
198
|
-
nestedStore: descendantStoreRoots(projectScopeRoots(process.cwd(),
|
|
199
|
+
nestedStore: descendantStoreRoots(projectScopeRoots(process.cwd(), envProfileId() || null))
|
|
199
200
|
.map((root) => realpathOrSelf(join(root, 'memory')))
|
|
200
201
|
.includes(realpathOrSelf(memoryDir)),
|
|
201
202
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// `crtr node bash` — file-backed background job controls.
|
|
2
|
+
import { envNodeId } from '../../shared/env.js';
|
|
2
3
|
import { defineBranch, defineLeaf } from '../../core/command.js';
|
|
3
4
|
import { InputError } from '../../core/io.js';
|
|
4
5
|
import { displayMessage } from '../../core/runtime/tmux-chrome.js';
|
|
@@ -12,7 +13,7 @@ function resolveBashTarget(input, missingMessage) {
|
|
|
12
13
|
if (id === undefined || id === '')
|
|
13
14
|
id = nodeInPane(pane);
|
|
14
15
|
if (id === undefined || id === '')
|
|
15
|
-
id =
|
|
16
|
+
id = envNodeId();
|
|
16
17
|
if (id === undefined || id === '') {
|
|
17
18
|
throw new InputError({ error: 'no_node', message: missingMessage, next: 'Run from inside a node, pass --node <id>, or --pane <pane>.' });
|
|
18
19
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// `crtr node new` — creation commands and persona-kind helpers.
|
|
2
|
+
import { envNodeId } from '../../shared/env.js';
|
|
2
3
|
import { defineLeaf } from '../../core/command.js';
|
|
3
4
|
import { InputError } from '../../core/io.js';
|
|
4
5
|
import { mark } from '../../core/timing.js';
|
|
@@ -207,7 +208,7 @@ async function runNodeCreation(input) {
|
|
|
207
208
|
if (noKickoff && mode === 'orchestrator') {
|
|
208
209
|
throw new InputError({ 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.' });
|
|
209
210
|
}
|
|
210
|
-
const parentId = parent ??
|
|
211
|
+
const parentId = parent ?? envNodeId();
|
|
211
212
|
mark('node_new.create_start', { root });
|
|
212
213
|
const detail = await cliClient().createNode({
|
|
213
214
|
...(kind !== undefined ? { kind } : {}),
|
|
@@ -89,9 +89,7 @@ const nodeList = defineLeaf({
|
|
|
89
89
|
return { nodes };
|
|
90
90
|
},
|
|
91
91
|
});
|
|
92
|
-
// ---------------------------------------------------------------------------
|
|
93
92
|
// node inspect show — a node + its place in the spine
|
|
94
|
-
// ---------------------------------------------------------------------------
|
|
95
93
|
// The renderer receives only the command result, while JSON output bypasses it.
|
|
96
94
|
// Keep remote provenance out of the returned DTO-shaped object without adding a
|
|
97
95
|
// second wire field or mutating the remote response.
|
|
@@ -233,9 +231,7 @@ const nodeShow = defineLeaf({
|
|
|
233
231
|
return parts.join('\n\n');
|
|
234
232
|
},
|
|
235
233
|
});
|
|
236
|
-
// ---------------------------------------------------------------------------
|
|
237
234
|
// node fork — branch a conversation + durable context into an idle root
|
|
238
|
-
// ---------------------------------------------------------------------------
|
|
239
235
|
export const nodeFork = defineLeaf({
|
|
240
236
|
name: 'fork',
|
|
241
237
|
description: 'fork a node into an independent idle root with the same conversation and durable context',
|
|
@@ -287,9 +283,7 @@ export const nodeFork = defineLeaf({
|
|
|
287
283
|
return `Forked independent idle root ${result['node_id']}.${placement} It will make no model call until its first real user message.`;
|
|
288
284
|
},
|
|
289
285
|
});
|
|
290
|
-
// ---------------------------------------------------------------------------
|
|
291
286
|
// node inspect — read the graph (list, show, context)
|
|
292
|
-
// ---------------------------------------------------------------------------
|
|
293
287
|
export const nodeInspect = defineBranch({
|
|
294
288
|
name: 'inspect',
|
|
295
289
|
description: 'read one node — its graph position, context, and artifacts',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// `crtr node` lifecycle and durable configuration commands.
|
|
2
|
+
import { envNodeId } from '../../shared/env.js';
|
|
2
3
|
import { defineBranch, defineLeaf } from '../../core/command.js';
|
|
3
4
|
import { InputError } from '../../core/io.js';
|
|
4
5
|
import { cliClient, getNodeOrNull, rethrowAsCliError } from '../api-client.js';
|
|
@@ -65,9 +66,7 @@ const nodeRecycle = defineLeaf({
|
|
|
65
66
|
return lines.join('\n');
|
|
66
67
|
},
|
|
67
68
|
});
|
|
68
|
-
// ---------------------------------------------------------------------------
|
|
69
69
|
// node lifecycle close — close a node + cascade-cancel its exclusive subtree (Alt+C → x)
|
|
70
|
-
// ---------------------------------------------------------------------------
|
|
71
70
|
const nodeClose = defineLeaf({
|
|
72
71
|
name: 'close',
|
|
73
72
|
description: 'close a node + cascade-cancel its exclusive subtree (revivable)',
|
|
@@ -110,9 +109,7 @@ const nodeClose = defineLeaf({
|
|
|
110
109
|
return `Closed ${r['node_id']} and its exclusive subtree — ${r['count']} node(s) closed${spared > 0 ? `, ${spared} spared (still managed from outside the subtree)` : ''}.`;
|
|
111
110
|
},
|
|
112
111
|
});
|
|
113
|
-
// ---------------------------------------------------------------------------
|
|
114
112
|
// node config — reconfigure a node's settings headlessly (model/lifecycle/kind/mode/name)
|
|
115
|
-
// ---------------------------------------------------------------------------
|
|
116
113
|
const NODE_CONFIG_MODEL_EFFECT = '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.';
|
|
117
114
|
export const nodeConfig = defineLeaf({
|
|
118
115
|
name: 'config',
|
|
@@ -268,7 +265,7 @@ export const nodePromote = defineLeaf({
|
|
|
268
265
|
effects: ['Flips mode→orchestrator + kind→chosen (lifecycle unchanged unless --resident, which also flips lifecycle→resident); --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.'],
|
|
269
266
|
},
|
|
270
267
|
run: async (input) => {
|
|
271
|
-
const id = input['node'] ??
|
|
268
|
+
const id = input['node'] ?? envNodeId();
|
|
272
269
|
if (id === undefined || id === '')
|
|
273
270
|
throw new InputError({ 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>.' });
|
|
274
271
|
const kind = input['kind'];
|
|
@@ -300,7 +297,7 @@ async function resolveLifecycleNode(input, pane) {
|
|
|
300
297
|
if (id === undefined || id === '')
|
|
301
298
|
id = nodeInPane(pane);
|
|
302
299
|
if (id === undefined || id === '')
|
|
303
|
-
id =
|
|
300
|
+
id = envNodeId();
|
|
304
301
|
if (id === undefined || id === '')
|
|
305
302
|
throw new InputError({ 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>.' });
|
|
306
303
|
const exists = await getNodeOrNull(id);
|
|
@@ -308,13 +305,11 @@ async function resolveLifecycleNode(input, pane) {
|
|
|
308
305
|
throw new InputError({ error: 'not_found', message: `no node: ${id}`, next: 'List nodes with `crtr node inspect list`.' });
|
|
309
306
|
return id;
|
|
310
307
|
}
|
|
311
|
-
// ---------------------------------------------------------------------------
|
|
312
308
|
// node lifecycle demote — flip a node to TERMINAL in place (the friendly half
|
|
313
309
|
// of the promote/demote pair; bound to Alt+C → d, and → D with --detach). It
|
|
314
310
|
// stays focused and running but now owes a final up the spine. `node config
|
|
315
311
|
// --lifecycle` remains the orthogonal low-level command (it also does resident).
|
|
316
312
|
// See vision F5.
|
|
317
|
-
// ---------------------------------------------------------------------------
|
|
318
313
|
const nodeDemote = defineLeaf({
|
|
319
314
|
name: 'demote',
|
|
320
315
|
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)',
|
|
@@ -352,9 +347,7 @@ const nodeDemote = defineLeaf({
|
|
|
352
347
|
},
|
|
353
348
|
render: (r) => `Demoted ${r['node_id']} — lifecycle now terminal (in place)${r['detached'] === true ? ', viewer closed (broker still running off-screen)' : ''}.`,
|
|
354
349
|
});
|
|
355
|
-
// ---------------------------------------------------------------------------
|
|
356
350
|
// node lifecycle — recycle, close, or demote a node
|
|
357
|
-
// ---------------------------------------------------------------------------
|
|
358
351
|
export const nodeLifecycle = defineBranch({
|
|
359
352
|
name: 'lifecycle',
|
|
360
353
|
description: 'lifecycle actions — recycle, close, demote, or revive a node',
|
|
@@ -365,9 +358,7 @@ export const nodeLifecycle = defineBranch({
|
|
|
365
358
|
},
|
|
366
359
|
children: [nodeRecycle, nodeClose, nodeDemote, nodeReviveLeaf],
|
|
367
360
|
});
|
|
368
|
-
// ---------------------------------------------------------------------------
|
|
369
361
|
// node yield — refresh: discard context, revive fresh in the same mode against roadmap or goal
|
|
370
|
-
// ---------------------------------------------------------------------------
|
|
371
362
|
export const nodeYield = defineLeaf({
|
|
372
363
|
name: 'yield',
|
|
373
364
|
description: 'refresh your context, same mode, against your roadmap or goal',
|
|
@@ -395,7 +386,7 @@ export const nodeYield = defineLeaf({
|
|
|
395
386
|
effects: ['The stophook shuts the process down on next stop and the daemon revives it fresh.', '--kind and/or --model durably reshape the node (kind respecialization, model-tier pin) before the refresh-revive; --promote additionally flips mode→orchestrator and seeds a roadmap scaffold — mode is otherwise left exactly as it was.'],
|
|
396
387
|
},
|
|
397
388
|
run: async (input) => {
|
|
398
|
-
const id =
|
|
389
|
+
const id = envNodeId();
|
|
399
390
|
if (id === undefined || id === '')
|
|
400
391
|
throw new InputError({ error: 'no_node', message: 'no node to yield (CRTR_NODE_ID unset)', next: 'Run from inside a node.' });
|
|
401
392
|
const kind = input['kind'];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// `crtr node message` — immediate inbox delivery and typed-output requests.
|
|
2
|
+
import { envNodeId } from '../../shared/env.js';
|
|
2
3
|
import { defineBranch, defineLeaf } from '../../core/command.js';
|
|
3
4
|
import { InputError } from '../../core/io.js';
|
|
4
5
|
import { OUTPUT_SCHEMA_CONSTRAINTS, OUTPUT_SCHEMA_TRANSPORT, parseOutputSchemaValue } from '../../core/runtime/structured-output.js';
|
|
@@ -22,7 +23,7 @@ async function resolveMsgTarget(input) {
|
|
|
22
23
|
});
|
|
23
24
|
}
|
|
24
25
|
if (self) {
|
|
25
|
-
const id =
|
|
26
|
+
const id = envNodeId();
|
|
26
27
|
if (id === undefined || id === '') {
|
|
27
28
|
throw new InputError({ error: 'no_node', message: 'no node to target with --self (CRTR_NODE_ID unset)', next: 'Run from inside a node, or pass --to <node-id>.' });
|
|
28
29
|
}
|
|
@@ -80,7 +81,7 @@ async function runMessageEngine(input) {
|
|
|
80
81
|
if (outputSchema !== null && tierRaw === 'deferred') {
|
|
81
82
|
throw new InputError({ error: 'output_schema_deferred_tier', message: '--output-schema cannot combine with --tier deferred because the target must answer', field: 'tier', next: 'Use normal, urgent, or critical tier, or drop --output-schema.' });
|
|
82
83
|
}
|
|
83
|
-
const senderFrom =
|
|
84
|
+
const senderFrom = envNodeId();
|
|
84
85
|
const client = cliClient();
|
|
85
86
|
if (!hasBody && !hasSituational && outputSchema === null) {
|
|
86
87
|
throw new InputError({ error: 'empty_body', message: 'a message body is required unless --output-schema or --situational-context is supplied', field: 'body', next: 'Pass the message on stdin, or supply one of the documented alternatives.' });
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// `crtr node subscription` — push-delivery edge controls.
|
|
2
|
+
import { envNodeId } from '../../shared/env.js';
|
|
2
3
|
import { defineBranch, defineLeaf } from '../../core/command.js';
|
|
3
4
|
import { InputError } from '../../core/io.js';
|
|
4
5
|
import { cliClient, rethrowAsCliError } from '../api-client.js';
|
|
5
6
|
function resolveSubscriber(input) {
|
|
6
|
-
const sub = input['subscriber'] ??
|
|
7
|
+
const sub = input['subscriber'] ?? envNodeId();
|
|
7
8
|
if (sub === undefined || sub === '') {
|
|
8
9
|
throw new InputError({ error: 'no_subscriber', message: 'no subscriber (set CRTR_NODE_ID or pass --subscriber)', field: 'subscriber', next: 'Run from inside a node, or pass --subscriber <id>.' });
|
|
9
10
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// `crtr node wait` — durable controller and deadline waits.
|
|
2
|
+
import { envNodeId, envProfileId } from '../../shared/env.js';
|
|
2
3
|
import { defineBranch, defineLeaf } from '../../core/command.js';
|
|
3
4
|
import { InputError } from '../../core/io.js';
|
|
4
5
|
import { parseWhen } from '../../core/wake.js';
|
|
5
6
|
import { cliClient, getNodeOrNull, rethrowAsCliError } from '../api-client.js';
|
|
6
7
|
import { shellQuote } from '../surface/node/placement.js';
|
|
7
8
|
function armerId() {
|
|
8
|
-
const id =
|
|
9
|
+
const id = envNodeId();
|
|
9
10
|
if (id === undefined || id === '') {
|
|
10
11
|
throw new InputError({ error: 'no_node', message: 'no node to anchor a deadline cron (CRTR_NODE_ID unset)', next: 'Run from inside a node.' });
|
|
11
12
|
}
|
|
@@ -84,7 +85,7 @@ const nodeWaitDeadline = defineLeaf({
|
|
|
84
85
|
const parsed = parseWhen(until, parseOpts(now, tz));
|
|
85
86
|
if ('error' in parsed)
|
|
86
87
|
throwTimeError(parsed.error);
|
|
87
|
-
const profile =
|
|
88
|
+
const profile = envProfileId();
|
|
88
89
|
// One deadline per node: the arm seam REPLACES this node's pending
|
|
89
90
|
// cancel-on-wake cron rather than stacking a second one (see armCron in
|
|
90
91
|
// core/canvas/crons.ts, where the invariant is enforced for every caller).
|
|
@@ -129,7 +130,7 @@ const nodeWait = defineLeaf({
|
|
|
129
130
|
effects: ['Durably records the controller on this node. The stop guard permits dormancy only while that controller remains active or idle; its next inbox delivery clears the record before the delivery wakes this node.'],
|
|
130
131
|
},
|
|
131
132
|
run: async (input) => {
|
|
132
|
-
const nodeId =
|
|
133
|
+
const nodeId = envNodeId();
|
|
133
134
|
if (nodeId === undefined || nodeId === '')
|
|
134
135
|
throw new InputError({ error: 'no_node', message: 'no node to wait (CRTR_NODE_ID unset)', next: 'Run from inside the terminal node that is blocked.' });
|
|
135
136
|
const node = await getNodeOrNull(nodeId);
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
// and the on-disk existence filter is a local fs read (neither touches canvas
|
|
18
18
|
// state). The /context popup (src/pi-extensions/canvas-context.ts) shells this
|
|
19
19
|
// leaf inside a tmux display-popup. Piped / non-TTY it prints the roster.
|
|
20
|
+
import { envNodeId } from '../shared/env.js';
|
|
20
21
|
import { spawnSync } from 'node:child_process';
|
|
21
22
|
import { existsSync, mkdirSync, mkdtempSync, rmSync, symlinkSync } from 'node:fs';
|
|
22
23
|
import { tmpdir } from 'node:os';
|
|
@@ -106,7 +107,7 @@ export const nodeContextLeaf = defineLeaf({
|
|
|
106
107
|
],
|
|
107
108
|
},
|
|
108
109
|
run: async (input) => {
|
|
109
|
-
const selfId = input['node']?.trim() ||
|
|
110
|
+
const selfId = input['node']?.trim() || envNodeId();
|
|
110
111
|
if (selfId === undefined || selfId === '') {
|
|
111
112
|
throw new InputError({
|
|
112
113
|
error: 'no_node',
|
|
@@ -52,9 +52,7 @@ export function isNowEligibleFault(fault) {
|
|
|
52
52
|
return true;
|
|
53
53
|
return fault.retry.by === 'daemon';
|
|
54
54
|
}
|
|
55
|
-
// ---------------------------------------------------------------------------
|
|
56
55
|
// Local, db-free helpers (inlined so the leaf never imports the canvas barrel)
|
|
57
|
-
// ---------------------------------------------------------------------------
|
|
58
56
|
/** Inlined from `runtime/busy.ts` (which reaches the canvas barrel via `jobDir`):
|
|
59
57
|
* is the node mid-turn right now? `<jobDir>/busy` exists for the span pi is
|
|
60
58
|
* inside a run. `jobDir` here is the pure path helper from paths.js. */
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
// `node new --worktree <base>`; this branch holds the single close
|
|
3
3
|
// verb, symmetric with birth, so a git worktree's whole lifecycle sits under
|
|
4
4
|
// `node`.
|
|
5
|
+
import { envNodeId } from '../shared/env.js';
|
|
5
6
|
import { defineBranch, defineLeaf } from '../core/command.js';
|
|
6
7
|
import { InputError } from '../core/io.js';
|
|
7
8
|
import { ApiError } from '../api/index.js';
|
|
8
9
|
import { cliClient } from './api-client.js';
|
|
9
10
|
function requireCallerNode() {
|
|
10
|
-
const id =
|
|
11
|
+
const id = envNodeId();
|
|
11
12
|
if (id === undefined || id.trim() === '') {
|
|
12
13
|
throw new InputError({
|
|
13
14
|
error: 'no_node_context',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ActionPresentation, ActionRequest, ActionOutcome } from
|
|
1
|
+
import type { ActionPresentation, ActionRequest, ActionOutcome } from './model.js';
|
|
2
2
|
/** How an action reads before it runs — and whether it needs confirming. */
|
|
3
3
|
export declare function presentAction(request: ActionRequest): ActionPresentation;
|
|
4
4
|
/** Actions available for a request's subject right now, in offer order. */
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Mutations for `crtr pkg browse`. Each action delegates to the same leaf the
|
|
2
2
|
// CLI runs, so the browser and `crtr pkg …` can never drift.
|
|
3
|
-
import { marketAdd, marketRemove, marketUpdate } from
|
|
4
|
-
import { pluginDisable, pluginEnable, pluginInstall, pluginRemove, pluginUpdate, } from
|
|
5
|
-
import { listAllMarketplaces } from
|
|
6
|
-
import { projectScopeRoot } from
|
|
3
|
+
import { marketAdd, marketRemove, marketUpdate } from '../market-manage.js';
|
|
4
|
+
import { pluginDisable, pluginEnable, pluginInstall, pluginRemove, pluginUpdate, } from '../plugin-manage.js';
|
|
5
|
+
import { listAllMarketplaces } from '../../../core/resolver.js';
|
|
6
|
+
import { projectScopeRoot } from '../../../core/scope.js';
|
|
7
7
|
function pluginName(request) {
|
|
8
8
|
return request.entry?.name ?? "plugin";
|
|
9
9
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Catalog, type PluginCapability, type PluginEntry } from
|
|
1
|
+
import { type Catalog, type PluginCapability, type PluginEntry } from './model.js';
|
|
2
2
|
/** Every rail source with its rows: the installed library first, then each
|
|
3
3
|
* registered marketplace. Called on open and after any action that could
|
|
4
4
|
* change install state. Must never throw for a broken marketplace — record it
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
// Catalog reads for `crtr pkg browse`. Everything here is read-only; mutations
|
|
2
2
|
// live in actions.ts.
|
|
3
|
-
import { statSync } from
|
|
4
|
-
import { isAbsolute, join } from
|
|
5
|
-
import { SUBTREE_NAMES, coreCommandPaths } from
|
|
6
|
-
import { discoverPluginCommandCandidates, validateEffectiveCommandPlugins, validatePluginCommands } from
|
|
7
|
-
import { qualifiedTopLevelCommandName } from
|
|
8
|
-
import { listDirs, pathExists, walkFiles } from
|
|
9
|
-
import { currentSha, gitSync } from
|
|
10
|
-
import { listPluginMemoryDocs } from
|
|
11
|
-
import { memoryExtensionEffectiveCatalog, projectEffectiveMemoryExtensions } from
|
|
12
|
-
import { readMarketplaceManifest, readPluginManifest } from
|
|
13
|
-
import { readConfig } from
|
|
14
|
-
import { parseSubstrateDoc } from
|
|
15
|
-
import { projectScopeRoot, userScopeRoot } from
|
|
16
|
-
import { isGitUrl } from
|
|
17
|
-
import { INSTALLED_SOURCE_ID, marketplaceSourceId, } from
|
|
3
|
+
import { statSync } from 'node:fs';
|
|
4
|
+
import { isAbsolute, join } from 'node:path';
|
|
5
|
+
import { SUBTREE_NAMES, coreCommandPaths } from '../../../build-root.js';
|
|
6
|
+
import { discoverPluginCommandCandidates, validateEffectiveCommandPlugins, validatePluginCommands } from '../../../core/command-plugins/discovery.js';
|
|
7
|
+
import { qualifiedTopLevelCommandName } from '../../../core/command-manifests/registry.js';
|
|
8
|
+
import { listDirs, pathExists, walkFiles } from '../../../core/fs-utils.js';
|
|
9
|
+
import { currentSha, gitSync } from '../../../core/git.js';
|
|
10
|
+
import { listPluginMemoryDocs } from '../../../core/memory-resolver.js';
|
|
11
|
+
import { memoryExtensionEffectiveCatalog, projectEffectiveMemoryExtensions } from '../../../core/memory/extensions.js';
|
|
12
|
+
import { readMarketplaceManifest, readPluginManifest } from '../../../core/manifest.js';
|
|
13
|
+
import { readConfig } from '../../../core/config.js';
|
|
14
|
+
import { parseSubstrateDoc } from '../../../core/substrate/schema.js';
|
|
15
|
+
import { projectScopeRoot, userScopeRoot } from '../../../core/scope.js';
|
|
16
|
+
import { isGitUrl } from '../shared.js';
|
|
17
|
+
import { INSTALLED_SOURCE_ID, marketplaceSourceId, } from './model.js';
|
|
18
18
|
function parseSemver(version) {
|
|
19
19
|
const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z.-]+)?$/.exec(version);
|
|
20
20
|
return match === null
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { CommandNode, PluginCapability } from
|
|
1
|
+
import type { CommandNode, PluginCapability } from './model.js';
|
|
2
2
|
/** Every line of one command's contract view, wrapped to `width`. */
|
|
3
3
|
export declare function renderCommandView(node: CommandNode, capability: PluginCapability, width: number): string[];
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
//
|
|
4
4
|
// Pure rendering. It returns styled lines already wrapped to `width`; the
|
|
5
5
|
// dossier owns scrolling and never truncates what comes back.
|
|
6
|
-
import { visibleWidth, wrapTextWithAnsi } from
|
|
7
|
-
import { theme, wrapText } from
|
|
8
|
-
import { commandLabel } from
|
|
6
|
+
import { visibleWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';
|
|
7
|
+
import { theme, wrapText } from '../../../core/tui/panel.js';
|
|
8
|
+
import { commandLabel } from './model.js';
|
|
9
9
|
/** Every line of one command's contract view, wrapped to `width`. */
|
|
10
10
|
export function renderCommandView(node, capability, width) {
|
|
11
11
|
const out = [];
|