@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
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// The reader-side surface for every environment variable crouter reads back
|
|
2
|
+
// out of `process.env`, outside `core/runtime/spawn-env.ts`'s writer
|
|
3
|
+
// allowlist. That module documents what a broker child is ADMITTED to see;
|
|
4
|
+
// this one documents what crouter itself reads. Two families:
|
|
5
|
+
//
|
|
6
|
+
// - Identity: raw passthrough (`string | undefined`, exactly what
|
|
7
|
+
// `process.env[name]` returns). Every existing call site keeps its own
|
|
8
|
+
// established fallback (`?? ''`, `|| null`, `?? cfg.cwd`, a presence
|
|
9
|
+
// check, ...) — the fallback has always been call-site-owned, not
|
|
10
|
+
// var-owned, so centralizing it here would be a behavior change, not a
|
|
11
|
+
// dedup. `CRTR_HOME` also has a resolved-path accessor, `crtrHome()` in
|
|
12
|
+
// `core/canvas/paths.ts`; that stays the canonical way to get the
|
|
13
|
+
// resolved canvas home; `envHomeOverride()` here is for the handful of
|
|
14
|
+
// sites that want the raw override value itself (to check presence or
|
|
15
|
+
// propagate it verbatim to a child env).
|
|
16
|
+
//
|
|
17
|
+
// - Tuning: parsed, with the default baked into the accessor. Each of
|
|
18
|
+
// these had exactly one parse site before this module existed; the
|
|
19
|
+
// parse logic moved here unchanged so a second site, if one appears,
|
|
20
|
+
// reads the single implementation instead of re-deriving it.
|
|
21
|
+
//
|
|
22
|
+
// `CRTR_DIR_NAME` is NOT here — it is a plain exported string constant
|
|
23
|
+
// (`types.ts`), never read off `process.env`.
|
|
24
|
+
// Identity
|
|
25
|
+
/** The current node's id (`CRTR_NODE_ID`), or undefined outside a node. */
|
|
26
|
+
export function envNodeId() {
|
|
27
|
+
return process.env['CRTR_NODE_ID'];
|
|
28
|
+
}
|
|
29
|
+
/** The current node's target profile id (`CRTR_PROFILE_ID`), or undefined. */
|
|
30
|
+
export function envProfileId() {
|
|
31
|
+
return process.env['CRTR_PROFILE_ID'];
|
|
32
|
+
}
|
|
33
|
+
/** The current node's working directory (`CRTR_NODE_CWD`), or undefined. */
|
|
34
|
+
export function envNodeCwd() {
|
|
35
|
+
return process.env['CRTR_NODE_CWD'];
|
|
36
|
+
}
|
|
37
|
+
/** An explicit model-routing override for this turn (`CRTR_MODEL_INTENT`), or
|
|
38
|
+
* undefined. Cleared (not read) via `delete process.env['CRTR_MODEL_INTENT']`
|
|
39
|
+
* in `runtime/broker.ts` — a mutation, not a read, so it stays there. */
|
|
40
|
+
export function envModelIntent() {
|
|
41
|
+
return process.env['CRTR_MODEL_INTENT'];
|
|
42
|
+
}
|
|
43
|
+
/** The raw `CRTR_HOME` override, unresolved. Use `crtrHome()`
|
|
44
|
+
* (`core/canvas/paths.ts`) to get the resolved canvas-home path; use this
|
|
45
|
+
* only when a caller needs the override itself — to check whether one is
|
|
46
|
+
* set, or to propagate it verbatim into a child process's env. */
|
|
47
|
+
export function envHomeOverride() {
|
|
48
|
+
return process.env['CRTR_HOME'];
|
|
49
|
+
}
|
|
50
|
+
// Tuning
|
|
51
|
+
/** Generic `Number(raw)` parse with a positive-finite guard, shared by every
|
|
52
|
+
* millisecond tuning var below (each previously reimplemented this locally,
|
|
53
|
+
* identically). */
|
|
54
|
+
function parsePositiveMs(raw, fallback) {
|
|
55
|
+
if (raw === undefined)
|
|
56
|
+
return fallback;
|
|
57
|
+
const n = Number(raw);
|
|
58
|
+
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
59
|
+
}
|
|
60
|
+
const DEFAULT_STREAM_WATCHDOG_MS = 5 * 60_000; // 5 minutes.
|
|
61
|
+
/** Dead-provider watchdog timeout (`CRTR_STREAM_WATCHDOG_MS`), 5 minutes by
|
|
62
|
+
* default. See `runtime/stream-watchdog.ts` for what it guards. */
|
|
63
|
+
export function envStreamWatchdogMs() {
|
|
64
|
+
return parsePositiveMs(process.env['CRTR_STREAM_WATCHDOG_MS'], DEFAULT_STREAM_WATCHDOG_MS);
|
|
65
|
+
}
|
|
66
|
+
const DEFAULT_WATCHER_TICK_MS = 800;
|
|
67
|
+
/** The canvas inbox watcher's poll tick (`CRTR_WATCHER_TICK_MS`). */
|
|
68
|
+
export function envWatcherTickMs() {
|
|
69
|
+
return parsePositiveMs(process.env['CRTR_WATCHER_TICK_MS'], DEFAULT_WATCHER_TICK_MS);
|
|
70
|
+
}
|
|
71
|
+
const DEFAULT_WATCHER_DEBOUNCE_MS = 1000;
|
|
72
|
+
/** The canvas inbox watcher's debounce window (`CRTR_WATCHER_DEBOUNCE_MS`). */
|
|
73
|
+
export function envWatcherDebounceMs() {
|
|
74
|
+
return parsePositiveMs(process.env['CRTR_WATCHER_DEBOUNCE_MS'], DEFAULT_WATCHER_DEBOUNCE_MS);
|
|
75
|
+
}
|
|
76
|
+
const DEFAULT_RECAP_IDLE_MS = 60_000;
|
|
77
|
+
/** No-new-message window before a recap is shown (`CRTR_RECAP_IDLE_MS`), 60s
|
|
78
|
+
* by default. */
|
|
79
|
+
export function envRecapIdleMs() {
|
|
80
|
+
return parsePositiveMs(process.env['CRTR_RECAP_IDLE_MS'], DEFAULT_RECAP_IDLE_MS);
|
|
81
|
+
}
|
|
82
|
+
/** Explicit recap-model override (`CRTR_RECAP_MODEL`), trimmed; undefined if
|
|
83
|
+
* unset or blank. */
|
|
84
|
+
export function envRecapModelOverride() {
|
|
85
|
+
const raw = process.env['CRTR_RECAP_MODEL'];
|
|
86
|
+
return raw !== undefined && raw.trim() !== '' ? raw.trim() : undefined;
|
|
87
|
+
}
|
|
88
|
+
const DEFAULT_BASH_VALVE_MS = 5 * 60 * 1000;
|
|
89
|
+
/** The bash safety-valve deadline (`CRTR_BASH_VALVE_MS`), 5 minutes by
|
|
90
|
+
* default; undocumented test-only override so the E2E valve check doesn't
|
|
91
|
+
* sleep 5 minutes. */
|
|
92
|
+
export function envBashValveMs() {
|
|
93
|
+
return parsePositiveMs(process.env['CRTR_BASH_VALVE_MS'], DEFAULT_BASH_VALVE_MS);
|
|
94
|
+
}
|
|
95
|
+
/** Explicit pidfile path override (`CRTR_PIDFILE`, tests only); undefined if
|
|
96
|
+
* unset or blank. */
|
|
97
|
+
export function envPidfileOverride() {
|
|
98
|
+
const raw = process.env['CRTR_PIDFILE'];
|
|
99
|
+
return raw !== undefined && raw !== '' ? raw : undefined;
|
|
100
|
+
}
|
|
101
|
+
const DEFAULT_BROKER_ENGINE = '@earendil-works/pi-coding-agent';
|
|
102
|
+
/** The broker engine module spec (`CRTR_BROKER_ENGINE`, the T11 test seam),
|
|
103
|
+
* defaulting to the real SDK. `runtime/host.ts` layers `inv.env` ahead of
|
|
104
|
+
* this (a launch-time override mirrored into the child's env, since
|
|
105
|
+
* spawn-env.ts's default-deny allowlist strips `CRTR_*` from ambient env). */
|
|
106
|
+
export function envBrokerEngine() {
|
|
107
|
+
return process.env['CRTR_BROKER_ENGINE'] ?? DEFAULT_BROKER_ENGINE;
|
|
108
|
+
}
|
|
109
|
+
/** Test-only pi-binary substitution (`CRTR_PI_BINARY`) so the integration
|
|
110
|
+
* harness can point a real `crtr node new` at a deterministic fake-pi
|
|
111
|
+
* vehicle. Undefined in production. */
|
|
112
|
+
export function envPiBinaryOverride() {
|
|
113
|
+
return process.env['CRTR_PI_BINARY'];
|
|
114
|
+
}
|
|
115
|
+
/** Whether implicit daemon autostart is suppressed for this invocation
|
|
116
|
+
* (`CRTR_NO_DAEMON_AUTOSTART=1`). */
|
|
117
|
+
export function envNoDaemonAutostart() {
|
|
118
|
+
return process.env['CRTR_NO_DAEMON_AUTOSTART'] === '1';
|
|
119
|
+
}
|
|
120
|
+
/** The `--tcp` fallback for crtrd's opt-in TCP listener (`CRTRD_TCP`), raw
|
|
121
|
+
* (`host:port` or undefined — absent means unix socket only). */
|
|
122
|
+
export function envCrtrdTcp() {
|
|
123
|
+
return process.env['CRTRD_TCP'];
|
|
124
|
+
}
|
|
125
|
+
/** Kill switch for the host-exports writer/pruner (`CRTR_NO_EXPORTS=1`). */
|
|
126
|
+
export function envNoExports() {
|
|
127
|
+
return process.env['CRTR_NO_EXPORTS'] === '1';
|
|
128
|
+
}
|
|
129
|
+
/** Verbose-diagnostics gate for otherwise-silent best-effort catches
|
|
130
|
+
* (`CRTR_DEBUG=1`). Distinct from `CRTR_DEBUG_PID_LIVENESS`
|
|
131
|
+
* (`core/canvas/pid.ts`), a different, unrelated var. */
|
|
132
|
+
export function envDebug() {
|
|
133
|
+
return process.env['CRTR_DEBUG'] === '1';
|
|
134
|
+
}
|
|
135
|
+
// Precedence — broker-supervision.ts's threshold/interval overrides. Each
|
|
136
|
+
// returns the raw parsed value with NO default: the caller (config for the
|
|
137
|
+
// thresholds, a hardcoded production constant for the intervals) supplies
|
|
138
|
+
// the default, and env wins over it when set. Undefined, unparseable, or
|
|
139
|
+
// non-positive all mean "no override" — the caller's own default applies.
|
|
140
|
+
function parsePositiveInteger(raw) {
|
|
141
|
+
if (raw === undefined || raw === '')
|
|
142
|
+
return undefined;
|
|
143
|
+
const n = Number(raw);
|
|
144
|
+
return Number.isSafeInteger(n) && n >= 1 ? n : undefined;
|
|
145
|
+
}
|
|
146
|
+
/** Live-broker automatic-revive cap override (`CRTR_MAX_LIVE_BROKERS`); wins
|
|
147
|
+
* over `readConfig('user').brokerThresholds.automaticReviveCap` when set. */
|
|
148
|
+
export function envMaxLiveBrokers() {
|
|
149
|
+
return parsePositiveInteger(process.env['CRTR_MAX_LIVE_BROKERS']);
|
|
150
|
+
}
|
|
151
|
+
/** Live-broker warning threshold override (`CRTR_WARN_LIVE_BROKERS`); wins
|
|
152
|
+
* over `readConfig('user').brokerThresholds.warning` when set. */
|
|
153
|
+
export function envWarnLiveBrokers() {
|
|
154
|
+
return parsePositiveInteger(process.env['CRTR_WARN_LIVE_BROKERS']);
|
|
155
|
+
}
|
|
156
|
+
function parsePositiveMsNoDefault(raw) {
|
|
157
|
+
if (raw === undefined)
|
|
158
|
+
return undefined;
|
|
159
|
+
const n = Number(raw);
|
|
160
|
+
return Number.isFinite(n) && n > 0 ? n : undefined;
|
|
161
|
+
}
|
|
162
|
+
/** Test-only unattended-park interval override (`CRTR_TEST_UNATTENDED_PARK_MS`),
|
|
163
|
+
* gated by `envNoDaemonAutostart()` at the call site; no production default. */
|
|
164
|
+
export function envTestUnattendedParkMs() {
|
|
165
|
+
return parsePositiveMsNoDefault(process.env['CRTR_TEST_UNATTENDED_PARK_MS']);
|
|
166
|
+
}
|
|
167
|
+
/** Test-only park-summary grace-period override
|
|
168
|
+
* (`CRTR_TEST_PARK_SUMMARY_GRACE_MS`); no production default. */
|
|
169
|
+
export function envTestParkSummaryGraceMs() {
|
|
170
|
+
return parsePositiveMsNoDefault(process.env['CRTR_TEST_PARK_SUMMARY_GRACE_MS']);
|
|
171
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/crouter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.234",
|
|
4
4
|
"description": "crtr — agent runtime with memory, plugins, and marketplaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -74,6 +74,8 @@
|
|
|
74
74
|
"typecheck:pi-packages": "npx tsc -p src/builtin-pi-packages/pi-crtr-extensions/tsconfig.json",
|
|
75
75
|
"test:build-output": "node scripts/build-concurrency-test.mjs",
|
|
76
76
|
"check:cli-no-canvas": "node scripts/check-cli-no-canvas.mjs",
|
|
77
|
+
"check:daemon-no-barrel": "node scripts/check-daemon-no-barrel.mjs",
|
|
78
|
+
"check:quote-style": "node scripts/check-quote-style.mjs",
|
|
77
79
|
"postinstall": "node scripts/postinstall.mjs",
|
|
78
80
|
"install-runtime": "node scripts/install-runtime.mjs",
|
|
79
81
|
"prepack": "node scripts/runtime-lock.mjs prepack",
|
package/runtime.lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/crouter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.234",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@north-light/crouter",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.234",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { type DashboardRow } from './render-source.js';
|
|
2
|
-
export * from './render-source.js';
|
|
3
|
-
/**
|
|
4
|
-
* Render the subscription sub-DAG rooted at `rootId` as an ASCII tree.
|
|
5
|
-
* The root is the first line (no connector prefix); children are indented.
|
|
6
|
-
*
|
|
7
|
-
* Each line: `<glyph> <name> [<kind>/<mode>] ctx <Nk>[ ⚑<asks>]`
|
|
8
|
-
*
|
|
9
|
-
* Returns a multi-line string (no trailing newline).
|
|
10
|
-
*/
|
|
11
|
-
export declare function renderTree(rootId: string): string;
|
|
12
|
-
/**
|
|
13
|
-
* Render all canvas roots as a forest. A root is a node with no subscribers
|
|
14
|
-
* (no one subscribes to it = it has no managers in the org chart).
|
|
15
|
-
*
|
|
16
|
-
* If there are no roots on the canvas, returns a placeholder string.
|
|
17
|
-
*/
|
|
18
|
-
export declare function renderForest(): string;
|
|
19
|
-
/** One row per node visible in the sub-DAG of `rootId` (including root). */
|
|
20
|
-
export declare function dashboardRows(rootId: string): DashboardRow[];
|
|
21
|
-
/**
|
|
22
|
-
* CHEAP boot builder — one row per node across the entire canvas, with only the
|
|
23
|
-
* fields that need no per-node meta/telemetry/session read. Two db queries total:
|
|
24
|
-
* `listNodes()` + `listFocuses()` (the focus set replaces per-node getFocusByNode
|
|
25
|
-
* calls). See {@link dashboardRowFromNodeRow} for the per-row projection, and
|
|
26
|
-
* {@link enrichRow}/{@link enrichRows}/{@link loadPreview} for the lazy fields.
|
|
27
|
-
*/
|
|
28
|
-
export declare function dashboardRowsAll(): DashboardRow[];
|
|
29
|
-
/** Fold the cheap-boot row's deferred fields in for ONE row: the full label
|
|
30
|
-
* (meta.description → fullName), ctx tokens (telemetry.json), and ⚑ asks. One
|
|
31
|
-
* meta read + one telemetry read + one ticket scan. Idempotent (no-op once enriched).
|
|
32
|
-
* For a batch, prefer {@link enrichRows} — it scans each cwd's ticket inbox once. */
|
|
33
|
-
export declare function enrichRow(row: DashboardRow): DashboardRow;
|
|
34
|
-
/** Batch {@link enrichRow}: enrich every not-yet-enriched row, scanning each
|
|
35
|
-
* distinct cwd's ticket inbox exactly ONCE (via `ticketCountsForNodes`) instead
|
|
36
|
-
* of per row. Use this for a whole viewport / the full forest; mutates each row in place. */
|
|
37
|
-
export declare function enrichRows(rows: DashboardRow[]): void;
|
|
38
|
-
/** Load the SELECTED row's preview text: the spawn `goal` (initial-prompt.md) plus
|
|
39
|
-
* the whole-conversation `prompts` and the `lastAssistant` reply — the latter two
|
|
40
|
-
* folded into ONE session-file read (see {@link readSessionParts}). Mutates the row
|
|
41
|
-
* in place; idempotent. Call only for the cursor row (and lazily/in-background to
|
|
42
|
-
* warm the prompt super-search corpus), never on the boot path. */
|
|
43
|
-
export declare function loadPreview(row: DashboardRow): DashboardRow;
|
|
44
|
-
/** {@link isStreaming} keyed by node id alone — hydrates the broker pid off the
|
|
45
|
-
* db row. The exported "is this node actively generating right now?" guard so a
|
|
46
|
-
* reap never nukes a node mid-first-turn before its output lands on disk. */
|
|
47
|
-
export declare function isNodeStreaming(nodeId: string): boolean;
|
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
// render.ts — the db-backed (sync, `openDb`) half of canvas rendering.
|
|
2
|
-
//
|
|
3
|
-
// Holds the SYNC renderers that read the local canvas.db directly
|
|
4
|
-
// (renderTree/renderForest/dashboardRows/dashboardRowsAll/enrichRow(s)/loadPreview
|
|
5
|
-
// /isNodeStreaming). The openDb-FREE `*FromSource` variants + every pure/disk
|
|
6
|
-
// helper they share live in ./render-source.ts; this module imports those helpers
|
|
7
|
-
// (one direction) and RE-EXPORTS the whole render-source module, so existing
|
|
8
|
-
// importers of `render.js` keep resolving both the sync and the FromSource APIs
|
|
9
|
-
// unchanged. A caller that must stay off openDb imports from ./render-source.js
|
|
10
|
-
// directly instead.
|
|
11
|
-
//
|
|
12
|
-
// `subscriptionsOf(nodeId)` returns the nodes a node subscribes to (its reports /
|
|
13
|
-
// children); walking it recursively walks DOWN the org chart.
|
|
14
|
-
import { getNode, listNodes, subscriptionsOf, view } from './canvas.js';
|
|
15
|
-
import { fullName } from './labels.js';
|
|
16
|
-
import { countTickets, ticketCountsForNodes } from './attention.js';
|
|
17
|
-
import { listFocuses } from './focuses.js';
|
|
18
|
-
import { resolveNodeVisual, faultSummary } from './status-glyph.js';
|
|
19
|
-
import { readNodeTelemetry, fmtCtx, hangingFor, isStreaming, dashboardRowFromNodeRow, readGoalText, readSessionParts, } from './render-source.js';
|
|
20
|
-
// Re-export the openDb-free half so `render.js` importers keep resolving the
|
|
21
|
-
// FromSource variants + shared types/helpers unchanged.
|
|
22
|
-
export * from './render-source.js';
|
|
23
|
-
// ---------------------------------------------------------------------------
|
|
24
|
-
// Tree builder (sync, db-backed)
|
|
25
|
-
// ---------------------------------------------------------------------------
|
|
26
|
-
/** Build one line of the ASCII tree. */
|
|
27
|
-
function nodeLine(nodeId, indent, connector) {
|
|
28
|
-
const node = getNode(nodeId);
|
|
29
|
-
if (node === null) {
|
|
30
|
-
// Node id is in the db but meta.json is gone — paranoid guard.
|
|
31
|
-
return `${indent}${connector}? <missing meta: ${nodeId}>`;
|
|
32
|
-
}
|
|
33
|
-
const hanging = hangingFor(node);
|
|
34
|
-
const glyph = resolveNodeVisual(node.status, { hanging }).glyph;
|
|
35
|
-
const tel = readNodeTelemetry(nodeId);
|
|
36
|
-
const ctx = fmtCtx(tel.tokens_in);
|
|
37
|
-
const asks = countTickets(nodeId);
|
|
38
|
-
const askSuffix = asks > 0 ? ` ⚑${asks}` : '';
|
|
39
|
-
const faultSuffix = hanging !== null ? ` · ${faultSummary(hanging)}` : '';
|
|
40
|
-
return `${indent}${connector}${glyph} ${fullName(node)} [${node.kind}/${node.mode}] ctx ${ctx}${askSuffix}${faultSuffix}`;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Recursively walk the subscription sub-DAG rooted at `nodeId`, appending
|
|
44
|
-
* rendered lines to `out`. Cycle-safe via `visited`.
|
|
45
|
-
*/
|
|
46
|
-
function walkTree(nodeId, indent, isLast, visited, out) {
|
|
47
|
-
// Guard: if we have already rendered this node in this traversal, emit a
|
|
48
|
-
// back-ref marker instead of recursing (prevents infinite loops in graphs
|
|
49
|
-
// with cycles introduced by manual edge manipulation).
|
|
50
|
-
if (visited.has(nodeId)) {
|
|
51
|
-
// The line for this node was already emitted by the caller; just return.
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
visited.add(nodeId);
|
|
55
|
-
const connector = isLast ? '└─ ' : '├─ ';
|
|
56
|
-
out.push(nodeLine(nodeId, indent, connector));
|
|
57
|
-
const children = subscriptionsOf(nodeId);
|
|
58
|
-
const childIndent = indent + (isLast ? ' ' : '│ ');
|
|
59
|
-
for (let i = 0; i < children.length; i++) {
|
|
60
|
-
const child = children[i];
|
|
61
|
-
const childIsLast = i === children.length - 1;
|
|
62
|
-
if (visited.has(child.node_id)) {
|
|
63
|
-
// Cycle reference — show the back-edge without recursing.
|
|
64
|
-
const cycleConnector = childIsLast ? '└─ ' : '├─ ';
|
|
65
|
-
out.push(`${childIndent}${cycleConnector}↺ <cycle: ${child.node_id}>`);
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
walkTree(child.node_id, childIndent, childIsLast, visited, out);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
// ---------------------------------------------------------------------------
|
|
72
|
-
// Public API (sync)
|
|
73
|
-
// ---------------------------------------------------------------------------
|
|
74
|
-
/**
|
|
75
|
-
* Render the subscription sub-DAG rooted at `rootId` as an ASCII tree.
|
|
76
|
-
* The root is the first line (no connector prefix); children are indented.
|
|
77
|
-
*
|
|
78
|
-
* Each line: `<glyph> <name> [<kind>/<mode>] ctx <Nk>[ ⚑<asks>]`
|
|
79
|
-
*
|
|
80
|
-
* Returns a multi-line string (no trailing newline).
|
|
81
|
-
*/
|
|
82
|
-
export function renderTree(rootId) {
|
|
83
|
-
const node = getNode(rootId);
|
|
84
|
-
if (node === null)
|
|
85
|
-
return `? <missing node: ${rootId}>`;
|
|
86
|
-
const tel = readNodeTelemetry(rootId);
|
|
87
|
-
const ctx = fmtCtx(tel.tokens_in);
|
|
88
|
-
const asks = countTickets(rootId);
|
|
89
|
-
const askSuffix = asks > 0 ? ` ⚑${asks}` : '';
|
|
90
|
-
const hanging = hangingFor(node);
|
|
91
|
-
const glyph = resolveNodeVisual(node.status, { hanging }).glyph;
|
|
92
|
-
const faultSuffix = hanging !== null ? ` · ${faultSummary(hanging)}` : '';
|
|
93
|
-
const out = [];
|
|
94
|
-
out.push(`${glyph} ${fullName(node)} [${node.kind}/${node.mode}] ctx ${ctx}${askSuffix}${faultSuffix}`);
|
|
95
|
-
// visited starts with root already rendered (walkTree doesn't re-emit root).
|
|
96
|
-
const visited = new Set([rootId]);
|
|
97
|
-
const children = subscriptionsOf(rootId);
|
|
98
|
-
for (let i = 0; i < children.length; i++) {
|
|
99
|
-
const child = children[i];
|
|
100
|
-
const isLast = i === children.length - 1;
|
|
101
|
-
walkTree(child.node_id, '', isLast, visited, out);
|
|
102
|
-
}
|
|
103
|
-
return out.join('\n');
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Render all canvas roots as a forest. A root is a node with no subscribers
|
|
107
|
-
* (no one subscribes to it = it has no managers in the org chart).
|
|
108
|
-
*
|
|
109
|
-
* If there are no roots on the canvas, returns a placeholder string.
|
|
110
|
-
*/
|
|
111
|
-
export function renderForest() {
|
|
112
|
-
const all = listNodes();
|
|
113
|
-
if (all.length === 0)
|
|
114
|
-
return '(canvas is empty)';
|
|
115
|
-
// A root has no subscribers (nobody is watching it). We discover this by
|
|
116
|
-
// looking for nodes whose node_id never appears as a "to" side of a
|
|
117
|
-
// subscribes_to edge — equivalently, nodes with parent === null are the
|
|
118
|
-
// authoritative roots per the spawn contract (spawn sets parent and records
|
|
119
|
-
// a spawned_by edge + subscribe). Fall back to parent===null because querying
|
|
120
|
-
// the full edge table would require opening the db here.
|
|
121
|
-
//
|
|
122
|
-
// Fine to use parent===null: roots are created by bare `crtr` / `node new --root`
|
|
123
|
-
// without a parent; non-roots always have a parent.
|
|
124
|
-
//
|
|
125
|
-
// Filter to LIVE roots: each `/new` parks a `done` root (option C relaunch)
|
|
126
|
-
// with parent===null, so an unfiltered forest would render every parked root
|
|
127
|
-
// as a sibling tree and clutter the dashboard. Showing only active|idle roots
|
|
128
|
-
// drops parked (`done`) roots and, as a bonus, stray `dead`/`canceled` roots.
|
|
129
|
-
// Parked roots stay reachable by id (inspect / revive / focus).
|
|
130
|
-
const roots = all.filter((n) => n.parent === null && (n.status === 'active' || n.status === 'idle'));
|
|
131
|
-
// No LIVE roots: render an empty/placeholder forest rather than resurrecting
|
|
132
|
-
// parked (`done`) / dead / canceled roots. The live-only filter is the intent;
|
|
133
|
-
// falling back to all-status roots would re-clutter the dashboard with the very
|
|
134
|
-
// parked trees the filter drops (e.g. a sole root `/quit`'d with no `/new`).
|
|
135
|
-
// Parked roots stay reachable by id (inspect / revive / focus).
|
|
136
|
-
if (roots.length === 0)
|
|
137
|
-
return '(no live roots)';
|
|
138
|
-
const parts = [];
|
|
139
|
-
for (const r of roots) {
|
|
140
|
-
parts.push(renderTree(r.node_id));
|
|
141
|
-
}
|
|
142
|
-
return parts.join('\n\n');
|
|
143
|
-
}
|
|
144
|
-
// ---------------------------------------------------------------------------
|
|
145
|
-
// Structured row builder (sync, db-backed)
|
|
146
|
-
// ---------------------------------------------------------------------------
|
|
147
|
-
/** One row per node visible in the sub-DAG of `rootId` (including root). */
|
|
148
|
-
export function dashboardRows(rootId) {
|
|
149
|
-
const ids = [rootId, ...view(rootId)];
|
|
150
|
-
return ids.flatMap((id) => {
|
|
151
|
-
const node = getNode(id);
|
|
152
|
-
if (node === null)
|
|
153
|
-
return [];
|
|
154
|
-
const tel = readNodeTelemetry(id);
|
|
155
|
-
return [{
|
|
156
|
-
node_id: id,
|
|
157
|
-
name: fullName(node),
|
|
158
|
-
handle: node.name,
|
|
159
|
-
description: node.description,
|
|
160
|
-
status: node.status,
|
|
161
|
-
kind: node.kind,
|
|
162
|
-
mode: node.mode,
|
|
163
|
-
ctx_tokens: tel.tokens_in ?? 0,
|
|
164
|
-
asks: countTickets(id),
|
|
165
|
-
cwd: node.cwd,
|
|
166
|
-
created: node.created,
|
|
167
|
-
}];
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* CHEAP boot builder — one row per node across the entire canvas, with only the
|
|
172
|
-
* fields that need no per-node meta/telemetry/session read. Two db queries total:
|
|
173
|
-
* `listNodes()` + `listFocuses()` (the focus set replaces per-node getFocusByNode
|
|
174
|
-
* calls). See {@link dashboardRowFromNodeRow} for the per-row projection, and
|
|
175
|
-
* {@link enrichRow}/{@link enrichRows}/{@link loadPreview} for the lazy fields.
|
|
176
|
-
*/
|
|
177
|
-
export function dashboardRowsAll() {
|
|
178
|
-
const focusedNodeIds = new Set(listFocuses().map((f) => f.node_id));
|
|
179
|
-
return listNodes().map((row) => dashboardRowFromNodeRow(row, focusedNodeIds, false));
|
|
180
|
-
}
|
|
181
|
-
// ---------------------------------------------------------------------------
|
|
182
|
-
// Lazy enrichment API (sync, db-backed) — fold the expensive per-node reads into
|
|
183
|
-
// rows on demand, for the VISIBLE viewport / top tiers only (never all up front).
|
|
184
|
-
// Each function mutates the row in place and is idempotent via a guard flag.
|
|
185
|
-
// ---------------------------------------------------------------------------
|
|
186
|
-
/** Fold the cheap-boot row's deferred fields in for ONE row: the full label
|
|
187
|
-
* (meta.description → fullName), ctx tokens (telemetry.json), and ⚑ asks. One
|
|
188
|
-
* meta read + one telemetry read + one ticket scan. Idempotent (no-op once enriched).
|
|
189
|
-
* For a batch, prefer {@link enrichRows} — it scans each cwd's ticket inbox once. */
|
|
190
|
-
export function enrichRow(row) {
|
|
191
|
-
if (row.enriched === true)
|
|
192
|
-
return row;
|
|
193
|
-
const meta = getNode(row.node_id);
|
|
194
|
-
if (meta !== null) {
|
|
195
|
-
row.name = fullName(meta);
|
|
196
|
-
row.handle = meta.name;
|
|
197
|
-
row.description = meta.description;
|
|
198
|
-
}
|
|
199
|
-
row.ctx_tokens = readNodeTelemetry(row.node_id).tokens_in ?? 0;
|
|
200
|
-
row.asks = countTickets(row.node_id);
|
|
201
|
-
row.enriched = true;
|
|
202
|
-
return row;
|
|
203
|
-
}
|
|
204
|
-
/** Batch {@link enrichRow}: enrich every not-yet-enriched row, scanning each
|
|
205
|
-
* distinct cwd's ticket inbox exactly ONCE (via `ticketCountsForNodes`) instead
|
|
206
|
-
* of per row. Use this for a whole viewport / the full forest; mutates each row in place. */
|
|
207
|
-
export function enrichRows(rows) {
|
|
208
|
-
const todo = rows.filter((r) => r.enriched !== true);
|
|
209
|
-
if (todo.length === 0)
|
|
210
|
-
return;
|
|
211
|
-
const asks = ticketCountsForNodes(todo.map((r) => r.node_id));
|
|
212
|
-
for (const row of todo) {
|
|
213
|
-
const meta = getNode(row.node_id);
|
|
214
|
-
if (meta !== null) {
|
|
215
|
-
row.name = fullName(meta);
|
|
216
|
-
row.handle = meta.name;
|
|
217
|
-
row.description = meta.description;
|
|
218
|
-
}
|
|
219
|
-
row.ctx_tokens = readNodeTelemetry(row.node_id).tokens_in ?? 0;
|
|
220
|
-
row.asks = asks[row.node_id] ?? 0;
|
|
221
|
-
row.enriched = true;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
/** Load the SELECTED row's preview text: the spawn `goal` (initial-prompt.md) plus
|
|
225
|
-
* the whole-conversation `prompts` and the `lastAssistant` reply — the latter two
|
|
226
|
-
* folded into ONE session-file read (see {@link readSessionParts}). Mutates the row
|
|
227
|
-
* in place; idempotent. Call only for the cursor row (and lazily/in-background to
|
|
228
|
-
* warm the prompt super-search corpus), never on the boot path. */
|
|
229
|
-
export function loadPreview(row) {
|
|
230
|
-
if (row.previewLoaded === true)
|
|
231
|
-
return row;
|
|
232
|
-
row.goal = readGoalText(row.node_id);
|
|
233
|
-
const meta = getNode(row.node_id);
|
|
234
|
-
const { prompts, lastAssistant } = readSessionParts(meta?.pi_session_file);
|
|
235
|
-
row.prompts = prompts;
|
|
236
|
-
row.lastAssistant = lastAssistant;
|
|
237
|
-
row.previewLoaded = true;
|
|
238
|
-
return row;
|
|
239
|
-
}
|
|
240
|
-
/** {@link isStreaming} keyed by node id alone — hydrates the broker pid off the
|
|
241
|
-
* db row. The exported "is this node actively generating right now?" guard so a
|
|
242
|
-
* reap never nukes a node mid-first-turn before its output lands on disk. */
|
|
243
|
-
export function isNodeStreaming(nodeId) {
|
|
244
|
-
return isStreaming(nodeId, getNode(nodeId)?.pi_pid ?? null);
|
|
245
|
-
}
|