@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
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
// trigger, so the agent cannot run on context alone before hearing the person.
|
|
12
12
|
// A context-only batch keeps its wake by triggering on its LAST card while idle,
|
|
13
13
|
// and rides the running turn while streaming.
|
|
14
|
+
import { envNodeId, envProfileId, envWatcherDebounceMs, envWatcherTickMs } from '../shared/env.js';
|
|
14
15
|
import { coalesceBrokerInbox, entryCards, readBrokerCanceledEntryIds, readBrokerCursor, readBrokerInboxSince, reportRefNodeId, } from '../core/runtime/broker/inbox.js';
|
|
15
16
|
import { advanceBrokerInboxCursor, brokerExtensionState } from '../core/runtime/broker/daemon-ops.js';
|
|
16
17
|
import { emitEvent } from '../core/events/emit.js';
|
|
@@ -18,8 +19,6 @@ import { errorClassFromError } from '../core/events/errors.js';
|
|
|
18
19
|
import { operationIdContext } from '../core/events/operation-id.js';
|
|
19
20
|
import { situationalContextEnvelope, SITUATIONAL_CONTEXT_CUSTOM_TYPE } from '../core/runtime/situational-context.js';
|
|
20
21
|
import { isProfilePaused } from '../core/profiles/manifest.js';
|
|
21
|
-
const DEFAULT_TICK_MS = 800;
|
|
22
|
-
const DEFAULT_DEBOUNCE_MS = 1000;
|
|
23
22
|
const MAX_PENDING_HANDOFFS = 64;
|
|
24
23
|
const MAX_SOURCE_OPERATION_IDS = 16;
|
|
25
24
|
let currentWatcher;
|
|
@@ -31,26 +30,20 @@ class WatcherFatalError extends Error {
|
|
|
31
30
|
}
|
|
32
31
|
}
|
|
33
32
|
function resolveCadence() {
|
|
34
|
-
const parse = (raw, fallback) => {
|
|
35
|
-
if (raw === undefined)
|
|
36
|
-
return fallback;
|
|
37
|
-
const value = Number(raw);
|
|
38
|
-
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
39
|
-
};
|
|
40
33
|
return {
|
|
41
|
-
tickMs:
|
|
42
|
-
debounceMs:
|
|
34
|
+
tickMs: envWatcherTickMs(),
|
|
35
|
+
debounceMs: envWatcherDebounceMs(),
|
|
43
36
|
};
|
|
44
37
|
}
|
|
45
38
|
function currentNodeId() {
|
|
46
|
-
const nodeId =
|
|
39
|
+
const nodeId = envNodeId();
|
|
47
40
|
return nodeId === undefined || nodeId.trim() === '' ? undefined : nodeId;
|
|
48
41
|
}
|
|
49
42
|
/** The node's profile, read fresh each poll: `crtr profile pause` mutates the
|
|
50
43
|
* manifest file directly, so a live broker sees the flip on its next tick with
|
|
51
44
|
* no daemon round-trip. '' is the historical no-profile row. */
|
|
52
45
|
function profilePaused() {
|
|
53
|
-
const profileId =
|
|
46
|
+
const profileId = envProfileId();
|
|
54
47
|
return profileId !== undefined && profileId !== '' && isProfilePaused(profileId);
|
|
55
48
|
}
|
|
56
49
|
function isFilesystemError(error) {
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
//
|
|
19
19
|
// Plain TS-with-types — no imports from @earendil-works/* so this compiles inside
|
|
20
20
|
// crouter's own tsc build without a dep on the pi packages.
|
|
21
|
+
import { envNodeId } from '../shared/env.js';
|
|
21
22
|
import { existsSync, readFileSync } from 'node:fs';
|
|
22
23
|
import { brokerExtensionState } from '../core/runtime/broker/daemon-ops.js';
|
|
23
24
|
import { reportPathFromRef } from '../core/runtime/broker-extension-render.js';
|
|
@@ -26,9 +27,7 @@ import { parseCard } from '../shared/generated-context.js';
|
|
|
26
27
|
// Per-entry body cap so a single fat report can't blow the context budget. The
|
|
27
28
|
// full report stays on disk at `ref` if the agent needs more.
|
|
28
29
|
const BODY_CAP = 4_000;
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
30
|
// Report dereference — turn a passive pointer into the message text it carries.
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
31
|
/** Strip the leading YAML frontmatter block a report is written with, returning
|
|
33
32
|
* just the body. Tolerant: no frontmatter → returns the input unchanged. */
|
|
34
33
|
function stripFrontmatter(raw) {
|
|
@@ -126,9 +125,7 @@ export function placeBacklog(text, preText) {
|
|
|
126
125
|
const bodyStart = text.length - card.body.length - CARD_CLOSE.length;
|
|
127
126
|
return `${text.slice(0, bodyStart)}${preText}\n${text.slice(bodyStart)}`;
|
|
128
127
|
}
|
|
129
|
-
// ---------------------------------------------------------------------------
|
|
130
128
|
// Extension
|
|
131
|
-
// ---------------------------------------------------------------------------
|
|
132
129
|
/**
|
|
133
130
|
* Register the passive-context drain on `pi`.
|
|
134
131
|
*
|
|
@@ -138,7 +135,7 @@ export function placeBacklog(text, preText) {
|
|
|
138
135
|
export function registerCanvasPassiveContext(pi) {
|
|
139
136
|
pi.on('input', async (event) => {
|
|
140
137
|
try {
|
|
141
|
-
const nodeId =
|
|
138
|
+
const nodeId = envNodeId();
|
|
142
139
|
if (nodeId === undefined || nodeId.trim() === '')
|
|
143
140
|
return; // not a canvas node
|
|
144
141
|
const drained = drainBrokerPassive(nodeId);
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// mirrors its record there, and this hook attaches the record to Pi's
|
|
7
7
|
// ToolResult.details. The attach viewer can render a structured preview
|
|
8
8
|
// without parsing the agent-facing text.
|
|
9
|
+
import { envNodeId } from '../shared/env.js';
|
|
9
10
|
import { existsSync, readFileSync, rmSync } from 'node:fs';
|
|
10
11
|
import { previewResultPath } from '../core/preview-result-path.js';
|
|
11
12
|
function isPreviewRecord(value) {
|
|
@@ -19,7 +20,7 @@ function isPreviewRecord(value) {
|
|
|
19
20
|
/** Loaded into every canvas broker. Plain Pi sessions have no node id and
|
|
20
21
|
* deliberately receive no filesystem transport. */
|
|
21
22
|
export function registerCanvasPreviewResult(pi) {
|
|
22
|
-
if (
|
|
23
|
+
if (envNodeId() === undefined || envNodeId() === '')
|
|
23
24
|
return;
|
|
24
25
|
pi.on('tool_result', (event) => {
|
|
25
26
|
if (event.toolName !== 'bash')
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
//
|
|
24
24
|
// Every rule below is anchored to pi's exact wording and degrades to a no-op if
|
|
25
25
|
// pi rewords, so a pi upgrade can never break a turn here.
|
|
26
|
+
import { envNodeId } from '../shared/env.js';
|
|
26
27
|
const PI_IDENTITY = 'You are an expert coding assistant operating inside pi, a coding agent harness.';
|
|
27
28
|
const NEUTRAL_IDENTITY = 'You are an expert coding assistant.';
|
|
28
29
|
const PI_DOCS_MARKER = 'Pi documentation (read only';
|
|
@@ -40,7 +41,7 @@ export function scrubPromptSelfReference(systemPrompt) {
|
|
|
40
41
|
}
|
|
41
42
|
/** Register the system-prompt scrub for a canvas node. */
|
|
42
43
|
export function registerCanvasPromptScrub(pi) {
|
|
43
|
-
const nodeId =
|
|
44
|
+
const nodeId = envNodeId();
|
|
44
45
|
if (nodeId === undefined || nodeId.trim() === '')
|
|
45
46
|
return;
|
|
46
47
|
pi.on('before_agent_start', (event) => {
|
|
@@ -38,20 +38,17 @@
|
|
|
38
38
|
//
|
|
39
39
|
// Plain TS-with-types — no imports from @earendil-works/* so this compiles
|
|
40
40
|
// inside crouter's own tsc build without a dep on the pi packages.
|
|
41
|
+
import { envNodeId, envRecapIdleMs } from '../shared/env.js';
|
|
41
42
|
import { brokerExtensionState } from '../core/runtime/broker/daemon-ops.js';
|
|
42
43
|
import { generateRecap } from '../core/runtime/recap.js';
|
|
43
44
|
import { isReviewBoundary } from '../core/runtime/session-visibility.js';
|
|
44
45
|
import { editorLabelForBrokerNode } from '../core/runtime/broker-extension-render.js';
|
|
45
46
|
import { generateAndCommitRecapName, readRoadmap } from './broker-local.js';
|
|
46
|
-
// ---------------------------------------------------------------------------
|
|
47
47
|
// Tuning constants
|
|
48
|
-
// ---------------------------------------------------------------------------
|
|
49
48
|
/** No-new-message window before a recap is shown. 60s by default; override with
|
|
50
49
|
* CRTR_RECAP_IDLE_MS (for fast runtime verification). */
|
|
51
50
|
function idleMs() {
|
|
52
|
-
|
|
53
|
-
const n = raw !== undefined ? parseInt(raw, 10) : NaN;
|
|
54
|
-
return Number.isFinite(n) && n > 0 ? n : 60_000;
|
|
51
|
+
return envRecapIdleMs();
|
|
55
52
|
}
|
|
56
53
|
/** How often the single low-rate timer checks elapsed-since-last-message. */
|
|
57
54
|
const POLL_MS = 7_000;
|
|
@@ -62,14 +59,10 @@ const CONVO_EDGE_MESSAGES = 5;
|
|
|
62
59
|
* (10 messages × this ≈ the total budget the model needs for the gist). */
|
|
63
60
|
const MESSAGE_CHAR_BUDGET = 1_200;
|
|
64
61
|
const WIDGET_KEY = 'crtr-recap';
|
|
65
|
-
// ---------------------------------------------------------------------------
|
|
66
62
|
// Module-level state — persists across /reload so the timer doesn't stack.
|
|
67
|
-
// ---------------------------------------------------------------------------
|
|
68
63
|
/** The one live poll timer. Cleared and replaced on every re-registration. */
|
|
69
64
|
let liveTimer;
|
|
70
|
-
// ---------------------------------------------------------------------------
|
|
71
65
|
// Conversation extraction — literal user+assistant text ONLY.
|
|
72
|
-
// ---------------------------------------------------------------------------
|
|
73
66
|
/** Pull the literal text out of a message's content (string or text blocks),
|
|
74
67
|
* dropping non-text blocks (thinking, toolCall, image). */
|
|
75
68
|
function messageText(msg) {
|
|
@@ -162,9 +155,7 @@ function buildNamingConversation(sm, assistantPartial, reviewId) {
|
|
|
162
155
|
});
|
|
163
156
|
return sampled.join('\n\n');
|
|
164
157
|
}
|
|
165
|
-
// ---------------------------------------------------------------------------
|
|
166
158
|
// Extension
|
|
167
|
-
// ---------------------------------------------------------------------------
|
|
168
159
|
/**
|
|
169
160
|
* Register the inactivity-recap chrome on `pi`.
|
|
170
161
|
*
|
|
@@ -172,7 +163,7 @@ function buildNamingConversation(sm, assistantPartial, reviewId) {
|
|
|
172
163
|
* or legacy job agent loads it as a no-op.
|
|
173
164
|
*/
|
|
174
165
|
export function registerCanvasRecap(pi, recapGenerator = generateRecap, nameRegenerator) {
|
|
175
|
-
const nodeId =
|
|
166
|
+
const nodeId = envNodeId();
|
|
176
167
|
if (nodeId === undefined || nodeId.trim() === '')
|
|
177
168
|
return; // not a canvas node
|
|
178
169
|
// Captured on session_start; used by the timer and the message handlers.
|
|
@@ -344,9 +335,7 @@ export function registerCanvasRecap(pi, recapGenerator = generateRecap, nameRege
|
|
|
344
335
|
requestRecap(true);
|
|
345
336
|
},
|
|
346
337
|
});
|
|
347
|
-
// -------------------------------------------------------------------------
|
|
348
338
|
// Events
|
|
349
|
-
// -------------------------------------------------------------------------
|
|
350
339
|
pi.on('session_start', (_event, ctx) => {
|
|
351
340
|
ui = ctx.ui;
|
|
352
341
|
sessionManager = ctx.sessionManager;
|
|
@@ -382,9 +371,7 @@ export function registerCanvasRecap(pi, recapGenerator = generateRecap, nameRege
|
|
|
382
371
|
captureLiveModel(ctx);
|
|
383
372
|
onMessage();
|
|
384
373
|
});
|
|
385
|
-
// -------------------------------------------------------------------------
|
|
386
374
|
// The single low-rate idle poll.
|
|
387
|
-
// -------------------------------------------------------------------------
|
|
388
375
|
if (liveTimer !== undefined)
|
|
389
376
|
clearInterval(liveTimer);
|
|
390
377
|
const timer = setInterval(() => {
|
|
@@ -4,13 +4,12 @@
|
|
|
4
4
|
// inherited fork context and before canvas-context-intro appends fork bearings.
|
|
5
5
|
// The display projection starts at this marker while the model keeps the full
|
|
6
6
|
// inherited context.
|
|
7
|
+
import { envNodeId } from '../shared/env.js';
|
|
7
8
|
import { brokerExtensionState } from '../core/runtime/broker/daemon-ops.js';
|
|
8
9
|
import { isReviewBoundary, REVIEW_BOUNDARY_CUSTOM_TYPE } from '../core/runtime/session-visibility.js';
|
|
9
10
|
import { formatCard, parseCard } from '../shared/generated-context.js';
|
|
10
11
|
import { truncateToWidth } from './truncate.js';
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
12
|
// Collapsed-by-default rendering
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
13
|
/** Render the marker as a single compact divider; its full content remains in
|
|
15
14
|
* the message list for the model and generated-context presenters. */
|
|
16
15
|
export function renderReviewBoundary(message, options, theme) {
|
|
@@ -32,9 +31,7 @@ export function renderReviewBoundary(message, options, theme) {
|
|
|
32
31
|
},
|
|
33
32
|
};
|
|
34
33
|
}
|
|
35
|
-
// ---------------------------------------------------------------------------
|
|
36
34
|
// Extension
|
|
37
|
-
// ---------------------------------------------------------------------------
|
|
38
35
|
/**
|
|
39
36
|
* Register the review boundary marker. Companion nodes receive one boundary
|
|
40
37
|
* marker on session_start that separates inherited context from the visible
|
|
@@ -43,7 +40,7 @@ export function renderReviewBoundary(message, options, theme) {
|
|
|
43
40
|
export function registerCanvasReviewBoundary(pi) {
|
|
44
41
|
pi.registerMessageRenderer(REVIEW_BOUNDARY_CUSTOM_TYPE, renderReviewBoundary);
|
|
45
42
|
pi.on('session_start', async (_event, ctx) => {
|
|
46
|
-
const nodeId =
|
|
43
|
+
const nodeId = envNodeId();
|
|
47
44
|
if (!nodeId || nodeId.trim() === '')
|
|
48
45
|
return;
|
|
49
46
|
let node;
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
//
|
|
21
21
|
// Plain TS-with-types — no imports from @earendil-works/* so this compiles inside
|
|
22
22
|
// crouter's own tsc build without a dep on the pi packages.
|
|
23
|
+
import { envNodeId } from '../shared/env.js';
|
|
23
24
|
import { writeFileSync, mkdirSync, existsSync, readFileSync } from 'node:fs';
|
|
24
25
|
import { join } from 'node:path';
|
|
25
26
|
import { contextDir, jobDir } from '../core/canvas/paths.js';
|
|
@@ -79,9 +80,7 @@ function flushTelemetry(jobDirPath, tokensIn, tokensOut, model, contextTokens, a
|
|
|
79
80
|
/* telemetry is best-effort; never surface */
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
|
-
// ---------------------------------------------------------------------------
|
|
83
83
|
// Message-extraction helpers
|
|
84
|
-
// ---------------------------------------------------------------------------
|
|
85
84
|
/** Walk backwards through the agent_end messages array to find the last
|
|
86
85
|
* assistant turn. */
|
|
87
86
|
function lastAssistantMessage(messages) {
|
|
@@ -117,7 +116,6 @@ function currentReviewBoundaryIds(ctx) {
|
|
|
117
116
|
return [];
|
|
118
117
|
}
|
|
119
118
|
}
|
|
120
|
-
// ---------------------------------------------------------------------------
|
|
121
119
|
// Context-size steering bands — a single shared schedule of thresholds that
|
|
122
120
|
// ESCALATE in tone as input context grows. The first band is a gentle
|
|
123
121
|
// "consider it"; a later band turns firm. The schedule TIGHTENS as it climbs:
|
|
@@ -150,7 +148,6 @@ function currentReviewBoundaryIds(ctx) {
|
|
|
150
148
|
// worthwhile parallel work. Only a terminal node is ever told `push final` (a
|
|
151
149
|
// resident finishes by yielding or being closed); only an orchestrator already
|
|
152
150
|
// HAS a roadmap to checkpoint before it yields.
|
|
153
|
-
// ---------------------------------------------------------------------------
|
|
154
151
|
const STEER_STEP = 10_000;
|
|
155
152
|
// Shared escalation schedule (both lifecycles). Tightens as it climbs:
|
|
156
153
|
// 130k, 150k, 170k, 185k, 200k, then every 10k (210k, 220k, …).
|
|
@@ -233,9 +230,7 @@ export function steerNote(at, lifecycle, mode) {
|
|
|
233
230
|
}
|
|
234
231
|
return `Context ~${k}k — this is getting long. Wrap up now before this context overflows: \`crtr push final\` if you're close, otherwise \`crtr node yield\` immediately to continue in a fresh window against your goal and your note.`;
|
|
235
232
|
}
|
|
236
|
-
// ---------------------------------------------------------------------------
|
|
237
233
|
// Extension
|
|
238
|
-
// ---------------------------------------------------------------------------
|
|
239
234
|
/**
|
|
240
235
|
* Register the canvas turn and settlement handlers on `pi`.
|
|
241
236
|
*
|
|
@@ -245,7 +240,7 @@ export function steerNote(at, lifecycle, mode) {
|
|
|
245
240
|
* per node lifecycle, matching how pi loads extensions).
|
|
246
241
|
*/
|
|
247
242
|
export function registerCanvasStophook(pi) {
|
|
248
|
-
const nodeId =
|
|
243
|
+
const nodeId = envNodeId();
|
|
249
244
|
if (nodeId === undefined || nodeId.trim() === '')
|
|
250
245
|
return; // not a canvas node
|
|
251
246
|
const jobDirPath = jobDir(nodeId);
|
|
@@ -310,7 +305,6 @@ export function registerCanvasStophook(pi) {
|
|
|
310
305
|
touchBusy(nodeId);
|
|
311
306
|
clearFault(nodeId, { link: 'daemon→node' });
|
|
312
307
|
};
|
|
313
|
-
// ---------------------------------------------------------------------------
|
|
314
308
|
// session_start — capture pi's session id, and detect `/new`.
|
|
315
309
|
//
|
|
316
310
|
// pi tags each session_start with a `reason`: 'startup' on boot (a fresh
|
|
@@ -327,7 +321,6 @@ export function registerCanvasStophook(pi) {
|
|
|
327
321
|
//
|
|
328
322
|
// `/new` splits by who ran it: crtrd derives rootness from the node row and
|
|
329
323
|
// either directs a root relaunch or resets a child's session coordinates.
|
|
330
|
-
// ---------------------------------------------------------------------------
|
|
331
324
|
pi.on('session_start', async (event, ctx) => {
|
|
332
325
|
try {
|
|
333
326
|
const id = ctx?.sessionManager?.getSessionId?.();
|
|
@@ -390,11 +383,9 @@ export function registerCanvasStophook(pi) {
|
|
|
390
383
|
});
|
|
391
384
|
}
|
|
392
385
|
});
|
|
393
|
-
// ---------------------------------------------------------------------------
|
|
394
386
|
// agent_start — pi entered a turn. Mark the node mid-turn (busy) so a
|
|
395
387
|
// focus-away while it is genuinely working backstages it (Invariant F2)
|
|
396
388
|
// rather than reaping it. Cleared only after the whole run settles.
|
|
397
|
-
// ---------------------------------------------------------------------------
|
|
398
389
|
pi.on('agent_start', () => {
|
|
399
390
|
// A fresh turn started. Keep any active fault marker in place so the daemon's
|
|
400
391
|
// retry accounting survives a failed retry cycle; just mark the turn busy.
|
|
@@ -403,7 +394,6 @@ export function registerCanvasStophook(pi) {
|
|
|
403
394
|
}
|
|
404
395
|
catch { /* best-effort */ }
|
|
405
396
|
});
|
|
406
|
-
// ---------------------------------------------------------------------------
|
|
407
397
|
// input — a new user-directed run is beginning. This is the ONLY place stop
|
|
408
398
|
// signals are cleared: `agent_start` re-fires for pi's automatic retries and
|
|
409
399
|
// post-compaction continuations within the SAME run, so clearing there would
|
|
@@ -413,18 +403,15 @@ export function registerCanvasStophook(pi) {
|
|
|
413
403
|
// `agent_settled` consumes them; a leftover from an errored or interrupted run
|
|
414
404
|
// of this same broker is discarded here, when the next prompt arrives (the pid
|
|
415
405
|
// stamp only rules out a PRIOR broker's markers, not this broker's own).
|
|
416
|
-
// ---------------------------------------------------------------------------
|
|
417
406
|
pi.on('input', () => {
|
|
418
407
|
try {
|
|
419
408
|
clearStopSignals(nodeId);
|
|
420
409
|
}
|
|
421
410
|
catch { /* best-effort */ }
|
|
422
411
|
});
|
|
423
|
-
// ---------------------------------------------------------------------------
|
|
424
412
|
// tool_execution_start — capture the live "what is it doing" cue. Writes the
|
|
425
413
|
// one-line tool summary to telemetry.json so out-of-process readers (the nav
|
|
426
414
|
// chrome) show it inline without a second file or any extra read on their side.
|
|
427
|
-
// ---------------------------------------------------------------------------
|
|
428
415
|
pi.on('tool_execution_start', (event) => {
|
|
429
416
|
try {
|
|
430
417
|
lastActivity = summarizeActivity(String(event?.toolName ?? ''), event?.args);
|
|
@@ -434,7 +421,6 @@ export function registerCanvasStophook(pi) {
|
|
|
434
421
|
}
|
|
435
422
|
catch { /* best-effort */ }
|
|
436
423
|
});
|
|
437
|
-
// ---------------------------------------------------------------------------
|
|
438
424
|
// tool_execution_update — wedge heartbeat + fault clear only. Fired with
|
|
439
425
|
// partial/streaming tool output (when a tool reports progress); throttled via
|
|
440
426
|
// `heartbeat()` since it can arrive many times per second. Most tools (e.g.
|
|
@@ -442,27 +428,23 @@ export function registerCanvasStophook(pi) {
|
|
|
442
428
|
// for them — it exists so any tool that DOES stream partial output (now or in
|
|
443
429
|
// the future) counts as live progress instead of tripping the wedge detector,
|
|
444
430
|
// AND clears any wedge notice that already fired before this progress resumed.
|
|
445
|
-
// ---------------------------------------------------------------------------
|
|
446
431
|
pi.on('tool_execution_update', () => {
|
|
447
432
|
try {
|
|
448
433
|
heartbeat();
|
|
449
434
|
}
|
|
450
435
|
catch { /* best-effort */ }
|
|
451
436
|
});
|
|
452
|
-
// ---------------------------------------------------------------------------
|
|
453
437
|
// message_update — wedge heartbeat + fault clear only. Fired token-by-token
|
|
454
438
|
// while the assistant is actively streaming a reply — genuine progress,
|
|
455
439
|
// throttled the same way, and equally clears a stale wedge notice if streaming
|
|
456
440
|
// resumes before a coarser boundary. A node stuck streaming forever without
|
|
457
441
|
// ever firing this is exactly the daemon's busy+quiet wedge signature.
|
|
458
|
-
// ---------------------------------------------------------------------------
|
|
459
442
|
pi.on('message_update', () => {
|
|
460
443
|
try {
|
|
461
444
|
heartbeat();
|
|
462
445
|
}
|
|
463
446
|
catch { /* best-effort */ }
|
|
464
447
|
});
|
|
465
|
-
// ---------------------------------------------------------------------------
|
|
466
448
|
// tool_execution_end — IMMEDIATE refresh-yield. When a tool this turn set
|
|
467
449
|
// intent='refresh' (the node ran `crtr node yield`), shut the broker down NOW
|
|
468
450
|
// instead of letting the model keep burning its bloated context to the turn's
|
|
@@ -494,11 +476,9 @@ export function registerCanvasStophook(pi) {
|
|
|
494
476
|
}
|
|
495
477
|
catch { /* best-effort */ }
|
|
496
478
|
});
|
|
497
|
-
// ---------------------------------------------------------------------------
|
|
498
479
|
// session_shutdown — Pi's clean /quit fact goes to crtrd, which owns the
|
|
499
480
|
// finish transition, focus teardown, presence clear, and fault clear. Other
|
|
500
481
|
// session swaps keep the same node and need no durable settlement.
|
|
501
|
-
// ---------------------------------------------------------------------------
|
|
502
482
|
pi.on('session_shutdown', async (event, ctx) => {
|
|
503
483
|
clearBusy(nodeId); // turn marker is meaningless once Pi is exiting
|
|
504
484
|
if (event?.reason !== 'quit')
|
|
@@ -525,10 +505,8 @@ export function registerCanvasStophook(pi) {
|
|
|
525
505
|
if (typeof msg.model === 'string' && msg.model !== '')
|
|
526
506
|
model = msg.model;
|
|
527
507
|
};
|
|
528
|
-
// ---------------------------------------------------------------------------
|
|
529
508
|
// turn_end — live telemetry refresh.
|
|
530
509
|
// event shape: { message: AssistantMessage, ... }
|
|
531
|
-
// ---------------------------------------------------------------------------
|
|
532
510
|
pi.on('turn_end', async (event, ctx) => {
|
|
533
511
|
accumulate(event?.message);
|
|
534
512
|
// The CURRENT context size via ctx.getContextUsage() — the exact figure pi's
|
|
@@ -615,10 +593,8 @@ export function registerCanvasStophook(pi) {
|
|
|
615
593
|
}
|
|
616
594
|
catch { /* best-effort */ }
|
|
617
595
|
});
|
|
618
|
-
// ---------------------------------------------------------------------------
|
|
619
596
|
// agent_settled — Pi supplies stop facts; crtrd commits every canvas effect
|
|
620
597
|
// and returns the one Pi-side consequence to enact.
|
|
621
|
-
// ---------------------------------------------------------------------------
|
|
622
598
|
pi.on('agent_settled', async (_event, ctx) => {
|
|
623
599
|
const event = stagedAgentEnd;
|
|
624
600
|
stagedAgentEnd = null;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// Loaded into every canvas node. Inert unless nodes/<id>/output-schema.json exists
|
|
4
4
|
// and is valid. If the request file is malformed, the tool is not registered — the
|
|
5
5
|
// stop-guard will reprompt the node with an explicit error about the invalid file.
|
|
6
|
+
import { envNodeId } from '../shared/env.js';
|
|
6
7
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
7
8
|
import { dirname } from 'node:path';
|
|
8
9
|
import { validateToolArguments } from '@earendil-works/pi-ai';
|
|
@@ -168,7 +169,7 @@ function toolDescription(request) {
|
|
|
168
169
|
return 'Submit the requested one-off structured result. Calling this records the result, pushes an update report automatically, frees you from the structured-output gate, and lets you continue working.';
|
|
169
170
|
}
|
|
170
171
|
export function registerCanvasStructuredOutput(pi) {
|
|
171
|
-
const nodeId =
|
|
172
|
+
const nodeId = envNodeId();
|
|
172
173
|
if (nodeId === undefined || nodeId.trim() === '')
|
|
173
174
|
return;
|
|
174
175
|
let registeredKey = null;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// Capturing `crtr -h` builds the full configured command tree, including commands
|
|
4
4
|
// discovered from the node's cwd. It runs only at session start; before_agent_start
|
|
5
5
|
// injects the last successful capture without starting work or waiting.
|
|
6
|
+
import { envNodeId } from '../shared/env.js';
|
|
6
7
|
import { execFile } from 'node:child_process';
|
|
7
8
|
import { createHash } from 'node:crypto';
|
|
8
9
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
@@ -25,7 +26,7 @@ function injectToolGuide(systemPrompt, helpText) {
|
|
|
25
26
|
}
|
|
26
27
|
/** Register the root crtr tool-guide injection for a canvas node. */
|
|
27
28
|
export function registerCanvasToolGuide(pi) {
|
|
28
|
-
const nodeId =
|
|
29
|
+
const nodeId = envNodeId();
|
|
29
30
|
if (nodeId === undefined || nodeId.trim() === '')
|
|
30
31
|
return;
|
|
31
32
|
let helpText = '';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// `shared/env.ts` is the reader-side surface for the env vars listed below —
|
|
2
|
+
// every one of them was migrated off a scattered `process.env` read onto a
|
|
3
|
+
// named accessor there. This grep-enforces that boundary: outside the owner
|
|
4
|
+
// module itself, a read of any migrated var may live only in an explicitly
|
|
5
|
+
// documented exemption — a distinct, non-read use of the SAME var. Exemptions
|
|
6
|
+
// are itemized below so a new stray read fails loud instead of silently
|
|
7
|
+
// reintroducing the var outside its accessor.
|
|
8
|
+
import { test } from 'node:test';
|
|
9
|
+
import assert from 'node:assert/strict';
|
|
10
|
+
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
11
|
+
import { join, resolve, relative } from 'node:path';
|
|
12
|
+
const SRC_ROOT = resolve(process.cwd(), 'src');
|
|
13
|
+
// Every var migrated onto an accessor in `shared/env.ts`. Complete: every
|
|
14
|
+
// forbidden-file sweep has landed, so this is the full migrated set.
|
|
15
|
+
const MIGRATED_VARS = [
|
|
16
|
+
'CRTR_NODE_ID',
|
|
17
|
+
'CRTR_PROFILE_ID',
|
|
18
|
+
'CRTR_NODE_CWD',
|
|
19
|
+
'CRTR_MODEL_INTENT',
|
|
20
|
+
'CRTR_HOME',
|
|
21
|
+
'CRTR_STREAM_WATCHDOG_MS',
|
|
22
|
+
'CRTR_WATCHER_TICK_MS',
|
|
23
|
+
'CRTR_WATCHER_DEBOUNCE_MS',
|
|
24
|
+
'CRTR_RECAP_IDLE_MS',
|
|
25
|
+
'CRTR_RECAP_MODEL',
|
|
26
|
+
'CRTR_BASH_VALVE_MS',
|
|
27
|
+
'CRTR_PIDFILE',
|
|
28
|
+
'CRTR_BROKER_ENGINE',
|
|
29
|
+
'CRTR_PI_BINARY',
|
|
30
|
+
'CRTR_NO_DAEMON_AUTOSTART',
|
|
31
|
+
'CRTRD_TCP',
|
|
32
|
+
'CRTR_NO_EXPORTS',
|
|
33
|
+
'CRTR_DEBUG',
|
|
34
|
+
'CRTR_MAX_LIVE_BROKERS',
|
|
35
|
+
'CRTR_WARN_LIVE_BROKERS',
|
|
36
|
+
'CRTR_TEST_UNATTENDED_PARK_MS',
|
|
37
|
+
'CRTR_TEST_PARK_SUMMARY_GRACE_MS',
|
|
38
|
+
];
|
|
39
|
+
// Matches `process.env['VAR']`, `process.env.VAR`, or `process.env[\`VAR\`]`
|
|
40
|
+
// for exactly one of MIGRATED_VARS — not a longer name that merely starts
|
|
41
|
+
// with it (e.g. `CRTR_DEBUG_PID_LIVENESS` must NOT match `CRTR_DEBUG`).
|
|
42
|
+
const VAR_PATTERN = MIGRATED_VARS.join('|');
|
|
43
|
+
const READ_RE = new RegExp(String.raw `process\.env(?:\.(?:${VAR_PATTERN})\b|\[['"\`](?:${VAR_PATTERN})['"\`]\])`);
|
|
44
|
+
// Relative to src/, forward-slash form. Each entry is a genuinely distinct
|
|
45
|
+
// use of the SAME var name that the migration deliberately leaves in place —
|
|
46
|
+
// not an unmigrated read.
|
|
47
|
+
const EXEMPTIONS = new Map([
|
|
48
|
+
[
|
|
49
|
+
'core/canvas/paths.ts',
|
|
50
|
+
'crtrHome() is the canonical resolved-path accessor for CRTR_HOME; ' +
|
|
51
|
+
'envHomeOverride() in shared/env.ts is for callers that want the raw ' +
|
|
52
|
+
'override itself (see the header comment there).',
|
|
53
|
+
],
|
|
54
|
+
[
|
|
55
|
+
'core/runtime/broker.ts',
|
|
56
|
+
"clears CRTR_MODEL_INTENT via `delete process.env[...]` — a mutation, " +
|
|
57
|
+
'not a read, so it stays here per shared/env.ts\'s header comment.',
|
|
58
|
+
],
|
|
59
|
+
]);
|
|
60
|
+
function tsFilesUnder(dir) {
|
|
61
|
+
const out = [];
|
|
62
|
+
for (const entry of readdirSync(dir)) {
|
|
63
|
+
const path = join(dir, entry);
|
|
64
|
+
const stat = statSync(path);
|
|
65
|
+
if (stat.isDirectory()) {
|
|
66
|
+
if (entry === '__tests__')
|
|
67
|
+
continue;
|
|
68
|
+
out.push(...tsFilesUnder(path));
|
|
69
|
+
}
|
|
70
|
+
else if (entry.endsWith('.ts') && !entry.endsWith('.test.ts')) {
|
|
71
|
+
out.push(path);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
test('every migrated env var is read only through shared/env.ts or an explicit exemption', () => {
|
|
77
|
+
const offenders = [];
|
|
78
|
+
for (const file of tsFilesUnder(SRC_ROOT)) {
|
|
79
|
+
const relPath = relative(SRC_ROOT, file).split('\\').join('/');
|
|
80
|
+
if (relPath === 'shared/env.ts')
|
|
81
|
+
continue;
|
|
82
|
+
if (EXEMPTIONS.has(relPath))
|
|
83
|
+
continue;
|
|
84
|
+
const source = readFileSync(file, 'utf8');
|
|
85
|
+
const lines = source.split('\n');
|
|
86
|
+
lines.forEach((line, index) => {
|
|
87
|
+
if (READ_RE.test(line)) {
|
|
88
|
+
offenders.push(`${relPath}:${index + 1}: ${line.trim()}`);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
assert.deepEqual(offenders, [], `migrated env var read(s) outside shared/env.ts and its exemptions:\n${offenders.join('\n')}`);
|
|
93
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/** The current node's id (`CRTR_NODE_ID`), or undefined outside a node. */
|
|
2
|
+
export declare function envNodeId(): string | undefined;
|
|
3
|
+
/** The current node's target profile id (`CRTR_PROFILE_ID`), or undefined. */
|
|
4
|
+
export declare function envProfileId(): string | undefined;
|
|
5
|
+
/** The current node's working directory (`CRTR_NODE_CWD`), or undefined. */
|
|
6
|
+
export declare function envNodeCwd(): string | undefined;
|
|
7
|
+
/** An explicit model-routing override for this turn (`CRTR_MODEL_INTENT`), or
|
|
8
|
+
* undefined. Cleared (not read) via `delete process.env['CRTR_MODEL_INTENT']`
|
|
9
|
+
* in `runtime/broker.ts` — a mutation, not a read, so it stays there. */
|
|
10
|
+
export declare function envModelIntent(): string | undefined;
|
|
11
|
+
/** The raw `CRTR_HOME` override, unresolved. Use `crtrHome()`
|
|
12
|
+
* (`core/canvas/paths.ts`) to get the resolved canvas-home path; use this
|
|
13
|
+
* only when a caller needs the override itself — to check whether one is
|
|
14
|
+
* set, or to propagate it verbatim into a child process's env. */
|
|
15
|
+
export declare function envHomeOverride(): string | undefined;
|
|
16
|
+
/** Dead-provider watchdog timeout (`CRTR_STREAM_WATCHDOG_MS`), 5 minutes by
|
|
17
|
+
* default. See `runtime/stream-watchdog.ts` for what it guards. */
|
|
18
|
+
export declare function envStreamWatchdogMs(): number;
|
|
19
|
+
/** The canvas inbox watcher's poll tick (`CRTR_WATCHER_TICK_MS`). */
|
|
20
|
+
export declare function envWatcherTickMs(): number;
|
|
21
|
+
/** The canvas inbox watcher's debounce window (`CRTR_WATCHER_DEBOUNCE_MS`). */
|
|
22
|
+
export declare function envWatcherDebounceMs(): number;
|
|
23
|
+
/** No-new-message window before a recap is shown (`CRTR_RECAP_IDLE_MS`), 60s
|
|
24
|
+
* by default. */
|
|
25
|
+
export declare function envRecapIdleMs(): number;
|
|
26
|
+
/** Explicit recap-model override (`CRTR_RECAP_MODEL`), trimmed; undefined if
|
|
27
|
+
* unset or blank. */
|
|
28
|
+
export declare function envRecapModelOverride(): string | undefined;
|
|
29
|
+
/** The bash safety-valve deadline (`CRTR_BASH_VALVE_MS`), 5 minutes by
|
|
30
|
+
* default; undocumented test-only override so the E2E valve check doesn't
|
|
31
|
+
* sleep 5 minutes. */
|
|
32
|
+
export declare function envBashValveMs(): number;
|
|
33
|
+
/** Explicit pidfile path override (`CRTR_PIDFILE`, tests only); undefined if
|
|
34
|
+
* unset or blank. */
|
|
35
|
+
export declare function envPidfileOverride(): string | undefined;
|
|
36
|
+
/** The broker engine module spec (`CRTR_BROKER_ENGINE`, the T11 test seam),
|
|
37
|
+
* defaulting to the real SDK. `runtime/host.ts` layers `inv.env` ahead of
|
|
38
|
+
* this (a launch-time override mirrored into the child's env, since
|
|
39
|
+
* spawn-env.ts's default-deny allowlist strips `CRTR_*` from ambient env). */
|
|
40
|
+
export declare function envBrokerEngine(): string;
|
|
41
|
+
/** Test-only pi-binary substitution (`CRTR_PI_BINARY`) so the integration
|
|
42
|
+
* harness can point a real `crtr node new` at a deterministic fake-pi
|
|
43
|
+
* vehicle. Undefined in production. */
|
|
44
|
+
export declare function envPiBinaryOverride(): string | undefined;
|
|
45
|
+
/** Whether implicit daemon autostart is suppressed for this invocation
|
|
46
|
+
* (`CRTR_NO_DAEMON_AUTOSTART=1`). */
|
|
47
|
+
export declare function envNoDaemonAutostart(): boolean;
|
|
48
|
+
/** The `--tcp` fallback for crtrd's opt-in TCP listener (`CRTRD_TCP`), raw
|
|
49
|
+
* (`host:port` or undefined — absent means unix socket only). */
|
|
50
|
+
export declare function envCrtrdTcp(): string | undefined;
|
|
51
|
+
/** Kill switch for the host-exports writer/pruner (`CRTR_NO_EXPORTS=1`). */
|
|
52
|
+
export declare function envNoExports(): boolean;
|
|
53
|
+
/** Verbose-diagnostics gate for otherwise-silent best-effort catches
|
|
54
|
+
* (`CRTR_DEBUG=1`). Distinct from `CRTR_DEBUG_PID_LIVENESS`
|
|
55
|
+
* (`core/canvas/pid.ts`), a different, unrelated var. */
|
|
56
|
+
export declare function envDebug(): boolean;
|
|
57
|
+
/** Live-broker automatic-revive cap override (`CRTR_MAX_LIVE_BROKERS`); wins
|
|
58
|
+
* over `readConfig('user').brokerThresholds.automaticReviveCap` when set. */
|
|
59
|
+
export declare function envMaxLiveBrokers(): number | undefined;
|
|
60
|
+
/** Live-broker warning threshold override (`CRTR_WARN_LIVE_BROKERS`); wins
|
|
61
|
+
* over `readConfig('user').brokerThresholds.warning` when set. */
|
|
62
|
+
export declare function envWarnLiveBrokers(): number | undefined;
|
|
63
|
+
/** Test-only unattended-park interval override (`CRTR_TEST_UNATTENDED_PARK_MS`),
|
|
64
|
+
* gated by `envNoDaemonAutostart()` at the call site; no production default. */
|
|
65
|
+
export declare function envTestUnattendedParkMs(): number | undefined;
|
|
66
|
+
/** Test-only park-summary grace-period override
|
|
67
|
+
* (`CRTR_TEST_PARK_SUMMARY_GRACE_MS`); no production default. */
|
|
68
|
+
export declare function envTestParkSummaryGraceMs(): number | undefined;
|