@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
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
// + model registry are real SDK construction helpers (NOT part of the swappable
|
|
17
17
|
// engine seam — the fake engine receives the real, extension-loaded loader so
|
|
18
18
|
// the real canvas-stophook fires session_start).
|
|
19
|
+
import { envModelIntent, envNodeCwd, envProfileId } from '../../shared/env.js';
|
|
19
20
|
import { createServer } from 'node:net';
|
|
20
21
|
import { existsSync, readFileSync, unlinkSync } from 'node:fs';
|
|
21
22
|
import { join } from 'node:path';
|
|
@@ -54,7 +55,7 @@ import { FrameOverflowError, normalizeSnapshotTail, } from './broker-protocol.js
|
|
|
54
55
|
/** A review companion may only navigate or fork within a branch whose ancestry
|
|
55
56
|
* has crossed its durable transcript boundary. The broker sends this typed local
|
|
56
57
|
* failure as a dedicated error frame without invoking pi's tree mutation. */
|
|
57
|
-
export { ReviewBoundaryNavigationError, REVIEW_BOUNDARY_NAVIGATION_CODE } from './broker/frame-
|
|
58
|
+
export { ReviewBoundaryNavigationError, REVIEW_BOUNDARY_NAVIGATION_CODE } from './broker/frame-replies.js';
|
|
58
59
|
/**
|
|
59
60
|
* pi 0.82 made `ModelRuntime` the canonical model/auth surface and demoted
|
|
60
61
|
* `ModelRegistry` to the synchronous facade over it (`find`/`getAll`/
|
|
@@ -83,9 +84,7 @@ function formatExactModelSpec(model, thinkingLevel) {
|
|
|
83
84
|
const base = formatModelSpec(model, undefined);
|
|
84
85
|
return base === null ? null : `${base}:${thinkingLevel === undefined || thinkingLevel === '' ? 'off' : thinkingLevel}`;
|
|
85
86
|
}
|
|
86
|
-
// ---------------------------------------------------------------------------
|
|
87
87
|
// Tunables (backpressure / dialog anti-deadlock)
|
|
88
|
-
// ---------------------------------------------------------------------------
|
|
89
88
|
/** Broker-side default dialog timeout (anti-deadlock). When an extension
|
|
90
89
|
* dialog is forwarded to every writable client, the broker ALWAYS arms a timeout
|
|
91
90
|
* (this default, or a shorter per-dialog `opts.timeout` if the extension passed
|
|
@@ -93,14 +92,12 @@ function formatExactModelSpec(model, thinkingLevel) {
|
|
|
93
92
|
* — can never hang the agent turn forever. On fire it resolves to the SAFE default
|
|
94
93
|
* (deny for confirm; cancel/undefined for select/input/editor). */
|
|
95
94
|
const DEFAULT_DIALOG_TIMEOUT_MS = 120_000; // 120 s
|
|
96
|
-
// ---------------------------------------------------------------------------
|
|
97
95
|
// M3 (scout mq5thyli): the active engine session, exposed so broker-cli's FATAL
|
|
98
96
|
// handlers (uncaughtException / unhandledRejection / the runBroker reject) can
|
|
99
97
|
// dispose it before process.exit. The bash tool spawns children `detached` (own
|
|
100
98
|
// pgid); only session.dispose() (→ abortBash / agent.abort → killProcessTree)
|
|
101
99
|
// reaps them. The graceful exit path already disposes; without this the crash
|
|
102
100
|
// path would `process.exit(1)` and ORPHAN every in-flight bash subprocess.
|
|
103
|
-
// ---------------------------------------------------------------------------
|
|
104
101
|
let activeSession = null;
|
|
105
102
|
/** Dispose the live engine session if one exists (idempotent). Called by
|
|
106
103
|
* broker-cli's fatal handlers before exit so a crash never orphans detached
|
|
@@ -117,9 +114,7 @@ export function disposeActiveSession() {
|
|
|
117
114
|
}
|
|
118
115
|
}
|
|
119
116
|
}
|
|
120
|
-
// ---------------------------------------------------------------------------
|
|
121
117
|
// runBroker — the broker process body (plan T4 steps 1–6)
|
|
122
|
-
// ---------------------------------------------------------------------------
|
|
123
118
|
export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), startupTs = new Date().toISOString()) {
|
|
124
119
|
// A clean-abort certificate belongs only to the dead broker that wrote it.
|
|
125
120
|
// Fleet classification consumes it as proof that the dead broker had a turn
|
|
@@ -275,9 +270,7 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
|
|
|
275
270
|
// N3: the node's display name is re-applied by the rebind lane below so it
|
|
276
271
|
// survives a session replacement (new_session/switch_session/fork), not only at
|
|
277
272
|
// boot.
|
|
278
|
-
// -------------------------------------------------------------------------
|
|
279
273
|
// Socket fan-out, dialogs, and transcript tool groups
|
|
280
|
-
// -------------------------------------------------------------------------
|
|
281
274
|
const sockPath = viewSocketPath(nodeId);
|
|
282
275
|
const registry = new BrokerClientRegistry(nodeId);
|
|
283
276
|
const pendingDialogs = new Map();
|
|
@@ -445,10 +438,8 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
|
|
|
445
438
|
const reWelcomeAll = () => {
|
|
446
439
|
registry.forEachHelloed(sendWelcome);
|
|
447
440
|
};
|
|
448
|
-
// -------------------------------------------------------------------------
|
|
449
441
|
// The single exit helper: dispose the engine, close + unlink the
|
|
450
442
|
// socket, exit 0. Idempotent — every trigger converges here.
|
|
451
|
-
// -------------------------------------------------------------------------
|
|
452
443
|
const completeExit = (status) => {
|
|
453
444
|
if (disposed)
|
|
454
445
|
return;
|
|
@@ -509,7 +500,6 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
|
|
|
509
500
|
}
|
|
510
501
|
completeExit(status);
|
|
511
502
|
};
|
|
512
|
-
// -------------------------------------------------------------------------
|
|
513
503
|
// Extension-dialog routing (C2). makeBrokerUiContext owns the dialogPromise;
|
|
514
504
|
// here we just give it the three broker-side hooks it needs: the live set of
|
|
515
505
|
// writable clients (empty = nobody can answer → noOp fallback), how to forward a
|
|
@@ -517,7 +507,6 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
|
|
|
517
507
|
// first settles through. The zero-writable path NEVER hangs and NEVER waits on a
|
|
518
508
|
// per-dialog timeout (design §5.4's timeout premise is false — see
|
|
519
509
|
// makeBrokerUiContext).
|
|
520
|
-
// -------------------------------------------------------------------------
|
|
521
510
|
uiContext = makeBrokerUiContext({
|
|
522
511
|
writable: () => registry.writableClients(),
|
|
523
512
|
forward: (client, request) => registry.sendFrame(client, request),
|
|
@@ -542,9 +531,7 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
|
|
|
542
531
|
});
|
|
543
532
|
notifyTurnAccepted = frameDispatch.notifyTurnAccepted;
|
|
544
533
|
resetFrameState = frameDispatch.resetForSession;
|
|
545
|
-
// -------------------------------------------------------------------------
|
|
546
534
|
// 4 (plan): the socket listener — unlink any stale socket first.
|
|
547
|
-
// -------------------------------------------------------------------------
|
|
548
535
|
try {
|
|
549
536
|
if (existsSync(sockPath))
|
|
550
537
|
unlinkSync(sockPath);
|
|
@@ -671,7 +658,6 @@ export async function runBroker(nodeId, startupAt = process.hrtime.bigint(), sta
|
|
|
671
658
|
process.on('SIGTERM', () => { void abortAndExit('SIGTERM'); });
|
|
672
659
|
process.on('SIGINT', () => { void abortAndExit('SIGINT'); });
|
|
673
660
|
}
|
|
674
|
-
// ---------------------------------------------------------------------------
|
|
675
661
|
// snapshotMessages — the catch-up snapshot's ordered message history.
|
|
676
662
|
//
|
|
677
663
|
// The broker is the SOLE writer of the node's session `.jsonl`, so the session
|
|
@@ -722,7 +708,6 @@ export function snapshotMessages(session, boundaryReviewId) {
|
|
|
722
708
|
}
|
|
723
709
|
return messages === undefined ? undefined : visibleMessages(messages, { boundaryReviewId });
|
|
724
710
|
}
|
|
725
|
-
// ---------------------------------------------------------------------------
|
|
726
711
|
// resolveLaunchModel — the SOLE launch model-selection policy, module-scoped
|
|
727
712
|
// so both buildForManager (initial boot, inside buildBrokerSession below) and
|
|
728
713
|
// the reload_auth re-drive (inside runBroker, a DIFFERENT function scope) can
|
|
@@ -731,15 +716,14 @@ export function snapshotMessages(session, boundaryReviewId) {
|
|
|
731
716
|
// viable at all (tier 3) — this is NOT a fault; the caller decides what to do
|
|
732
717
|
// with it (construct a model-less session at boot, or leave a running session
|
|
733
718
|
// alone on a failed re-drive attempt).
|
|
734
|
-
// ---------------------------------------------------------------------------
|
|
735
719
|
async function resolveLaunchModel(services, cfg) {
|
|
736
|
-
const routeRequest = modelRequestFromConfig(cfg.model,
|
|
720
|
+
const routeRequest = modelRequestFromConfig(cfg.model, envModelIntent(), cfg.modelExact === true);
|
|
737
721
|
if (routeRequest === undefined)
|
|
738
722
|
return undefined;
|
|
739
723
|
const registry = registryOf(services);
|
|
740
724
|
const routeOptions = {
|
|
741
|
-
cwd:
|
|
742
|
-
profileId:
|
|
725
|
+
cwd: envNodeCwd() ?? cfg.cwd,
|
|
726
|
+
profileId: envProfileId(),
|
|
743
727
|
};
|
|
744
728
|
const unknown = unregisteredConcreteModel(routeRequest, registry, routeOptions);
|
|
745
729
|
if (unknown !== undefined) {
|
|
@@ -812,11 +796,9 @@ function modelLessRegistry(real) {
|
|
|
812
796
|
});
|
|
813
797
|
return { runtime, reveal: () => { masked = false; } };
|
|
814
798
|
}
|
|
815
|
-
// ---------------------------------------------------------------------------
|
|
816
799
|
// buildBrokerSession (plan T4 steps 2–4) — turn the launch recipe into a live
|
|
817
800
|
// engine session via the pi SDK SERVICES path. Exported so the C3/C4 real-SDK
|
|
818
801
|
// regression tests can drive the EXACT production wiring (not the mock).
|
|
819
|
-
// ---------------------------------------------------------------------------
|
|
820
802
|
export async function buildBrokerSession(engine, cfg) {
|
|
821
803
|
// 2. Build cwd-bound runtime services via the SERVICES path (C3) — NOT plain
|
|
822
804
|
// createAgentSession. createAgentSessionServices builds + reloads the
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { envNodeId } from '../../shared/env.js';
|
|
1
2
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
3
|
import { join } from 'node:path';
|
|
3
4
|
import { jobDir } from '../canvas/paths.js';
|
|
@@ -140,7 +141,7 @@ export function recordFault(nodeId, input) {
|
|
|
140
141
|
updateMarker(nodeId, fault);
|
|
141
142
|
}
|
|
142
143
|
export function recordFaultForCurrentNode(input) {
|
|
143
|
-
const nodeId =
|
|
144
|
+
const nodeId = envNodeId();
|
|
144
145
|
if (nodeId === undefined || nodeId.trim() === '')
|
|
145
146
|
return false;
|
|
146
147
|
if (!existsSync(jobDir(nodeId)))
|
|
@@ -186,7 +187,7 @@ export function clearFault(nodeId, opts) {
|
|
|
186
187
|
}
|
|
187
188
|
}
|
|
188
189
|
export function clearFaultForCurrentNode(opts) {
|
|
189
|
-
const nodeId =
|
|
190
|
+
const nodeId = envNodeId();
|
|
190
191
|
if (nodeId === undefined || nodeId.trim() === '')
|
|
191
192
|
return false;
|
|
192
193
|
if (!existsSync(jobDir(nodeId)))
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// Each call uses crouter's credential pool and route policy, an in-memory session,
|
|
4
4
|
// and only the inline provider-rotation extension. No conversation resources or
|
|
5
5
|
// canvas lifecycle hooks enter the helper session.
|
|
6
|
+
import { envNodeCwd, envProfileId } from '../../shared/env.js';
|
|
6
7
|
import { join } from 'node:path';
|
|
7
8
|
import { PoolCredentialStore } from '../pool-credential-store.js';
|
|
8
9
|
import { modelRequestFromConfig, selectInitialModelRoute } from '../model-routes.js';
|
|
@@ -55,8 +56,8 @@ async function runHeadless(request, fallback, collect) {
|
|
|
55
56
|
]);
|
|
56
57
|
if (timedOut)
|
|
57
58
|
return fallback;
|
|
58
|
-
const nodeCwd =
|
|
59
|
-
const profileId =
|
|
59
|
+
const nodeCwd = envNodeCwd() ?? process.cwd();
|
|
60
|
+
const profileId = envProfileId();
|
|
60
61
|
const agentDir = sdk.getAgentDir();
|
|
61
62
|
const modelRuntime = await sdk.ModelRuntime.create({
|
|
62
63
|
credentials: new PoolCredentialStore(join(agentDir, 'auth.json')),
|
|
@@ -25,12 +25,11 @@ import { assertMandatoryCanvasExtensions } from './canvas-extensions.js';
|
|
|
25
25
|
import { boundFleet } from './fleet.js';
|
|
26
26
|
import { emitEvent } from '../events/emit.js';
|
|
27
27
|
import { bindBrokerEventSource, eventSource } from '../events/source.js';
|
|
28
|
-
|
|
28
|
+
import { envBrokerEngine } from '../../shared/env.js';
|
|
29
29
|
// HeadlessBrokerHost (design §3.3): a detached broker PROCESS, no tmux pane. It
|
|
30
30
|
// boots the dedicated broker-cli entry directly (NEVER src/cli.ts), supervises
|
|
31
31
|
// via the broker pid recorded as pi_pid, and tears down over the node's unix
|
|
32
32
|
// socket (graceful `shutdown` frame, SIGTERM fallback).
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
33
|
/** Resolve the broker entry beside this module. A broker must run from the
|
|
35
34
|
* same generation as the crtrd launching it, so module-relative resolution
|
|
36
35
|
* preserves that invariant. */
|
|
@@ -48,7 +47,7 @@ const DEFAULT_BROKER_ENGINE = '@earendil-works/pi-coding-agent';
|
|
|
48
47
|
* why: the default-deny allowlist in spawn-env.ts strips `CRTR_*` from
|
|
49
48
|
* ambient env, so the child can no longer re-derive this itself). */
|
|
50
49
|
function resolveEngineSpec(inv) {
|
|
51
|
-
return inv.env['CRTR_BROKER_ENGINE'] ??
|
|
50
|
+
return inv.env['CRTR_BROKER_ENGINE'] ?? envBrokerEngine();
|
|
52
51
|
}
|
|
53
52
|
function isPlainLaunchSessionPath(token) {
|
|
54
53
|
return token.includes('/') || token.endsWith('.jsonl');
|
|
@@ -30,10 +30,8 @@ import { formatCard } from '../../shared/generated-context.js';
|
|
|
30
30
|
/** The runtime-restart continuation exactly as delivered. `revive.ts` injects
|
|
31
31
|
* it as the prompt of a strict resume that follows a cleanly aborted turn. */
|
|
32
32
|
export const RUNTIME_RESTART_CONTINUATION = formatCard('restart-continuation', {}, 'continue');
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
33
|
// Companion context files: the goal (the spawning mandate) and the one-shot
|
|
35
34
|
// yield message (a note from the prior self to the revived self).
|
|
36
|
-
// ---------------------------------------------------------------------------
|
|
37
35
|
/** The goal file — the prompt/task a node was spawned with, persisted at birth
|
|
38
36
|
* so a fresh revive can re-read its mandate. */
|
|
39
37
|
export function goalPath(nodeId) {
|
|
@@ -230,9 +228,7 @@ function backgroundJobsBlock(nodeId) {
|
|
|
230
228
|
lines.push('', 'Read output so far: `tail -n 50 <log>` (or `crtr node bash list --tail 20`). Abandon one: `crtr node bash kill <job-id>`.');
|
|
231
229
|
return `<background-jobs>\n${lines.join('\n')}\n</background-jobs>`;
|
|
232
230
|
}
|
|
233
|
-
// ---------------------------------------------------------------------------
|
|
234
231
|
// buildReviveKickoff — assemble the full fresh-revive first message.
|
|
235
|
-
// ---------------------------------------------------------------------------
|
|
236
232
|
/** Assemble the auto-injected first message for a FRESH revive of `meta` from its
|
|
237
233
|
* already-drained `bearings` (see drainBearings) plus pure on-disk reads of the
|
|
238
234
|
* node's goal, roadmap, and context dir, framed so the revived node can rebuild
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { envProfileId } from '../../shared/env.js';
|
|
1
2
|
import { resolve } from 'node:path';
|
|
2
3
|
import { getNode } from '../canvas/canvas.js';
|
|
3
4
|
import { usage } from '../errors.js';
|
|
@@ -10,7 +11,7 @@ export function resolveCreateKind(kind, profile) {
|
|
|
10
11
|
/** Validate a kind against the same cwd/profile configuration used to build its launch.
|
|
11
12
|
* Resolution is subprocess-isolated: crtrd is single-threaded and a config read can
|
|
12
13
|
* block indefinitely on a network filesystem. */
|
|
13
|
-
export async function assertLaunchKind(kind, cwd = process.cwd(), profileId =
|
|
14
|
+
export async function assertLaunchKind(kind, cwd = process.cwd(), profileId = envProfileId() || null) {
|
|
14
15
|
const kinds = Object.keys((await readMergedLaunchConfigAsync(cwd, profileId)).kinds);
|
|
15
16
|
if (!kinds.includes(kind)) {
|
|
16
17
|
throw usage(`unknown kind: ${kind}`, { received: kind, next: `Valid kinds: ${kinds.sort().join(', ')}.` });
|
|
@@ -15,8 +15,8 @@ export type { PortableModelSelection } from './model-selection.js';
|
|
|
15
15
|
* stays unpinned. */
|
|
16
16
|
export declare function isProviderPinnedModelToken(model: string): boolean;
|
|
17
17
|
/** True when `model` is a PORTABLE ladder token — a bare strength/alias
|
|
18
|
-
* (`ultra`, `normal`, `opus`, …)
|
|
19
|
-
* i.e. a form `normalizeModel` resolves through the ladders rather than
|
|
18
|
+
* (`ultra`, `normal`, `opus`, …), an `anthropic|openai / strength` pair, or
|
|
19
|
+
* an anthropic family alias — i.e. a form `normalizeModel` resolves through the ladders rather than
|
|
20
20
|
* passing through as a concrete id. Portable tokens are safe to PERSIST as
|
|
21
21
|
* defaults (`persistDefaultKindModel`): they re-resolve against whatever
|
|
22
22
|
* ladder the running build ships, so they never freeze a stale concrete
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// fresh cycle as a new branch rather than starting a new file.
|
|
9
9
|
// The spec is rewritten on every polymorph (base→orchestrator) so a node
|
|
10
10
|
// always comes back as its *current* self.
|
|
11
|
+
import { envProfileId } from '../../shared/env.js';
|
|
11
12
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
12
13
|
import { join } from 'node:path';
|
|
13
14
|
import { readMergedLaunchConfig } from '../config.js';
|
|
@@ -25,7 +26,6 @@ import { modelLadders, defaultProvider, STRENGTH_ALIASES, MODEL_PROVIDER_KEYS, M
|
|
|
25
26
|
// file's openDb-reaching graph. Re-exported here so existing importers of these
|
|
26
27
|
// launch.ts symbols keep working.
|
|
27
28
|
export { OPENAI_PROVIDER_ENV, configuredLadderProviders, inferPortableModelSelection } from './model-selection.js';
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
29
|
// Two-axis model resolution: (provider × strength) → concrete `model:thinking`.
|
|
30
30
|
//
|
|
31
31
|
// A persona declares ONE `model:` field valued `provider/strength` (e.g.
|
|
@@ -36,7 +36,6 @@ export { OPENAI_PROVIDER_ENV, configuredLadderProviders, inferPortableModelSelec
|
|
|
36
36
|
// pi accepts the `:thinking` suffix on `--model` (off,minimal,low,medium,high,
|
|
37
37
|
// xhigh — confirmed via `pi --help`), so the resolved spec is exactly the
|
|
38
38
|
// string buildPiArgv passes to `--model`; no extra launch plumbing.
|
|
39
|
-
// ---------------------------------------------------------------------------
|
|
40
39
|
/** Model-ladder resolution goes through `readMergedLaunchConfig` — the SAME
|
|
41
40
|
* project-stack > profile > user > builtin precedence `resolveKindConfig`
|
|
42
41
|
* already uses for `kinds` — so a project/profile override of `modelLadders`
|
|
@@ -86,10 +85,14 @@ function findLadderCell(normalized, ladders, providers) {
|
|
|
86
85
|
* strong/medium/light, ALWAYS anthropic (ignores the env/config default).
|
|
87
86
|
* 4. Anything else → pass through unchanged. */
|
|
88
87
|
function modelTokenStrength(model) {
|
|
89
|
-
const
|
|
88
|
+
const slash = model.indexOf('/');
|
|
89
|
+
const provider = slash === -1 ? undefined : model.slice(0, slash);
|
|
90
|
+
const rest = slash === -1 ? model : model.slice(slash + 1);
|
|
90
91
|
const strength = STRENGTH_ALIASES[rest];
|
|
91
92
|
if (strength !== undefined)
|
|
92
93
|
return strength;
|
|
94
|
+
if (provider !== undefined && provider !== 'anthropic')
|
|
95
|
+
return null;
|
|
93
96
|
if (rest === 'opus')
|
|
94
97
|
return 'strong';
|
|
95
98
|
if (rest === 'sonnet')
|
|
@@ -134,8 +137,8 @@ export function isProviderPinnedModelToken(model) {
|
|
|
134
137
|
return model.includes('/') && !isPortableModelToken(model);
|
|
135
138
|
}
|
|
136
139
|
/** True when `model` is a PORTABLE ladder token — a bare strength/alias
|
|
137
|
-
* (`ultra`, `normal`, `opus`, …)
|
|
138
|
-
* i.e. a form `normalizeModel` resolves through the ladders rather than
|
|
140
|
+
* (`ultra`, `normal`, `opus`, …), an `anthropic|openai / strength` pair, or
|
|
141
|
+
* an anthropic family alias — i.e. a form `normalizeModel` resolves through the ladders rather than
|
|
139
142
|
* passing through as a concrete id. Portable tokens are safe to PERSIST as
|
|
140
143
|
* defaults (`persistDefaultKindModel`): they re-resolve against whatever
|
|
141
144
|
* ladder the running build ships, so they never freeze a stale concrete
|
|
@@ -145,7 +148,8 @@ export function isPortableModelToken(model) {
|
|
|
145
148
|
const slash = model.indexOf('/');
|
|
146
149
|
const provider = model.slice(0, slash);
|
|
147
150
|
const rest = model.slice(slash + 1);
|
|
148
|
-
return (provider === 'anthropic' || provider === 'openai') && STRENGTH_ALIASES[rest] !== undefined
|
|
151
|
+
return (provider === 'anthropic' || provider === 'openai') && (STRENGTH_ALIASES[rest] !== undefined
|
|
152
|
+
|| (provider === 'anthropic' && (rest === 'opus' || rest === 'sonnet' || rest === 'haiku')));
|
|
149
153
|
}
|
|
150
154
|
return STRENGTH_ALIASES[model] !== undefined || model === 'opus' || model === 'sonnet' || model === 'haiku';
|
|
151
155
|
}
|
|
@@ -169,6 +173,14 @@ export function normalizeModel(model, ladders = modelLadders()) {
|
|
|
169
173
|
if (strength !== undefined && (provider === 'anthropic' || provider === 'openai')) {
|
|
170
174
|
return ladderFor(provider, ladders)[strength];
|
|
171
175
|
}
|
|
176
|
+
if (provider === 'anthropic') {
|
|
177
|
+
if (rest === 'opus')
|
|
178
|
+
return ladders.anthropic.strong;
|
|
179
|
+
if (rest === 'sonnet')
|
|
180
|
+
return ladders.anthropic.medium;
|
|
181
|
+
if (rest === 'haiku')
|
|
182
|
+
return ladders.anthropic.light;
|
|
183
|
+
}
|
|
172
184
|
// Concrete `provider/id` (optionally `...:thinking`) — pass through.
|
|
173
185
|
return model;
|
|
174
186
|
}
|
|
@@ -258,7 +270,7 @@ function buildLaunchSpecFromMerged(kind, mode, opts, merged) {
|
|
|
258
270
|
}
|
|
259
271
|
/** Build a launch recipe for callers that are not on crtrd's event loop. */
|
|
260
272
|
export function buildLaunchSpec(kind, mode, opts) {
|
|
261
|
-
return buildLaunchSpecFromMerged(kind, mode, opts, readMergedLaunchConfig(opts.cwd ?? process.cwd(), opts.profileId !== undefined ? opts.profileId : (
|
|
273
|
+
return buildLaunchSpecFromMerged(kind, mode, opts, readMergedLaunchConfig(opts.cwd ?? process.cwd(), opts.profileId !== undefined ? opts.profileId : (envProfileId() || null)));
|
|
262
274
|
}
|
|
263
275
|
/**
|
|
264
276
|
* Resolve launch config in a bounded subprocess before building a recipe.
|
|
@@ -268,7 +280,7 @@ export function buildLaunchSpec(kind, mode, opts) {
|
|
|
268
280
|
*/
|
|
269
281
|
export async function buildLaunchSpecAsync(kind, mode, opts) {
|
|
270
282
|
const cwd = opts.cwd ?? process.cwd();
|
|
271
|
-
const profileId = opts.profileId !== undefined ? opts.profileId : (
|
|
283
|
+
const profileId = opts.profileId !== undefined ? opts.profileId : (envProfileId() || null);
|
|
272
284
|
const merged = await readMergedLaunchConfigAsync(cwd, profileId);
|
|
273
285
|
return buildLaunchSpecFromMerged(kind, mode, opts, merged);
|
|
274
286
|
}
|
|
@@ -308,9 +320,7 @@ export function readMergedLaunchConfigAsync(cwd, profileId) {
|
|
|
308
320
|
});
|
|
309
321
|
});
|
|
310
322
|
}
|
|
311
|
-
// ---------------------------------------------------------------------------
|
|
312
323
|
// Build the pi argv to launch / revive a node
|
|
313
|
-
// ---------------------------------------------------------------------------
|
|
314
324
|
/** Persist a node's (possibly large) system prompt to a file in its node dir and
|
|
315
325
|
* return the absolute path, so callers can pass a short path to pi instead of
|
|
316
326
|
* the inline text. Returns null if the write fails — the caller then falls back
|
|
@@ -25,11 +25,13 @@
|
|
|
25
25
|
// `cancel`.
|
|
26
26
|
//
|
|
27
27
|
// Layering note: lifecycle.ts is runtime, but it is the canvas write surface's
|
|
28
|
-
// `transition` verb (the only writer of status+intent), so it
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
|
|
28
|
+
// `transition` verb (the only writer of status+intent), so it drives the
|
|
29
|
+
// atomic status+intent write through canvas.ts's `transitionStatusIntent`
|
|
30
|
+
// (its own decision logic — the legality table below, and the
|
|
31
|
+
// unknown-node/illegal-move/already-finalized-cancel branching — stays here;
|
|
32
|
+
// only the raw conditional UPDATE lives in canvas.ts, keeping every `.prepare(`
|
|
33
|
+
// inside `core/canvas/`).
|
|
34
|
+
import { getNode, cancelCronsOnWake, transitionStatusIntent } from '../canvas/index.js';
|
|
33
35
|
const ANY = '*';
|
|
34
36
|
/** The supervised statuses — a live node the daemon watches. */
|
|
35
37
|
const LIVE = ['active', 'idle'];
|
|
@@ -71,28 +73,17 @@ export function transition(nodeId, event) {
|
|
|
71
73
|
const spec = TRANSITIONS[event];
|
|
72
74
|
const writeStatus = Object.prototype.hasOwnProperty.call(spec, 'status');
|
|
73
75
|
const writeIntent = Object.prototype.hasOwnProperty.call(spec, 'intent');
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
if (writeIntent) {
|
|
81
|
-
assignments.push('intent = ?');
|
|
82
|
-
values.push(spec.intent ?? null);
|
|
83
|
-
}
|
|
84
|
-
const predicates = ['node_id = ?'];
|
|
85
|
-
values.push(nodeId);
|
|
86
|
-
if (spec.from !== ANY) {
|
|
87
|
-
predicates.push(`status IN (${spec.from.map(() => '?').join(', ')})`);
|
|
88
|
-
values.push(...spec.from);
|
|
89
|
-
}
|
|
76
|
+
const fields = {};
|
|
77
|
+
if (writeStatus)
|
|
78
|
+
fields.status = spec.status;
|
|
79
|
+
if (writeIntent)
|
|
80
|
+
fields.intent = spec.intent ?? null;
|
|
90
81
|
// A committed canonical result is protected from a concurrent close.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (
|
|
82
|
+
const changes = transitionStatusIntent(nodeId, fields, {
|
|
83
|
+
fromStatuses: spec.from === ANY ? undefined : spec.from,
|
|
84
|
+
requireNoFinalReport: event === 'cancel',
|
|
85
|
+
});
|
|
86
|
+
if (changes === 0) {
|
|
96
87
|
const cur = getNode(nodeId);
|
|
97
88
|
if (cur === null)
|
|
98
89
|
throw new Error(`transition: unknown node ${nodeId}`);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AssistantMessageDiagnostic } from
|
|
1
|
+
import type { AssistantMessageDiagnostic } from '@earendil-works/pi-ai';
|
|
2
2
|
/** Diagnostic `type` tag carrying the cooling deadline; also the wire contract the
|
|
3
3
|
* stophook matches on. */
|
|
4
4
|
export declare const MANAGED_PROVIDER_COOLING_DIAGNOSTIC = "crtr:managed-provider-cooling";
|
|
@@ -217,10 +217,8 @@ export async function headlessName(body, sourceCap = PROMPT_CAP) {
|
|
|
217
217
|
export function headlessNameFromConversation(conversation) {
|
|
218
218
|
return headlessName(conversation, 30_000);
|
|
219
219
|
}
|
|
220
|
-
// ---------------------------------------------------------------------------
|
|
221
220
|
// Issue titles — turn a free-text todo/idea/bug note into a short, human-readable
|
|
222
221
|
// GitHub-issue title (sentence case, NOT kebab). Used by `crtr canvas issue new`.
|
|
223
|
-
// ---------------------------------------------------------------------------
|
|
224
222
|
const TITLE_SYSTEM_PROMPT = 'You write GitHub issue titles. Given a free-text note (a todo, idea, or bug ' +
|
|
225
223
|
'report), reply with ONLY a concise issue title: sentence case, 4-10 words, no ' +
|
|
226
224
|
'trailing period, no quotes, no prefix like "Bug:" or "Idea:", no markdown. ' +
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
// learns when the work finishes — this seeds the subscription
|
|
13
13
|
// graph to mirror the spawn structure. A `spawned_by` audit edge
|
|
14
14
|
// is also recorded.
|
|
15
|
+
import { envHomeOverride } from '../../shared/env.js';
|
|
15
16
|
import { randomBytes } from 'node:crypto';
|
|
16
17
|
import { mkdirSync } from 'node:fs';
|
|
17
18
|
import { createNode, getNode, getRow, subscribe, recordSpawn, contextDir, } from '../canvas/index.js';
|
|
@@ -200,7 +201,7 @@ export function nodeEnv(meta) {
|
|
|
200
201
|
if (meta.parent)
|
|
201
202
|
env['CRTR_PARENT_NODE_ID'] = meta.parent;
|
|
202
203
|
// Propagate an explicit canvas home so children share the same canvas.
|
|
203
|
-
const home =
|
|
204
|
+
const home = envHomeOverride();
|
|
204
205
|
if (home !== undefined && home !== '')
|
|
205
206
|
env['CRTR_HOME'] = home;
|
|
206
207
|
// Propagate the subtree-root node id. The broker uses it to group a subtree;
|
|
@@ -4,9 +4,7 @@
|
|
|
4
4
|
import { getNode, updateNode } from '../canvas/index.js';
|
|
5
5
|
import { readRoadmap, roadmapPath } from './roadmap.js';
|
|
6
6
|
import { orchestratorContextNote } from './bearings.js';
|
|
7
|
-
// ---------------------------------------------------------------------------
|
|
8
7
|
// Base → orchestrator guidance
|
|
9
|
-
// ---------------------------------------------------------------------------
|
|
10
8
|
/** Fresh-context framing for a base → orchestrator change. */
|
|
11
9
|
function orchestrationGuidance(nodeId, kind) {
|
|
12
10
|
const roadmap = readRoadmap(nodeId) ?? '(no roadmap yet)';
|
|
@@ -18,9 +16,7 @@ function orchestrationGuidance(nodeId, kind) {
|
|
|
18
16
|
parts.push('', `Your roadmap scaffold (\`${rmPath}\`) — author it now: state the goal, exit criteria, and the phase skeleton, using your orchestration protocol. Current contents:`, '', roadmap, '', orchestratorContextNote(nodeId), '', 'Your three long-term memory scopes (user-global, project, node-local) already surface in your bearings at boot. What promotion changes is USE, not access: you now persist across refresh cycles, so node-local carries what THIS goal needs between your refreshes, and durable facts you commit to user-global or project outlive this node. Use `crtr memory write` to save a document; `crtr memory list` to browse; `crtr memory find` to search (see "Your long-term memory" above for the full substrate flow).', '', 'Then delegate each phase with `crtr node new --kind <kind>`. When your context fills, run `crtr node yield` to refresh against this roadmap.');
|
|
19
17
|
return parts.join('\n');
|
|
20
18
|
}
|
|
21
|
-
// ---------------------------------------------------------------------------
|
|
22
19
|
// Orchestrator → base guidance
|
|
23
|
-
// ---------------------------------------------------------------------------
|
|
24
20
|
/** orchestrator → base (demote): hands-on again, finish in-window. */
|
|
25
21
|
function baseModeGuidance() {
|
|
26
22
|
return ('You are HANDS-ON again — base mode. Do the work yourself in THIS window and finish it here; ' +
|
|
@@ -36,9 +32,7 @@ export function transitionGuidance(nodeId, from, to) {
|
|
|
36
32
|
const node = getNode(nodeId);
|
|
37
33
|
return orchestrationGuidance(nodeId, node?.kind ?? 'general');
|
|
38
34
|
}
|
|
39
|
-
// ---------------------------------------------------------------------------
|
|
40
35
|
// Detector + ack commit.
|
|
41
|
-
// ---------------------------------------------------------------------------
|
|
42
36
|
/** Compare the live persona with the last acknowledged context delivery.
|
|
43
37
|
* `guidance` contains only fresh-context framing; current snapshots supply its
|
|
44
38
|
* documents. An absent or pre-kind acknowledgment cannot fabricate drift. */
|
|
@@ -15,19 +15,16 @@
|
|
|
15
15
|
// §5.1 import-lint: placement-tmux.ts is an allowed direct importer of
|
|
16
16
|
// tmux-driver.ts — it is the sanctioned pure-tmux seam, re-exporting the driver
|
|
17
17
|
// verbs other modules need so they never import the driver directly.
|
|
18
|
+
import { envHomeOverride } from '../../shared/env.js';
|
|
18
19
|
import { paneLocation, ensureSession, openNodeWindow, splitWindow, selectLayout, } from './tmux-driver.js';
|
|
19
20
|
import { BROKER_VIEW_SOCKET_WAIT_MS } from './view-socket.js';
|
|
20
21
|
// Re-export the pure tmux driver verbs the CLI/viewer consumers need without
|
|
21
22
|
// exposing the canvas focuses table or sending command modules to the raw driver.
|
|
22
23
|
export { paneExists, paneLocation, paneOfNode, paneCurrentPath, paneSize, paneRunning, ensureSession, openNodeWindow, splitWindow, closePane, currentTmux, switchClient, selectWindow, selectLayout, selectPane, getPaneOption, setPaneOption, breakPane, inTmux, piCommand, shellQuote, renameWindow, displayPopup, windowOfPane, respawnPaneSync, respawnPaneInBackground, respawnPaneInPlace, paneStartCommand, panePid, windowAlive, listLivePanes, VIEWER_STAMP_OPTION, stampViewerPaneAsync, liveViewerPanes, sendAttachControl, displayClientMessage, } from './tmux-driver.js';
|
|
23
24
|
export { installTmuxBindings } from './tmux-bindings.js';
|
|
24
|
-
// ---------------------------------------------------------------------------
|
|
25
25
|
// view.sock readiness — the one shared broker-cold-start primitive
|
|
26
|
-
// ---------------------------------------------------------------------------
|
|
27
26
|
export { BROKER_VIEW_SOCKET_WAIT_MS, waitForBrokerViewSocket } from './view-socket.js';
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
27
|
// Viewer pane opener (tmux half, NO focus-row write)
|
|
30
|
-
// ---------------------------------------------------------------------------
|
|
31
28
|
/** Env for a `crtr surface attach` VIEWER pane (the focus split, the spawn viewer
|
|
32
29
|
* window, AND recycle's re-attach respawn): propagate CRTR_HOME so the viewer
|
|
33
30
|
* resolves the SAME canvas home — and thus the right view.sock — under a
|
|
@@ -35,7 +32,7 @@ export { BROKER_VIEW_SOCKET_WAIT_MS, waitForBrokerViewSocket } from './view-sock
|
|
|
35
32
|
* server env, like every other crtr chrome pane). One helper so the viewer-pane
|
|
36
33
|
* sites can't drift. */
|
|
37
34
|
export function viewerSplitEnv() {
|
|
38
|
-
const crtrHome =
|
|
35
|
+
const crtrHome = envHomeOverride();
|
|
39
36
|
return crtrHome !== undefined ? { CRTR_HOME: crtrHome } : {};
|
|
40
37
|
}
|
|
41
38
|
/** Open a `crtr surface attach` VIEWER pane for `nodeId` — the PURE tmux half of
|
|
@@ -22,8 +22,9 @@
|
|
|
22
22
|
// • The chrome/viewer tmux re-exports (§2.1): placement stays the sanctioned
|
|
23
23
|
// model-over-driver. Raw driver access is confined to placement, its pure
|
|
24
24
|
// tmux half, the bindings owner, and tmux chrome.
|
|
25
|
+
import { envNodeId } from '../../shared/env.js';
|
|
25
26
|
import { getNode, fullName, deleteNode, listNodes, openFocusRow, closeFocusRow, getFocusByNode, getFocusByPane, getFocusById, listFocuses as listFocusRows, } from '../canvas/index.js';
|
|
26
|
-
import { nodeHasAssistantMessage,
|
|
27
|
+
import { nodeHasAssistantMessage, isStreaming } from '../canvas/render-source.js';
|
|
27
28
|
import { headlessBrokerHost } from './host.js';
|
|
28
29
|
import { paneExists, paneLocation, closePane, currentTmux, switchClient, selectWindow, selectLayout, selectPane, getPaneOption, setPaneOption, respawnPaneSync, windowOfPane, renameWindow, } from './tmux-driver.js';
|
|
29
30
|
// The PURE tmux + broker-socket half now lives in placement-tmux.ts. placement
|
|
@@ -47,7 +48,6 @@ import { isPidAlive } from '../canvas/pid.js';
|
|
|
47
48
|
// tmux-driver.ts directly.
|
|
48
49
|
export { splitWindow, breakPane, selectLayout, selectPane, focusWindow, selectWindow, switchClient, openNodeWindow, ensureSession, paneLocation, paneExists, paneRunning, paneCurrentPath, currentTmux, inTmux, paneOfNode, setPaneOption, getPaneOption, piCommand, shellQuote, respawnPaneSync, closePane, displayPopup, windowOfPane, renameWindow, paneOfWindow, windowAlive, listLivePanes, } from './tmux-driver.js';
|
|
49
50
|
export { installTmuxBindings } from './tmux-bindings.js';
|
|
50
|
-
// ---------------------------------------------------------------------------
|
|
51
51
|
// Viewer registry reads — COMPOSE over the canvas focuses table (§2.3/§4).
|
|
52
52
|
//
|
|
53
53
|
// placement is the front door for "which nodes have a viewer on screen"; the SQL
|
|
@@ -57,7 +57,6 @@ export { installTmuxBindings } from './tmux-bindings.js';
|
|
|
57
57
|
// GC is lazy on read: a row whose viewer pane no longer exists (the user closed
|
|
58
58
|
// the window, the attach client died) is pruned the next time it is read, so the
|
|
59
59
|
// registry self-heals without a sweeper.
|
|
60
|
-
// ---------------------------------------------------------------------------
|
|
61
60
|
/** Prune a viewer row whose pane is gone; return it iff its pane is still live. */
|
|
62
61
|
function liveOrPrune(f) {
|
|
63
62
|
if (f === null)
|
|
@@ -131,9 +130,7 @@ export function openViewerWindow(nodeId, session, opts = {}) {
|
|
|
131
130
|
return null;
|
|
132
131
|
return registerViewerFocus(nodeId, opened.pane, opened.session, opened.window);
|
|
133
132
|
}
|
|
134
|
-
// ---------------------------------------------------------------------------
|
|
135
133
|
// focus — the front door for `surface node focus` / `surface node cycle` / nav (§A.4)
|
|
136
|
-
// ---------------------------------------------------------------------------
|
|
137
134
|
/** Bring a node's ONE viewer pane forefront (§A.4). Every node is a detached
|
|
138
135
|
* broker, so there is no engine pane to swap into the caller's viewport — focus
|
|
139
136
|
* instead ensures the node's single surface-attach viewer is on screen beside (or
|
|
@@ -283,9 +280,7 @@ export async function focus(nodeId, opts) {
|
|
|
283
280
|
surfaceNewPane(opened.pane);
|
|
284
281
|
return { focused: true, session: opened.session, inPlace: false, revived };
|
|
285
282
|
}
|
|
286
|
-
// ---------------------------------------------------------------------------
|
|
287
283
|
// Teardown / detach — close a node's viewer pane + row
|
|
288
|
-
// ---------------------------------------------------------------------------
|
|
289
284
|
/** Tear a node off its viewer (close/reset/cancel teardown). The broker engine
|
|
290
285
|
* is killed by its own host teardown over view.sock — this only closes the
|
|
291
286
|
* on-screen viewer: kill its pane (the window collapses once its last pane goes)
|
|
@@ -326,9 +321,7 @@ export function detachToBackground(nodeId, pane) {
|
|
|
326
321
|
reapIfEmpty(nodeId);
|
|
327
322
|
return closed;
|
|
328
323
|
}
|
|
329
|
-
// ---------------------------------------------------------------------------
|
|
330
324
|
// Reaping empty nodes (no AI output) on close / detach
|
|
331
|
-
// ---------------------------------------------------------------------------
|
|
332
325
|
/** Is this node an EMPTY SHELL right now — a node whose engine never produced an
|
|
333
326
|
* assistant message? Such nodes are pure dead weight on the graph. A node
|
|
334
327
|
* actively generating its FIRST turn is NOT empty (its output just hasn't landed
|
|
@@ -337,7 +330,7 @@ function isEmptyNode(nodeId) {
|
|
|
337
330
|
const m = getNode(nodeId);
|
|
338
331
|
if (m === null)
|
|
339
332
|
return false;
|
|
340
|
-
if (
|
|
333
|
+
if (isStreaming(nodeId, getNode(nodeId)?.pi_pid ?? null))
|
|
341
334
|
return false;
|
|
342
335
|
return !nodeHasAssistantMessage(m.pi_session_file);
|
|
343
336
|
}
|
|
@@ -366,7 +359,7 @@ export function reapIfEmpty(nodeId, keepPane) {
|
|
|
366
359
|
* deleting. Returns the reaped (or, under dryRun, reapable) node ids. */
|
|
367
360
|
export function reapEmptyNodes(opts = {}) {
|
|
368
361
|
const dryRun = opts.dryRun ?? false;
|
|
369
|
-
const selfId =
|
|
362
|
+
const selfId = envNodeId() ?? '';
|
|
370
363
|
const reaped = [];
|
|
371
364
|
for (const row of listNodes()) {
|
|
372
365
|
const id = row.node_id;
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
// there is no local fallback, unlike naming, because a wrong recap is worse than
|
|
12
12
|
// none.
|
|
13
13
|
import { headlessText } from './headless-pi.js';
|
|
14
|
+
import { envRecapModelOverride } from '../../shared/env.js';
|
|
14
15
|
/** Wall-clock budget for the headless pi call before we give up (no recap). */
|
|
15
16
|
const RECAP_TIMEOUT_MS = 25_000;
|
|
16
17
|
/** Fallback model when the live session has not resolved one yet. Ordinarily the
|
|
@@ -59,9 +60,9 @@ function recapUserPrompt(conversation, roadmap) {
|
|
|
59
60
|
/** Model precedence is explicit env override → the conversation's live
|
|
60
61
|
* working model → the small fallback. */
|
|
61
62
|
function recapModel(liveModel) {
|
|
62
|
-
const override =
|
|
63
|
-
if (override !== undefined
|
|
64
|
-
return override
|
|
63
|
+
const override = envRecapModelOverride();
|
|
64
|
+
if (override !== undefined)
|
|
65
|
+
return override;
|
|
65
66
|
if (liveModel !== undefined && liveModel.trim() !== '')
|
|
66
67
|
return liveModel.trim();
|
|
67
68
|
return DEFAULT_RECAP_MODEL;
|