@north-light/crouter 0.3.170 → 0.3.172
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.d.ts +37 -11
- package/dist/api/client.js +84 -15
- package/dist/api/dto/human.d.ts +53 -39
- package/dist/api/dto/human.js +2 -3
- package/dist/api/dto/inbox.d.ts +0 -1
- package/dist/api/dto/nodes.d.ts +12 -0
- package/dist/api/dto/review-comments.d.ts +137 -0
- package/dist/api/dto/review-comments.js +5 -0
- package/dist/api/dto/reviews.d.ts +109 -0
- package/dist/api/dto/reviews.js +5 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +2 -0
- package/dist/api/routes.d.ts +17 -4
- package/dist/api/routes.js +21 -5
- package/dist/build-root.d.ts +1 -16
- package/dist/build-root.js +1 -25
- package/dist/builtin-memory/00-runtime-base.md +7 -5
- package/dist/builtin-memory/04-base-worker.md +1 -1
- package/dist/builtin-memory/04-orchestration-kernel.md +7 -7
- package/dist/builtin-memory/05-kinds/design/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/design/01-orchestrator.md +1 -1
- package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/explore/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/plan/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +1 -1
- package/dist/builtin-memory/05-kinds/review/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/review/companion/00-base.md +20 -0
- package/dist/builtin-memory/05-kinds/spec/00-base.md +3 -7
- package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +3 -3
- package/dist/builtin-memory/05-kinds/spec/requirements.md +3 -3
- package/dist/builtin-memory/design.md +2 -2
- package/dist/builtin-memory/insights/capture.md +50 -0
- package/dist/builtin-memory/insights/init.md +45 -0
- package/dist/builtin-memory/insights/listen.md +9 -0
- package/dist/builtin-memory/internal/agent-shaping.md +2 -2
- package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
- package/dist/builtin-memory/internal/plugins.md +12 -11
- package/dist/builtin-memory/internal/storage-tiers.md +2 -2
- package/dist/builtin-memory/{planning.md → plan/roadmap.md} +3 -3
- package/dist/builtin-memory/plan.md +19 -0
- package/dist/builtin-memory/spec/guide.md +38 -0
- package/dist/builtin-memory/spec/requirements.md +31 -0
- package/dist/builtin-memory/spec/roadmap.md +35 -0
- package/dist/builtin-memory/spec.md +10 -86
- package/dist/builtin-pi-packages/pi-crtr-extensions/README.md +3 -4
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/provider-rotation.test.ts +49 -5
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +56 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +920 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +221 -156
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +4 -5
- package/dist/cli.js +2 -6
- package/dist/clients/attach/__tests__/attach-chrome-remote.test.js +7 -35
- package/dist/clients/attach/__tests__/attach-keybindings.test.js +32 -16
- package/dist/clients/attach/__tests__/context-message.test.js +142 -6
- package/dist/clients/attach/__tests__/crtr-output.test.js +29 -45
- package/dist/clients/attach/__tests__/diagram.test.js +1 -1
- package/dist/clients/attach/__tests__/file-review-focus.test.js +48 -0
- package/dist/clients/attach/__tests__/group-activity.test.js +266 -0
- package/dist/clients/attach/__tests__/input-controller-extension-command.test.js +32 -0
- package/dist/clients/attach/__tests__/session-identity-refresh.test.js +32 -0
- package/dist/clients/attach/__tests__/titled-editor-preview.test.js +1 -2
- package/dist/clients/attach/chrome/header.d.ts +10 -0
- package/dist/clients/attach/chrome/header.js +30 -0
- package/dist/clients/attach/chrome/recap.d.ts +7 -0
- package/dist/clients/attach/chrome/recap.js +19 -0
- package/dist/clients/attach/chrome/status-line.d.ts +3 -0
- package/dist/clients/attach/chrome/status-line.js +5 -0
- package/dist/clients/attach/chrome/widgets.js +11 -21
- package/dist/clients/attach/command.js +11 -7
- package/dist/clients/attach/config.d.ts +4 -0
- package/dist/clients/attach/config.js +3 -0
- package/dist/clients/attach/input/controller.d.ts +19 -0
- package/dist/clients/attach/input/controller.js +62 -28
- package/dist/clients/attach/input/titled-editor.d.ts +0 -4
- package/dist/clients/attach/input/titled-editor.js +2 -10
- package/dist/clients/attach/overlays/file-review.d.ts +9 -5
- package/dist/clients/attach/overlays/file-review.js +9 -70
- package/dist/clients/attach/overlays/help.d.ts +33 -0
- package/dist/clients/attach/overlays/help.js +204 -0
- package/dist/clients/attach/render/activity-slot.d.ts +4 -0
- package/dist/clients/attach/render/activity-slot.js +13 -0
- package/dist/clients/attach/render/chat-view.d.ts +117 -12
- package/dist/clients/attach/render/chat-view.js +604 -135
- package/dist/clients/attach/render/context-message.d.ts +2 -1
- package/dist/clients/attach/render/context-message.js +17 -13
- package/dist/clients/attach/render/crtr-output.js +1 -3
- package/dist/clients/attach/render/diagram.js +2 -2
- package/dist/clients/attach/render/edit-diff.d.ts +4 -1
- package/dist/clients/attach/render/edit-diff.js +7 -11
- package/dist/clients/attach/render/group-activity.d.ts +32 -0
- package/dist/clients/attach/render/group-activity.js +206 -0
- package/dist/clients/attach/render/group-recap.d.ts +10 -0
- package/dist/clients/attach/render/group-recap.js +93 -0
- package/dist/clients/attach/render/html-markdown.d.ts +17 -0
- package/dist/clients/attach/render/html-markdown.js +228 -0
- package/dist/clients/attach/render/measured-container.d.ts +96 -0
- package/dist/clients/attach/render/measured-container.js +322 -0
- package/dist/clients/attach/render/scroll-animation.d.ts +8 -0
- package/dist/clients/attach/render/scroll-animation.js +80 -0
- package/dist/clients/attach/render/tool-calls.js +6 -6
- package/dist/clients/attach/render/transcript-copy.d.ts +9 -0
- package/dist/clients/attach/render/transcript-copy.js +81 -0
- package/dist/clients/attach/render/viewport.d.ts +29 -0
- package/dist/clients/attach/render/viewport.js +159 -0
- package/dist/clients/attach/session/bindings.d.ts +10 -7
- package/dist/clients/attach/session/bindings.js +23 -8
- package/dist/clients/attach/session/connection.js +4 -5
- package/dist/clients/attach/session/context.d.ts +6 -4
- package/dist/clients/attach/session/frame.d.ts +34 -0
- package/dist/clients/attach/session/frame.js +176 -0
- package/dist/clients/attach/session/frames.d.ts +4 -1
- package/dist/clients/attach/session/frames.js +14 -1
- package/dist/clients/attach/session/identity.js +4 -3
- package/dist/clients/attach/session/input-wiring.d.ts +14 -4
- package/dist/clients/attach/session/input-wiring.js +15 -13
- package/dist/clients/attach/session/invariant.d.ts +9 -0
- package/dist/clients/attach/session/invariant.js +15 -0
- package/dist/clients/attach/session/keys.d.ts +10 -2
- package/dist/clients/attach/session/keys.js +13 -5
- package/dist/clients/attach/session/layout.d.ts +10 -8
- package/dist/clients/attach/session/layout.js +33 -34
- package/dist/clients/attach/session/mouse.d.ts +18 -0
- package/dist/clients/attach/session/mouse.js +64 -0
- package/dist/clients/attach/session/pane-tag.d.ts +3 -0
- package/dist/clients/attach/session/pane-tag.js +51 -8
- package/dist/clients/attach/session/reconnect.d.ts +3 -0
- package/dist/clients/attach/session/reconnect.js +42 -5
- package/dist/clients/attach/session/surface-frame.d.ts +20 -0
- package/dist/clients/attach/session/surface-frame.js +73 -0
- package/dist/clients/attach/session/surface-host.d.ts +64 -0
- package/dist/clients/attach/session/surface-host.js +255 -0
- package/dist/clients/attach/session/whip.d.ts +17 -0
- package/dist/clients/attach/session/whip.js +334 -0
- package/dist/clients/attach/slash/dispatch.d.ts +13 -1
- package/dist/clients/attach/slash/dispatch.js +51 -29
- package/dist/clients/attach/viewer.js +907 -819
- package/dist/clients/conversation/conversation.d.ts +65 -0
- package/dist/clients/conversation/conversation.js +318 -0
- package/dist/clients/conversation/frames.d.ts +30 -0
- package/dist/clients/conversation/frames.js +52 -0
- package/dist/clients/conversation/region.d.ts +51 -0
- package/dist/clients/conversation/region.js +265 -0
- package/dist/clients/conversation/submit.d.ts +38 -0
- package/dist/clients/conversation/submit.js +51 -0
- package/dist/clients/inbox/__tests__/inbox-controller.test.js +247 -0
- package/dist/clients/inbox/__tests__/mount-panel.test.js +776 -0
- package/dist/clients/inbox/controller.d.ts +79 -0
- package/dist/clients/inbox/controller.js +448 -0
- package/dist/clients/inbox/deck-adapter.d.ts +29 -0
- package/dist/clients/inbox/deck-adapter.js +62 -0
- package/dist/clients/inbox/layout.d.ts +8 -0
- package/dist/clients/inbox/layout.js +9 -0
- package/dist/clients/inbox/resolve.d.ts +10 -0
- package/dist/clients/inbox/resolve.js +34 -0
- package/dist/clients/inbox/review/__tests__/editor-roundtrip.test.js +29 -0
- package/dist/clients/inbox/review/__tests__/remap.test.js +196 -0
- package/dist/clients/inbox/review/__tests__/review-core.test.js +341 -0
- package/dist/clients/inbox/review/anchors.d.ts +41 -0
- package/dist/clients/inbox/review/anchors.js +89 -0
- package/dist/clients/inbox/review/columns.d.ts +22 -0
- package/dist/clients/inbox/review/columns.js +40 -0
- package/dist/clients/inbox/review/comments-client.d.ts +66 -0
- package/dist/clients/inbox/review/comments-client.js +98 -0
- package/dist/clients/inbox/review/composition.d.ts +60 -0
- package/dist/clients/inbox/review/composition.js +278 -0
- package/dist/clients/inbox/review/document-region.d.ts +120 -0
- package/dist/clients/inbox/review/document-region.js +902 -0
- package/dist/clients/inbox/review/frame.d.ts +45 -0
- package/dist/clients/inbox/review/frame.js +215 -0
- package/dist/clients/inbox/review/keys.d.ts +67 -0
- package/dist/clients/inbox/review/keys.js +130 -0
- package/dist/clients/inbox/review/launch.d.ts +10 -0
- package/dist/clients/inbox/review/launch.js +129 -0
- package/dist/clients/inbox/review/live-source.d.ts +24 -0
- package/dist/clients/inbox/review/live-source.js +160 -0
- package/dist/clients/inbox/review/nvim.d.ts +13 -0
- package/dist/clients/inbox/review/nvim.js +42 -0
- package/dist/clients/inbox/review/remap.d.ts +51 -0
- package/dist/clients/inbox/review/remap.js +157 -0
- package/dist/clients/inbox/review/review-client.d.ts +30 -0
- package/dist/clients/inbox/review/review-client.js +107 -0
- package/dist/clients/inbox/review/roundtrip.d.ts +5 -0
- package/dist/clients/inbox/review/roundtrip.js +36 -0
- package/dist/clients/inbox/review/state.d.ts +143 -0
- package/dist/clients/inbox/review/state.js +282 -0
- package/dist/clients/inbox/review-adapter.d.ts +29 -0
- package/dist/clients/inbox/review-adapter.js +92 -0
- package/dist/clients/inbox/review-visibility.d.ts +5 -0
- package/dist/clients/inbox/review-visibility.js +19 -0
- package/dist/clients/inbox/surface.d.ts +19 -0
- package/dist/clients/inbox/surface.js +128 -0
- package/dist/clients/inbox/tui/ansi.d.ts +66 -0
- package/dist/clients/inbox/tui/ansi.js +317 -0
- package/dist/clients/inbox/tui/clipboard.d.ts +2 -0
- package/dist/clients/inbox/tui/clipboard.js +26 -0
- package/dist/clients/inbox/tui/input.d.ts +7 -0
- package/dist/clients/inbox/tui/input.js +653 -0
- package/dist/clients/inbox/tui/keys.d.ts +28 -0
- package/dist/clients/inbox/tui/keys.js +111 -0
- package/dist/clients/inbox/tui/panel.d.ts +2 -0
- package/dist/clients/inbox/tui/panel.js +217 -0
- package/dist/clients/inbox/tui/render.d.ts +37 -0
- package/dist/clients/inbox/tui/render.js +476 -0
- package/dist/clients/inbox/tui/types.d.ts +57 -0
- package/dist/clients/inbox/tui/types.js +1 -0
- package/dist/clients/inbox/tui.d.ts +6 -0
- package/dist/clients/inbox/tui.js +74 -0
- package/dist/clients/surfaces/host.d.ts +66 -0
- package/dist/clients/surfaces/host.js +1 -0
- package/dist/clients/surfaces/region.d.ts +16 -0
- package/dist/clients/surfaces/region.js +1 -0
- package/dist/clients/web/__tests__/push-engine.test.js +14 -158
- package/dist/clients/web/dev-server.d.ts +3 -3
- package/dist/clients/web/dev-server.js +9 -23
- package/dist/clients/web/events.js +4 -6
- package/dist/clients/web/push-engine.d.ts +2 -66
- package/dist/clients/web/push-engine.js +30 -161
- package/dist/clients/web/push-registry.d.ts +0 -4
- package/dist/clients/web/push-registry.js +2 -7
- package/dist/clients/web/server.js +3 -35
- package/dist/clients/web/web-client/shared/protocol.d.ts +0 -108
- package/dist/clients/web/web-cmd.js +2 -2
- package/dist/commands/__tests__/human.test.js +27 -15
- package/dist/commands/api-client.js +3 -3
- package/dist/commands/canvas-browse.js +1 -1
- package/dist/commands/canvas-issue.js +1 -1
- package/dist/commands/canvas-use.js +1 -1
- package/dist/commands/human/doc.d.ts +2 -0
- package/dist/commands/human/doc.js +98 -0
- package/dist/commands/human/inbox.d.ts +2 -0
- package/dist/commands/human/inbox.js +101 -0
- package/dist/commands/human/prompts.d.ts +2 -3
- package/dist/commands/human/prompts.js +27 -180
- package/dist/commands/human/queue.d.ts +1 -5
- package/dist/commands/human/queue.js +54 -216
- package/dist/commands/human/review.d.ts +2 -0
- package/dist/commands/human/review.js +298 -0
- package/dist/commands/human/shared.d.ts +2 -69
- package/dist/commands/human/shared.js +1 -181
- package/dist/commands/human.js +15 -20
- package/dist/commands/memory/__tests__/lint.test.d.ts +1 -0
- package/dist/commands/memory/__tests__/lint.test.js +15 -0
- package/dist/commands/memory/delete.js +2 -2
- package/dist/commands/memory/lint.d.ts +1 -0
- package/dist/commands/memory/lint.js +21 -3
- package/dist/commands/memory/read.js +4 -4
- package/dist/commands/node.js +8 -7
- package/dist/commands/pkg/plugin-manage.js +143 -68
- package/dist/commands/surface-inspect.js +2 -2
- package/dist/commands/surface.js +6 -12
- package/dist/commands/sys/__tests__/setup-core.test.js +9 -5
- package/dist/commands/sys/__tests__/setup-front-door.test.js +7 -42
- package/dist/commands/sys/config.js +29 -3
- package/dist/commands/sys/feedback.js +1 -1
- package/dist/commands/sys/setup-core.d.ts +12 -11
- package/dist/commands/sys/setup-core.js +55 -46
- package/dist/commands/sys/setup-wizard.d.ts +4 -1
- package/dist/commands/sys/setup-wizard.js +50 -9
- package/dist/commands/sys/sync-deps.js +1 -1
- package/dist/commands/sys.js +4 -6
- package/dist/core/__tests__/broker-sdk-wiring.test.js +6 -1
- package/dist/core/__tests__/broker-snapshot-history.test.js +9 -1
- package/dist/core/__tests__/dead-node-policy-table.test.js +3 -4
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +8 -5
- package/dist/core/__tests__/fixtures/fake-engine.js +28 -2
- package/dist/core/__tests__/full/broker-provider-retry.test.js +87 -2
- package/dist/core/__tests__/full/broker-whip-interrupt.test.d.ts +1 -0
- package/dist/core/__tests__/full/broker-whip-interrupt.test.js +39 -0
- package/dist/core/__tests__/full/detach-focus.test.js +1 -1
- package/dist/core/__tests__/human-deliver-e2e.test.js +64 -64
- package/dist/core/__tests__/human-deliver.test.js +71 -345
- package/dist/core/__tests__/inline-memory-refs.test.js +2 -12
- package/dist/core/__tests__/memory-resolver-precedence.test.js +12 -15
- package/dist/core/__tests__/migration.test.js +10 -0
- package/dist/core/__tests__/model-pin-durability.test.js +14 -0
- package/dist/core/__tests__/phase4-review-migration.test.d.ts +1 -0
- package/dist/core/__tests__/phase4-review-migration.test.js +100 -0
- package/dist/core/__tests__/phase4-review-store.test.d.ts +1 -0
- package/dist/core/__tests__/phase4-review-store.test.js +143 -0
- package/dist/core/__tests__/remote-canvas-target.test.js +2 -2
- package/dist/core/__tests__/revive.test.js +22 -53
- package/dist/core/__tests__/session-cycles.test.js +48 -18
- package/dist/core/__tests__/spawn-no-kickoff.test.js +8 -12
- package/dist/core/__tests__/stop-guard.test.js +16 -1
- package/dist/core/__tests__/tmux-surface.test.js +21 -25
- package/dist/core/asset-root.d.ts +7 -0
- package/dist/core/asset-root.js +18 -0
- package/dist/core/broker-client/client.d.ts +0 -7
- package/dist/core/broker-client/client.js +4 -10
- package/dist/core/broker-client/transport-relay.d.ts +3 -4
- package/dist/core/broker-client/transport-relay.js +3 -4
- package/dist/core/canvas/__tests__/attention.test.js +1 -1
- package/dist/core/canvas/__tests__/remote-canvas-source.test.js +1 -1
- package/dist/core/canvas/__tests__/remote-transport.test.d.ts +1 -0
- package/dist/core/{view/__tests__/transport-remote.test.js → canvas/__tests__/remote-transport.test.js} +2 -2
- package/dist/core/canvas/__tests__/render-remote.test.js +1 -1
- package/dist/core/canvas/attention.js +4 -4
- package/dist/core/canvas/canvas.d.ts +6 -11
- package/dist/core/canvas/canvas.js +11 -33
- package/dist/core/canvas/db.js +207 -38
- package/dist/core/canvas/extensions.d.ts +1 -1
- package/dist/core/canvas/extensions.js +8 -1
- package/dist/core/canvas/index.d.ts +0 -1
- package/dist/core/canvas/index.js +0 -1
- package/dist/core/canvas/nav-model.d.ts +1 -1
- package/dist/core/canvas/nav-model.js +1 -1
- package/dist/core/canvas/paths.d.ts +5 -0
- package/dist/core/canvas/paths.js +16 -0
- package/dist/core/canvas/remote-canvas-source.js +2 -2
- package/dist/core/canvas/remote-transport.d.ts +7 -0
- package/dist/core/{view/transport-remote.js → canvas/remote-transport.js} +3 -4
- package/dist/core/canvas/source.js +1 -1
- package/dist/core/canvas/status-glyph.js +4 -12
- package/dist/core/canvas/types.d.ts +10 -35
- package/dist/core/clipboard-text.d.ts +8 -0
- package/dist/core/clipboard-text.js +18 -0
- package/dist/core/command-manifests/registry.d.ts +1 -3
- package/dist/core/command-plugins/bundle.d.ts +29 -0
- package/dist/core/command-plugins/bundle.js +198 -0
- package/dist/core/command-plugins/discovery.d.ts +0 -8
- package/dist/core/command-plugins/discovery.js +2 -39
- package/dist/core/command-plugins/transport/http-fetch.d.ts +4 -30
- package/dist/core/command-plugins/transport/http-fetch.js +17 -95
- package/dist/core/command.d.ts +1 -13
- package/dist/core/command.js +1 -16
- package/dist/core/config.d.ts +4 -0
- package/dist/core/config.js +28 -3
- package/dist/core/document-lines.d.ts +4 -0
- package/dist/core/document-lines.js +6 -0
- package/dist/core/feed/feed.d.ts +2 -0
- package/dist/core/feed/feed.js +11 -7
- package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +1 -0
- package/dist/core/human/__tests__/inbox-cancel-worker.js +7 -0
- package/dist/core/human/__tests__/inbox-claim-worker.d.ts +1 -0
- package/dist/core/human/__tests__/inbox-claim-worker.js +17 -0
- package/dist/core/human/__tests__/inbox-core.test.d.ts +1 -0
- package/dist/core/human/__tests__/inbox-core.test.js +144 -0
- package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +1 -0
- package/dist/core/human/__tests__/inbox-stale-claim-worker.js +8 -0
- package/dist/core/human/__tests__/visible-paths.test.d.ts +1 -0
- package/dist/{clients/attach → core/human}/__tests__/visible-paths.test.js +9 -0
- package/dist/core/human/claim.d.ts +23 -0
- package/dist/core/human/claim.js +67 -0
- package/dist/core/human/convention.d.ts +30 -0
- package/dist/core/human/convention.js +202 -0
- package/dist/core/human/deck-factories.d.ts +8 -0
- package/dist/core/human/deck-factories.js +15 -0
- package/dist/core/human/deck-schema.d.ts +70 -0
- package/dist/core/human/deck-schema.js +92 -0
- package/dist/core/human/root.d.ts +7 -0
- package/dist/core/human/root.js +37 -0
- package/dist/core/human/scan.d.ts +3 -0
- package/dist/core/human/scan.js +76 -0
- package/dist/core/human/summary.d.ts +8 -0
- package/dist/core/human/summary.js +44 -0
- package/dist/core/human/tickets.d.ts +49 -0
- package/dist/core/human/tickets.js +190 -0
- package/dist/core/human/types.d.ts +136 -0
- package/dist/core/human/types.js +5 -0
- package/dist/{clients/attach → core/human}/visible-paths.d.ts +1 -1
- package/dist/{clients/attach → core/human}/visible-paths.js +3 -2
- package/dist/core/inspector/chrome.d.ts +6 -0
- package/dist/core/inspector/chrome.js +14 -0
- package/dist/core/inspector/contract.d.ts +105 -0
- package/dist/core/inspector/contract.js +1 -0
- package/dist/core/inspector/core.d.ts +4 -5
- package/dist/core/inspector/core.js +3 -5
- package/dist/core/inspector/host.d.ts +46 -0
- package/dist/core/{tui → inspector}/host.js +42 -208
- package/dist/core/inspector/text.d.ts +2 -2
- package/dist/core/inspector/transport.d.ts +6 -0
- package/dist/core/inspector/transport.js +36 -0
- package/dist/core/inspector/tui.d.ts +2 -2
- package/dist/core/inspector/tui.js +15 -15
- package/dist/core/keybindings/__tests__/inbox-affordance.test.js +11 -11
- package/dist/core/keybindings/__tests__/resolve.test.js +10 -19
- package/dist/core/keybindings/attach-control.d.ts +9 -3
- package/dist/core/keybindings/attach-control.js +3 -1
- package/dist/core/keybindings/catalog.d.ts +6 -5
- package/dist/core/keybindings/catalog.js +61 -133
- package/dist/core/keybindings/inbox.d.ts +5 -6
- package/dist/core/keybindings/inbox.js +9 -10
- package/dist/core/keybindings/index.d.ts +3 -3
- package/dist/core/keybindings/index.js +3 -3
- package/dist/core/keybindings/persistence.d.ts +5 -1
- package/dist/core/keybindings/persistence.js +24 -6
- package/dist/core/keybindings/resolve.d.ts +6 -0
- package/dist/core/keybindings/resolve.js +10 -3
- package/dist/core/memory/inline-ref-grammar.js +2 -3
- package/dist/core/memory-resolver.d.ts +27 -29
- package/dist/core/memory-resolver.js +45 -39
- package/dist/core/model-routes.d.ts +33 -0
- package/dist/core/model-routes.js +42 -3
- package/dist/core/preview-registry.js +17 -55
- package/dist/core/profiles/select.js +3 -3
- package/dist/core/{view/remote-canvas-target.d.ts → remote-canvas-target.d.ts} +2 -2
- package/dist/core/{view/remote-canvas-target.js → remote-canvas-target.js} +4 -4
- package/dist/core/review/__tests__/capture-origin.test.d.ts +1 -0
- package/dist/core/review/__tests__/capture-origin.test.js +139 -0
- package/dist/core/review/__tests__/comments.test.d.ts +1 -0
- package/dist/core/review/__tests__/comments.test.js +98 -0
- package/dist/core/review/__tests__/project.test.d.ts +1 -0
- package/dist/core/review/__tests__/project.test.js +71 -0
- package/dist/core/review/__tests__/remap.test.d.ts +1 -0
- package/dist/core/review/__tests__/remap.test.js +159 -0
- package/dist/core/review/__tests__/stage-identity.test.d.ts +1 -0
- package/dist/core/review/__tests__/stage-identity.test.js +140 -0
- package/dist/core/review/birth.d.ts +7 -0
- package/dist/core/review/birth.js +23 -0
- package/dist/core/review/comments.d.ts +69 -0
- package/dist/core/review/comments.js +295 -0
- package/dist/core/review/companion.d.ts +35 -0
- package/dist/core/review/companion.js +205 -0
- package/dist/core/review/document.d.ts +27 -0
- package/dist/core/review/document.js +138 -0
- package/dist/core/review/project.d.ts +13 -0
- package/dist/core/review/project.js +58 -0
- package/dist/core/review/realize.d.ts +19 -0
- package/dist/core/review/realize.js +217 -0
- package/dist/core/review/remap.d.ts +24 -0
- package/dist/core/review/remap.js +156 -0
- package/dist/core/review/signal.d.ts +5 -0
- package/dist/core/review/signal.js +31 -0
- package/dist/core/review/stage.d.ts +26 -0
- package/dist/core/review/stage.js +184 -0
- package/dist/core/review/store.d.ts +46 -0
- package/dist/core/review/store.js +163 -0
- package/dist/core/review/ticket-filter.d.ts +17 -0
- package/dist/core/review/ticket-filter.js +32 -0
- package/dist/core/review/types.d.ts +130 -0
- package/dist/core/review/types.js +23 -0
- package/dist/core/runtime/__tests__/session-visibility.test.d.ts +1 -0
- package/dist/core/runtime/__tests__/session-visibility.test.js +119 -0
- package/dist/core/runtime/bearings.d.ts +5 -17
- package/dist/core/runtime/bearings.js +88 -71
- package/dist/core/runtime/broker-protocol.d.ts +31 -8
- package/dist/core/runtime/broker.d.ts +15 -1
- package/dist/core/runtime/broker.js +573 -141
- package/dist/core/runtime/canvas-extensions.d.ts +4 -5
- package/dist/core/runtime/canvas-extensions.js +5 -5
- package/dist/core/runtime/front-door.js +4 -4
- package/dist/core/runtime/headless-pi.d.ts +24 -0
- package/dist/core/runtime/headless-pi.js +152 -0
- package/dist/core/runtime/kickoff.d.ts +1 -5
- package/dist/core/runtime/kickoff.js +1 -5
- package/dist/core/runtime/model-registry.d.ts +3 -0
- package/dist/core/runtime/model-registry.js +13 -0
- package/dist/core/runtime/naming-persist.d.ts +4 -0
- package/dist/core/runtime/naming-persist.js +27 -1
- package/dist/core/runtime/naming.d.ts +17 -12
- package/dist/core/runtime/naming.js +91 -140
- package/dist/core/runtime/node-read.js +19 -10
- package/dist/core/runtime/nodes.d.ts +9 -14
- package/dist/core/runtime/nodes.js +3 -53
- package/dist/core/runtime/package-health.d.ts +6 -21
- package/dist/core/runtime/package-health.js +12 -123
- package/dist/core/runtime/placement-tmux.d.ts +2 -1
- package/dist/core/runtime/placement-tmux.js +6 -4
- package/dist/core/runtime/placement.d.ts +1 -0
- package/dist/core/runtime/placement.js +4 -8
- package/dist/core/runtime/promote.js +3 -0
- package/dist/core/runtime/recap.d.ts +2 -7
- package/dist/core/runtime/recap.js +35 -69
- package/dist/core/runtime/revive.js +34 -77
- package/dist/core/runtime/session-cycles.d.ts +4 -0
- package/dist/core/runtime/session-cycles.js +14 -1
- package/dist/core/runtime/session-visibility.d.ts +37 -0
- package/dist/core/runtime/session-visibility.js +83 -0
- package/dist/core/runtime/spawn.js +10 -22
- package/dist/core/runtime/stop-guard.d.ts +1 -1
- package/dist/core/runtime/stop-guard.js +18 -13
- package/dist/core/runtime/surface-bg.js +1 -1
- package/dist/core/runtime/tmux-chrome.d.ts +1 -1
- package/dist/core/runtime/tmux-chrome.js +1 -1
- package/dist/core/runtime/tmux.d.ts +35 -7
- package/dist/core/runtime/tmux.js +439 -62
- package/dist/core/runtime/tool-group-summary.d.ts +19 -0
- package/dist/core/runtime/tool-group-summary.js +88 -0
- package/dist/core/scope.d.ts +2 -7
- package/dist/core/scope.js +9 -35
- package/dist/core/substrate/schema.d.ts +2 -2
- package/dist/core/termrender/code-doc.d.ts +12 -0
- package/dist/core/termrender/code-doc.js +92 -0
- package/dist/core/termrender/display.d.ts +12 -0
- package/dist/core/termrender/display.js +19 -0
- package/dist/core/termrender/termrender.d.ts +73 -0
- package/dist/core/termrender/termrender.js +795 -0
- package/dist/core/termrender/version.d.ts +1 -0
- package/dist/core/termrender/version.js +1 -0
- package/dist/core/tui/terminal.js +1 -2
- package/dist/core/user-settings.d.ts +71 -3
- package/dist/core/user-settings.js +83 -1
- package/dist/daemon/api/__tests__/inbox.test.js +44 -133
- package/dist/daemon/api/handlers/human.d.ts +0 -10
- package/dist/daemon/api/handlers/human.js +104 -702
- package/dist/daemon/api/handlers/inbox.js +113 -142
- package/dist/daemon/api/handlers/review-comments.d.ts +2 -0
- package/dist/daemon/api/handlers/review-comments.js +500 -0
- package/dist/daemon/api/handlers/reviews.d.ts +2 -0
- package/dist/daemon/api/handlers/reviews.js +287 -0
- package/dist/daemon/api/map.d.ts +22 -7
- package/dist/daemon/api/map.js +159 -11
- package/dist/daemon/api/server.js +4 -0
- package/dist/daemon/cron-run.js +6 -9
- package/dist/daemon/crtrd.js +17 -33
- package/dist/daemon/fleet.d.ts +1 -8
- package/dist/daemon/fleet.js +4 -30
- package/dist/daemon/human/finish.d.ts +14 -0
- package/dist/daemon/human/finish.js +115 -0
- package/dist/daemon/human/sweep.d.ts +6 -0
- package/dist/daemon/human/sweep.js +49 -0
- package/dist/daemon/messaging/node-message.d.ts +18 -0
- package/dist/daemon/messaging/node-message.js +70 -0
- package/dist/daemon/review/comment-notify.d.ts +26 -0
- package/dist/daemon/review/comment-notify.js +107 -0
- package/dist/daemon/review/deliver.d.ts +7 -0
- package/dist/daemon/review/deliver.js +56 -0
- package/dist/daemon/review/finish.d.ts +22 -0
- package/dist/daemon/review/finish.js +254 -0
- package/dist/daemon/review/sweep.d.ts +11 -0
- package/dist/daemon/review/sweep.js +120 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -2
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +42 -64
- package/dist/pi-extensions/__tests__/canvas-recap.test.d.ts +1 -0
- package/dist/pi-extensions/__tests__/canvas-recap.test.js +159 -0
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +16 -38
- package/dist/pi-extensions/__tests__/canvas-structured-output.test.d.ts +1 -0
- package/dist/pi-extensions/__tests__/canvas-structured-output.test.js +63 -0
- package/dist/pi-extensions/canvas-context-intro.d.ts +8 -11
- package/dist/pi-extensions/canvas-context-intro.js +50 -104
- package/dist/pi-extensions/canvas-recap.d.ts +15 -2
- package/dist/pi-extensions/canvas-recap.js +192 -69
- package/dist/pi-extensions/canvas-review-boundary.d.ts +59 -0
- package/dist/pi-extensions/canvas-review-boundary.js +81 -0
- package/dist/pi-extensions/canvas-stophook.d.ts +3 -3
- package/dist/pi-extensions/canvas-stophook.js +78 -128
- package/dist/pi-extensions/canvas-structured-output.js +52 -8
- package/dist/shared/generated-context.d.ts +29 -4
- package/dist/shared/generated-context.js +122 -7
- package/dist/shared/tool-groups.d.ts +23 -0
- package/dist/shared/tool-groups.js +60 -0
- package/dist/shared/working-activity.d.ts +8 -0
- package/dist/shared/working-activity.js +26 -0
- package/dist/types.d.ts +36 -2
- package/dist/types.js +51 -0
- package/dist/web-client/assets/index-CCPaLeW7.css +2 -0
- package/dist/web-client/assets/index-kyOWsnZK.js +86 -0
- package/dist/web-client/index.html +2 -2
- package/dist/web-client/sw.js +1 -1
- package/docs/compat/hearth-crtr-v4.md +2 -2
- package/docs/compat/hearth-crtr-v5.md +4 -2
- package/docs/public-api.md +3 -3
- package/package.json +21 -14
- package/runtime.lock.json +4661 -1453
- package/scripts/postinstall.mjs +15 -2
- package/dist/builtin-pi-packages/pi-mode-switch/README.md +0 -36
- package/dist/builtin-pi-packages/pi-mode-switch/bin/mode +0 -36
- package/dist/builtin-pi-packages/pi-mode-switch/extensions/index.ts +0 -449
- package/dist/builtin-pi-packages/pi-mode-switch/package.json +0 -14
- package/dist/builtin-pi-packages/pi-mode-switch/tsconfig.json +0 -9
- package/dist/builtin-views/_lib/states.mjs +0 -161
- package/dist/builtin-views/canvas/core.mjs +0 -657
- package/dist/builtin-views/canvas/text.mjs +0 -58
- package/dist/builtin-views/canvas/tui.mjs +0 -168
- package/dist/builtin-views/canvas/web.jsx +0 -121
- package/dist/builtin-views/chat/core.mjs +0 -684
- package/dist/builtin-views/chat/text.mjs +0 -101
- package/dist/builtin-views/chat/tui.mjs +0 -360
- package/dist/builtin-views/chat/web.jsx +0 -362
- package/dist/builtin-views/git-pr/core.mjs +0 -673
- package/dist/builtin-views/git-pr/text.mjs +0 -84
- package/dist/builtin-views/git-pr/tui.mjs +0 -301
- package/dist/builtin-views/git-pr/web.jsx +0 -216
- package/dist/builtin-views/inbox/_lib/render.mjs +0 -175
- package/dist/builtin-views/inbox/core.mjs +0 -1273
- package/dist/builtin-views/inbox/text.mjs +0 -73
- package/dist/builtin-views/inbox/tui.mjs +0 -314
- package/dist/builtin-views/inbox/web.jsx +0 -188
- package/dist/builtin-views/linkedin/core.mjs +0 -906
- package/dist/builtin-views/linkedin/text.mjs +0 -69
- package/dist/builtin-views/linkedin/tui.mjs +0 -413
- package/dist/builtin-views/linkedin/web.jsx +0 -206
- package/dist/builtin-views/prompt-review/core.mjs +0 -735
- package/dist/builtin-views/prompt-review/text.mjs +0 -15
- package/dist/builtin-views/prompt-review/tui.mjs +0 -196
- package/dist/builtin-views/prompt-review/web.jsx +0 -484
- package/dist/builtin-views/workspace-sidebar/__tests__/core.test.js +0 -50
- package/dist/builtin-views/workspace-sidebar/__tests__/core.test.ts +0 -53
- package/dist/builtin-views/workspace-sidebar/core.mjs +0 -670
- package/dist/builtin-views/workspace-sidebar/text.mjs +0 -53
- package/dist/builtin-views/workspace-sidebar/tui.mjs +0 -141
- package/dist/builtin-views/workspace-sidebar/web.jsx +0 -109
- package/dist/clients/attach/session/mode.d.ts +0 -25
- package/dist/clients/attach/session/mode.js +0 -97
- package/dist/commands/sys/promptstudio.d.ts +0 -2
- package/dist/commands/sys/promptstudio.js +0 -65
- package/dist/commands/view-cycle.d.ts +0 -2
- package/dist/commands/view-cycle.js +0 -130
- package/dist/commands/view-list.d.ts +0 -2
- package/dist/commands/view-list.js +0 -66
- package/dist/commands/view-new.d.ts +0 -2
- package/dist/commands/view-new.js +0 -74
- package/dist/commands/view-pick.d.ts +0 -6
- package/dist/commands/view-pick.js +0 -129
- package/dist/commands/view-run.d.ts +0 -2
- package/dist/commands/view-run.js +0 -214
- package/dist/commands/view.d.ts +0 -2
- package/dist/commands/view.js +0 -31
- package/dist/commands/workspace.d.ts +0 -2
- package/dist/commands/workspace.js +0 -165
- package/dist/core/__tests__/chat-view-reconnect.test.js +0 -105
- package/dist/core/__tests__/full/consult-startup-failure.test.js +0 -124
- package/dist/core/canvas/__tests__/human-work-outbox.test.js +0 -123
- package/dist/core/canvas/human-work-outbox.d.ts +0 -73
- package/dist/core/canvas/human-work-outbox.js +0 -261
- package/dist/core/command-plugins/store.d.ts +0 -16
- package/dist/core/command-plugins/store.js +0 -64
- package/dist/core/keybindings/__tests__/bespoke-consumers.test.js +0 -40
- package/dist/core/runtime/fault-recovery-nudge.d.ts +0 -3
- package/dist/core/runtime/fault-recovery-nudge.js +0 -3
- package/dist/core/tui/__tests__/host-keybindings.test.js +0 -113
- package/dist/core/tui/host.d.ts +0 -66
- package/dist/core/view/__tests__/transport-cache.test.js +0 -62
- package/dist/core/view/bridge.d.ts +0 -10
- package/dist/core/view/bridge.js +0 -31
- package/dist/core/view/chrome.d.ts +0 -9
- package/dist/core/view/chrome.js +0 -22
- package/dist/core/view/contract.d.ts +0 -205
- package/dist/core/view/contract.js +0 -23
- package/dist/core/view/loader.d.ts +0 -31
- package/dist/core/view/loader.js +0 -188
- package/dist/core/view/stream-local.d.ts +0 -3
- package/dist/core/view/stream-local.js +0 -231
- package/dist/core/view/transport-cache.d.ts +0 -8
- package/dist/core/view/transport-cache.js +0 -38
- package/dist/core/view/transport-local.d.ts +0 -7
- package/dist/core/view/transport-local.js +0 -83
- package/dist/core/view/transport-remote.d.ts +0 -2
- package/dist/core/view/transport.d.ts +0 -10
- package/dist/core/view/transport.js +0 -15
- package/dist/pi-extensions/naming-tool.d.ts +0 -24
- package/dist/pi-extensions/naming-tool.js +0 -67
- package/dist/prompts/view.d.ts +0 -7
- package/dist/prompts/view.js +0 -172
- package/dist/web/ViewChrome.d.ts +0 -7
- package/dist/web/ViewChrome.js +0 -28
- package/dist/web/ViewPane.d.ts +0 -39
- package/dist/web/ViewPane.js +0 -48
- package/dist/web/index.d.ts +0 -8
- package/dist/web/index.js +0 -22
- package/dist/web/runtime.d.ts +0 -39
- package/dist/web/runtime.js +0 -232
- package/dist/web/states.d.ts +0 -24
- package/dist/web/states.js +0 -24
- package/dist/web/transport-http.d.ts +0 -5
- package/dist/web/transport-http.js +0 -34
- package/dist/web/transport-stream.d.ts +0 -3
- package/dist/web/transport-stream.js +0 -204
- package/dist/web-client/assets/index-U_NZ66VE.js +0 -79
- package/dist/web-client/assets/index-aaeu4adv.css +0 -2
- /package/dist/{builtin-views/workspace-sidebar/__tests__/core.test.d.ts → clients/attach/__tests__/file-review-focus.test.d.ts} +0 -0
- /package/dist/clients/attach/__tests__/{visible-paths.test.d.ts → group-activity.test.d.ts} +0 -0
- /package/dist/{core/__tests__/chat-view-reconnect.test.d.ts → clients/attach/__tests__/input-controller-extension-command.test.d.ts} +0 -0
- /package/dist/{core/__tests__/full/consult-startup-failure.test.d.ts → clients/attach/__tests__/session-identity-refresh.test.d.ts} +0 -0
- /package/dist/{core/canvas/__tests__/human-work-outbox.test.d.ts → clients/inbox/__tests__/inbox-controller.test.d.ts} +0 -0
- /package/dist/{core/keybindings/__tests__/bespoke-consumers.test.d.ts → clients/inbox/__tests__/mount-panel.test.d.ts} +0 -0
- /package/dist/{core/tui/__tests__/host-keybindings.test.d.ts → clients/inbox/review/__tests__/editor-roundtrip.test.d.ts} +0 -0
- /package/dist/{core/view/__tests__/transport-cache.test.d.ts → clients/inbox/review/__tests__/remap.test.d.ts} +0 -0
- /package/dist/{core/view/__tests__/transport-remote.test.d.ts → clients/inbox/review/__tests__/review-core.test.d.ts} +0 -0
|
@@ -59,15 +59,32 @@ const TRANSIENT_ROTATE_COOLDOWN_MS = 60 * 1000;
|
|
|
59
59
|
// healthy model response into a fatal generation fault.
|
|
60
60
|
const SUBSCRIPTION_LOCK_RETRY_BACKOFFS_MS = [25, 75, 150];
|
|
61
61
|
|
|
62
|
-
let runtimeContext: ExtensionContext | undefined;
|
|
63
|
-
let extensionAPI: ExtensionAPI | undefined;
|
|
64
|
-
|
|
65
62
|
// A declared non-managed provider is re-registered with the route driver at
|
|
66
63
|
// session start, after its owning extension has registered its real transport.
|
|
67
64
|
// Keep that composed transport here: calling the registry after our wrapper is
|
|
68
65
|
// installed would recurse back into the route driver.
|
|
69
66
|
type ProviderStream = (model: Model<any>, context: Context, options?: SimpleStreamOptions) => AssistantMessageEventStream;
|
|
70
|
-
|
|
67
|
+
|
|
68
|
+
export interface ProviderRotationOptions {
|
|
69
|
+
modelIntent?: string;
|
|
70
|
+
nodeCwd?: string;
|
|
71
|
+
profileId?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
type ProviderRotationState = {
|
|
75
|
+
runtimeContext?: ExtensionContext;
|
|
76
|
+
extensionAPI?: ExtensionAPI;
|
|
77
|
+
delegatedProviderStreams: Map<string, ProviderStream>;
|
|
78
|
+
options?: Readonly<ProviderRotationOptions>;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
function createProviderRotationState(options?: ProviderRotationOptions): ProviderRotationState {
|
|
82
|
+
return { delegatedProviderStreams: new Map(), ...(options === undefined ? {} : { options: { ...options } }) };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function configuredValue(state: ProviderRotationState, key: keyof ProviderRotationOptions, envName: string): string | undefined {
|
|
86
|
+
return state.options === undefined ? process.env[envName] : state.options[key];
|
|
87
|
+
}
|
|
71
88
|
|
|
72
89
|
type AttemptResult = {
|
|
73
90
|
result: "success" | "rate_limited" | "transient_exhausted" | "fatal";
|
|
@@ -75,6 +92,7 @@ type AttemptResult = {
|
|
|
75
92
|
attemptAt: number;
|
|
76
93
|
attempts?: number;
|
|
77
94
|
classification?: ProviderErrorClassification;
|
|
95
|
+
failureMessage?: string;
|
|
78
96
|
};
|
|
79
97
|
|
|
80
98
|
// A genuine rate limit (HTTP 429, or 503 with a real Retry-After header) must
|
|
@@ -126,6 +144,18 @@ function classifyProviderError(error: unknown, observed: { status?: number; retr
|
|
|
126
144
|
return { kind: "fatal", status, reason: "unclassified", hadRetryAfterHeader };
|
|
127
145
|
}
|
|
128
146
|
|
|
147
|
+
function providerErrorMessage(error: unknown): string | undefined {
|
|
148
|
+
const value = error as { errorMessage?: unknown; message?: unknown } | undefined;
|
|
149
|
+
const message = typeof value?.errorMessage === "string" && value.errorMessage.trim()
|
|
150
|
+
? value.errorMessage.trim()
|
|
151
|
+
: typeof value?.message === "string" && value.message.trim()
|
|
152
|
+
? value.message.trim()
|
|
153
|
+
: error instanceof Error && error.message.trim()
|
|
154
|
+
? error.message.trim()
|
|
155
|
+
: undefined;
|
|
156
|
+
return message;
|
|
157
|
+
}
|
|
158
|
+
|
|
129
159
|
async function defaultSleep(ms: number): Promise<void> {
|
|
130
160
|
await new Promise<void>((resolve) => setTimeout(resolve, ms));
|
|
131
161
|
}
|
|
@@ -186,8 +216,8 @@ function isUserAbortError(error: unknown, signal: AbortSignal | undefined): bool
|
|
|
186
216
|
return (error instanceof Error && /abort/i.test(error.name)) || /request was aborted|operation was aborted|the user aborted/i.test(message);
|
|
187
217
|
}
|
|
188
218
|
|
|
189
|
-
function setStatus(text: string): void {
|
|
190
|
-
runtimeContext?.ui.setStatus("provider-rotation", text);
|
|
219
|
+
function setStatus(state: ProviderRotationState, text: string): void {
|
|
220
|
+
state.runtimeContext?.ui.setStatus("provider-rotation", text);
|
|
191
221
|
}
|
|
192
222
|
|
|
193
223
|
function logRotation(message: string): void {
|
|
@@ -251,24 +281,26 @@ type ResolvedCredential = SubscriptionCredential & { access: string };
|
|
|
251
281
|
|
|
252
282
|
// The registered provider exposes its OAuth flow through `provider.auth.oauth`. Composed managed
|
|
253
283
|
// providers retain that flow, so the session registry supplies the Anthropic and Codex flows.
|
|
254
|
-
function oauthFlow(providerId: ManagedProviderId, ctx
|
|
255
|
-
const oauth =
|
|
284
|
+
function oauthFlow(providerId: ManagedProviderId, ctx: ExtensionContext | undefined): OAuthAuth {
|
|
285
|
+
const oauth = ctx?.modelRegistry.getProvider(providerId)?.auth.oauth;
|
|
256
286
|
if (!oauth) throw new Error(`${getProviderLabel(providerId)} has no OAuth flow registered`);
|
|
257
287
|
return oauth;
|
|
258
288
|
}
|
|
259
289
|
|
|
260
290
|
// `refresh` is a pure token exchange that reads only `credential.refresh` and persists
|
|
261
291
|
// nothing; crouter records the rotated token in the selected pool row.
|
|
262
|
-
async function defaultRefreshForProvider(providerId: ManagedProviderId, refreshToken: string): Promise<RefreshedCredential> {
|
|
263
|
-
return oauthFlow(providerId).refresh({ type: "oauth", refresh: refreshToken, access: "", expires: 0 });
|
|
292
|
+
async function defaultRefreshForProvider(state: ProviderRotationState, providerId: ManagedProviderId, refreshToken: string): Promise<RefreshedCredential> {
|
|
293
|
+
return oauthFlow(providerId, state.runtimeContext).refresh({ type: "oauth", refresh: refreshToken, access: "", expires: 0 });
|
|
264
294
|
}
|
|
265
295
|
|
|
296
|
+
type RefreshForProvider = (providerId: ManagedProviderId, refreshToken: string) => Promise<RefreshedCredential>;
|
|
297
|
+
|
|
266
298
|
// Indirection so tests can inject refresh failures without real network calls.
|
|
267
|
-
let activeRefreshForProvider:
|
|
299
|
+
let activeRefreshForProvider: RefreshForProvider | undefined;
|
|
268
300
|
|
|
269
301
|
/** Test-only seam: override the per-provider refresh function. Pass undefined to restore the default. */
|
|
270
|
-
export function __setRefreshForProviderForTest(fn:
|
|
271
|
-
activeRefreshForProvider = fn
|
|
302
|
+
export function __setRefreshForProviderForTest(fn: RefreshForProvider | undefined): void {
|
|
303
|
+
activeRefreshForProvider = fn;
|
|
272
304
|
}
|
|
273
305
|
|
|
274
306
|
function openBrowser(url: string): void {
|
|
@@ -295,19 +327,21 @@ function openBrowser(url: string): void {
|
|
|
295
327
|
// `getApiKey`, which wraps pi-ai's `getOAuthApiKey` and collapses a refresh failure into a
|
|
296
328
|
// generic message; calling `activeRefreshForProvider` directly keeps the real error intact so
|
|
297
329
|
// `isInvalidRefreshTokenError` can classify it (cooldown -> reauth -> cross-provider-fallback).
|
|
298
|
-
async function refreshCredentialIfNeeded(providerId: ManagedProviderId, credential: SubscriptionCredential): Promise<ResolvedCredential> {
|
|
330
|
+
async function refreshCredentialIfNeeded(state: ProviderRotationState, providerId: ManagedProviderId, credential: SubscriptionCredential): Promise<ResolvedCredential> {
|
|
299
331
|
if (!credential.refresh || !credential.access || credential.expires === undefined) {
|
|
300
332
|
throw new Error(`${getProviderLabel(providerId)} subscription "${credential.label}" is missing its credential value`);
|
|
301
333
|
}
|
|
302
334
|
if (credential.expires > Date.now()) return credential as ResolvedCredential;
|
|
303
|
-
const refreshed = await refreshSubscriptionCredential(providerId, credential.label, (token) =>
|
|
335
|
+
const refreshed = await refreshSubscriptionCredential(providerId, credential.label, (token) =>
|
|
336
|
+
activeRefreshForProvider?.(providerId, token) ?? defaultRefreshForProvider(state, providerId, token),
|
|
337
|
+
);
|
|
304
338
|
return { ...credential, ...refreshed } as ResolvedCredential;
|
|
305
339
|
}
|
|
306
340
|
|
|
307
341
|
/** Test-only seam: exercises the real `refreshCredentialIfNeeded` (including its locked refresh
|
|
308
342
|
* transaction) without duplicating its logic. */
|
|
309
343
|
export async function __refreshCredentialIfNeededForTest(providerId: ManagedProviderId, credential: SubscriptionCredential): Promise<ResolvedCredential> {
|
|
310
|
-
return refreshCredentialIfNeeded(providerId, credential);
|
|
344
|
+
return refreshCredentialIfNeeded(createProviderRotationState(), providerId, credential);
|
|
311
345
|
}
|
|
312
346
|
|
|
313
347
|
async function defaultLoginForProvider(providerId: ManagedProviderId, ctx: ExtensionContext): Promise<LoginCredential> {
|
|
@@ -321,8 +355,8 @@ export function __setLoginForProviderForTest(fn: typeof defaultLoginForProvider
|
|
|
321
355
|
activeLoginForProvider = fn ?? defaultLoginForProvider;
|
|
322
356
|
}
|
|
323
357
|
|
|
324
|
-
async function reauthenticateCredential(providerId: ManagedProviderId, credential: SubscriptionCredential): Promise<ResolvedCredential | undefined> {
|
|
325
|
-
const ctx = runtimeContext;
|
|
358
|
+
async function reauthenticateCredential(state: ProviderRotationState, providerId: ManagedProviderId, credential: SubscriptionCredential): Promise<ResolvedCredential | undefined> {
|
|
359
|
+
const ctx = state.runtimeContext;
|
|
326
360
|
if (!ctx?.hasUI) return undefined;
|
|
327
361
|
ctx.ui.notify(`${getProviderLabel(providerId)} subscription "${credential.label}" needs re-authentication. Opening OAuth login...`, "warning");
|
|
328
362
|
const authenticated = await activeLoginForProvider(providerId, ctx);
|
|
@@ -375,6 +409,7 @@ export function __setStreamForProviderForTest(fn: typeof defaultStreamForProvide
|
|
|
375
409
|
// A genuine rate limit ends the attempt immediately (the caller cools the credential down
|
|
376
410
|
// and rotates); a transient blip gets a short in-place retry budget before giving up.
|
|
377
411
|
async function streamProviderAttempt(
|
|
412
|
+
state: ProviderRotationState,
|
|
378
413
|
providerId: string,
|
|
379
414
|
model: Model<any>,
|
|
380
415
|
context: Context,
|
|
@@ -397,10 +432,10 @@ async function streamProviderAttempt(
|
|
|
397
432
|
await options?.onResponse?.(response as any, responseModel);
|
|
398
433
|
},
|
|
399
434
|
};
|
|
400
|
-
const provider = runtimeContext?.modelRegistry.getProvider?.(model.provider);
|
|
435
|
+
const provider = state.runtimeContext?.modelRegistry.getProvider?.(model.provider);
|
|
401
436
|
const inner = credential
|
|
402
437
|
? streamForProvider(model, context, streamOptions)
|
|
403
|
-
: delegatedProviderStreams.get(providerId)?.(model, context, streamOptions)
|
|
438
|
+
: state.delegatedProviderStreams.get(providerId)?.(model, context, streamOptions)
|
|
404
439
|
?? provider?.streamSimple(model, context, streamOptions)
|
|
405
440
|
?? streamForProvider(model, context, streamOptions);
|
|
406
441
|
|
|
@@ -408,6 +443,7 @@ async function streamProviderAttempt(
|
|
|
408
443
|
let sawContent = false;
|
|
409
444
|
let committed = false;
|
|
410
445
|
let classification: ProviderErrorClassification | undefined;
|
|
446
|
+
let failureMessage: string | undefined;
|
|
411
447
|
|
|
412
448
|
// Events are buffered ONLY until this attempt commits to the provider -- i.e. until the
|
|
413
449
|
// first real content event (thinking/text/toolcall) arrives, after which rotating away is
|
|
@@ -433,6 +469,7 @@ async function streamProviderAttempt(
|
|
|
433
469
|
flush();
|
|
434
470
|
return { result: "fatal", attemptAt };
|
|
435
471
|
}
|
|
472
|
+
failureMessage = providerErrorMessage(event.error);
|
|
436
473
|
classification = classifyProviderError(event.error, { status: observedStatus, retryAfterMs: requestedRetryAfterMs });
|
|
437
474
|
if (classification.kind === "fatal" || sawContent) {
|
|
438
475
|
emit(event);
|
|
@@ -457,6 +494,7 @@ async function streamProviderAttempt(
|
|
|
457
494
|
flush();
|
|
458
495
|
return { result: "fatal", attemptAt };
|
|
459
496
|
}
|
|
497
|
+
failureMessage = providerErrorMessage(error);
|
|
460
498
|
classification = classifyProviderError(error, { status: observedStatus, retryAfterMs: requestedRetryAfterMs });
|
|
461
499
|
if (classification.kind === "fatal" || sawContent) {
|
|
462
500
|
emit({
|
|
@@ -493,7 +531,7 @@ async function streamProviderAttempt(
|
|
|
493
531
|
// to another credential / fallback provider. Nothing is emitted into the stream here:
|
|
494
532
|
// the buffered (pre-content) events are discarded exactly like the rate-limit path, so
|
|
495
533
|
// the rotation target streams a clean turn.
|
|
496
|
-
return { result: "transient_exhausted", attemptAt, classification, attempts: attempt };
|
|
534
|
+
return { result: "transient_exhausted", attemptAt, classification, attempts: attempt, failureMessage };
|
|
497
535
|
}
|
|
498
536
|
logRotation(
|
|
499
537
|
`${credential ? `${getProviderLabel(providerId as ManagedProviderId)} subscription "${credential.label}"` : providerId} hit a transient error (${classification.reason}, status=${classification.status ?? "n/a"}); retrying same route in ${backoffMs}ms (attempt ${attempt + 1})`,
|
|
@@ -560,20 +598,29 @@ function logRouteQueueAdvance(from: RouteCandidate, to: RouteCandidate | undefin
|
|
|
560
598
|
// Drive the deterministic route queue from the live rank. Managed routes walk
|
|
561
599
|
// their pool rows; every other declared route is one configured credential.
|
|
562
600
|
async function runManagedProvider(
|
|
601
|
+
state: ProviderRotationState,
|
|
563
602
|
model: Model<any>,
|
|
564
603
|
context: Context,
|
|
565
604
|
options: SimpleStreamOptions | undefined,
|
|
566
605
|
stream: AssistantMessageEventStream,
|
|
567
606
|
): Promise<void> {
|
|
568
|
-
const liveThinking = runtimeContext?.thinkingLevel === undefined || runtimeContext?.thinkingLevel === 'off'
|
|
607
|
+
const liveThinking = state.runtimeContext?.thinkingLevel === undefined || state.runtimeContext?.thinkingLevel === 'off'
|
|
569
608
|
? undefined
|
|
570
|
-
: runtimeContext.thinkingLevel;
|
|
571
|
-
const request = modelRequestFromConfig(
|
|
572
|
-
|
|
609
|
+
: state.runtimeContext.thinkingLevel;
|
|
610
|
+
const request = modelRequestFromConfig(
|
|
611
|
+
`${model.provider}/${model.id}${liveThinking ? `:${liveThinking}` : ''}`,
|
|
612
|
+
configuredValue(state, 'modelIntent', 'CRTR_MODEL_INTENT'),
|
|
613
|
+
false,
|
|
614
|
+
);
|
|
615
|
+
const expanded = request ? expandModelCandidates(
|
|
616
|
+
request,
|
|
617
|
+
configuredValue(state, 'nodeCwd', 'CRTR_NODE_CWD'),
|
|
618
|
+
configuredValue(state, 'profileId', 'CRTR_PROFILE_ID'),
|
|
619
|
+
) : [];
|
|
573
620
|
const liveRank = expanded.find((candidate) => candidate.providerId === model.provider && candidate.modelId === model.id && candidate.thinkingLevel === liveThinking)?.rank ?? 0;
|
|
574
621
|
const routeCandidates: RouteCandidate[] = expanded.slice(liveRank)
|
|
575
622
|
.map((route) => {
|
|
576
|
-
const registry = runtimeContext?.modelRegistry;
|
|
623
|
+
const registry = state.runtimeContext?.modelRegistry;
|
|
577
624
|
const routeModel = registry?.find(route.providerId, route.modelId);
|
|
578
625
|
if (!registry || !routeModel) return undefined;
|
|
579
626
|
const availability = probeRouteAvailability(route, registry);
|
|
@@ -598,6 +645,7 @@ async function runManagedProvider(
|
|
|
598
645
|
const seenReadyLabels = new Map<string, Set<string>>();
|
|
599
646
|
const cooldownAttempts = new Map<string, number>();
|
|
600
647
|
let terminalModel = model;
|
|
648
|
+
let lastTransientFailure: AttemptResult | undefined;
|
|
601
649
|
|
|
602
650
|
for (let candidate = candidates.shift(); candidate !== undefined; candidate = candidates.shift()) {
|
|
603
651
|
const { routeId, providerId, model: candidateModel } = candidate;
|
|
@@ -606,16 +654,17 @@ async function runManagedProvider(
|
|
|
606
654
|
attemptedRoutes.add(routeId);
|
|
607
655
|
terminalModel = candidateModel;
|
|
608
656
|
|
|
609
|
-
if (!await switchToRoute(extensionAPI!, runtimeContext!, candidate)) {
|
|
657
|
+
if (!await switchToRoute(state.extensionAPI!, state.runtimeContext!, candidate)) {
|
|
610
658
|
emitTerminalError(stream, candidateModel, `Provider route ${routeId} is unavailable: failed to select ${providerId}/${candidateModel.id}`);
|
|
611
659
|
return;
|
|
612
660
|
}
|
|
613
661
|
|
|
614
662
|
if (!isManagedProvider(providerId)) {
|
|
615
|
-
const result = await streamProviderAttempt(providerId, candidateModel, context, options, undefined, stream);
|
|
663
|
+
const result = await streamProviderAttempt(state, providerId, candidateModel, context, options, undefined, stream);
|
|
616
664
|
if (result.result === 'success') { stream.end(); return; }
|
|
617
665
|
if (result.result === 'fatal') { stream.end(); return; }
|
|
618
666
|
const cooldownMs = result.result === 'rate_limited' ? result.retryAfterMs ?? DEFAULT_RATE_LIMIT_BACKOFF_MS : TRANSIENT_ROTATE_COOLDOWN_MS;
|
|
667
|
+
if (result.result === 'transient_exhausted') lastTransientFailure = result;
|
|
619
668
|
localCoolingDeadlines.set(routeId, Math.max(localCoolingDeadlines.get(routeId) ?? 0, Date.now() + cooldownMs));
|
|
620
669
|
logRouteQueueAdvance(candidate, candidates[0], result);
|
|
621
670
|
continue;
|
|
@@ -632,12 +681,12 @@ async function runManagedProvider(
|
|
|
632
681
|
for (const credential of available) {
|
|
633
682
|
let freshCredential: ResolvedCredential;
|
|
634
683
|
try {
|
|
635
|
-
freshCredential = await refreshCredentialIfNeeded(providerId, credential);
|
|
684
|
+
freshCredential = await refreshCredentialIfNeeded(state, providerId, credential);
|
|
636
685
|
} catch (error) {
|
|
637
686
|
if (!isInvalidRefreshTokenError(error)) throw error;
|
|
638
687
|
let reauthenticated: ResolvedCredential | undefined;
|
|
639
|
-
try { reauthenticated = await reauthenticateCredential(providerId, credential); } catch (loginError) {
|
|
640
|
-
runtimeContext?.ui.notify(`${getProviderLabel(providerId)} re-authentication failed: ${loginError instanceof Error ? loginError.message : String(loginError)}`, 'error');
|
|
688
|
+
try { reauthenticated = await reauthenticateCredential(state, providerId, credential); } catch (loginError) {
|
|
689
|
+
state.runtimeContext?.ui.notify(`${getProviderLabel(providerId)} re-authentication failed: ${loginError instanceof Error ? loginError.message : String(loginError)}`, 'error');
|
|
641
690
|
}
|
|
642
691
|
if (!reauthenticated) {
|
|
643
692
|
const attemptAt = Date.now();
|
|
@@ -647,7 +696,7 @@ async function runManagedProvider(
|
|
|
647
696
|
}
|
|
648
697
|
freshCredential = reauthenticated;
|
|
649
698
|
}
|
|
650
|
-
const result = await streamProviderAttempt(providerId, candidateModel, context, options, freshCredential, stream);
|
|
699
|
+
const result = await streamProviderAttempt(state, providerId, candidateModel, context, options, freshCredential, stream);
|
|
651
700
|
if (result.result === 'success') {
|
|
652
701
|
if (freshCredential.rateLimitedUntil || freshCredential.authFailure) await recordSubscriptionMutation(`recording ${getProviderLabel(providerId)} success`, () => markSubscriptionSuccess(providerId, freshCredential.label, result.attemptAt));
|
|
653
702
|
stream.end();
|
|
@@ -655,9 +704,9 @@ async function runManagedProvider(
|
|
|
655
704
|
}
|
|
656
705
|
if (result.result === 'fatal') { stream.end(); return; }
|
|
657
706
|
const cooldownMs = result.result === 'rate_limited' ? result.retryAfterMs ?? DEFAULT_RATE_LIMIT_BACKOFF_MS : TRANSIENT_ROTATE_COOLDOWN_MS;
|
|
658
|
-
if (
|
|
659
|
-
|
|
660
|
-
const persisted = await recordSubscriptionMutation(`recording ${getProviderLabel(providerId)}
|
|
707
|
+
if (result.result === 'transient_exhausted') lastTransientFailure = result;
|
|
708
|
+
if (result.result === 'rate_limited' && result.retryAfterMs !== undefined) {
|
|
709
|
+
const persisted = await recordSubscriptionMutation(`recording ${getProviderLabel(providerId)} server cooldown`, () => markSubscriptionRateLimited(providerId, freshCredential.label, cooldownMs, result.attemptAt));
|
|
661
710
|
if (persisted) cooldownAttempts.set(`${routeId}/${freshCredential.label}`, result.attemptAt);
|
|
662
711
|
else localCoolingDeadlines.set(routeId, Math.max(localCoolingDeadlines.get(routeId) ?? 0, Date.now() + cooldownMs));
|
|
663
712
|
} else {
|
|
@@ -672,6 +721,11 @@ async function runManagedProvider(
|
|
|
672
721
|
|
|
673
722
|
const coolingDeadline = earliestCoolingDeadline([...knownRoutes.values()], localCoolingDeadlines);
|
|
674
723
|
const tried = [...attemptedRoutes].join(', ');
|
|
724
|
+
if (lastTransientFailure !== undefined) {
|
|
725
|
+
const detail = lastTransientFailure.failureMessage ?? lastTransientFailure.classification?.reason ?? 'unknown connection failure';
|
|
726
|
+
emitTerminalError(stream, terminalModel, `Provider routes failed after transient retries: ${detail} (tried ${tried})`);
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
675
729
|
if (coolingDeadline !== undefined) {
|
|
676
730
|
emitCoolingError(stream, terminalModel, new ManagedProviderCoolingError(`All provider routes are rate limited (cooling down ~${Math.ceil((coolingDeadline - Date.now()) / 1000)}s; tried ${tried})`, coolingDeadline));
|
|
677
731
|
return;
|
|
@@ -720,10 +774,10 @@ function emitCoolingError(stream: AssistantMessageEventStream, model: Model<any>
|
|
|
720
774
|
stream.end();
|
|
721
775
|
}
|
|
722
776
|
|
|
723
|
-
function streamManagedProvider(model: Model<any>, context: Context, options?: SimpleStreamOptions): AssistantMessageEventStream {
|
|
777
|
+
function streamManagedProvider(state: ProviderRotationState, model: Model<any>, context: Context, options?: SimpleStreamOptions): AssistantMessageEventStream {
|
|
724
778
|
const stream = createAssistantMessageEventStream();
|
|
725
779
|
|
|
726
|
-
runManagedProvider(model, context, options, stream).catch((error) => {
|
|
780
|
+
runManagedProvider(state, model, context, options, stream).catch((error) => {
|
|
727
781
|
stream.push({
|
|
728
782
|
type: "error",
|
|
729
783
|
reason: "error",
|
|
@@ -747,39 +801,43 @@ function parseProvider(value: string | undefined): ManagedProviderId | undefined
|
|
|
747
801
|
return isManagedProvider(value) ? value : undefined;
|
|
748
802
|
}
|
|
749
803
|
|
|
750
|
-
function installDeclaredRouteProviders(pi: ExtensionAPI, ctx: ExtensionContext): void {
|
|
751
|
-
const config = readMergedLaunchConfig(ctx.cwd,
|
|
804
|
+
function installDeclaredRouteProviders(state: ProviderRotationState, pi: ExtensionAPI, ctx: ExtensionContext): void {
|
|
805
|
+
const config = readMergedLaunchConfig(ctx.cwd, configuredValue(state, 'profileId', 'CRTR_PROFILE_ID') || null);
|
|
752
806
|
const providerIds = new Set(Object.values(config.modelRoutes ?? {}).map((route) => route.providerId));
|
|
753
807
|
for (const providerId of providerIds) {
|
|
754
|
-
if (isManagedProvider(providerId) || delegatedProviderStreams.has(providerId)) continue;
|
|
808
|
+
if (isManagedProvider(providerId) || state.delegatedProviderStreams.has(providerId)) continue;
|
|
755
809
|
const provider = ctx.modelRegistry.getProvider?.(providerId);
|
|
756
810
|
const model = ctx.modelRegistry.getAll?.().find((entry) => entry.provider === providerId);
|
|
757
811
|
if (!provider || !model) continue;
|
|
758
|
-
delegatedProviderStreams.set(providerId, provider.streamSimple.bind(provider));
|
|
812
|
+
state.delegatedProviderStreams.set(providerId, provider.streamSimple.bind(provider));
|
|
759
813
|
// `api` is required by pi whenever a registration supplies streamSimple.
|
|
760
814
|
// Re-registration merges this wrapper over the existing declaration, so the
|
|
761
815
|
// provider's models, auth, and captured composed transport remain intact.
|
|
762
|
-
pi.registerProvider(providerId, { api: model.api, streamSimple: streamManagedProvider });
|
|
816
|
+
pi.registerProvider(providerId, { api: model.api, streamSimple: (model, context, options) => streamManagedProvider(state, model, context, options) });
|
|
763
817
|
}
|
|
764
818
|
}
|
|
765
819
|
|
|
766
|
-
function updateRotationStatus(ctx: ExtensionContext): void {
|
|
820
|
+
function updateRotationStatus(state: ProviderRotationState, ctx: ExtensionContext): void {
|
|
767
821
|
const current = getCurrentModelRef(ctx.model);
|
|
768
|
-
if (current && isManagedProvider(current.providerId)) setStatus(formatStatusLine(current.providerId));
|
|
822
|
+
if (current && isManagedProvider(current.providerId)) setStatus(state, formatStatusLine(current.providerId));
|
|
769
823
|
}
|
|
770
824
|
|
|
771
825
|
/** Restore only when the deterministic route rank improves; no shared-home
|
|
772
826
|
* preferred-model state is needed or consulted. */
|
|
773
|
-
async function restoreHigherRankIfAvailable(pi: ExtensionAPI, ctx: ExtensionContext): Promise<boolean> {
|
|
827
|
+
async function restoreHigherRankIfAvailable(state: ProviderRotationState, pi: ExtensionAPI, ctx: ExtensionContext): Promise<boolean> {
|
|
774
828
|
if (!readRotationConfig().revertWhenAvailable) return false;
|
|
775
829
|
const liveThinking = ctx.thinkingLevel === undefined || ctx.thinkingLevel === 'off' ? undefined : ctx.thinkingLevel;
|
|
776
830
|
const request = modelRequestFromConfig(
|
|
777
831
|
`${ctx.model?.provider ?? ''}/${ctx.model?.id ?? ''}${liveThinking ? `:${liveThinking}` : ''}`,
|
|
778
|
-
|
|
832
|
+
configuredValue(state, 'modelIntent', 'CRTR_MODEL_INTENT'),
|
|
779
833
|
false,
|
|
780
834
|
);
|
|
781
835
|
if (!request || !ctx.model) return false;
|
|
782
|
-
const candidates = expandModelCandidates(
|
|
836
|
+
const candidates = expandModelCandidates(
|
|
837
|
+
request,
|
|
838
|
+
configuredValue(state, 'nodeCwd', 'CRTR_NODE_CWD'),
|
|
839
|
+
configuredValue(state, 'profileId', 'CRTR_PROFILE_ID'),
|
|
840
|
+
);
|
|
783
841
|
const liveRank = candidates.find((candidate) => candidate.providerId === ctx.model?.provider && candidate.modelId === ctx.model?.id && candidate.thinkingLevel === liveThinking)?.rank;
|
|
784
842
|
if (liveRank === undefined) return false;
|
|
785
843
|
const preferred = candidates.find((candidate) => candidate.rank < liveRank && resolveProviderCandidates([{
|
|
@@ -895,134 +953,141 @@ async function loginProvider(providerId: ManagedProviderId, ctx: ExtensionContex
|
|
|
895
953
|
);
|
|
896
954
|
}
|
|
897
955
|
|
|
898
|
-
export
|
|
899
|
-
|
|
956
|
+
export function createProviderRotationExtension(options?: ProviderRotationOptions): (pi: ExtensionAPI) => Promise<void> {
|
|
957
|
+
const state = createProviderRotationState(options);
|
|
900
958
|
|
|
901
|
-
pi
|
|
902
|
-
|
|
903
|
-
streamSimple: streamManagedProvider,
|
|
904
|
-
});
|
|
905
|
-
|
|
906
|
-
pi.registerProvider(OPENAI_CODEX_PROVIDER_ID, {
|
|
907
|
-
api: "openai-codex-responses",
|
|
908
|
-
streamSimple: streamManagedProvider,
|
|
909
|
-
});
|
|
959
|
+
return async (pi: ExtensionAPI): Promise<void> => {
|
|
960
|
+
state.extensionAPI = pi;
|
|
910
961
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
});
|
|
962
|
+
pi.registerProvider(ANTHROPIC_PROVIDER_ID, {
|
|
963
|
+
api: "anthropic-messages",
|
|
964
|
+
streamSimple: (model, context, streamOptions) => streamManagedProvider(state, model, context, streamOptions),
|
|
965
|
+
});
|
|
916
966
|
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
logRotation(`restored higher-ranked route ${ctx.model.provider}/${ctx.model.id}`);
|
|
922
|
-
setStatus(formatStatusLine(ctx.model.provider));
|
|
923
|
-
}
|
|
924
|
-
});
|
|
967
|
+
pi.registerProvider(OPENAI_CODEX_PROVIDER_ID, {
|
|
968
|
+
api: "openai-codex-responses",
|
|
969
|
+
streamSimple: (model, context, streamOptions) => streamManagedProvider(state, model, context, streamOptions),
|
|
970
|
+
});
|
|
925
971
|
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
972
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
973
|
+
state.runtimeContext = ctx;
|
|
974
|
+
installDeclaredRouteProviders(state, pi, ctx);
|
|
975
|
+
updateRotationStatus(state, ctx);
|
|
976
|
+
});
|
|
930
977
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
ctx.ui.notify("Usage: /provider-sub <anthropic|openai-codex> <list|add|select|rm>", "error");
|
|
938
|
-
return;
|
|
978
|
+
pi.on("before_agent_start", async (_event, ctx) => {
|
|
979
|
+
state.runtimeContext = ctx;
|
|
980
|
+
const restored = await restoreHigherRankIfAvailable(state, pi, ctx);
|
|
981
|
+
if (restored && ctx.model && isManagedProvider(ctx.model.provider)) {
|
|
982
|
+
logRotation(`restored higher-ranked route ${ctx.model.provider}/${ctx.model.id}`);
|
|
983
|
+
setStatus(state, formatStatusLine(ctx.model.provider));
|
|
939
984
|
}
|
|
985
|
+
});
|
|
940
986
|
|
|
941
|
-
|
|
987
|
+
pi.on("model_select", async (_event, ctx) => {
|
|
988
|
+
state.runtimeContext = ctx;
|
|
989
|
+
updateRotationStatus(state, ctx);
|
|
990
|
+
});
|
|
942
991
|
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
992
|
+
pi.registerCommand("provider-sub", {
|
|
993
|
+
description: "Manage subscription credential pools for provider rotation",
|
|
994
|
+
handler: async (args, ctx) => {
|
|
995
|
+
const [providerArg, verb, ...rest] = parseCommand(args);
|
|
996
|
+
const providerId = parseProvider(providerArg);
|
|
997
|
+
if (!providerId) {
|
|
998
|
+
ctx.ui.notify("Usage: /provider-sub <anthropic|openai-codex> <list|add|select|rm>", "error");
|
|
999
|
+
return;
|
|
950
1000
|
}
|
|
951
|
-
ctx.ui.notify(lines.join("\n"), "info");
|
|
952
|
-
return;
|
|
953
|
-
}
|
|
954
1001
|
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1002
|
+
const action = verb === "rm" ? "remove" : verb || "list";
|
|
1003
|
+
|
|
1004
|
+
if (action === "status" || action === "list") {
|
|
1005
|
+
const pool = readSubscriptionPool(providerId);
|
|
1006
|
+
const lines = [formatStatusLine(providerId), ""];
|
|
1007
|
+
for (const [index, entry] of pool.entries()) {
|
|
1008
|
+
const cooldown = entry.rateLimitedUntil > Date.now() ? ` cooldown=${Math.ceil((entry.rateLimitedUntil - Date.now()) / 1000)}s` : "";
|
|
1009
|
+
const account = entry.accountId ? ` account=${shortAccountId(entry.accountId)}` : "";
|
|
1010
|
+
lines.push(`${index + 1}. ${entry.label}${account}${cooldown}`);
|
|
1011
|
+
}
|
|
1012
|
+
ctx.ui.notify(lines.join("\n"), "info");
|
|
958
1013
|
return;
|
|
959
1014
|
}
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1015
|
+
|
|
1016
|
+
if (action === "add") {
|
|
1017
|
+
if (!ctx.hasUI) {
|
|
1018
|
+
ctx.ui.notify(`${getProviderLabel(providerId)} login requires an interactive UI.`, "error");
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
const pool = readSubscriptionPool(providerId);
|
|
1022
|
+
const label = (rest.join(" ") || (await ctx.ui.input(`${getProviderLabel(providerId)} subscription label`, "")) || "").trim();
|
|
1023
|
+
if (!label) return;
|
|
1024
|
+
if (pool.some((entry) => entry.label.toLowerCase() === label.toLowerCase())) {
|
|
1025
|
+
ctx.ui.notify(`${getProviderLabel(providerId)} subscription already exists: ${label}`, "error");
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
try {
|
|
1029
|
+
const cred = await activeLoginForProvider(providerId, ctx);
|
|
1030
|
+
const identity = await enrichManagedLoginIdentity(providerId, cred);
|
|
1031
|
+
// Explicit add always creates a new label, so a matching real account is rejected by
|
|
1032
|
+
// the locked uniqueness gate rather than creating a second quota slot.
|
|
1033
|
+
await addSubscription(providerId, {
|
|
1034
|
+
label,
|
|
1035
|
+
refresh: cred.refresh,
|
|
1036
|
+
access: cred.access,
|
|
1037
|
+
expires: cred.expires,
|
|
1038
|
+
...(identity.accountId ? { accountId: identity.accountId } : {}),
|
|
1039
|
+
rateLimitedUntil: 0,
|
|
1040
|
+
lastAttemptAt: 0,
|
|
1041
|
+
lastRateLimitedAt: 0,
|
|
1042
|
+
});
|
|
1043
|
+
logRotation(`added ${getProviderLabel(providerId)} subscription "${label}"`);
|
|
1044
|
+
ctx.ui.notify(`Added ${getProviderLabel(providerId)} subscription: ${label}`, "info");
|
|
1045
|
+
updateRotationStatus(state, ctx);
|
|
1046
|
+
} catch (error) {
|
|
1047
|
+
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
1048
|
+
}
|
|
965
1049
|
return;
|
|
966
1050
|
}
|
|
967
|
-
try {
|
|
968
|
-
const cred = await activeLoginForProvider(providerId, ctx);
|
|
969
|
-
const identity = await enrichManagedLoginIdentity(providerId, cred);
|
|
970
|
-
// Explicit add always creates a new label, so a matching real account is rejected by
|
|
971
|
-
// the locked uniqueness gate rather than creating a second quota slot.
|
|
972
|
-
await addSubscription(providerId, {
|
|
973
|
-
label,
|
|
974
|
-
refresh: cred.refresh,
|
|
975
|
-
access: cred.access,
|
|
976
|
-
expires: cred.expires,
|
|
977
|
-
...(identity.accountId ? { accountId: identity.accountId } : {}),
|
|
978
|
-
rateLimitedUntil: 0,
|
|
979
|
-
lastAttemptAt: 0,
|
|
980
|
-
lastRateLimitedAt: 0,
|
|
981
|
-
});
|
|
982
|
-
logRotation(`added ${getProviderLabel(providerId)} subscription "${label}"`);
|
|
983
|
-
ctx.ui.notify(`Added ${getProviderLabel(providerId)} subscription: ${label}`, "info");
|
|
984
|
-
updateRotationStatus(ctx);
|
|
985
|
-
} catch (error) {
|
|
986
|
-
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
987
|
-
}
|
|
988
|
-
return;
|
|
989
|
-
}
|
|
990
1051
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1052
|
+
if (action === "select") {
|
|
1053
|
+
const ref = rest.join(" ");
|
|
1054
|
+
if (!ref) {
|
|
1055
|
+
ctx.ui.notify(`Usage: /provider-sub ${providerId} select <label|index>`, "error");
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
try {
|
|
1059
|
+
await promoteSubscription(providerId, ref);
|
|
1060
|
+
logRotation(`selected ${getProviderLabel(providerId)} subscription "${ref}"`);
|
|
1061
|
+
ctx.ui.notify(`Preferred ${getProviderLabel(providerId)} subscription: ${ref}`, "info");
|
|
1062
|
+
updateRotationStatus(state, ctx);
|
|
1063
|
+
} catch (error) {
|
|
1064
|
+
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
1065
|
+
}
|
|
995
1066
|
return;
|
|
996
1067
|
}
|
|
997
|
-
try {
|
|
998
|
-
await promoteSubscription(providerId, ref);
|
|
999
|
-
logRotation(`selected ${getProviderLabel(providerId)} subscription "${ref}"`);
|
|
1000
|
-
ctx.ui.notify(`Preferred ${getProviderLabel(providerId)} subscription: ${ref}`, "info");
|
|
1001
|
-
updateRotationStatus(ctx);
|
|
1002
|
-
} catch (error) {
|
|
1003
|
-
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
1004
|
-
}
|
|
1005
|
-
return;
|
|
1006
|
-
}
|
|
1007
1068
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1069
|
+
if (action === "remove") {
|
|
1070
|
+
const ref = rest.join(" ");
|
|
1071
|
+
if (!ref) {
|
|
1072
|
+
ctx.ui.notify(`Usage: /provider-sub ${providerId} rm <label|index>`, "error");
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1075
|
+
try {
|
|
1076
|
+
await removeManagedAccount(providerId, ref);
|
|
1077
|
+
logRotation(`removed ${getProviderLabel(providerId)} subscription "${ref}"`);
|
|
1078
|
+
ctx.ui.notify(`Removed ${getProviderLabel(providerId)} subscription: ${ref}`, "info");
|
|
1079
|
+
updateRotationStatus(state, ctx);
|
|
1080
|
+
} catch (error) {
|
|
1081
|
+
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
1082
|
+
}
|
|
1012
1083
|
return;
|
|
1013
1084
|
}
|
|
1014
|
-
try {
|
|
1015
|
-
await removeManagedAccount(providerId, ref);
|
|
1016
|
-
logRotation(`removed ${getProviderLabel(providerId)} subscription "${ref}"`);
|
|
1017
|
-
ctx.ui.notify(`Removed ${getProviderLabel(providerId)} subscription: ${ref}`, "info");
|
|
1018
|
-
updateRotationStatus(ctx);
|
|
1019
|
-
} catch (error) {
|
|
1020
|
-
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
1021
|
-
}
|
|
1022
|
-
return;
|
|
1023
|
-
}
|
|
1024
1085
|
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1086
|
+
ctx.ui.notify(`Unknown /provider-sub verb: ${verb}`, "error");
|
|
1087
|
+
},
|
|
1088
|
+
});
|
|
1089
|
+
};
|
|
1028
1090
|
}
|
|
1091
|
+
|
|
1092
|
+
const defaultProviderRotationExtension = createProviderRotationExtension();
|
|
1093
|
+
export default defaultProviderRotationExtension;
|
|
@@ -218,11 +218,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
218
218
|
});
|
|
219
219
|
|
|
220
220
|
// --- Input bar border: session-name badge with solid background ---
|
|
221
|
-
// Compose with whatever editor is already installed
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
//
|
|
225
|
-
// order.
|
|
221
|
+
// Compose with whatever editor is already installed instead of replacing it:
|
|
222
|
+
// wrap the previous factory in a Proxy that overrides only render
|
|
223
|
+
// (session-name badge on the top border). Other editor decorations keep
|
|
224
|
+
// working regardless of load order.
|
|
226
225
|
const previousEditorFactory = ctx.ui.getEditorComponent();
|
|
227
226
|
ctx.ui.setEditorComponent((tui, theme, keybindings) => {
|
|
228
227
|
const base = (
|