@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
|
@@ -43,9 +43,7 @@ export const FAIL_BEFORE_SESSION_START_ONCE = '__FAIL_BEFORE_SESSION_START_ONCE_
|
|
|
43
43
|
* no turn) — the shape a broker whose model resolved but whose provider has
|
|
44
44
|
* no installed credential produces ("No API key found for <provider>"). */
|
|
45
45
|
export const REJECT_PROMPT_CALL = '__REJECT_PROMPT_CALL__';
|
|
46
|
-
// ---------------------------------------------------------------------------
|
|
47
46
|
// node dir / proof helpers
|
|
48
|
-
// ---------------------------------------------------------------------------
|
|
49
47
|
function nodeDirFromEnv() {
|
|
50
48
|
const home = (process.env['CRTR_HOME'] ?? '').trim();
|
|
51
49
|
const nodeId = (process.env['CRTR_NODE_ID'] ?? '').trim();
|
|
@@ -70,12 +68,10 @@ function recordError(dir, msg) {
|
|
|
70
68
|
/* ignore */
|
|
71
69
|
}
|
|
72
70
|
}
|
|
73
|
-
// ---------------------------------------------------------------------------
|
|
74
71
|
// SessionManager — the broker calls .open(path) (resume) or .create(cwd) (fresh)
|
|
75
72
|
// and hands the result to createAgentSession. sessionId/sessionFile round-trip
|
|
76
73
|
// through it, so a resume (`--session <pi_session_file>`) re-opens the SAME
|
|
77
74
|
// .jsonl the fresh start created — the load-bearing identity for revive.
|
|
78
|
-
// ---------------------------------------------------------------------------
|
|
79
75
|
export class SessionManager {
|
|
80
76
|
sessionId;
|
|
81
77
|
sessionFile;
|
|
@@ -138,7 +134,6 @@ export class SessionManager {
|
|
|
138
134
|
return this.leafId;
|
|
139
135
|
}
|
|
140
136
|
}
|
|
141
|
-
// ---------------------------------------------------------------------------
|
|
142
137
|
// AgentSessionEvent stream synthesis. The fake emits a
|
|
143
138
|
// REALISTIC streaming assistant turn through session.subscribe — the SAME channel
|
|
144
139
|
// the real pi engine feeds the broker's fan-out — so the frames a `crtr surface attach`
|
|
@@ -150,7 +145,6 @@ export class SessionManager {
|
|
|
150
145
|
// union, so a drift in the shape of any variant emitTurn() constructs (the
|
|
151
146
|
// streaming subset: the message_*, tool_execution_*, agent/turn start+end events)
|
|
152
147
|
// fails the build, not a test.
|
|
153
|
-
// ---------------------------------------------------------------------------
|
|
154
148
|
/** A minimal but fully-typed AssistantMessage. `pad` bytes of filler text let a
|
|
155
149
|
* test size a single frame to multiple MiB (G8 backpressure flood). */
|
|
156
150
|
function assistantMessage(text, pad = 0) {
|
|
@@ -403,7 +397,7 @@ class FakeSession {
|
|
|
403
397
|
this.recordModel();
|
|
404
398
|
return Promise.resolve();
|
|
405
399
|
}
|
|
406
|
-
//
|
|
400
|
+
// list_models / cycle_model read surface (real-SDK parity)
|
|
407
401
|
/** The broker's read-op picker data (buildListModelsData → registryOf(session))
|
|
408
402
|
* reads this. For a model-less boot it is the self-healing mask proxy — see
|
|
409
403
|
* modelRt. */
|
|
@@ -448,11 +442,11 @@ class FakeSession {
|
|
|
448
442
|
/* best effort */
|
|
449
443
|
}
|
|
450
444
|
}
|
|
451
|
-
//
|
|
445
|
+
// naming is cosmetic (broker calls it in a try/catch)
|
|
452
446
|
setSessionName(_name) {
|
|
453
447
|
/* no-op recording stub */
|
|
454
448
|
}
|
|
455
|
-
//
|
|
449
|
+
// controller-drive stubs (no controller connects in these tests)
|
|
456
450
|
prompt(text, _options) {
|
|
457
451
|
// Rejection seam: the engine refuses the call itself (pi's no-provider-
|
|
458
452
|
// credential shape) — the promise rejects and NO lifecycle event fires.
|
|
@@ -865,7 +859,7 @@ class FakeSession {
|
|
|
865
859
|
/* best effort */
|
|
866
860
|
}
|
|
867
861
|
}
|
|
868
|
-
//
|
|
862
|
+
// the ctx passed to fired handlers (union across both focus extensions)
|
|
869
863
|
buildCtx() {
|
|
870
864
|
return {
|
|
871
865
|
sessionManager: {
|
|
@@ -1250,16 +1244,12 @@ export async function createAgentSessionRuntime(createRuntime, options) {
|
|
|
1250
1244
|
const initial = await createRuntime(options);
|
|
1251
1245
|
return new FakeAgentSessionRuntime(createRuntime, options.cwd, options.agentDir, initial.session, initial.services);
|
|
1252
1246
|
}
|
|
1253
|
-
// ---------------------------------------------------------------------------
|
|
1254
1247
|
// VERSION — set to the SDK's published version so assertEngineVersion (which
|
|
1255
1248
|
// only logs, never throws) emits no spurious mismatch warning.
|
|
1256
|
-
// ---------------------------------------------------------------------------
|
|
1257
1249
|
export const VERSION = '0.78.1';
|
|
1258
|
-
// ---------------------------------------------------------------------------
|
|
1259
1250
|
// Parse the broker-launch.json recipe the host serialized (the PiInvocation
|
|
1260
1251
|
// buildPiArgv produced) for the proof shape — the same `-e`/`-n`/positional
|
|
1261
1252
|
// vocabulary fake-pi-host parses off its argv.
|
|
1262
|
-
// ---------------------------------------------------------------------------
|
|
1263
1253
|
function readLaunch(dir) {
|
|
1264
1254
|
let argv = [];
|
|
1265
1255
|
try {
|
|
@@ -61,7 +61,7 @@ if (home === '')
|
|
|
61
61
|
fail('CRTR_HOME missing in env');
|
|
62
62
|
const nodeDir = join(home, 'nodes', nodeId);
|
|
63
63
|
mkdirSync(nodeDir, { recursive: true });
|
|
64
|
-
//
|
|
64
|
+
// parse the argv the runtime built (buildPiArgv → piCommand)
|
|
65
65
|
const extPaths = [];
|
|
66
66
|
let sessionArg;
|
|
67
67
|
let label;
|
|
@@ -167,7 +167,7 @@ const ctx = {
|
|
|
167
167
|
/* spike: no-op */
|
|
168
168
|
},
|
|
169
169
|
};
|
|
170
|
-
//
|
|
170
|
+
// load the REAL extension modules from the -e paths
|
|
171
171
|
const loaded = [];
|
|
172
172
|
const failedExt = [];
|
|
173
173
|
for (const p of extPaths) {
|
|
@@ -187,9 +187,9 @@ for (const p of extPaths) {
|
|
|
187
187
|
recordError(`import ${p} failed: ${String(e)}`);
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
|
-
//
|
|
190
|
+
// session_start: the real boot-confirm hook captures session id + pid
|
|
191
191
|
await fire('session_start', { reason: resuming ? 'resume' : 'startup' }, ctx);
|
|
192
|
-
//
|
|
192
|
+
// the boot proof the harness asserts on
|
|
193
193
|
const boot = {
|
|
194
194
|
pid: process.pid,
|
|
195
195
|
nodeId,
|
|
@@ -226,7 +226,7 @@ try {
|
|
|
226
226
|
catch {
|
|
227
227
|
/* best effort */
|
|
228
228
|
}
|
|
229
|
-
//
|
|
229
|
+
// control loop: poll for one harness command at a time
|
|
230
230
|
const cmdFile = join(nodeDir, 'fake-pi.cmd');
|
|
231
231
|
const ackFile = join(nodeDir, 'fake-pi.ack');
|
|
232
232
|
function ack(id, body) {
|
|
@@ -38,17 +38,13 @@ after(() => {
|
|
|
38
38
|
rmSync(home, { recursive: true, force: true });
|
|
39
39
|
delete process.env['CRTR_HOME'];
|
|
40
40
|
});
|
|
41
|
-
// ---------------------------------------------------------------------------
|
|
42
41
|
// Migration v6 — the additive `focuses` table.
|
|
43
|
-
// ---------------------------------------------------------------------------
|
|
44
42
|
test('a fresh db migrates to the latest version and has the focuses table', () => {
|
|
45
43
|
const db = openDb();
|
|
46
44
|
assert.equal(userVersion(db), MIGRATIONS.length);
|
|
47
45
|
assert.ok(tableNames(db).includes('focuses'), 'focuses table exists on a fresh db');
|
|
48
46
|
});
|
|
49
|
-
// ---------------------------------------------------------------------------
|
|
50
47
|
// Canvas setters / reads — open / setOccupant / setPane / close round-trip.
|
|
51
|
-
// ---------------------------------------------------------------------------
|
|
52
48
|
test('open / setOccupant / close round-trip with the reads', () => {
|
|
53
49
|
openDb();
|
|
54
50
|
openFocusRow('f1', '%a', 'Sa', 'A');
|
|
@@ -85,7 +81,6 @@ test('independent focus rows do not contend', () => {
|
|
|
85
81
|
assert.deepEqual(getFocusByNode('B'), { focus_id: 'f2', pane: '%b', session: 'Sb', node_id: 'B' });
|
|
86
82
|
assert.deepEqual(listFocuses().map((f) => f.focus_id), ['f2']);
|
|
87
83
|
});
|
|
88
|
-
// ---------------------------------------------------------------------------
|
|
89
84
|
// Placement reads — focusOf / isFocused / focusByPane / focusedNodes /
|
|
90
85
|
// listFocuses GC dead-pane viewer rows on read (broker-host cut: liveOrPrune).
|
|
91
86
|
// A row whose viewer pane no longer exists is pruned the next time it is read,
|
|
@@ -93,7 +88,6 @@ test('independent focus rows do not contend', () => {
|
|
|
93
88
|
// registered-but-not-yet-realized viewer) is passed through. A live tmux pane
|
|
94
89
|
// can't be fabricated in the ordinary suite, so we cover the prune + null-pane paths
|
|
95
90
|
// here; the live-pane read is covered in the compiled-seam broker lifecycle suite.
|
|
96
|
-
// ---------------------------------------------------------------------------
|
|
97
91
|
test('placement reads GC dead-pane viewer rows and keep null-pane rows', () => {
|
|
98
92
|
openDb();
|
|
99
93
|
openFocusRow('f1', '%a', 'Sa', 'A'); // %a is not a live tmux pane → pruned on read
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { test, before, after } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { mkdtempSync, mkdirSync, rmSync, readdirSync, statSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { atomicWriteJson, atomicWriteText, readJson } from '../fs-utils.js';
|
|
7
|
+
let dir;
|
|
8
|
+
before(() => {
|
|
9
|
+
dir = mkdtempSync(join(tmpdir(), 'crtr-fs-utils-'));
|
|
10
|
+
});
|
|
11
|
+
after(() => {
|
|
12
|
+
rmSync(dir, { recursive: true, force: true });
|
|
13
|
+
});
|
|
14
|
+
test('atomicWriteText defaults a new file to 0o600', () => {
|
|
15
|
+
const path = join(dir, 'new-file.txt');
|
|
16
|
+
atomicWriteText(path, 'hello');
|
|
17
|
+
const mode = statSync(path).mode & 0o777;
|
|
18
|
+
assert.equal(mode, 0o600);
|
|
19
|
+
});
|
|
20
|
+
test('atomicWriteText preserves an existing file\'s mode on rewrite', () => {
|
|
21
|
+
const path = join(dir, 'existing-file.txt');
|
|
22
|
+
writeFileSync(path, 'first', { mode: 0o640 });
|
|
23
|
+
atomicWriteText(path, 'second');
|
|
24
|
+
const mode = statSync(path).mode & 0o777;
|
|
25
|
+
assert.equal(mode, 0o640);
|
|
26
|
+
});
|
|
27
|
+
test('atomicWriteText opts.mode forces a mode regardless of the existing file', () => {
|
|
28
|
+
const path = join(dir, 'forced-mode.txt');
|
|
29
|
+
writeFileSync(path, 'first', { mode: 0o640 });
|
|
30
|
+
atomicWriteText(path, 'second', { mode: 0o600 });
|
|
31
|
+
const mode = statSync(path).mode & 0o777;
|
|
32
|
+
assert.equal(mode, 0o600);
|
|
33
|
+
});
|
|
34
|
+
test('atomicWriteJson round-trips data and leaves no temp file after success', () => {
|
|
35
|
+
const path = join(dir, 'data.json');
|
|
36
|
+
atomicWriteJson(path, { hello: 'world' });
|
|
37
|
+
assert.deepEqual(readJson(path), { hello: 'world' });
|
|
38
|
+
const leftovers = readdirSync(dir).filter((name) => name.includes('.tmp'));
|
|
39
|
+
assert.deepEqual(leftovers, []);
|
|
40
|
+
});
|
|
41
|
+
test('atomicWriteText leaves no temp file behind after a forced rename failure', () => {
|
|
42
|
+
// Target an existing directory as the write path so ensureDir succeeds, the
|
|
43
|
+
// temp file is actually created, and only the rename step fails (EISDIR),
|
|
44
|
+
// exercising the finally-block cleanup path.
|
|
45
|
+
const path = join(dir, 'a-directory');
|
|
46
|
+
mkdirSync(path);
|
|
47
|
+
assert.throws(() => atomicWriteText(path, 'nope'));
|
|
48
|
+
const leftovers = readdirSync(dir).filter((name) => name.includes('.tmp'));
|
|
49
|
+
assert.deepEqual(leftovers, []);
|
|
50
|
+
});
|
|
@@ -36,7 +36,7 @@ import { bindDaemonEventSource, resetEventSourceForTests } from '../../events/so
|
|
|
36
36
|
import { bindFleet, resetFleetForTests } from '../../runtime/fleet.js';
|
|
37
37
|
import { readInboxSince } from '../../feed/inbox.js';
|
|
38
38
|
import { capturePidCommand, recordedPidLiveness } from '../../canvas/pid.js';
|
|
39
|
-
//
|
|
39
|
+
// locations
|
|
40
40
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
41
41
|
const TREE_ROOT = join(HERE, '..', '..', '..'); // src/ or dist/
|
|
42
42
|
const CROUTER = join(TREE_ROOT, '..'); // package root
|
|
@@ -15,14 +15,12 @@ import { clearSessionCache } from '../substrate/session-cache.js';
|
|
|
15
15
|
import { memoryDir as nodeMemoryDir } from '../runtime/memory.js';
|
|
16
16
|
import { buildRefInventory } from '../memory/inline-ref-inventory.js';
|
|
17
17
|
import { gatewayMemoryRows } from '../runtime/chat-inventory-rows.js';
|
|
18
|
-
// ---------------------------------------------------------------------------
|
|
19
18
|
// Wave C4 — buildRefInventory: the authoritative corpus builder. Fixture-
|
|
20
19
|
// backed (node/project/user scope docs on disk), since precedence dedup,
|
|
21
20
|
// referenceability-ignores-gate/slash, and directory browse names are all corpus-shape
|
|
22
21
|
// facts that a pure in-memory test can't exercise. Fixture names are prefixed
|
|
23
22
|
// to avoid any collision with the real shipped builtin/user corpus that
|
|
24
23
|
// listAllMemoryDocs() also picks up in this environment.
|
|
25
|
-
// ---------------------------------------------------------------------------
|
|
26
24
|
describe('buildRefInventory (fixture-backed corpus)', () => {
|
|
27
25
|
const NODE_ID = 'crtr-inline-ref-fixture-node';
|
|
28
26
|
const PROJECT_NAMESPACE = 'crtr-inline-ref-fixture-project';
|
|
@@ -118,11 +118,9 @@ test('D2 broker fork branch: buildBrokerSession(cfg.forkFrom) yields a NEW id +
|
|
|
118
118
|
session.dispose();
|
|
119
119
|
}
|
|
120
120
|
});
|
|
121
|
-
// ---------------------------------------------------------------------------
|
|
122
121
|
// resolveForkSource — a reference that resolves to no forkable session file
|
|
123
122
|
// must fail loudly BEFORE launch, rather than hand the broker a source it
|
|
124
123
|
// cannot fork.
|
|
125
|
-
// ---------------------------------------------------------------------------
|
|
126
124
|
function nodeRow(id, over = {}) {
|
|
127
125
|
return {
|
|
128
126
|
node_id: id,
|
|
@@ -27,9 +27,10 @@ import { join, dirname } from 'node:path';
|
|
|
27
27
|
import { fileURLToPath } from 'node:url';
|
|
28
28
|
import { createAgentSessionServices, createAgentSessionFromServices, SessionManager, VERSION, } from '../../runtime/broker-sdk.js';
|
|
29
29
|
import { buildBrokerSession, makeBrokerUiContext, snapshotMessages } from '../../runtime/broker.js';
|
|
30
|
-
import { isLeadingEngineCommand, resolveSteerCall, chooseGuidanceDeliveryMode, promptWithNextTurnGuidance,
|
|
30
|
+
import { isLeadingEngineCommand, resolveSteerCall, chooseGuidanceDeliveryMode, promptWithNextTurnGuidance, engineLeadingCommandTokens, } from '../../runtime/broker/engine-routing.js';
|
|
31
|
+
import { isHiddenJsonlBranchEntry, stripHiddenEntriesFromJsonlExport, } from '../../runtime/broker/frame-session.js';
|
|
31
32
|
import { CANVAS_EXTENSIONS } from '../../runtime/launch.js';
|
|
32
|
-
import { prepareAdvertisedCommandPersistence } from '../../runtime/advertised-command-invocation.js';
|
|
33
|
+
import { prepareAdvertisedCommandPersistence, promptWithAdvertisedCommandInvocation, } from '../../runtime/advertised-command-invocation.js';
|
|
33
34
|
// The REAL engine, assembled from broker-sdk's static SDK re-exports — bypasses
|
|
34
35
|
// the CRTR_BROKER_ENGINE seam entirely so these tests can never accidentally hit
|
|
35
36
|
// the fake (the whole point: prove the wiring the mock hid).
|
|
@@ -74,11 +75,9 @@ function brokerExts() {
|
|
|
74
75
|
function cfg(cwd, extra = {}) {
|
|
75
76
|
return { cwd, extensionPaths: brokerExts(), ...extra };
|
|
76
77
|
}
|
|
77
|
-
// ===========================================================================
|
|
78
78
|
// C3 — the SERVICES path registers an extension's custom model provider, so the
|
|
79
79
|
// broker resolves a model that plain createAgentSession (no registerProvider)
|
|
80
80
|
// would never see.
|
|
81
|
-
// ===========================================================================
|
|
82
81
|
test('C3 — services path registers an extension model provider; the broker session gets it', async () => {
|
|
83
82
|
const cwd = mkdtempSync(join(tmpdir(), 'crtr-c3-'));
|
|
84
83
|
try {
|
|
@@ -283,12 +282,10 @@ test('C3h — a cooling managed launch target boots model-less rather than falli
|
|
|
283
282
|
// `noContextFiles: true` in buildBrokerSession, and buildContextIntro's
|
|
284
283
|
// `<project_context>` block is environment-only. Covered by
|
|
285
284
|
// context-intro.test.ts's environment-only regression.)
|
|
286
|
-
// ===========================================================================
|
|
287
285
|
// C2 — zero-writable dialogs resolve to deny/cancel IMMEDIATELY (noOp), never
|
|
288
286
|
// hanging the turn and never waiting on a per-dialog timeout. Drives the REAL
|
|
289
287
|
// makeBrokerUiContext (the exact ExtensionUIContext the SDK hands extensions),
|
|
290
288
|
// with a writable() snapshot that reports zero writable viewers.
|
|
291
|
-
// ===========================================================================
|
|
292
289
|
test('C2 — zero-writable UI context resolves dialogs to deny/cancel immediately (noOp, no hang)', async () => {
|
|
293
290
|
const ctx = makeBrokerUiContext({
|
|
294
291
|
writable: () => [], // ZERO writable viewers attached
|
|
@@ -315,14 +312,12 @@ test('C2 — zero-writable UI context resolves dialogs to deny/cancel immediatel
|
|
|
315
312
|
assert.equal(await ctx.input('name'), undefined, 'C2: input() cancels (undefined)');
|
|
316
313
|
assert.equal(await ctx.editor('edit'), undefined, 'C2: editor() cancels (undefined)');
|
|
317
314
|
});
|
|
318
|
-
// ===========================================================================
|
|
319
315
|
// M2 (review mq5wkqep / T4) — REPLACES the Wave-0 M-1 cancel-on-detach. A dialog
|
|
320
316
|
// forwarded to a writable viewer that then DETACHES must NOT be cancelled: it
|
|
321
317
|
// stays pending so a brief detach/reattach (or another writable viewer joining)
|
|
322
318
|
// does not lose an answerable dialog. The broker-side default timeout is the ONLY
|
|
323
319
|
// non-answer resolution (proven here with a short per-dialog timeout standing in
|
|
324
320
|
// for the 120s default). Guards against regressing to the over-eager cancel.
|
|
325
|
-
// ===========================================================================
|
|
326
321
|
test('M2 — a forwarded dialog stays pending when its writable viewer detaches, resolving only on the broker-side timeout', async () => {
|
|
327
322
|
const pending = new Map();
|
|
328
323
|
let attached = true;
|
|
@@ -355,7 +350,6 @@ test('M2 — a forwarded dialog stays pending when its writable viewer detaches,
|
|
|
355
350
|
assert.equal(resolved, false, 'M2: resolves to deny on the broker-side timeout, never hangs');
|
|
356
351
|
assert.equal(pending.size, 0, 'M2: the pending registry is drained after the timeout');
|
|
357
352
|
});
|
|
358
|
-
// ===========================================================================
|
|
359
353
|
// C5 — exact leading engine-command suppression and hidden display:false
|
|
360
354
|
// guidance delivery ordering.
|
|
361
355
|
//
|
|
@@ -374,7 +368,6 @@ test('M2 — a forwarded dialog stays pending when its writable viewer detaches,
|
|
|
374
368
|
// verbatim sibling of the compiled-seam-covered `list_models` dispatch whose only
|
|
375
369
|
// non-trivial input, `engineLeadingCommandTokens(session)`, is proven below
|
|
376
370
|
// against a real session.
|
|
377
|
-
// ===========================================================================
|
|
378
371
|
test('a streaming extension command uses prompt preflight instead of the rejecting steer queue', () => {
|
|
379
372
|
const session = { extensionRunner: { getCommand: (name) => (name === 'recap' ? { name: 'recap' } : undefined) } };
|
|
380
373
|
assert.equal(resolveSteerCall('/recap', session), 'prompt');
|
|
@@ -555,14 +548,12 @@ test('C5 — fake-engine sendCustomMessage records the call in order without cra
|
|
|
555
548
|
rmSync(cwd, { recursive: true, force: true });
|
|
556
549
|
}
|
|
557
550
|
});
|
|
558
|
-
// ===========================================================================
|
|
559
551
|
// Review fix (Major 1) — promptWithNextTurnGuidance atomically clears its own
|
|
560
552
|
// pending nextTurn guidance if the prompt it rode alongside never reaches pi's
|
|
561
553
|
// internal drain point (agent-session.js `prompt()` step 8) — an extension-
|
|
562
554
|
// command interception (step 1, `_tryExecuteExtensionCommand`) is a genuine,
|
|
563
555
|
// fully offline SDK early-return that proves the exact leak window the review
|
|
564
556
|
// flagged, without touching model/auth/network.
|
|
565
|
-
// ===========================================================================
|
|
566
557
|
test('Major 1 fix — promptWithNextTurnGuidance clears its own pending guidance when the human prompt is intercepted by an extension command (never reaches pi\'s drain)', async () => {
|
|
567
558
|
const cwd = mkdtempSync(join(tmpdir(), 'crtr-m1-atomic-'));
|
|
568
559
|
try {
|
|
@@ -628,13 +619,11 @@ test('Major 1 fix — promptWithNextTurnGuidance leaves the queue drained (not d
|
|
|
628
619
|
rmSync(cwd, { recursive: true, force: true });
|
|
629
620
|
}
|
|
630
621
|
});
|
|
631
|
-
// ===========================================================================
|
|
632
622
|
// Review fix (Major 2) — JSONL export (`session.exportToJsonl` via the broker
|
|
633
623
|
// `case 'export'` handler) must honor the general `display:false` boundary,
|
|
634
624
|
// not just `crtr-memory-refs` guidance. `stripHiddenEntriesFromJsonlExport`
|
|
635
625
|
// rewrites the exported file in place; covers ACTUAL exported JSONL bytes,
|
|
636
626
|
// not `transcriptMarkdown`.
|
|
637
|
-
// ===========================================================================
|
|
638
627
|
test('Major 2 fix — isHiddenJsonlBranchEntry recognizes both persisted display:false shapes', () => {
|
|
639
628
|
assert.equal(isHiddenJsonlBranchEntry({ type: 'custom_message', display: false }), true, 'a hidden custom_message entry matches');
|
|
640
629
|
assert.equal(isHiddenJsonlBranchEntry({ type: 'custom_message', display: true }), false, 'a visible custom_message entry does not match');
|
|
@@ -684,12 +673,10 @@ test('Major 2 fix — exportToJsonl (via the broker export path) strips display:
|
|
|
684
673
|
rmSync(cwd, { recursive: true, force: true });
|
|
685
674
|
}
|
|
686
675
|
});
|
|
687
|
-
// ===========================================================================
|
|
688
676
|
// Review fix (Major 6, broker/protocol half) — the `list_memory_refs` read-op
|
|
689
677
|
// publishes `engineLeadingCommandNames` as metadata SEPARATE from `refs`
|
|
690
678
|
// (RefMeta rows), exactly matching `isLeadingEngineCommand`'s three sources,
|
|
691
679
|
// so viewers can combine it with their own locally-consumed commands.
|
|
692
|
-
// ===========================================================================
|
|
693
680
|
test('Major 6 (broker half) — engineLeadingCommandTokens degrades to empty per-source without throwing, and never touches refs/RefMeta shape', () => {
|
|
694
681
|
assert.deepEqual(engineLeadingCommandTokens({}), [], 'a bare session with no accessors at all degrades to an empty enumeration');
|
|
695
682
|
const throwingExtButRealTemplate = {
|
|
@@ -45,10 +45,8 @@ import { pluginDisable, pluginEnable, pluginInstall } from '../../../commands/pk
|
|
|
45
45
|
// import the real SUBTREE_NAMES (build-root.ts pulls the whole tree); a small
|
|
46
46
|
// explicit set is enough for the collision contract and keeps the test cheap.
|
|
47
47
|
const RESERVED = new Set(['push', 'node', 'canvas', 'sys', 'memory']);
|
|
48
|
-
// ---------------------------------------------------------------------------
|
|
49
48
|
// Fixture executable: reads one JSON request on stdin, writes one envelope.
|
|
50
49
|
// Behavior is selected by req.input.mode so one binary drives the whole table.
|
|
51
|
-
// ---------------------------------------------------------------------------
|
|
52
50
|
const FIXTURE_EXEC = `#!/usr/bin/env node
|
|
53
51
|
const fs = require('fs');
|
|
54
52
|
let data = '';
|
|
@@ -163,9 +161,7 @@ function installPlugin(scopeRoot, name, opts = {}) {
|
|
|
163
161
|
}
|
|
164
162
|
return root;
|
|
165
163
|
}
|
|
166
|
-
// ---------------------------------------------------------------------------
|
|
167
164
|
// Isolated home + workspace
|
|
168
|
-
// ---------------------------------------------------------------------------
|
|
169
165
|
let home; // becomes HOME → user scope root = $HOME/.crouter
|
|
170
166
|
let userRoot;
|
|
171
167
|
let projectDir; // a workspace with its own .crouter (project scope)
|
|
@@ -219,9 +215,7 @@ function leafOf(branch, name) {
|
|
|
219
215
|
assert.ok(c !== undefined && c.kind === 'leaf', `expected leaf ${name}`);
|
|
220
216
|
return c;
|
|
221
217
|
}
|
|
222
|
-
// ---------------------------------------------------------------------------
|
|
223
218
|
// 1. Registry composition
|
|
224
|
-
// ---------------------------------------------------------------------------
|
|
225
219
|
describe('registry composition', () => {
|
|
226
220
|
test('a fixture top-level branch composes with plugin-owned help, schema, effects, stable order', () => {
|
|
227
221
|
installPlugin(userRoot, 'deploy-tools');
|
|
@@ -258,9 +252,7 @@ describe('registry composition', () => {
|
|
|
258
252
|
assert.match(leafOut, /None\. Read-only\./);
|
|
259
253
|
});
|
|
260
254
|
});
|
|
261
|
-
// ---------------------------------------------------------------------------
|
|
262
255
|
// 2. Core collision
|
|
263
|
-
// ---------------------------------------------------------------------------
|
|
264
256
|
describe('core collision', () => {
|
|
265
257
|
test('a fixture claiming a core top-level name is skipped + recorded', () => {
|
|
266
258
|
installPlugin(userRoot, 'rogue', { manifest: commandsJson('push') });
|
|
@@ -274,9 +266,7 @@ describe('core collision', () => {
|
|
|
274
266
|
assert.equal(collision.contributor.name, 'rogue');
|
|
275
267
|
});
|
|
276
268
|
});
|
|
277
|
-
// ---------------------------------------------------------------------------
|
|
278
269
|
// 3. Scope / shadowing
|
|
279
|
-
// ---------------------------------------------------------------------------
|
|
280
270
|
describe('scope shadowing', () => {
|
|
281
271
|
test('a project copy shadows a user copy of the same plugin name', () => {
|
|
282
272
|
installPlugin(userRoot, 'deploy-tools');
|
|
@@ -298,9 +288,7 @@ describe('scope shadowing', () => {
|
|
|
298
288
|
assert.equal(effective.length, 0, 'the disabled higher-precedence copy must suppress the user copy');
|
|
299
289
|
});
|
|
300
290
|
});
|
|
301
|
-
// ---------------------------------------------------------------------------
|
|
302
291
|
// 4. Protocol integration (table-driven)
|
|
303
|
-
// ---------------------------------------------------------------------------
|
|
304
292
|
describe('protocol integration', () => {
|
|
305
293
|
function showLeaf() {
|
|
306
294
|
installPlugin(userRoot, 'deploy-tools');
|
|
@@ -368,9 +356,7 @@ describe('protocol integration', () => {
|
|
|
368
356
|
});
|
|
369
357
|
}
|
|
370
358
|
});
|
|
371
|
-
// ---------------------------------------------------------------------------
|
|
372
359
|
// 4b. True end-to-end CLI invocation (argv → parseArgv → adapter → renderer)
|
|
373
|
-
// ---------------------------------------------------------------------------
|
|
374
360
|
describe('end-to-end CLI invocation', () => {
|
|
375
361
|
// dist/cli.js is up 4 from src/core/__tests__/integration/. Requires a prior
|
|
376
362
|
// `npm run build` (the harness/CI builds before tests). Drives the WHOLE seam: the
|
|
@@ -398,9 +384,7 @@ describe('end-to-end CLI invocation', () => {
|
|
|
398
384
|
assert.equal(obj.status, 'running');
|
|
399
385
|
});
|
|
400
386
|
});
|
|
401
|
-
// ---------------------------------------------------------------------------
|
|
402
387
|
// 5. Lifecycle without restart (per-invocation discovery)
|
|
403
|
-
// ---------------------------------------------------------------------------
|
|
404
388
|
describe('lifecycle without restart', () => {
|
|
405
389
|
test('install → appears; disable → gone; edit → visible; remove → gone', () => {
|
|
406
390
|
const discover = () => {
|
|
@@ -425,9 +409,7 @@ describe('lifecycle without restart', () => {
|
|
|
425
409
|
assert.equal(discover().length, 0);
|
|
426
410
|
});
|
|
427
411
|
});
|
|
428
|
-
// ---------------------------------------------------------------------------
|
|
429
412
|
// 6/7. Typed issues without executing the binary
|
|
430
|
-
// ---------------------------------------------------------------------------
|
|
431
413
|
describe('typed validation issues', () => {
|
|
432
414
|
function validate(manifest, extra = {}) {
|
|
433
415
|
installPlugin(userRoot, 'p', { manifest, ...extra });
|
|
@@ -513,7 +495,6 @@ describe('typed validation issues', () => {
|
|
|
513
495
|
assert.equal(v.contributions[0].node.name, 'app');
|
|
514
496
|
});
|
|
515
497
|
});
|
|
516
|
-
// ---------------------------------------------------------------------------
|
|
517
498
|
// Plugin help addenda — the append-only product-guidance seam. An addendum
|
|
518
499
|
// that quietly stops rendering is exactly the silent-absence class: pin that a
|
|
519
500
|
// valid entry survives validation and is collected attributed, and that the
|
|
@@ -522,7 +503,6 @@ describe('typed validation issues', () => {
|
|
|
522
503
|
// plugin's tree. The help-render lookup receives the gate's exact inputs, so a
|
|
523
504
|
// map rejected at ingress renders nothing — render never disagrees with the
|
|
524
505
|
// install report.
|
|
525
|
-
// ---------------------------------------------------------------------------
|
|
526
506
|
describe('plugin help addenda', () => {
|
|
527
507
|
const gate = (paths) => ({
|
|
528
508
|
reservedCoreNames: RESERVED,
|
|
@@ -599,11 +579,9 @@ describe('plugin help addenda', () => {
|
|
|
599
579
|
assert.ok(out.includes('ADDENDUM RENDERED THROUGH THE REAL HELP PATH'), out.slice(-400));
|
|
600
580
|
});
|
|
601
581
|
});
|
|
602
|
-
// ---------------------------------------------------------------------------
|
|
603
582
|
// Lifecycle surfaces — the validator's verdict must reach the caller WITHOUT
|
|
604
583
|
// executing the plugin binary, and a cross-plugin top-level collision must
|
|
605
584
|
// preserve every claimant under its origin-qualified command name.
|
|
606
|
-
// ---------------------------------------------------------------------------
|
|
607
585
|
describe('lifecycle surfaces report validation without executing the plugin', () => {
|
|
608
586
|
// Records the fact it ran. No validation surface may ever spawn it.
|
|
609
587
|
const SENTINEL_EXEC = `#!/usr/bin/env node
|
|
@@ -664,14 +642,12 @@ process.stdout.write(JSON.stringify({ protocolVersion: 1, ok: true, result: { ap
|
|
|
664
642
|
assertNotExecuted();
|
|
665
643
|
});
|
|
666
644
|
});
|
|
667
|
-
// ---------------------------------------------------------------------------
|
|
668
645
|
// Memory-corpus gate across the plugin lifecycle — install, and enable of a
|
|
669
646
|
// package installed while disabled, both converge the candidate's memory store
|
|
670
647
|
// onto exact canonical identity BEFORE it can mount. A local-path install stays
|
|
671
648
|
// a live link, so the caller's own directory is the corpus that gets rewritten;
|
|
672
649
|
// a corpus that cannot converge writes nothing and changes no config. Update
|
|
673
650
|
// runs the same gate through the same helper, so it needs no cases of its own.
|
|
674
|
-
// ---------------------------------------------------------------------------
|
|
675
651
|
describe('memory corpus gate across the plugin lifecycle', () => {
|
|
676
652
|
let realCwd;
|
|
677
653
|
beforeEach(() => {
|
|
@@ -145,9 +145,7 @@ after(() => {
|
|
|
145
145
|
process.env['CRTR_NODE_ID'] = prevNodeId;
|
|
146
146
|
resetFleetForTests();
|
|
147
147
|
});
|
|
148
|
-
// ---------------------------------------------------------------------------
|
|
149
148
|
// Command layer — the immediate-delivery wake block in node.ts
|
|
150
|
-
// ---------------------------------------------------------------------------
|
|
151
149
|
test('node message send --tier deferred to an ordinary dormant (idle-released) target does not revive it — appended and held for the next natural cycle', { timeout: 30_000 }, async () => {
|
|
152
150
|
const id = 'idleReleaseTarget';
|
|
153
151
|
createNode(node(id, { status: 'idle', intent: 'idle-release' }));
|
|
@@ -286,12 +284,10 @@ test('#343 (immediate path): `node message send --tier deferred --reopen` agains
|
|
|
286
284
|
assert.equal(readInboxSince(id, undefined).length, inboxBefore, 'a rejected reopen+deferred retask must not append an inbox entry');
|
|
287
285
|
assert.equal(getNode(id)?.final_report, firstFinal, 'the canonical final must survive untouched — assertFinalizedForReopen/commitReopen never ran on the rejected path');
|
|
288
286
|
});
|
|
289
|
-
// ---------------------------------------------------------------------------
|
|
290
287
|
// The shared `withFreshTerminalGuard` primitive itself (Major, gh #341/#343
|
|
291
288
|
// review). Every caller that needs a fresh terminal-status check and a
|
|
292
289
|
// dependent write to share one transaction — the immediate deferred path
|
|
293
290
|
// above, and any future arm/schedule doorway — rides this one function.
|
|
294
|
-
// ---------------------------------------------------------------------------
|
|
295
291
|
// #343 review, Major 1: the fresh terminal-status check and a guarded write
|
|
296
292
|
// that depends on it must share ONE transaction, or a concurrent finish/
|
|
297
293
|
// cancel/finalization can land in the gap and silently strand the write. This
|
|
@@ -366,9 +362,7 @@ test("withFreshTerminalGuard reports 'missing' — never runs the guarded body
|
|
|
366
362
|
assert.deepEqual(outcome, { kind: 'missing' }, "the guard reports a distinct 'missing' outcome, not 'terminal' (nothing to report) and not a fabricated 'ran'");
|
|
367
363
|
assert.equal(existsSync(nodeDir(targetId)), false, 'the guarded appendInbox never ran, so no orphan node dir was recreated for the deleted target');
|
|
368
364
|
});
|
|
369
|
-
// ---------------------------------------------------------------------------
|
|
370
365
|
// Daemon second pass — crtrd.ts's idle-release inbox loop
|
|
371
|
-
// ---------------------------------------------------------------------------
|
|
372
366
|
// Deterministic: `headlessBrokerHost.launch` is fully STUBBED (never delegates
|
|
373
367
|
// to the real launcher) so `reviveNode` cannot spawn a real detached broker/pi
|
|
374
368
|
// process as a side effect of this decision test — the stubbed HostHandle's
|