@north-light/crouter 0.3.233 → 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-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.js +4 -7
- 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.js +3 -3
- 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__/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/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.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,149 @@
|
|
|
1
|
+
import { AUTH_FAULT_RECOVERY_BODY, formatCard, } from '../../../shared/generated-context.js';
|
|
2
|
+
import { envModelIntent } from '../../../shared/env.js';
|
|
3
|
+
import { emitEvent } from '../../events/emit.js';
|
|
4
|
+
import { clearFault, readFault } from '../fault.js';
|
|
5
|
+
import { isUnknownModel } from '../model-selection.js';
|
|
6
|
+
export function createAuthReloadGate(deps) {
|
|
7
|
+
const { nodeId, cfg, replies, rebind, session, services, broadcastModelChanged, formatModelSpec, resolveLaunchModel, driveKickoff, } = deps;
|
|
8
|
+
let reloadInFlight = null;
|
|
9
|
+
let faultRedriveInFlight = false;
|
|
10
|
+
/** True once the engine this work started against has been replaced — every
|
|
11
|
+
* step of both flows re-checks it before touching the session again. */
|
|
12
|
+
const supersededBy = (generation, boundSession) => rebind.installedGeneration() !== generation || session() !== boundSession;
|
|
13
|
+
/** Rebuild the model snapshot against re-read credentials and reconcile the
|
|
14
|
+
* session's model with the launch route. */
|
|
15
|
+
const runAuthReload = async (generation, authSession, authServices) => {
|
|
16
|
+
// Credentials are read fresh by PoolCredentialStore; only the
|
|
17
|
+
// ModelRuntime snapshot needs rebuilding. Authentication reloads
|
|
18
|
+
// never fetch provider catalogs over the network.
|
|
19
|
+
await authServices.modelRuntime.refresh({ allowNetwork: false });
|
|
20
|
+
if (supersededBy(generation, authSession))
|
|
21
|
+
return;
|
|
22
|
+
const modelLess = authSession.model === undefined || isUnknownModel(authSession.model);
|
|
23
|
+
const reconcilesLogicalRoute = cfg.modelExact !== true &&
|
|
24
|
+
cfg.modelProviderPinned !== true &&
|
|
25
|
+
(envModelIntent() ?? '').trim() !== '';
|
|
26
|
+
if (modelLess || reconcilesLogicalRoute) {
|
|
27
|
+
const resolved = await resolveLaunchModel(authServices, cfg);
|
|
28
|
+
if (supersededBy(generation, authSession))
|
|
29
|
+
return;
|
|
30
|
+
if (resolved !== undefined) {
|
|
31
|
+
const currentSpec = formatModelSpec(authSession.model, authSession.thinkingLevel);
|
|
32
|
+
const resolvedSpec = formatModelSpec(resolved.model, resolved.thinkingLevel);
|
|
33
|
+
if (resolvedSpec !== null && resolvedSpec !== currentSpec) {
|
|
34
|
+
await authSession.setModel(resolved.model);
|
|
35
|
+
if (supersededBy(generation, authSession))
|
|
36
|
+
return;
|
|
37
|
+
authSession.setThinkingLevel((resolved.thinkingLevel ?? 'off'));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (supersededBy(generation, authSession))
|
|
42
|
+
return;
|
|
43
|
+
// Persist an algorithmic route choice without clearing the logical
|
|
44
|
+
// intent that makes future reconciliation possible.
|
|
45
|
+
await broadcastModelChanged();
|
|
46
|
+
driveKickoff();
|
|
47
|
+
};
|
|
48
|
+
/** Start (or join) this generation's reconcile. */
|
|
49
|
+
const startAuthReload = () => {
|
|
50
|
+
const generation = rebind.installedGeneration();
|
|
51
|
+
const existing = reloadInFlight;
|
|
52
|
+
if (existing !== null && existing.generation === generation)
|
|
53
|
+
return existing.promise;
|
|
54
|
+
if (generation === undefined)
|
|
55
|
+
return undefined;
|
|
56
|
+
const authSession = session();
|
|
57
|
+
const authServices = services();
|
|
58
|
+
const promise = runAuthReload(generation, authSession, authServices).catch((err) => {
|
|
59
|
+
emitEvent({
|
|
60
|
+
level: 'warn',
|
|
61
|
+
event: 'broker.auth_reload.reconcile_failed',
|
|
62
|
+
error: err,
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
const work = { generation, promise };
|
|
66
|
+
reloadInFlight = work;
|
|
67
|
+
void promise.finally(() => {
|
|
68
|
+
if (reloadInFlight === work)
|
|
69
|
+
reloadInFlight = null;
|
|
70
|
+
});
|
|
71
|
+
return promise;
|
|
72
|
+
};
|
|
73
|
+
/** Rewind to the entry the recorded auth fault killed and re-drive the turn
|
|
74
|
+
* with the recovery prompt — once, after the reconcile it depends on. */
|
|
75
|
+
const redriveAuthFault = (reload) => {
|
|
76
|
+
const authFault = readFault(nodeId);
|
|
77
|
+
const generation = rebind.installedGeneration();
|
|
78
|
+
const faultSession = session();
|
|
79
|
+
if (authFault?.link !== 'pi→provider' ||
|
|
80
|
+
authFault.kind !== 'auth' ||
|
|
81
|
+
faultSession.isStreaming ||
|
|
82
|
+
faultRedriveInFlight)
|
|
83
|
+
return;
|
|
84
|
+
faultRedriveInFlight = true;
|
|
85
|
+
void (async () => {
|
|
86
|
+
try {
|
|
87
|
+
if (reload !== undefined)
|
|
88
|
+
await reload;
|
|
89
|
+
if (supersededBy(generation, faultSession))
|
|
90
|
+
return;
|
|
91
|
+
const anchorEntryId = authFault.anchorEntryId;
|
|
92
|
+
if (anchorEntryId !== undefined) {
|
|
93
|
+
try {
|
|
94
|
+
const leafId = faultSession.sessionManager.getLeafId?.() ?? null;
|
|
95
|
+
if (leafId !== anchorEntryId)
|
|
96
|
+
await faultSession.navigateTree(anchorEntryId);
|
|
97
|
+
if (supersededBy(generation, faultSession))
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
emitEvent({
|
|
102
|
+
level: 'warn',
|
|
103
|
+
event: 'broker.auth_fault.rewind_skipped',
|
|
104
|
+
error: err,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const fresh = readFault(nodeId);
|
|
109
|
+
if (supersededBy(generation, faultSession) ||
|
|
110
|
+
faultSession.isStreaming ||
|
|
111
|
+
fresh?.link !== 'pi→provider' ||
|
|
112
|
+
fresh.kind !== 'auth' ||
|
|
113
|
+
fresh.since !== authFault.since)
|
|
114
|
+
return;
|
|
115
|
+
clearFault(nodeId, { link: 'pi→provider' });
|
|
116
|
+
await faultSession.prompt(formatCard('recovery', {}, AUTH_FAULT_RECOVERY_BODY));
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
emitEvent({
|
|
120
|
+
level: 'error',
|
|
121
|
+
event: 'broker.auth_fault.redrive_failed',
|
|
122
|
+
error: err,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
faultRedriveInFlight = false;
|
|
127
|
+
}
|
|
128
|
+
})();
|
|
129
|
+
};
|
|
130
|
+
return {
|
|
131
|
+
inFlight: () => reloadInFlight?.promise,
|
|
132
|
+
handle(client) {
|
|
133
|
+
// Open to any client, observers included: reload_auth is an idempotent
|
|
134
|
+
// local re-read of shared credentials + the runtime's availability
|
|
135
|
+
// snapshot. It does not steer the conversation, so the daemon's
|
|
136
|
+
// canvas-wide /login fan can ride an observer connection.
|
|
137
|
+
try {
|
|
138
|
+
replies.ackTo(client, 'reload_auth');
|
|
139
|
+
redriveAuthFault(startAuthReload());
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
replies.engineErrorTo(client)(err);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
resetForSession() {
|
|
146
|
+
reloadInFlight = null;
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ClientToBroker } from '../broker-protocol.js';
|
|
2
|
+
import type { BrokerClient, BrokerClientRegistry } from './client-registry.js';
|
|
3
|
+
import type { EventProjection } from './event-projection.js';
|
|
4
|
+
import type { MemoryRefGuidance } from './frame-memory-refs.js';
|
|
5
|
+
import type { FrameReplies } from './frame-replies.js';
|
|
6
|
+
import type { AuthReloadGate } from './auth-reload.js';
|
|
7
|
+
import type { BrokerSession } from './read-ops.js';
|
|
8
|
+
import type { RebindDriver } from './rebind.js';
|
|
9
|
+
import type { ToolGroupTracker } from './tool-groups.js';
|
|
10
|
+
import type { PromptDispatchTracker } from './turn-ignition.js';
|
|
11
|
+
/** The frames that drive the live engine — the viewer's input vocabulary. */
|
|
12
|
+
export type DriveFrame = Extract<ClientToBroker, {
|
|
13
|
+
type: 'prompt' | 'steer' | 'follow_up' | 'abort' | 'bash';
|
|
14
|
+
}>;
|
|
15
|
+
export type EngineDriver = (client: BrokerClient, frame: DriveFrame) => Promise<unknown> | undefined;
|
|
16
|
+
export declare function createEngineDriver(deps: {
|
|
17
|
+
registry: BrokerClientRegistry;
|
|
18
|
+
replies: FrameReplies;
|
|
19
|
+
session: () => BrokerSession;
|
|
20
|
+
dispatches: PromptDispatchTracker;
|
|
21
|
+
memoryRefs: MemoryRefGuidance;
|
|
22
|
+
authReloadGate: AuthReloadGate;
|
|
23
|
+
rebind: RebindDriver;
|
|
24
|
+
projection: EventProjection;
|
|
25
|
+
toolGroups: ToolGroupTracker;
|
|
26
|
+
}): EngineDriver;
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { emitEvent } from '../../events/emit.js';
|
|
2
|
+
import { operationIdContext } from '../../events/operation-id.js';
|
|
3
|
+
import { promptWithAdvertisedCommandInvocation } from '../advertised-command-invocation.js';
|
|
4
|
+
import { chooseGuidanceDeliveryMode, promptWithNextTurnGuidance, resolveEngineRoute, resolveSteerCall, } from './engine-routing.js';
|
|
5
|
+
export function createEngineDriver(deps) {
|
|
6
|
+
const { registry, replies, session, dispatches, memoryRefs, authReloadGate, rebind, projection, toolGroups, } = deps;
|
|
7
|
+
const { ackTo, engineErrorTo } = replies;
|
|
8
|
+
const errorRelay = (client) => {
|
|
9
|
+
let failure;
|
|
10
|
+
return {
|
|
11
|
+
relay: (err) => {
|
|
12
|
+
failure = err;
|
|
13
|
+
registry.sendFrame(client, {
|
|
14
|
+
type: 'error',
|
|
15
|
+
code: 'engine_error',
|
|
16
|
+
message: String(err),
|
|
17
|
+
});
|
|
18
|
+
},
|
|
19
|
+
failure: () => failure,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
// Hidden `crtr-memory-refs` guidance rides ALONGSIDE the human frame's own
|
|
23
|
+
// engine call, never rewriting `frame.text` — see MemoryRefGuidance /
|
|
24
|
+
// chooseGuidanceDeliveryMode. A failed SEND (as opposed to a failed
|
|
25
|
+
// resolve, handled above) is likewise logged-and-swallowed: it must never
|
|
26
|
+
// reach the error relay, which is reserved for the human call's own outcome.
|
|
27
|
+
const sendGuidance = (guidance, deliverAs) => session()
|
|
28
|
+
.sendCustomMessage({ customType: 'crtr-memory-refs', content: guidance, display: false }, { deliverAs })
|
|
29
|
+
.catch((err) => {
|
|
30
|
+
emitEvent({
|
|
31
|
+
level: 'warn',
|
|
32
|
+
event: 'broker.memory_refs.guidance_send_failed',
|
|
33
|
+
error: err,
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
const drivePromptOrFollowUp = (client, frame, errors) => {
|
|
37
|
+
const relayError = errors.relay;
|
|
38
|
+
// Settle on the engine call's outcome: the failure is set by relayError
|
|
39
|
+
// before the caught promise resolves, so reading it after the chain is
|
|
40
|
+
// the call's verdict.
|
|
41
|
+
const settle = (p) => p.then(() => errors.failure());
|
|
42
|
+
const dispatch = () => {
|
|
43
|
+
const route = resolveEngineRoute(frame, session().isStreaming);
|
|
44
|
+
const guidance = memoryRefs.guidanceFor(frame.text);
|
|
45
|
+
if (guidance === null) {
|
|
46
|
+
if (route.call === 'prompt') {
|
|
47
|
+
// A routed prompt STARTS a turn — including an idle follow_up
|
|
48
|
+
// escalated by m-C — so it gets a fresh operation id. A true
|
|
49
|
+
// (mid-stream) followUp rides the current turn's operation, like
|
|
50
|
+
// steer.
|
|
51
|
+
return settle(dispatches.track(operationIdContext.fresh(() => promptWithAdvertisedCommandInvocation(session(), frame.text, () => session().prompt(frame.text, route.options)).catch(relayError))));
|
|
52
|
+
}
|
|
53
|
+
// C1: pi's followUp() takes images as a POSITIONAL 2nd arg (`followUp(text, images?)`).
|
|
54
|
+
return settle(session().followUp(frame.text, frame.images).catch(relayError));
|
|
55
|
+
}
|
|
56
|
+
const deliverAs = chooseGuidanceDeliveryMode(frame.type, route.call, session().isStreaming);
|
|
57
|
+
if (route.call === 'prompt') {
|
|
58
|
+
if (deliverAs === 'nextTurn') {
|
|
59
|
+
// The ONLY ordering where guidance precedes the human call — pi's
|
|
60
|
+
// prompt() reads+clears its pending-nextTurn queue synchronously
|
|
61
|
+
// at call time, injecting it into the SAME turn as the new user
|
|
62
|
+
// message. promptWithNextTurnGuidance queues the guidance and then
|
|
63
|
+
// ATOMICALLY clears its own pending entry if prompt() settles
|
|
64
|
+
// without ever reaching that drain (an early throw/return leaves
|
|
65
|
+
// nothing stranded to leak into a later, unrelated turn).
|
|
66
|
+
return settle(dispatches.track(promptWithNextTurnGuidance(session(), guidance, () => operationIdContext.fresh(() => promptWithAdvertisedCommandInvocation(session(), frame.text, () => session().prompt(frame.text, route.options)))).catch(relayError)));
|
|
67
|
+
}
|
|
68
|
+
return settle(dispatches.track(operationIdContext.fresh(() => promptWithAdvertisedCommandInvocation(session(), frame.text, () => session().prompt(frame.text, route.options))
|
|
69
|
+
.catch(relayError)
|
|
70
|
+
.then(() => sendGuidance(guidance, deliverAs)))));
|
|
71
|
+
}
|
|
72
|
+
// deliverAs is always 'followUp' here per chooseGuidanceDeliveryMode's
|
|
73
|
+
// contract (a followUp routeCall never yields 'nextTurn').
|
|
74
|
+
return settle(session()
|
|
75
|
+
.followUp(frame.text, frame.images)
|
|
76
|
+
.catch(relayError)
|
|
77
|
+
.then(() => sendGuidance(guidance, deliverAs)));
|
|
78
|
+
};
|
|
79
|
+
// /login acknowledges before its asynchronous local refresh completes.
|
|
80
|
+
// An idle turn must not overtake that refresh and launch on the stale
|
|
81
|
+
// route; true mid-stream follow-ups keep their immediate queue behavior.
|
|
82
|
+
const authReload = session().isStreaming
|
|
83
|
+
? undefined
|
|
84
|
+
: authReloadGate.inFlight();
|
|
85
|
+
if (authReload === undefined)
|
|
86
|
+
return dispatch();
|
|
87
|
+
const waitingGeneration = rebind.installedGeneration();
|
|
88
|
+
const waitingSession = session();
|
|
89
|
+
return authReload.then(() => {
|
|
90
|
+
if (rebind.installedGeneration() !== waitingGeneration ||
|
|
91
|
+
session() !== waitingSession) {
|
|
92
|
+
relayError(new Error('session changed while prompt waited for authentication reload'));
|
|
93
|
+
return errors.failure();
|
|
94
|
+
}
|
|
95
|
+
return dispatch();
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* `prompt { interrupt: true }` is one atomic viewer intention: end whatever
|
|
100
|
+
* is producing now, then start this as a new turn. A normal mid-stream
|
|
101
|
+
* prompt deliberately steers into pi's queue; the whip must not.
|
|
102
|
+
*/
|
|
103
|
+
const driveInterruptPrompt = (client, frame, errors) => (async () => {
|
|
104
|
+
if (session().isBashRunning) {
|
|
105
|
+
session().abortBash();
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
// A prompt can be in pi's async setup before isStreaming flips. Match
|
|
109
|
+
// the correlated interrupt's guard so a whip cannot silently miss it.
|
|
110
|
+
await dispatches.waitUntilAbortable();
|
|
111
|
+
if (session().isStreaming)
|
|
112
|
+
await session().abort();
|
|
113
|
+
}
|
|
114
|
+
return drivePromptOrFollowUp(client, {
|
|
115
|
+
type: 'prompt',
|
|
116
|
+
text: frame.text,
|
|
117
|
+
...(frame.images !== undefined ? { images: frame.images } : {}),
|
|
118
|
+
}, errorRelay(client));
|
|
119
|
+
})().catch((err) => {
|
|
120
|
+
errors.relay(err);
|
|
121
|
+
return errors.failure();
|
|
122
|
+
});
|
|
123
|
+
/**
|
|
124
|
+
* A viewer submits ordinary text as `steer` while the agent is running,
|
|
125
|
+
* including a slash command injected by the tmux prefix menu. pi's steer()
|
|
126
|
+
* deliberately rejects registered extension commands because they cannot be
|
|
127
|
+
* queued; prompt() performs the command preflight first and executes it
|
|
128
|
+
* immediately even while streaming. It also expands a matching
|
|
129
|
+
* skill/template before applying the same steer behavior.
|
|
130
|
+
*/
|
|
131
|
+
const driveSteer = (frame, errors) => {
|
|
132
|
+
const relayError = errors.relay;
|
|
133
|
+
if (resolveSteerCall(frame.text, session()) === 'prompt') {
|
|
134
|
+
void promptWithAdvertisedCommandInvocation(session(), frame.text, () => session().prompt(frame.text, {
|
|
135
|
+
images: frame.images,
|
|
136
|
+
streamingBehavior: 'steer',
|
|
137
|
+
})).catch(relayError);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const guidance = memoryRefs.guidanceFor(frame.text);
|
|
141
|
+
// C1: pi's steer() takes images as a POSITIONAL 2nd arg (`steer(text, images?)`).
|
|
142
|
+
if (guidance === null) {
|
|
143
|
+
void session().steer(frame.text, frame.images).catch(relayError);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
void session()
|
|
147
|
+
.steer(frame.text, frame.images)
|
|
148
|
+
.catch(relayError)
|
|
149
|
+
.then(() => sendGuidance(guidance, 'steer'));
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* esc/abort cancels whatever is live: a running `!` command (abortBash)
|
|
153
|
+
* takes precedence over the agent turn, mirroring pi interactive mode.
|
|
154
|
+
*/
|
|
155
|
+
const driveAbort = (client, frame, errors) => {
|
|
156
|
+
if (session().isBashRunning) {
|
|
157
|
+
session().abortBash();
|
|
158
|
+
if (frame.id !== undefined)
|
|
159
|
+
ackTo(client, 'abort', true, 'bash', frame.id);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (frame.id === undefined) {
|
|
163
|
+
// A viewer's Esc — unchanged instant semantics, no ack.
|
|
164
|
+
void session().abort().catch(errors.relay);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
// An id-bearing abort (a one-shot daemon interrupt) must close the
|
|
168
|
+
// pre-turn window: a routed deliver whose prompt() is still in async
|
|
169
|
+
// setup reads as idle and abort() would silently miss it. If a prompt
|
|
170
|
+
// dispatch is pending, wait (bounded) for the run to become abortable
|
|
171
|
+
// — or for every dispatch to settle without one (an early return) —
|
|
172
|
+
// then abort and ack with what was actually interrupted.
|
|
173
|
+
void (async () => {
|
|
174
|
+
try {
|
|
175
|
+
await dispatches.waitUntilAbortable();
|
|
176
|
+
const detail = session().isStreaming ? 'turn' : 'idle';
|
|
177
|
+
await session().abort();
|
|
178
|
+
ackTo(client, 'abort', true, detail, frame.id);
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
engineErrorTo(client, frame.id)(err);
|
|
182
|
+
}
|
|
183
|
+
})();
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* `!`/`!!` bash: run via session.executeBash (records a bashExecution context
|
|
187
|
+
* message, starts NO agent turn) and relay its lifecycle to ALL viewers as
|
|
188
|
+
* bash_start/bash_output/bash_end so each renders the live component.
|
|
189
|
+
* Serialized like pi's interactive mode — reject a second `!` while one is
|
|
190
|
+
* already running rather than racing _bashAbortController.
|
|
191
|
+
*/
|
|
192
|
+
const driveBash = (client, frame, errors) => {
|
|
193
|
+
const command = frame.command;
|
|
194
|
+
if (command.trim() === '')
|
|
195
|
+
return;
|
|
196
|
+
if (session().isBashRunning) {
|
|
197
|
+
registry.sendFrame(client, {
|
|
198
|
+
type: 'error',
|
|
199
|
+
code: 'bash_busy',
|
|
200
|
+
message: 'A bash command is already running',
|
|
201
|
+
});
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const exclude = frame.excludeFromContext === true;
|
|
205
|
+
// Order before any held assistant message_update, so a `!` run mid-stream
|
|
206
|
+
// never renders ahead of the update it follows.
|
|
207
|
+
projection.flush();
|
|
208
|
+
// The live bash component is a visible transcript boundary, even though
|
|
209
|
+
// its persisted bashExecution message arrives later via the session.
|
|
210
|
+
toolGroups.finishOpenToolGroup();
|
|
211
|
+
registry.broadcast({
|
|
212
|
+
type: 'bash_start',
|
|
213
|
+
command,
|
|
214
|
+
excludeFromContext: exclude,
|
|
215
|
+
});
|
|
216
|
+
void session()
|
|
217
|
+
.executeBash(command, (chunk) => registry.broadcast({ type: 'bash_output', chunk }), { excludeFromContext: exclude })
|
|
218
|
+
.then((result) => {
|
|
219
|
+
registry.broadcast({
|
|
220
|
+
type: 'bash_end',
|
|
221
|
+
exitCode: result.exitCode,
|
|
222
|
+
cancelled: result.cancelled,
|
|
223
|
+
truncated: result.truncated,
|
|
224
|
+
fullOutputPath: result.fullOutputPath,
|
|
225
|
+
});
|
|
226
|
+
})
|
|
227
|
+
.catch(errors.relay);
|
|
228
|
+
};
|
|
229
|
+
/**
|
|
230
|
+
* Drive the engine for one client frame. For a prompt/follow_up frame this
|
|
231
|
+
* returns a promise that settles with the engine call's OUTCOME — `undefined`
|
|
232
|
+
* when the call succeeded, the rejection value when it did not — so a caller
|
|
233
|
+
* that must report success (the `deliver` ack) can read it instead of assuming
|
|
234
|
+
* the dispatch worked. Every other frame type keeps the fire-and-forget shape
|
|
235
|
+
* and returns `undefined`.
|
|
236
|
+
*/
|
|
237
|
+
return (client, frame) => {
|
|
238
|
+
const errors = errorRelay(client);
|
|
239
|
+
switch (frame.type) {
|
|
240
|
+
case 'prompt':
|
|
241
|
+
return frame.interrupt === true
|
|
242
|
+
? driveInterruptPrompt(client, frame, errors)
|
|
243
|
+
: drivePromptOrFollowUp(client, frame, errors);
|
|
244
|
+
case 'follow_up':
|
|
245
|
+
return drivePromptOrFollowUp(client, frame, errors);
|
|
246
|
+
case 'steer':
|
|
247
|
+
driveSteer(frame, errors);
|
|
248
|
+
return undefined;
|
|
249
|
+
case 'abort':
|
|
250
|
+
driveAbort(client, frame, errors);
|
|
251
|
+
return undefined;
|
|
252
|
+
case 'bash':
|
|
253
|
+
driveBash(client, frame, errors);
|
|
254
|
+
return undefined;
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import type { PromptOptions } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
import type { ImageContent } from '@earendil-works/pi-ai';
|
|
3
|
+
/**
|
|
4
|
+
* Route a writable client's `prompt`/`follow_up` frame against the LIVE session
|
|
5
|
+
* state. The client picks its frame type off a possibly-STALE `isStreaming`
|
|
6
|
+
* snapshot, so the broker is authoritative and the client's choice is a HINT:
|
|
7
|
+
*
|
|
8
|
+
* - m-B (streaming-safe prompt): a `prompt` arriving mid-stream needs
|
|
9
|
+
* PromptOptions.streamingBehavior ("Required if streaming"; prompt() throws
|
|
10
|
+
* without it). "steer" mirrors pi interactive-mode's own
|
|
11
|
+
* Enter-while-streaming submit (`prompt(text, { streamingBehavior: "steer" })`).
|
|
12
|
+
* - m-C (idle-safe follow_up): pi's followUp() only enqueues into a RUNNING
|
|
13
|
+
* agent loop — on an idle session nothing ever drains the queue and the text
|
|
14
|
+
* is silently lost. An idle `follow_up` therefore runs as a prompt now.
|
|
15
|
+
*
|
|
16
|
+
* driveEngine calls this synchronously with `session.isStreaming`, so the
|
|
17
|
+
* routed state cannot go stale between the check and the engine call.
|
|
18
|
+
* C1: images ride as a field on PromptOptions (pi: `prompt(text, { images })`).
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveEngineRoute(frame: {
|
|
21
|
+
type: 'prompt' | 'follow_up';
|
|
22
|
+
images?: ImageContent[];
|
|
23
|
+
}, isStreaming: boolean): {
|
|
24
|
+
call: 'prompt';
|
|
25
|
+
options: PromptOptions;
|
|
26
|
+
} | {
|
|
27
|
+
call: 'followUp';
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* True iff `text` would be consumed by pi's OWN leading-name preflight before
|
|
31
|
+
* `session.prompt/steer/followUp` ever sees it as prose — an extension command
|
|
32
|
+
* (`session.extensionRunner.getCommand`), a `/skill:name` skill, or a `/name`
|
|
33
|
+
* prompt template (mirrors `_tryExecuteExtensionCommand` / `_expandSkillCommand`
|
|
34
|
+
* / `expandPromptTemplate` in the pinned SDK verbatim, including the exact
|
|
35
|
+
* name-parsing substrings). Inline memory-reference guidance must NEVER fire
|
|
36
|
+
* for these — the leading token routes to the engine's own command surface,
|
|
37
|
+
* not prose referencing a memory doc. Each lookup is independently wrapped so
|
|
38
|
+
* an engine missing one accessor (the fake, or a degraded session) degrades
|
|
39
|
+
* that check to "not a match" rather than aborting the whole classification —
|
|
40
|
+
* matching `buildCommandList`'s existing "no live extensionRunner" tolerance.
|
|
41
|
+
*/
|
|
42
|
+
export declare function isLeadingEngineCommand(text: string, session: {
|
|
43
|
+
extensionRunner?: {
|
|
44
|
+
getCommand(name: string): unknown;
|
|
45
|
+
};
|
|
46
|
+
resourceLoader?: {
|
|
47
|
+
getSkills(): {
|
|
48
|
+
skills: Array<{
|
|
49
|
+
name: string;
|
|
50
|
+
}>;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
promptTemplates?: ReadonlyArray<{
|
|
54
|
+
name: string;
|
|
55
|
+
}>;
|
|
56
|
+
}): boolean;
|
|
57
|
+
/** A `steer` frame normally maps directly to pi's steer queue. Engine commands,
|
|
58
|
+
* skills, and templates must instead pass through prompt()'s leading-command
|
|
59
|
+
* preflight; with streamingBehavior:'steer', ordinary expanded text still lands
|
|
60
|
+
* in the same queue. */
|
|
61
|
+
export declare function resolveSteerCall(text: string, session: Parameters<typeof isLeadingEngineCommand>[1]): 'prompt' | 'steer';
|
|
62
|
+
/**
|
|
63
|
+
* Enumerate every leading-token STRING this session's engine would
|
|
64
|
+
* independently consume as a leading command/skill/template dispatch BEFORE
|
|
65
|
+
* inline memory-reference guidance ever applies — the read-op sibling of
|
|
66
|
+
* `isLeadingEngineCommand`'s point-lookup, gathered as a full enumeration for
|
|
67
|
+
* viewer-side suppression instead of a per-submission membership check. Same
|
|
68
|
+
* three sources, same shape of the leading match `isLeadingEngineCommand`
|
|
69
|
+
* checks (bare extension-command invocation names and prompt-template names,
|
|
70
|
+
* `skill:<name>` for skills), so `/${token}` round-trips through
|
|
71
|
+
* `isLeadingEngineCommand(text, session)` for every emitted token (locked by
|
|
72
|
+
* a test). Kept STRICTLY separate from `buildCommandList` (command
|
|
73
|
+
* completion) and the ref inventory (`RefMeta` rows) — this is neither.
|
|
74
|
+
*/
|
|
75
|
+
export declare function engineLeadingCommandTokens(session: {
|
|
76
|
+
extensionRunner?: {
|
|
77
|
+
getRegisteredCommands(): Array<{
|
|
78
|
+
invocationName: string;
|
|
79
|
+
}>;
|
|
80
|
+
};
|
|
81
|
+
resourceLoader?: {
|
|
82
|
+
getSkills(): {
|
|
83
|
+
skills: Array<{
|
|
84
|
+
name: string;
|
|
85
|
+
}>;
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
promptTemplates?: ReadonlyArray<{
|
|
89
|
+
name: string;
|
|
90
|
+
}>;
|
|
91
|
+
}): string[];
|
|
92
|
+
/**
|
|
93
|
+
* Choose how the hidden `crtr-memory-refs` guidance custom message rides
|
|
94
|
+
* alongside a human frame's own engine call (design Flow B). Pure over the
|
|
95
|
+
* frame's routing outcome — never reads live session state itself, so a
|
|
96
|
+
* caller can decide the delivery mode from the exact same `route`
|
|
97
|
+
* `resolveEngineRoute` already computed for the human call.
|
|
98
|
+
*
|
|
99
|
+
* - `steer` frame -> 'steer' (always; no route call exists).
|
|
100
|
+
* - a TRUE mid-stream follow_up (`routeCall === 'followUp'`) -> 'followUp'.
|
|
101
|
+
* - every other `prompt`/`follow_up` routed as `routeCall === 'prompt'`:
|
|
102
|
+
* idle -> 'nextTurn' (the ONLY case guidance precedes the human call —
|
|
103
|
+
* pi's `prompt()` reads+clears its pending-nextTurn queue synchronously
|
|
104
|
+
* into the SAME turn as the new user message); streaming (m-B
|
|
105
|
+
* steer-while-streaming) -> 'steer', never 'nextTurn' (that would attach
|
|
106
|
+
* to a later, unrelated turn).
|
|
107
|
+
*/
|
|
108
|
+
export declare function chooseGuidanceDeliveryMode(frameType: 'prompt' | 'follow_up' | 'steer', routeCall: 'prompt' | 'followUp' | undefined, isStreaming: boolean): 'steer' | 'followUp' | 'nextTurn';
|
|
109
|
+
/**
|
|
110
|
+
* Deliver a `nextTurn` guidance custom message ATOMICALLY around the idle-
|
|
111
|
+
* prompt call it's meant to ride alongside. Pi's `_pendingNextTurnMessages`
|
|
112
|
+
* queue (the only public seam for `deliverAs:'nextTurn'`) is drained ONLY deep
|
|
113
|
+
* inside `session.prompt()`, well after several await points — extension-
|
|
114
|
+
* command interception, the `input` extension transform, a streaming reroute,
|
|
115
|
+
* model/auth validation, pre-turn compaction — that can return or throw BEFORE
|
|
116
|
+
* the drain ever runs. `sendCustomMessage`'s nextTurn branch pushes
|
|
117
|
+
* synchronously and unconditionally, so any of those early exits strands the
|
|
118
|
+
* pushed guidance in the queue to attach itself to whichever LATER, unrelated
|
|
119
|
+
* prompt happens to reach the drain first.
|
|
120
|
+
*
|
|
121
|
+
* There is no public SDK seam to observe or cancel a pending nextTurn message
|
|
122
|
+
* (`_pendingNextTurnMessages` is TS-`private` only — a plain runtime field, not
|
|
123
|
+
* `#private`), so this reaches into that one field and removes EXACTLY the
|
|
124
|
+
* entry this call pushed, identified by object identity via a locally-
|
|
125
|
+
* generated marker riding the message's own `details` field (never surfaced to
|
|
126
|
+
* the model, and irrelevant if the message WAS consumed normally — `details`
|
|
127
|
+
* is just carried through like any other field once folded into a real turn).
|
|
128
|
+
* Runs UNCONDITIONALLY after the human call settles, success or failure/early-
|
|
129
|
+
* return alike — a "successful" `prompt()` promise can just as easily be an
|
|
130
|
+
* early return that skipped the drain (an intercepted extension command, an
|
|
131
|
+
* `input` transform, a streaming reroute) as a genuine consumed turn, so only
|
|
132
|
+
* checking `.catch` is not enough.
|
|
133
|
+
*/
|
|
134
|
+
export declare function promptWithNextTurnGuidance(session: {
|
|
135
|
+
sendCustomMessage(message: {
|
|
136
|
+
customType: string;
|
|
137
|
+
content: unknown;
|
|
138
|
+
display?: boolean;
|
|
139
|
+
details?: unknown;
|
|
140
|
+
}, options?: {
|
|
141
|
+
deliverAs?: 'steer' | 'followUp' | 'nextTurn';
|
|
142
|
+
}): Promise<void>;
|
|
143
|
+
}, guidance: string, runPrompt: () => Promise<void>): Promise<void>;
|