@north-light/crouter 0.3.233 → 0.3.235
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.js +16 -15
- package/dist/api/dto/nodes.d.ts +11 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +1 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +14 -17
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/crtr-commands/index.ts +7 -11
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/index.ts +8 -8
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +10 -11
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/pi-shell-runner.ts +2 -2
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +3 -3
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +7 -7
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +8 -8
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +6 -6
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/sysprompt-window.ts +3 -3
- package/dist/builtin-pi-packages/pi-crtr-extensions/lib/subscription-state.ts +1 -1
- package/dist/clients/attach/chrome/ticket-panel.js +15 -2
- package/dist/clients/attach/overlays/graph.js +0 -3
- package/dist/clients/attach/overlays/mcp.js +1 -2
- package/dist/clients/attach/render/chat-view.js +0 -12
- package/dist/clients/attach/render/crtr-output.js +0 -2
- package/dist/clients/attach/render/tool-calls.js +0 -6
- package/dist/clients/attach/slash/dispatch.js +8 -11
- package/dist/clients/attach/viewer.js +535 -537
- package/dist/clients/conversation/projection.js +0 -2
- package/dist/clients/inbox/controller.js +22 -3
- package/dist/clients/inbox/review/companion-pane.js +0 -4
- package/dist/clients/inbox/review-adapter.js +0 -7
- package/dist/clients/inbox/tui/slots.d.ts +3 -3
- package/dist/clients/inbox/tui/types.d.ts +2 -2
- package/dist/commands/api-client.js +0 -8
- package/dist/commands/attention.js +1 -9
- package/dist/commands/canvas-browse.js +2 -1
- package/dist/commands/canvas-config.js +0 -10
- package/dist/commands/canvas-history.js +2 -1
- package/dist/commands/cron.js +10 -23
- package/dist/commands/dashboard.js +0 -2
- package/dist/commands/human/feedback.js +2 -1
- package/dist/commands/human/prompts.js +2 -5
- package/dist/commands/human/queue.js +2 -7
- package/dist/commands/human/request.js +0 -14
- package/dist/commands/human/review.js +2 -1
- package/dist/commands/human.js +1 -1
- package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +4 -4
- package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.d.ts +1 -0
- package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.js +96 -0
- package/dist/commands/memory/delete.js +1 -1
- package/dist/commands/memory/edit.js +6 -3
- package/dist/commands/memory/find.js +2 -2
- package/dist/commands/memory/lint.js +2 -1
- package/dist/commands/memory/list.d.ts +4 -0
- package/dist/commands/memory/list.js +20 -14
- package/dist/commands/memory/move.js +1 -1
- package/dist/commands/memory/read.d.ts +2 -7
- package/dist/commands/memory/read.js +5 -16
- package/dist/commands/memory/shared.d.ts +1 -0
- package/dist/commands/memory/shared.js +17 -8
- package/dist/commands/memory/write.js +8 -4
- package/dist/commands/node/bash.js +2 -1
- package/dist/commands/node/create.js +2 -1
- package/dist/commands/node/inspect.js +11 -10
- package/dist/commands/node/lifecycle.js +5 -13
- package/dist/commands/node/message.js +11 -6
- package/dist/commands/node/subscription.js +7 -2
- package/dist/commands/node/wait.js +9 -4
- package/dist/commands/node-context.js +2 -1
- package/dist/commands/node-lifecycle-revive.js +0 -2
- package/dist/commands/node-worktree.js +2 -1
- package/dist/commands/pkg/browse/actions.d.ts +1 -1
- package/dist/commands/pkg/browse/actions.js +4 -4
- package/dist/commands/pkg/browse/catalog.d.ts +1 -1
- package/dist/commands/pkg/browse/catalog.js +15 -15
- package/dist/commands/pkg/browse/command-view.d.ts +1 -1
- package/dist/commands/pkg/browse/command-view.js +3 -3
- package/dist/commands/pkg/browse/detail-panel.d.ts +1 -1
- package/dist/commands/pkg/browse/detail-panel.js +8 -8
- package/dist/commands/pkg/browse/doc-view.d.ts +1 -1
- package/dist/commands/pkg/browse/doc-view.js +3 -3
- package/dist/commands/pkg/browse/list-panel.d.ts +1 -1
- package/dist/commands/pkg/browse/list-panel.js +3 -3
- package/dist/commands/pkg/browse/model.d.ts +3 -3
- package/dist/commands/pkg/browse/shell.d.ts +2 -2
- package/dist/commands/pkg/browse/shell.js +13 -13
- package/dist/commands/pkg/plugin-manage.js +3 -2
- package/dist/commands/pkg/shared.js +0 -2
- package/dist/commands/pkg.js +1 -0
- package/dist/commands/profile/delete.js +2 -1
- package/dist/commands/profile/rename.js +1 -1
- package/dist/commands/push.js +2 -3
- package/dist/commands/revive.js +0 -2
- package/dist/commands/surface/node/placement.js +2 -1
- package/dist/commands/surface-edit.js +2 -1
- package/dist/commands/sys/config.js +1 -4
- package/dist/commands/sys/daemon.js +0 -10
- package/dist/commands/sys/doctor.js +3 -2
- package/dist/commands/sys/panels/broker-limits-panel.d.ts +2 -2
- package/dist/commands/sys/panels/broker-limits-panel.js +4 -4
- package/dist/commands/sys/panels/dependencies-panel.d.ts +2 -2
- package/dist/commands/sys/panels/dependencies-panel.js +2 -2
- package/dist/commands/sys/panels/keybindings-panel.d.ts +1 -1
- package/dist/commands/sys/panels/keybindings-panel.js +5 -5
- package/dist/commands/sys/panels/models-panel.d.ts +4 -4
- package/dist/commands/sys/panels/models-panel.js +11 -10
- package/dist/commands/sys/panels/plugins-panel.d.ts +2 -2
- package/dist/commands/sys/panels/plugins-panel.js +2 -2
- package/dist/commands/sys/panels/prefs-panel.d.ts +2 -2
- package/dist/commands/sys/panels/prefs-panel.js +4 -4
- package/dist/commands/sys/panels/profiles-panel.d.ts +1 -1
- package/dist/commands/sys/panels/profiles-panel.js +14 -13
- package/dist/commands/sys/panels/provider-panel.d.ts +3 -3
- package/dist/commands/sys/panels/provider-panel.js +8 -8
- package/dist/commands/sys/settings-shell.d.ts +3 -3
- package/dist/commands/sys/settings-shell.js +15 -15
- package/dist/commands/sys/setup-settings-runner.d.ts +3 -3
- package/dist/commands/sys/setup-settings-runner.js +5 -5
- package/dist/commands/sys/setup-wizard.d.ts +4 -4
- package/dist/commands/sys/setup-wizard.js +8 -8
- package/dist/commands/sys/support/prepare.js +4 -4
- package/dist/commands/sys/support/submit.js +2 -2
- package/dist/commands/sys/sync-deps.js +0 -2
- package/dist/commands/sys/sync-project-guidance.js +2 -1
- package/dist/commands/sys/sysprompt.js +2 -1
- package/dist/commands/sys.js +1 -0
- package/dist/core/__tests__/boot.test.js +0 -8
- package/dist/core/__tests__/broker-extension-canvas-db-boundary.test.js +23 -1
- package/dist/core/__tests__/canvas-db-boundary.test.d.ts +1 -0
- package/dist/core/__tests__/canvas-db-boundary.test.js +46 -0
- package/dist/core/__tests__/canvas.test.js +1 -1
- package/dist/core/__tests__/child-death-wake.test.js +0 -2
- package/dist/core/__tests__/cli-help-contract.test.d.ts +1 -0
- package/dist/core/__tests__/cli-help-contract.test.js +150 -0
- package/dist/core/__tests__/cron-armed-context-failure.test.d.ts +1 -0
- package/dist/core/__tests__/cron-armed-context-failure.test.js +145 -0
- package/dist/core/__tests__/daemon-wedge.test.js +0 -4
- package/dist/core/__tests__/dead-node-policy-table.test.js +0 -4
- package/dist/core/__tests__/fixtures/fake-engine.js +4 -14
- package/dist/core/__tests__/fixtures/fake-pi-host.js +5 -5
- package/dist/core/__tests__/focuses.test.js +0 -6
- package/dist/core/__tests__/fs-utils.test.d.ts +1 -0
- package/dist/core/__tests__/fs-utils.test.js +50 -0
- package/dist/core/__tests__/helpers/harness.js +1 -1
- package/dist/core/__tests__/inline-memory-refs.test.js +0 -2
- package/dist/core/__tests__/integration/broker-fork-seam.test.js +0 -2
- package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +3 -16
- package/dist/core/__tests__/integration/command-plugins.test.js +21 -24
- package/dist/core/__tests__/integration/deferred-no-wake.test.js +0 -6
- package/dist/core/__tests__/integration/flagship-lifecycle.test.js +0 -26
- package/dist/core/__tests__/integration/live-mutation-verbs.test.js +0 -4
- package/dist/core/__tests__/integration/live-mutation.test.js +1 -5
- package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +1 -5
- package/dist/core/__tests__/integration/revive.test.js +0 -12
- package/dist/core/__tests__/integration/subscription-delivery.test.js +0 -6
- package/dist/core/__tests__/integration/tmux-surface.test.js +24 -8
- package/dist/core/__tests__/integration/worktree-reap.test.js +0 -6
- package/dist/core/__tests__/lifecycle.test.js +0 -18
- package/dist/core/__tests__/memory-resolver-precedence.test.js +1 -1
- package/dist/core/__tests__/migration.test.js +2 -2
- package/dist/core/__tests__/on-read-dedup-resume.test.js +3 -3
- package/dist/core/__tests__/pid-identity-match.test.js +1 -1
- package/dist/core/__tests__/plugin-kinds.test.js +1 -1
- package/dist/core/__tests__/plugin-page-components.test.js +1 -1
- package/dist/core/__tests__/preview-registry-sync.test.js +42 -1
- package/dist/core/__tests__/respawn-throttle.test.js +0 -4
- package/dist/core/__tests__/revive-all.test.js +5 -5
- package/dist/core/__tests__/revive-parked-fresh.test.js +62 -11
- package/dist/core/__tests__/seam/broker-attach-multiclient.test.js +0 -8
- package/dist/core/__tests__/seam/broker-attach-stream.test.js +0 -8
- package/dist/core/__tests__/seam/broker-crash-teardown.test.js +0 -2
- package/dist/core/__tests__/tmux-driver-boundary.test.d.ts +1 -0
- package/dist/core/__tests__/tmux-driver-boundary.test.js +50 -0
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +11 -6
- package/dist/core/activity-signal.d.ts +7 -0
- package/dist/core/activity-signal.js +38 -0
- package/dist/core/auto-update.js +2 -1
- package/dist/core/bootstrap.js +2 -1
- package/dist/core/canvas/__tests__/remote-canvas-source.test.js +1 -1
- package/dist/core/canvas/__tests__/remote-transport.test.js +1 -1
- package/dist/core/canvas/__tests__/render-remote.test.js +1 -1
- package/dist/core/canvas/browse/app.js +3 -2
- package/dist/core/canvas/browse/model.d.ts +1 -1
- package/dist/core/canvas/browse/model.js +0 -4
- package/dist/core/canvas/canvas.d.ts +22 -0
- package/dist/core/canvas/canvas.js +61 -19
- package/dist/core/canvas/crons.js +0 -6
- package/dist/core/canvas/db.d.ts +14 -20
- package/dist/core/canvas/db.js +30 -1332
- package/dist/core/canvas/focuses.js +0 -4
- package/dist/core/canvas/history.js +2 -1
- package/dist/core/canvas/meta-file.js +18 -27
- package/dist/core/canvas/migrations.d.ts +20 -0
- package/dist/core/canvas/migrations.js +1339 -0
- package/dist/core/canvas/nav-model.js +1 -11
- package/dist/core/canvas/nav-render.js +0 -8
- package/dist/core/canvas/remote-canvas-source.d.ts +8 -0
- package/dist/core/canvas/remote-canvas-source.js +9 -3
- package/dist/core/canvas/render-source.js +31 -13
- package/dist/core/command-manifests/manifest.js +0 -10
- package/dist/core/command-manifests/registry.d.ts +2 -0
- package/dist/core/command-manifests/schema.js +0 -4
- package/dist/core/command-plugins/compose.js +4 -2
- package/dist/core/command-plugins/discovery.d.ts +1 -0
- package/dist/core/command-plugins/discovery.js +1 -1
- package/dist/core/command-plugins/transport/http-invoke.js +0 -14
- package/dist/core/command.js +2 -6
- package/dist/core/config.js +2 -1
- package/dist/core/fault-classifier.js +8 -0
- package/dist/core/feed/inbox.d.ts +10 -0
- package/dist/core/feed/inbox.js +18 -12
- package/dist/core/fs-utils.d.ts +9 -2
- package/dist/core/fs-utils.js +7 -15
- package/dist/core/help.js +0 -8
- package/dist/core/host-exports/export.d.ts +2 -2
- package/dist/core/host-exports/export.js +9 -12
- package/dist/core/human/answer.d.ts +2 -2
- package/dist/core/human/convention.d.ts +2 -5
- package/dist/core/human/convention.js +3 -13
- package/dist/core/human/page-schema.d.ts +2 -2
- package/dist/core/human/page-schema.js +2 -2
- package/dist/core/human/root.js +6 -23
- package/dist/core/human/scan.js +24 -7
- package/dist/core/human/tickets.d.ts +4 -1
- package/dist/core/human/tickets.js +20 -6
- package/dist/core/io.js +0 -12
- package/dist/core/memory/identity.js +0 -4
- package/dist/core/memory/inline-ref-inventory.js +3 -2
- package/dist/core/memory/lint.js +3 -6
- package/dist/core/memory-resolver.d.ts +5 -0
- package/dist/core/memory-resolver.js +14 -12
- package/dist/core/pagination.d.ts +2 -0
- package/dist/core/pagination.js +2 -3
- package/dist/core/preview-registry.d.ts +14 -0
- package/dist/core/preview-registry.js +2 -4
- package/dist/core/preview-result-path.js +2 -1
- package/dist/core/profiles/manifest.d.ts +37 -5
- package/dist/core/profiles/manifest.js +44 -24
- package/dist/core/profiles/select.js +0 -4
- package/dist/core/review/signal.js +4 -23
- package/dist/core/review/ticket-filter.d.ts +3 -3
- package/dist/core/review/ticket-filter.js +4 -9
- package/dist/core/runtime/__tests__/engine-route.test.js +1 -1
- package/dist/core/runtime/__tests__/spawn-env.test.js +0 -8
- package/dist/core/runtime/bearings-render.d.ts +56 -0
- package/dist/core/runtime/bearings-render.js +241 -0
- package/dist/core/runtime/bearings.d.ts +2 -17
- package/dist/core/runtime/bearings.js +12 -198
- package/dist/core/runtime/broker/auth-reload.d.ts +39 -0
- package/dist/core/runtime/broker/auth-reload.js +149 -0
- package/dist/core/runtime/broker/engine-drive.d.ts +26 -0
- package/dist/core/runtime/broker/engine-drive.js +257 -0
- package/dist/core/runtime/broker/engine-routing.d.ts +143 -0
- package/dist/core/runtime/broker/engine-routing.js +211 -0
- package/dist/core/runtime/broker/event-projection.js +3 -2
- package/dist/core/runtime/broker/fault-retry.js +11 -4
- package/dist/core/runtime/broker/frame-client.d.ts +38 -0
- package/dist/core/runtime/broker/frame-client.js +129 -0
- package/dist/core/runtime/broker/frame-dispatch.d.ts +12 -189
- package/dist/core/runtime/broker/frame-dispatch.js +89 -1476
- package/dist/core/runtime/broker/frame-engine-control.d.ts +20 -0
- package/dist/core/runtime/broker/frame-engine-control.js +231 -0
- package/dist/core/runtime/broker/frame-memory-refs.d.ts +19 -0
- package/dist/core/runtime/broker/frame-memory-refs.js +41 -0
- package/dist/core/runtime/broker/frame-model-query.d.ts +13 -0
- package/dist/core/runtime/broker/frame-model-query.js +69 -0
- package/dist/core/runtime/broker/frame-read.d.ts +19 -0
- package/dist/core/runtime/broker/frame-read.js +116 -0
- package/dist/core/runtime/broker/frame-replies.d.ts +24 -0
- package/dist/core/runtime/broker/frame-replies.js +64 -0
- package/dist/core/runtime/broker/frame-session.d.ts +34 -0
- package/dist/core/runtime/broker/frame-session.js +203 -0
- package/dist/core/runtime/broker/rebind.js +50 -0
- package/dist/core/runtime/broker/turn-ignition.d.ts +42 -0
- package/dist/core/runtime/broker/turn-ignition.js +74 -0
- package/dist/core/runtime/broker-extension-render.js +9 -85
- package/dist/core/runtime/broker-protocol.js +0 -4
- package/dist/core/runtime/broker-sdk.js +2 -1
- package/dist/core/runtime/broker.d.ts +1 -1
- package/dist/core/runtime/broker.js +5 -23
- package/dist/core/runtime/fault.js +3 -2
- package/dist/core/runtime/headless-pi.js +3 -2
- package/dist/core/runtime/host.js +2 -3
- package/dist/core/runtime/kickoff.js +0 -4
- package/dist/core/runtime/launch-target.js +2 -1
- package/dist/core/runtime/launch.d.ts +2 -2
- package/dist/core/runtime/launch.js +20 -10
- package/dist/core/runtime/lifecycle.js +17 -26
- package/dist/core/runtime/managed-provider-cooling.d.ts +1 -1
- package/dist/core/runtime/naming.js +0 -2
- package/dist/core/runtime/nodes.js +2 -1
- package/dist/core/runtime/persona.js +0 -6
- package/dist/core/runtime/placement-tmux.js +2 -5
- package/dist/core/runtime/placement.js +4 -11
- package/dist/core/runtime/recap.js +4 -3
- package/dist/core/runtime/reopen.js +4 -7
- package/dist/core/runtime/reset.js +0 -4
- package/dist/core/runtime/resume-root.js +0 -2
- package/dist/core/runtime/revive.js +17 -13
- package/dist/core/runtime/session-list-cache.js +2 -2
- package/dist/core/runtime/shell-expansion.js +0 -2
- package/dist/core/runtime/spawn.js +0 -2
- package/dist/core/runtime/stop-guard.js +28 -16
- package/dist/core/runtime/stream-watchdog.d.ts +0 -1
- package/dist/core/runtime/stream-watchdog.js +13 -18
- package/dist/core/runtime/tmux-bindings.js +0 -2
- package/dist/core/runtime/tmux-driver.d.ts +12 -0
- package/dist/core/runtime/tmux-driver.js +18 -13
- package/dist/core/runtime/warm-pool.js +0 -4
- package/dist/core/scope.js +4 -3
- package/dist/core/spawn.js +2 -3
- package/dist/core/subscription-state.js +10 -17
- package/dist/core/substrate/__tests__/surface-match-pre-command.test.js +3 -3
- package/dist/core/substrate/frontmatter-validation.d.ts +1 -0
- package/dist/core/substrate/frontmatter-validation.js +1 -1
- package/dist/core/substrate/render.js +0 -12
- package/dist/core/substrate/schema.js +0 -12
- package/dist/core/substrate/surface-match.js +0 -2
- package/dist/core/termrender/display.js +2 -1
- package/dist/core/tui/page-host.d.ts +3 -3
- package/dist/core/tui/page-host.js +4 -4
- package/dist/core/tui/panel.js +3 -3
- package/dist/core/wake.js +0 -12
- package/dist/core/worktree.js +0 -2
- package/dist/daemon/__tests__/reconciler-signature.test.d.ts +1 -0
- package/dist/daemon/__tests__/reconciler-signature.test.js +36 -0
- package/dist/daemon/api/__tests__/error-seam.test.js +27 -0
- package/dist/daemon/api/__tests__/seam/api-server.test.js +2 -16
- package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +3 -11
- package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +0 -6
- package/dist/daemon/api/handlers/attach.js +2 -1
- package/dist/daemon/api/handlers/broker-ops.js +3 -6
- package/dist/daemon/api/handlers/canvas.js +12 -18
- package/dist/daemon/api/handlers/feedback-comments.js +0 -8
- package/dist/daemon/api/handlers/health.js +3 -2
- package/dist/daemon/api/handlers/human-requests.js +0 -10
- package/dist/daemon/api/handlers/human.js +1 -5
- package/dist/daemon/api/handlers/inbox.js +0 -18
- package/dist/daemon/api/handlers/memory.js +1 -1
- package/dist/daemon/api/handlers/messages.js +16 -20
- package/dist/daemon/api/handlers/nodes.js +23 -22
- package/dist/daemon/api/handlers/reports.js +1 -1
- package/dist/daemon/api/handlers/reviews.js +1 -6
- package/dist/daemon/api/handlers/worktree.js +6 -22
- package/dist/daemon/api/map.d.ts +4 -2
- package/dist/daemon/api/map.js +22 -8
- package/dist/daemon/api/router.js +0 -4
- package/dist/daemon/api/server.js +2 -5
- package/dist/daemon/boot-migrations.d.ts +14 -0
- package/dist/daemon/boot-migrations.js +31 -0
- package/dist/daemon/cron/armed-context.d.ts +21 -0
- package/dist/daemon/cron/armed-context.js +100 -0
- package/dist/daemon/cron/capture.d.ts +20 -0
- package/dist/daemon/cron/capture.js +45 -0
- package/dist/daemon/cron/disposition.d.ts +19 -0
- package/dist/daemon/cron/disposition.js +52 -0
- package/dist/daemon/cron/escalation.d.ts +12 -0
- package/dist/daemon/cron/escalation.js +124 -0
- package/dist/daemon/cron/held.d.ts +4 -0
- package/dist/daemon/cron/held.js +20 -0
- package/dist/daemon/cron/lease-recovery.d.ts +3 -0
- package/dist/daemon/cron/lease-recovery.js +119 -0
- package/dist/daemon/cron/live-runs.d.ts +11 -0
- package/dist/daemon/cron/live-runs.js +23 -0
- package/dist/daemon/cron/passes.d.ts +11 -0
- package/dist/daemon/cron/passes.js +78 -0
- package/dist/daemon/cron/settle.d.ts +28 -0
- package/dist/daemon/cron/settle.js +37 -0
- package/dist/daemon/cron/sinks.d.ts +2 -0
- package/dist/daemon/cron/sinks.js +100 -0
- package/dist/daemon/cron-run.d.ts +5 -41
- package/dist/daemon/cron-run.js +193 -882
- package/dist/daemon/crtrd-cli.js +2 -1
- package/dist/daemon/crtrd.js +22 -22
- package/dist/daemon/fleet.js +0 -4
- package/dist/daemon/human/deliver-action.js +2 -1
- package/dist/daemon/human/sweep.js +15 -4
- package/dist/daemon/manage.d.ts +2 -2
- package/dist/daemon/manage.js +4 -13
- package/dist/daemon/pidfile.js +2 -2
- package/dist/daemon/reconcilers/broker-supervision.js +27 -30
- package/dist/daemon/reconcilers/dormant-inbox.d.ts +1 -1
- package/dist/daemon/reconcilers/dormant-inbox.js +2 -1
- package/dist/daemon/reconcilers/live-obligation.js +2 -2
- package/dist/daemon/reconcilers/pending-review-submit.d.ts +1 -1
- package/dist/daemon/reconcilers/pending-review-submit.js +2 -1
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -1
- package/dist/daemon/reconcilers/storage-maintenance.js +2 -1
- package/dist/daemon/review/companion.js +2 -2
- package/dist/daemon/review/sweep.js +8 -3
- package/dist/migrations/001-surfaces-frontmatter.js +0 -6
- package/dist/migrations/corpus.js +2 -5
- package/dist/migrations/registry.js +15 -2
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +0 -4
- package/dist/pi-extensions/broker-local.js +2 -1
- package/dist/pi-extensions/canvas-bash-valve.js +7 -20
- package/dist/pi-extensions/canvas-context-intro.js +2 -7
- package/dist/pi-extensions/canvas-doc-substrate.js +2 -3
- package/dist/pi-extensions/canvas-goal-capture.js +2 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +5 -12
- package/dist/pi-extensions/canvas-passive-context.js +2 -5
- package/dist/pi-extensions/canvas-preview-result.js +2 -1
- package/dist/pi-extensions/canvas-prompt-scrub.js +2 -1
- package/dist/pi-extensions/canvas-recap.js +3 -16
- package/dist/pi-extensions/canvas-review-boundary.js +2 -5
- package/dist/pi-extensions/canvas-stophook.js +2 -26
- package/dist/pi-extensions/canvas-structured-output.js +2 -1
- package/dist/pi-extensions/canvas-tool-guide.js +2 -1
- package/dist/shared/__tests__/env-boundary.test.d.ts +1 -0
- package/dist/shared/__tests__/env-boundary.test.js +93 -0
- package/dist/shared/env.d.ts +68 -0
- package/dist/shared/env.js +171 -0
- package/package.json +3 -1
- package/runtime.lock.json +2 -2
- package/dist/core/canvas/render.d.ts +0 -47
- package/dist/core/canvas/render.js +0 -245
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { captureSessionChatCapabilities } from '../command-surface.js';
|
|
6
|
+
import { isPreBoundaryReviewEntry } from './frame-replies.js';
|
|
7
|
+
/** True iff a parsed JSONL branch-entry line is a hidden (`display:false`)
|
|
8
|
+
* custom message — the general display boundary crossed if left in an
|
|
9
|
+
* exported branch (not just `crtr-memory-refs` guidance; any hidden custom
|
|
10
|
+
* content). Covers both persisted shapes a branch entry can take: a
|
|
11
|
+
* `type:'custom_message'` entry (display at the entry's own top level) and a
|
|
12
|
+
* `type:'message'` entry wrapping a `role:'custom'` message (display nested
|
|
13
|
+
* under `.message`). */
|
|
14
|
+
export function isHiddenJsonlBranchEntry(entry) {
|
|
15
|
+
if (entry === null || typeof entry !== 'object')
|
|
16
|
+
return false;
|
|
17
|
+
const e = entry;
|
|
18
|
+
if (e.type === 'custom_message' && e.display === false)
|
|
19
|
+
return true;
|
|
20
|
+
if (e.type === 'message' && e.message?.role === 'custom' && e.message.display === false)
|
|
21
|
+
return true;
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
/** Rewrite an already-exported JSONL file in place, dropping every hidden
|
|
25
|
+
* (`display:false`) branch entry while re-chaining `parentId` so the
|
|
26
|
+
* remaining entries stay a single valid linear branch — applying the general
|
|
27
|
+
* display:false boundary to `session.exportToJsonl`'s own output, which
|
|
28
|
+
* serializes every entry verbatim regardless of display. The header line
|
|
29
|
+
* (line 1) is copied through untouched. */
|
|
30
|
+
export function stripHiddenEntriesFromJsonlExport(filePath) {
|
|
31
|
+
const raw = readFileSync(filePath, 'utf8');
|
|
32
|
+
const lines = raw.split('\n').filter((l) => l !== '');
|
|
33
|
+
if (lines.length === 0)
|
|
34
|
+
return;
|
|
35
|
+
const [headerLine, ...entryLines] = lines;
|
|
36
|
+
let prevId = null;
|
|
37
|
+
const kept = [];
|
|
38
|
+
for (const line of entryLines) {
|
|
39
|
+
const entry = JSON.parse(line);
|
|
40
|
+
if (isHiddenJsonlBranchEntry(entry))
|
|
41
|
+
continue;
|
|
42
|
+
kept.push(JSON.stringify({ ...entry, parentId: prevId }));
|
|
43
|
+
if (typeof entry.id === 'string')
|
|
44
|
+
prevId = entry.id;
|
|
45
|
+
}
|
|
46
|
+
writeFileSync(filePath, `${[headerLine, ...kept].join('\n')}\n`);
|
|
47
|
+
}
|
|
48
|
+
export function createSessionHandler(deps) {
|
|
49
|
+
const { registry, replies, rebind, session, boundaryReviewId, memoryRefs, reWelcomeAll } = deps;
|
|
50
|
+
return (client, frame) => {
|
|
51
|
+
switch (frame.type) {
|
|
52
|
+
case 'navigate_tree': {
|
|
53
|
+
if (replies.notWritable(client, 'navigate the session tree'))
|
|
54
|
+
break;
|
|
55
|
+
if (isPreBoundaryReviewEntry(session(), boundaryReviewId, frame.targetId)) {
|
|
56
|
+
replies.reviewBoundaryRefusalTo(client, frame.targetId);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
// navigateTree rewinds IN-PLACE (same session file, new leaf) and emits no
|
|
60
|
+
// relayed event, so every viewer must be re-snapshotted onto the rewound
|
|
61
|
+
// transcript — same reWelcomeAll the session-replacing ops use. The ack's
|
|
62
|
+
// detail carries the navigated-to user message's text (pi parity: the
|
|
63
|
+
// interactive tree navigator restores it to the editor for re-editing).
|
|
64
|
+
void session()
|
|
65
|
+
.navigateTree(frame.targetId, frame.options)
|
|
66
|
+
.then((r) => {
|
|
67
|
+
if (!r.cancelled)
|
|
68
|
+
reWelcomeAll();
|
|
69
|
+
replies.ackTo(client, 'navigate_tree', !r.cancelled, r.editorText);
|
|
70
|
+
})
|
|
71
|
+
.catch(replies.engineErrorTo(client));
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case 'reload': {
|
|
75
|
+
if (replies.notWritable(client, 'reload'))
|
|
76
|
+
break;
|
|
77
|
+
// A SUCCESSFUL reload invalidates the memoized ref inventory (work item
|
|
78
|
+
// 3) so the next read-op/submission re-walks the corpus. A FAILED
|
|
79
|
+
// reload (`.catch`) leaves it untouched: nothing about the corpus is
|
|
80
|
+
// known to have changed.
|
|
81
|
+
void session()
|
|
82
|
+
.reload({ beforeSessionStart: () => captureSessionChatCapabilities(session()) })
|
|
83
|
+
.then(() => {
|
|
84
|
+
// pi's reload() re-syncs queue modes from the shared settings.json
|
|
85
|
+
// (its ONE post-bind syncQueueModesFromSettings call site) —
|
|
86
|
+
// re-apply the broker's 'all' modes so a reload cannot silently
|
|
87
|
+
// restore one-at-a-time draining (see rebind.enqueueRebind).
|
|
88
|
+
const agent = session().agent;
|
|
89
|
+
if (agent) {
|
|
90
|
+
agent.steeringMode = 'all';
|
|
91
|
+
agent.followUpMode = 'all';
|
|
92
|
+
}
|
|
93
|
+
memoryRefs.invalidate();
|
|
94
|
+
registry.forEachHelloed((observer) => {
|
|
95
|
+
if (observer.role === 'observer')
|
|
96
|
+
registry.sendFrame(observer, { type: 'resources_reloaded' });
|
|
97
|
+
});
|
|
98
|
+
replies.ackTo(client, 'reload');
|
|
99
|
+
})
|
|
100
|
+
.catch(replies.engineErrorTo(client));
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
case 'export': {
|
|
104
|
+
if (replies.notWritable(client, 'export the session'))
|
|
105
|
+
break;
|
|
106
|
+
if (frame.format === 'jsonl') {
|
|
107
|
+
try {
|
|
108
|
+
const outPath = session().exportToJsonl(frame.path);
|
|
109
|
+
stripHiddenEntriesFromJsonlExport(outPath);
|
|
110
|
+
replies.ackTo(client, 'export');
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
replies.engineErrorTo(client)(err);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
void session()
|
|
118
|
+
.exportToHtml(frame.path)
|
|
119
|
+
.then(() => replies.ackTo(client, 'export'))
|
|
120
|
+
.catch(replies.engineErrorTo(client));
|
|
121
|
+
}
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
case 'new_session': {
|
|
125
|
+
if (replies.notWritable(client, 'start a new session'))
|
|
126
|
+
break;
|
|
127
|
+
rebind.runReplacement(client, 'new_session', (rt) => rt.newSession());
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
case 'switch_session': {
|
|
131
|
+
if (replies.notWritable(client, 'switch sessions'))
|
|
132
|
+
break;
|
|
133
|
+
rebind.runReplacement(client, 'switch_session', (rt) => rt.switchSession(frame.path));
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
case 'fork': {
|
|
137
|
+
if (replies.notWritable(client, 'fork the session'))
|
|
138
|
+
break;
|
|
139
|
+
if (isPreBoundaryReviewEntry(session(), boundaryReviewId, frame.entryId)) {
|
|
140
|
+
replies.reviewBoundaryRefusalTo(client, frame.entryId);
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
rebind.runReplacement(client, 'fork', (rt) => rt.fork(frame.entryId));
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
case 'clone': {
|
|
147
|
+
if (replies.notWritable(client, 'clone the session'))
|
|
148
|
+
break;
|
|
149
|
+
rebind.runReplacement(client, 'clone', async (rt) => {
|
|
150
|
+
const sm = session().sessionManager;
|
|
151
|
+
const leafId = sm.getLeafId();
|
|
152
|
+
if (leafId === null) {
|
|
153
|
+
return { cancelled: true, detail: 'no current leaf to clone from' };
|
|
154
|
+
}
|
|
155
|
+
const newPath = sm.createBranchedSession(leafId);
|
|
156
|
+
if (newPath === undefined) {
|
|
157
|
+
return {
|
|
158
|
+
cancelled: true,
|
|
159
|
+
detail: 'createBranchedSession returned no path',
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return rt.switchSession(newPath);
|
|
163
|
+
});
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
case 'share': {
|
|
167
|
+
if (replies.notWritable(client, 'share the session'))
|
|
168
|
+
break;
|
|
169
|
+
const tmpPath = join(tmpdir(), `pi-share-${Date.now()}.html`);
|
|
170
|
+
void session()
|
|
171
|
+
.exportToHtml(tmpPath)
|
|
172
|
+
.then(() => new Promise((resolve, reject) => {
|
|
173
|
+
execFile('gh', ['gist', 'create', '--secret', tmpPath], { timeout: 30_000, maxBuffer: 1024 * 1024 }, (err, stdout) => {
|
|
174
|
+
try {
|
|
175
|
+
if (existsSync(tmpPath))
|
|
176
|
+
unlinkSync(tmpPath);
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
/* cleanup */
|
|
180
|
+
}
|
|
181
|
+
if (err) {
|
|
182
|
+
reject(err);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
resolve(stdout.trim());
|
|
186
|
+
});
|
|
187
|
+
}))
|
|
188
|
+
.then((url) => {
|
|
189
|
+
replies.ackTo(client, 'share', true, url);
|
|
190
|
+
})
|
|
191
|
+
.catch((err) => {
|
|
192
|
+
const msg = String(err?.message ?? err);
|
|
193
|
+
replies.ackTo(client, 'share', false, msg.includes('not found') ||
|
|
194
|
+
msg.includes('gh: command not found') ||
|
|
195
|
+
msg.includes('ENOENT')
|
|
196
|
+
? '`gh` CLI not found — install GitHub CLI and authenticate with `gh auth login`'
|
|
197
|
+
: `share failed: ${msg}`);
|
|
198
|
+
});
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
@@ -8,6 +8,55 @@ import { abortSessionFromExtension } from './extension-abort.js';
|
|
|
8
8
|
const MAX_ADMITTED_REPLACEMENTS = 2;
|
|
9
9
|
const REPLACEMENT_DEADLINE_MS = 30_000;
|
|
10
10
|
const REPLACEMENT_DEADLINE_EXCEEDED = Symbol('replacement-deadline-exceeded');
|
|
11
|
+
const TRAILING_THINKING_PLACEHOLDER = '(interrupted)';
|
|
12
|
+
const TRAILING_THINKING_GUARD = Symbol.for('crtr.trailing-thinking-guard');
|
|
13
|
+
/** The last block an Anthropic request will actually carry: the serializer
|
|
14
|
+
* drops whitespace-only text and signature-less empty thinking. */
|
|
15
|
+
function lastSerializedBlock(content) {
|
|
16
|
+
for (let i = content.length - 1; i >= 0; i--) {
|
|
17
|
+
const block = content[i];
|
|
18
|
+
if (block === undefined)
|
|
19
|
+
continue;
|
|
20
|
+
if (block.type === 'text') {
|
|
21
|
+
if (block.text.trim().length === 0)
|
|
22
|
+
continue;
|
|
23
|
+
return block;
|
|
24
|
+
}
|
|
25
|
+
if (block.type === 'thinking') {
|
|
26
|
+
const signature = block.thinkingSignature;
|
|
27
|
+
const hasSignature = typeof signature === 'string' && signature.trim().length > 0;
|
|
28
|
+
if (block.redacted !== true && block.thinking.trim().length === 0 && !hasSignature)
|
|
29
|
+
continue;
|
|
30
|
+
return block;
|
|
31
|
+
}
|
|
32
|
+
return block;
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
function guardTrailingThinking(messages) {
|
|
37
|
+
return messages.map((message) => {
|
|
38
|
+
if (message.role !== 'assistant')
|
|
39
|
+
return message;
|
|
40
|
+
if (lastSerializedBlock(message.content)?.type !== 'thinking')
|
|
41
|
+
return message;
|
|
42
|
+
return { ...message, content: [...message.content, { type: 'text', text: TRAILING_THINKING_PLACEHOLDER }] };
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/** Crouter aborts live streams (watchdog, extension abort, viewer esc), which
|
|
46
|
+
* persists assistant turns that end on a thinking block. Anthropic rejects a
|
|
47
|
+
* request whose final assistant block is `thinking`, and pi-ai's serializer
|
|
48
|
+
* has no guard for it, so every later turn re-fails on embedded history. */
|
|
49
|
+
function installTrailingThinkingGuard(agent) {
|
|
50
|
+
const inner = agent.convertToLlm;
|
|
51
|
+
if (inner[TRAILING_THINKING_GUARD] === true)
|
|
52
|
+
return;
|
|
53
|
+
const wrapped = (messages) => {
|
|
54
|
+
const converted = inner(messages);
|
|
55
|
+
return converted instanceof Promise ? converted.then(guardTrailingThinking) : guardTrailingThinking(converted);
|
|
56
|
+
};
|
|
57
|
+
wrapped[TRAILING_THINKING_GUARD] = true;
|
|
58
|
+
agent.convertToLlm = wrapped;
|
|
59
|
+
}
|
|
11
60
|
/** Owns session subscription replacement, its serialization lane, and replacement admission policy. */
|
|
12
61
|
export class RebindDriver {
|
|
13
62
|
deps;
|
|
@@ -86,6 +135,7 @@ export class RebindDriver {
|
|
|
86
135
|
});
|
|
87
136
|
agent.steeringMode = 'all';
|
|
88
137
|
agent.followUpMode = 'all';
|
|
138
|
+
installTrailingThinkingGuard(agent);
|
|
89
139
|
}
|
|
90
140
|
if (this.deps.cfg.editorName !== undefined && this.deps.cfg.editorName !== '') {
|
|
91
141
|
try {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { BrokerSession } from './read-ops.js';
|
|
2
|
+
/**
|
|
3
|
+
* Prompt dispatches whose promise has not yet settled. `session.prompt()` does
|
|
4
|
+
* async setup (input transforms, model/auth validation, compaction) BEFORE
|
|
5
|
+
* `_isAgentRunActive` flips, so for a short window after a routed deliver the
|
|
6
|
+
* engine reads idle and `session.abort()` is a silent no-op — an interrupt
|
|
7
|
+
* racing that window would miss the turn entirely (verified live). The counter
|
|
8
|
+
* lets a caller distinguish "genuinely idle" from "turn still igniting".
|
|
9
|
+
*/
|
|
10
|
+
export type PromptDispatchTracker = {
|
|
11
|
+
track(p: Promise<unknown>): Promise<unknown>;
|
|
12
|
+
pending(): number;
|
|
13
|
+
/** Wait (bounded) for a pending dispatch to reach an abortable turn — or for
|
|
14
|
+
* every dispatch to settle without one (an early return). Returns
|
|
15
|
+
* immediately when the engine is already streaming or nothing is pending. */
|
|
16
|
+
waitUntilAbortable(): Promise<void>;
|
|
17
|
+
};
|
|
18
|
+
export declare function createPromptDispatchTracker(session: () => BrokerSession): PromptDispatchTracker;
|
|
19
|
+
/**
|
|
20
|
+
* The one-shot waiters a `deliver` frame parks until its prompt is ACCEPTED by
|
|
21
|
+
* the engine (the broker's `agent_start`). Every waiter fires once, on the
|
|
22
|
+
* first acceptance after it was added.
|
|
23
|
+
*/
|
|
24
|
+
export type TurnAcceptanceGate = {
|
|
25
|
+
waitFor(waiter: () => void): void;
|
|
26
|
+
cancel(waiter: () => void): void;
|
|
27
|
+
notifyAccepted(): void;
|
|
28
|
+
};
|
|
29
|
+
export declare function createTurnAcceptanceGate(): TurnAcceptanceGate;
|
|
30
|
+
/**
|
|
31
|
+
* The launch prompt, held until the session actually has a model. A model-less
|
|
32
|
+
* tier-3 boot leaves it pending; `drivePending` is a no-op until the
|
|
33
|
+
* `reload_auth` re-drive resolves a model, at which point it fires.
|
|
34
|
+
*/
|
|
35
|
+
export type KickoffDriver = {
|
|
36
|
+
kickoff(prompt: string): void;
|
|
37
|
+
drivePending(): void;
|
|
38
|
+
};
|
|
39
|
+
export declare function createKickoffDriver(deps: {
|
|
40
|
+
session: () => BrokerSession;
|
|
41
|
+
dispatches: PromptDispatchTracker;
|
|
42
|
+
}): KickoffDriver;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { emitEvent } from '../../events/emit.js';
|
|
2
|
+
import { operationIdContext } from '../../events/operation-id.js';
|
|
3
|
+
import { isUnknownModel } from '../model-selection.js';
|
|
4
|
+
/** How long a caller waits for a dispatched prompt to become abortable, and how
|
|
5
|
+
* often it re-reads the engine while waiting. */
|
|
6
|
+
const ABORTABLE_WAIT_MS = 5_000;
|
|
7
|
+
const ABORTABLE_POLL_MS = 25;
|
|
8
|
+
export function createPromptDispatchTracker(session) {
|
|
9
|
+
let pending = 0;
|
|
10
|
+
return {
|
|
11
|
+
track(p) {
|
|
12
|
+
pending++;
|
|
13
|
+
const tracked = Promise.resolve(p);
|
|
14
|
+
void tracked.finally(() => {
|
|
15
|
+
pending--;
|
|
16
|
+
});
|
|
17
|
+
return tracked;
|
|
18
|
+
},
|
|
19
|
+
pending: () => pending,
|
|
20
|
+
async waitUntilAbortable() {
|
|
21
|
+
if (session().isStreaming || pending === 0)
|
|
22
|
+
return;
|
|
23
|
+
const deadline = Date.now() + ABORTABLE_WAIT_MS;
|
|
24
|
+
while (Date.now() < deadline && !session().isStreaming && pending > 0) {
|
|
25
|
+
await new Promise((resolve) => setTimeout(resolve, ABORTABLE_POLL_MS));
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function createTurnAcceptanceGate() {
|
|
31
|
+
const waiters = new Set();
|
|
32
|
+
return {
|
|
33
|
+
waitFor: (waiter) => void waiters.add(waiter),
|
|
34
|
+
cancel: (waiter) => void waiters.delete(waiter),
|
|
35
|
+
notifyAccepted() {
|
|
36
|
+
const pending = [...waiters];
|
|
37
|
+
waiters.clear();
|
|
38
|
+
for (const waiter of pending)
|
|
39
|
+
waiter();
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export function createKickoffDriver(deps) {
|
|
44
|
+
const { session, dispatches } = deps;
|
|
45
|
+
let pendingPrompt;
|
|
46
|
+
let inFlight = false;
|
|
47
|
+
const sessionHasNoModel = () => session().model === undefined || isUnknownModel(session().model);
|
|
48
|
+
const drivePending = () => {
|
|
49
|
+
if (pendingPrompt === undefined || inFlight || sessionHasNoModel())
|
|
50
|
+
return;
|
|
51
|
+
const prompt = pendingPrompt;
|
|
52
|
+
pendingPrompt = undefined;
|
|
53
|
+
inFlight = true;
|
|
54
|
+
dispatches.track(operationIdContext.fresh(() => session()
|
|
55
|
+
.prompt(prompt)
|
|
56
|
+
.catch((err) => {
|
|
57
|
+
emitEvent({
|
|
58
|
+
level: 'error',
|
|
59
|
+
event: 'broker.prompt.first_failed',
|
|
60
|
+
error: err,
|
|
61
|
+
});
|
|
62
|
+
})
|
|
63
|
+
.finally(() => {
|
|
64
|
+
inFlight = false;
|
|
65
|
+
})));
|
|
66
|
+
};
|
|
67
|
+
return {
|
|
68
|
+
kickoff(prompt) {
|
|
69
|
+
pendingPrompt = prompt;
|
|
70
|
+
drivePending();
|
|
71
|
+
},
|
|
72
|
+
drivePending,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -1,118 +1,42 @@
|
|
|
1
1
|
// Pure broker-side render adapters. crtrd supplies the fixed extension-state
|
|
2
2
|
// DTO; these functions only combine it with node-local/filesystem information.
|
|
3
3
|
import { contextDir, nodeDir } from '../canvas/paths.js';
|
|
4
|
-
import { execSync, spawnSync } from 'node:child_process';
|
|
5
|
-
import { readdirSync } from 'node:fs';
|
|
6
|
-
import { hostname } from 'node:os';
|
|
7
4
|
import { interpolateNodePaths } from '../canvas/paths.js';
|
|
8
5
|
import { fullName } from '../canvas/labels.js';
|
|
9
6
|
import { renderKnowledgeForSubject, renderPreferencesForSubject } from '../substrate/render.js';
|
|
10
7
|
import { renderWorkspaceOpenDocsForSubject } from '../substrate/on-read.js';
|
|
11
|
-
import {
|
|
8
|
+
import { buildProjectContextBlock, contextDirNote as contextDirNoteShared, profileNote as profileNoteShared, relativeLabel as relativeLabelShared, renderGraphMap, buildIdentityAssertion, worktreeNote as worktreeNoteShared, } from './bearings-render.js';
|
|
12
9
|
export function editorLabelForBrokerNode(node) {
|
|
13
10
|
const icon = (node.icon ?? '').trim();
|
|
14
11
|
const handle = node.name !== node.kind ? node.name.trim() : '';
|
|
15
12
|
const name = handle !== '' ? handle : (node.description ?? '').trim() || node.name;
|
|
16
13
|
return icon === '' ? name : `${icon} ${name}`;
|
|
17
14
|
}
|
|
18
|
-
function command(cwd, text) {
|
|
19
|
-
try {
|
|
20
|
-
return execSync(text, { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim();
|
|
21
|
-
}
|
|
22
|
-
catch {
|
|
23
|
-
return '';
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
15
|
/** Same environment-only project context rendered at normal boot, without a
|
|
27
16
|
* canvas import. */
|
|
28
17
|
export function buildProjectContextBlockForBroker(cwd) {
|
|
29
|
-
|
|
30
|
-
try {
|
|
31
|
-
const entries = readdirSync(cwd, { withFileTypes: true }).sort((a, b) => Number(b.isDirectory()) - Number(a.isDirectory()) || a.name.localeCompare(b.name));
|
|
32
|
-
const shown = entries.slice(0, 50).map((entry) => `${entry.name}${entry.isDirectory() ? '/' : ''}`);
|
|
33
|
-
listing = entries.length > shown.length ? [...shown, `[+${entries.length - shown.length} more]`] : shown;
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
listing = ['Directory listing: unavailable (cwd missing or unreadable).'];
|
|
37
|
-
}
|
|
38
|
-
const tmux = spawnSync('tmux', ['list-sessions'], { encoding: 'utf8', stdio: 'ignore' }).status === 0;
|
|
39
|
-
let git = 'Git: not a git repository.';
|
|
40
|
-
let worktrees = 'Worktrees: none.';
|
|
41
|
-
if (command(cwd, 'git rev-parse --is-inside-work-tree') !== '') {
|
|
42
|
-
const branch = command(cwd, 'git branch --show-current') || command(cwd, 'git rev-parse --abbrev-ref HEAD') || 'HEAD';
|
|
43
|
-
const sha = command(cwd, 'git rev-parse --short HEAD') || 'unknown';
|
|
44
|
-
const changes = command(cwd, 'git status --porcelain').split('\n').filter(Boolean).length;
|
|
45
|
-
const raw = command(cwd, 'git worktree list --porcelain').split('\n');
|
|
46
|
-
const found = [];
|
|
47
|
-
let path = '';
|
|
48
|
-
let wtBranch = 'detached HEAD';
|
|
49
|
-
for (const line of raw) {
|
|
50
|
-
if (line.startsWith('worktree ')) {
|
|
51
|
-
if (path !== '')
|
|
52
|
-
found.push(`${path} (${wtBranch})`);
|
|
53
|
-
path = line.slice(9);
|
|
54
|
-
wtBranch = 'detached HEAD';
|
|
55
|
-
}
|
|
56
|
-
else if (line.startsWith('branch '))
|
|
57
|
-
wtBranch = line.slice(7).replace(/^refs\/heads\//, '');
|
|
58
|
-
}
|
|
59
|
-
if (path !== '')
|
|
60
|
-
found.push(`${path} (${wtBranch})`);
|
|
61
|
-
git = `Git: ${branch} @ ${sha}; ${changes === 0 ? 'clean' : `${changes} uncommitted change${changes === 1 ? '' : 's'}`}; ${found.length} worktree${found.length === 1 ? '' : 's'}.`;
|
|
62
|
-
worktrees = found.length === 0 ? 'Worktrees: none.' : `Worktrees: ${found.join(', ')}`;
|
|
63
|
-
}
|
|
64
|
-
return `<project_context>\n\n<environment cwd="${cwd.replaceAll('&', '&').replaceAll('"', '"').replaceAll('<', '<')}">\nHost: ${process.platform} ${process.arch} · ${hostname()} · node ${process.version} · tmux server: ${tmux ? 'reachable' : 'none'}\nDirectory:\n${listing.map((line) => ` ${line}`).join('\n')}\n${git}\n${worktrees}\n</environment>\n</project_context>`;
|
|
18
|
+
return buildProjectContextBlock(cwd);
|
|
65
19
|
}
|
|
66
20
|
function contextDirNote(nodeId) {
|
|
67
|
-
return
|
|
21
|
+
return contextDirNoteShared(nodeId);
|
|
68
22
|
}
|
|
69
23
|
function profileNote(node) {
|
|
70
|
-
|
|
71
|
-
return '';
|
|
72
|
-
try {
|
|
73
|
-
const entry = loadProfileManifest(node.profile_id);
|
|
74
|
-
if (entry.manifest.projects.length === 0)
|
|
75
|
-
return '';
|
|
76
|
-
return `Your working dir is \`${node.cwd}\`. Your profile **${entry.manifest.name}** also has purview over: ${entry.manifest.projects.map((project) => project.path).join(', ')}.`;
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
return '';
|
|
80
|
-
}
|
|
24
|
+
return profileNoteShared(node.cwd, node.profile_id);
|
|
81
25
|
}
|
|
82
26
|
function relativeLabel(node) {
|
|
83
|
-
|
|
84
|
-
const descPart = desc !== '' && desc !== node.kind && desc !== node.name ? ` — ${desc}` : '';
|
|
85
|
-
return `${node.node_id} (${node.kind} · ${node.status})${descPart}`;
|
|
27
|
+
return relativeLabelShared(node);
|
|
86
28
|
}
|
|
87
29
|
function graphMap(state) {
|
|
88
30
|
const { ancestors, children, node } = state;
|
|
89
|
-
|
|
90
|
-
return '';
|
|
91
|
-
const indent = (depth) => ' '.repeat(depth);
|
|
92
|
-
const lines = ['Your place in the canvas graph (ancestry above you, your direct children below):'];
|
|
93
|
-
ancestors.forEach((ancestor, index) => lines.push(`${indent(index)}${index === 0 ? '' : '└ '}${relativeLabel(ancestor)}`));
|
|
94
|
-
const depth = ancestors.length;
|
|
95
|
-
lines.push(`${indent(depth)}${depth === 0 ? '' : '└ '}● you: ${node.node_id} (${node.kind}, ${node.mode})`);
|
|
96
|
-
const shown = children.slice(0, 5);
|
|
97
|
-
shown.forEach((child, index) => lines.push(`${indent(depth + 1)}${index === shown.length - 1 && children.length === shown.length ? '└ ' : '├ '}${relativeLabel(child)}`));
|
|
98
|
-
if (children.length > shown.length)
|
|
99
|
-
lines.push(`${indent(depth + 1)}└ +${children.length - shown.length} more`);
|
|
100
|
-
return lines.join('\n');
|
|
31
|
+
return renderGraphMap(node.node_id, node.kind, node.mode, ancestors, children);
|
|
101
32
|
}
|
|
102
33
|
function identity(state) {
|
|
103
34
|
const { node, fork_source: source } = state;
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
const sourceLabel = source === null ? node.fork_from : `${node.fork_from} ("${fullName(source)}")`;
|
|
107
|
-
lines.push('', `You are a new FORK of ${sourceLabel}, not ${sourceLabel}. Pi copied the earlier conversation into this session. Treat that first-person history as reference material, not your own past.`);
|
|
108
|
-
}
|
|
109
|
-
return lines.join('\n');
|
|
35
|
+
const sourceLabel = source === null ? (node.fork_from ?? '') : `${node.fork_from} ("${fullName(source)}")`;
|
|
36
|
+
return buildIdentityAssertion(node.node_id, node.kind, node.mode, node.fork_from, sourceLabel);
|
|
110
37
|
}
|
|
111
38
|
function worktreeNote(node) {
|
|
112
|
-
|
|
113
|
-
if (worktree === null || worktree === undefined || worktree.state !== 'open')
|
|
114
|
-
return '';
|
|
115
|
-
return `Branch: \`${worktree.branch}\`\nWorktree: \`${worktree.path}\`\nBase: \`${worktree.base_ref}\` @ \`${worktree.base_sha}\`\nCommit work here. Land it with \`crtr node worktree close\` before finishing. Auto-drop applies only when the worktree is clean (no uncommitted changes) and nothing remains to land (zero commits ahead of the base, or its commits are already contained in the base); unlanded commits (commits not already contained in the base) or uncommitted changes require an explicit close/landing decision.`;
|
|
39
|
+
return worktreeNoteShared(node.managed_worktree);
|
|
116
40
|
}
|
|
117
41
|
/** The companion note — rendered ONLY when a node carries its immutable
|
|
118
42
|
* companion binding. Names the target (the document under review, or the page
|
|
@@ -16,9 +16,7 @@
|
|
|
16
16
|
// pi. pi names the correlation field `id` (design §5.2 wrote `request_id`); we
|
|
17
17
|
// follow pi.
|
|
18
18
|
import { StringDecoder } from 'node:string_decoder';
|
|
19
|
-
// ---------------------------------------------------------------------------
|
|
20
19
|
// Client → broker frames
|
|
21
|
-
// ---------------------------------------------------------------------------
|
|
22
20
|
/** Largest transcript window a client may request in its welcome snapshot. */
|
|
23
21
|
export const SNAPSHOT_TAIL_MAX = 500;
|
|
24
22
|
/** Invalid requests preserve the complete welcome; valid requests are capped. */
|
|
@@ -27,10 +25,8 @@ export function normalizeSnapshotTail(value) {
|
|
|
27
25
|
return undefined;
|
|
28
26
|
return Math.min(value, SNAPSHOT_TAIL_MAX);
|
|
29
27
|
}
|
|
30
|
-
// ---------------------------------------------------------------------------
|
|
31
28
|
// Newline-delimited JSON codec (the framing pi solves with `jsonl`, reproduced
|
|
32
29
|
// locally so the protocol module owns no transport dependency)
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
30
|
/** Encode one frame as a single newline-terminated JSON line. */
|
|
35
31
|
export function encodeFrame(frame) {
|
|
36
32
|
return JSON.stringify(frame) + '\n';
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { execFileSync } from 'node:child_process';
|
|
11
11
|
import { readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
12
12
|
import { join } from 'node:path';
|
|
13
|
+
import { envBrokerEngine } from '../../shared/env.js';
|
|
13
14
|
import { createAgentSessionServices, createAgentSessionFromServices, createAgentSessionRuntime, SessionManager, VERSION, } from '@earendil-works/pi-coding-agent';
|
|
14
15
|
import { crtrHome } from '../canvas/paths.js';
|
|
15
16
|
import { emitEvent } from '../events/emit.js';
|
|
@@ -24,7 +25,7 @@ export { createAgentSessionServices, createAgentSessionFromServices, createAgent
|
|
|
24
25
|
* through here so the seam stays a single, auditable swap.
|
|
25
26
|
*/
|
|
26
27
|
export async function loadBrokerEngine() {
|
|
27
|
-
const spec =
|
|
28
|
+
const spec = envBrokerEngine();
|
|
28
29
|
const mod = (await import(spec));
|
|
29
30
|
if (typeof mod.createAgentSessionServices !== 'function' ||
|
|
30
31
|
typeof mod.createAgentSessionFromServices !== 'function' ||
|
|
@@ -7,7 +7,7 @@ import { type BrokerToClient, type RpcExtensionUIRequest, type RpcExtensionUIRes
|
|
|
7
7
|
/** A review companion may only navigate or fork within a branch whose ancestry
|
|
8
8
|
* has crossed its durable transcript boundary. The broker sends this typed local
|
|
9
9
|
* failure as a dedicated error frame without invoking pi's tree mutation. */
|
|
10
|
-
export { ReviewBoundaryNavigationError, REVIEW_BOUNDARY_NAVIGATION_CODE } from './broker/frame-
|
|
10
|
+
export { ReviewBoundaryNavigationError, REVIEW_BOUNDARY_NAVIGATION_CODE } from './broker/frame-replies.js';
|
|
11
11
|
export type { SubscriptionGeneration } from './broker/rebind.js';
|
|
12
12
|
/** A blocking dialog awaiting a response from ANY writable client, the
|
|
13
13
|
* broker-side default timeout, or the engine's abort. The dialog is fanned out
|