@oh-my-pi/pi-coding-agent 17.0.8 → 17.1.0
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/CHANGELOG.md +87 -1
- package/README.md +1 -1
- package/dist/cli.js +5495 -5021
- package/dist/types/async/job-manager.d.ts +37 -1
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/cli/bench-cli.d.ts +41 -0
- package/dist/types/commands/bench.d.ts +15 -3
- package/dist/types/commands/launch.d.ts +4 -0
- package/dist/types/config/__tests__/model-registry.test.d.ts +1 -0
- package/dist/types/config/model-registry.d.ts +30 -1
- package/dist/types/config/models-config-schema.d.ts +18 -6
- package/dist/types/config/models-config.d.ts +14 -5
- package/dist/types/config/provider-globals.d.ts +2 -2
- package/dist/types/config/service-tier.d.ts +5 -1
- package/dist/types/config/settings-schema.d.ts +350 -50
- package/dist/types/config/settings.d.ts +7 -0
- package/dist/types/dap/client.d.ts +20 -0
- package/dist/types/exec/bash-executor.d.ts +38 -0
- package/dist/types/exec/direnv.d.ts +33 -0
- package/dist/types/export/html/args.d.ts +15 -0
- package/dist/types/export/html/index.d.ts +11 -26
- package/dist/types/export/html/web-palette.d.ts +55 -116
- package/dist/types/extensibility/extensions/loader.d.ts +3 -0
- package/dist/types/extensibility/extensions/types.d.ts +17 -2
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -0
- package/dist/types/extensibility/legacy-pi-tui-shim.d.ts +10 -0
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +14 -1
- package/dist/types/internal-urls/registry-helpers.d.ts +11 -0
- package/dist/types/live/controller.d.ts +40 -0
- package/dist/types/live/protocol.d.ts +85 -0
- package/dist/types/live/protocol.test.d.ts +1 -0
- package/dist/types/live/transport.d.ts +48 -0
- package/dist/types/live/visualizer.d.ts +33 -0
- package/dist/types/lsp/client.d.ts +18 -1
- package/dist/types/mcp/config-writer.test.d.ts +1 -0
- package/dist/types/mcp/manager.d.ts +6 -2
- package/dist/types/mcp/oauth-discovery.d.ts +2 -0
- package/dist/types/mcp/render.d.ts +2 -2
- package/dist/types/mcp/smithery-auth.d.ts +1 -1
- package/dist/types/mcp/smithery-auth.test.d.ts +1 -0
- package/dist/types/mcp/tool-bridge.d.ts +7 -3
- package/dist/types/mcp/types.d.ts +6 -0
- package/dist/types/memory-backend/tool-names.d.ts +2 -0
- package/dist/types/modes/components/login-dialog.d.ts +2 -2
- package/dist/types/modes/components/oauth-selector.d.ts +8 -0
- package/dist/types/modes/components/plan-review-overlay.d.ts +26 -0
- package/dist/types/modes/components/settings-defs.d.ts +8 -1
- package/dist/types/modes/components/status-line/component.jj-cache.test.d.ts +1 -0
- package/dist/types/modes/components/tool-execution.d.ts +9 -1
- package/dist/types/modes/controllers/command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/event-controller.d.ts +6 -1
- package/dist/types/modes/controllers/live-command-controller.d.ts +14 -0
- package/dist/types/modes/controllers/mcp-command-controller.d.ts +3 -0
- package/dist/types/modes/interactive-mode.d.ts +5 -0
- package/dist/types/modes/rpc/rpc-client.d.ts +10 -1
- package/dist/types/modes/rpc/rpc-frame.d.ts +16 -0
- package/dist/types/modes/rpc/rpc-messages.d.ts +26 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +40 -0
- package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +1 -1
- package/dist/types/modes/setup-wizard/scenes/types.d.ts +9 -1
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +1 -1
- package/dist/types/modes/theme/theme.d.ts +1 -1
- package/dist/types/modes/types.d.ts +3 -1
- package/dist/types/modes/utils/context-usage.d.ts +12 -2
- package/dist/types/plan-mode/plan-files.d.ts +10 -0
- package/dist/types/registry/agent-lifecycle.d.ts +21 -9
- package/dist/types/registry/agent-registry.d.ts +11 -4
- package/dist/types/sdk.d.ts +15 -1
- package/dist/types/secrets/index.d.ts +15 -2
- package/dist/types/secrets/obfuscator.d.ts +113 -15
- package/dist/types/session/acp-permission-gate.d.ts +19 -0
- package/dist/types/session/agent-session-events.d.ts +84 -0
- package/dist/types/session/agent-session-types.d.ts +314 -0
- package/dist/types/session/agent-session.d.ts +120 -750
- package/dist/types/session/async-job-delivery.d.ts +28 -0
- package/dist/types/session/bash-runner.d.ts +75 -0
- package/dist/types/session/blob-store.d.ts +11 -1
- package/dist/types/session/blob-store.test.d.ts +1 -0
- package/dist/types/session/checkpoint-entries.d.ts +28 -0
- package/dist/types/session/eval-runner.d.ts +49 -0
- package/dist/types/session/irc-bridge.d.ts +46 -0
- package/dist/types/session/messages.d.ts +22 -0
- package/dist/types/session/model-controls.d.ts +180 -0
- package/dist/types/session/prewalk.d.ts +46 -0
- package/dist/types/session/queued-messages.d.ts +22 -0
- package/dist/types/session/redis-session-storage.d.ts +1 -0
- package/dist/types/session/retry-fallback-chains.d.ts +74 -0
- package/dist/types/session/role-models.d.ts +15 -0
- package/dist/types/session/session-advisors.d.ts +228 -0
- package/dist/types/session/session-entries.d.ts +8 -0
- package/dist/types/session/session-handoff.d.ts +70 -0
- package/dist/types/session/session-history-format.d.ts +6 -1
- package/dist/types/session/session-loader.d.ts +6 -4
- package/dist/types/session/session-maintenance.d.ts +246 -0
- package/dist/types/session/session-manager.d.ts +41 -0
- package/dist/types/session/session-memory.d.ts +56 -0
- package/dist/types/session/session-provider-boundary.d.ts +62 -0
- package/dist/types/session/session-stats.d.ts +48 -0
- package/dist/types/session/session-tools.d.ts +143 -0
- package/dist/types/session/session-workspace.d.ts +32 -0
- package/dist/types/session/stream-guards.d.ts +44 -0
- package/dist/types/session/todo-tracker.d.ts +56 -0
- package/dist/types/session/ttsr-coordinator.d.ts +51 -0
- package/dist/types/session/turn-recovery.d.ts +225 -0
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +4 -1
- package/dist/types/task/output-manager.d.ts +3 -1
- package/dist/types/task/types.d.ts +14 -0
- package/dist/types/tools/approval.d.ts +1 -0
- package/dist/types/tools/browser/launch.d.ts +5 -0
- package/dist/types/tools/hub/jobs.d.ts +1 -1
- package/dist/types/tools/image-gen.d.ts +4 -4
- package/dist/types/tools/image-providers.d.ts +38 -0
- package/dist/types/tools/index.d.ts +8 -0
- package/dist/types/tools/path-utils.d.ts +8 -0
- package/dist/types/tools/report-tool-issue.d.ts +24 -9
- package/dist/types/tools/todo.d.ts +10 -4
- package/dist/types/tools/xdev.d.ts +5 -1
- package/dist/types/tts/streaming-player.d.ts +14 -0
- package/dist/types/tts/vocalizer.d.ts +5 -0
- package/dist/types/utils/jj.d.ts +29 -0
- package/dist/types/utils/lang-from-path.d.ts +1 -0
- package/dist/types/utils/title-generator.d.ts +30 -0
- package/dist/types/vibe/runtime.d.ts +36 -8
- package/dist/types/web/search/index.d.ts +1 -1
- package/dist/types/web/search/provider.d.ts +15 -5
- package/dist/types/web/search/providers/firecrawl.d.ts +9 -0
- package/dist/types/web/search/types.d.ts +95 -1
- package/package.json +13 -12
- package/scripts/generate-share-viewer.ts +4 -6
- package/scripts/legacy-pi-virtual-module.ts +1 -1
- package/src/advisor/__tests__/advisor.test.ts +643 -0
- package/src/advisor/runtime.ts +144 -43
- package/src/async/job-manager.ts +90 -2
- package/src/cli/args.ts +2 -0
- package/src/cli/auth-gateway-cli.ts +18 -3
- package/src/cli/bench-cli.ts +395 -29
- package/src/cli/flag-tables.ts +3 -0
- package/src/cli/gc-cli.ts +2 -2
- package/src/cli/grievances-cli.ts +2 -2
- package/src/cli/usage-cli.ts +11 -2
- package/src/collab/host.ts +3 -2
- package/src/commands/bench.ts +18 -4
- package/src/commands/launch.ts +4 -0
- package/src/config/__tests__/model-registry.test.ts +147 -0
- package/src/config/model-registry.ts +50 -2
- package/src/config/model-resolver.ts +0 -1
- package/src/config/models-config-schema.ts +15 -4
- package/src/config/provider-globals.ts +9 -9
- package/src/config/service-tier.ts +26 -1
- package/src/config/settings-schema.ts +250 -54
- package/src/config/settings.ts +81 -2
- package/src/dap/client.ts +37 -4
- package/src/edit/index.ts +49 -12
- package/src/eval/py/executor.ts +103 -33
- package/src/exec/bash-executor.ts +89 -6
- package/src/exec/direnv.ts +145 -0
- package/src/export/html/args.ts +20 -0
- package/src/export/html/index.ts +45 -47
- package/src/export/html/template.css +19 -1
- package/src/export/html/template.html +6 -0
- package/src/export/html/template.js +21 -0
- package/src/export/html/tool-views.generated.js +31 -31
- package/src/export/html/web-palette.ts +116 -132
- package/src/export/share.ts +249 -49
- package/src/extensibility/extensions/loader.ts +29 -1
- package/src/extensibility/extensions/runner.ts +6 -0
- package/src/extensibility/extensions/types.ts +33 -2
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +1 -0
- package/src/extensibility/legacy-pi-tui-shim.ts +10 -0
- package/src/extensibility/plugins/legacy-pi-compat.ts +870 -311
- package/src/hindsight/state.ts +64 -6
- package/src/internal-urls/local-protocol.ts +2 -1
- package/src/internal-urls/memory-protocol.ts +2 -2
- package/src/internal-urls/registry-helpers.ts +40 -0
- package/src/internal-urls/skill-protocol.ts +2 -2
- package/src/internal-urls/ssh-protocol.ts +2 -1
- package/src/internal-urls/vault-protocol.ts +2 -1
- package/src/live/audio-worklet.txt +59 -0
- package/src/live/browser-runtime.txt +221 -0
- package/src/live/controller.ts +464 -0
- package/src/live/prompts/agent-final-message.md +3 -0
- package/src/live/prompts/live-instructions.md +23 -0
- package/src/live/protocol.test.ts +140 -0
- package/src/live/protocol.ts +233 -0
- package/src/live/transport.ts +490 -0
- package/src/live/visualizer.ts +234 -0
- package/src/lsp/client.ts +52 -9
- package/src/lsp/clients/biome-client.ts +3 -4
- package/src/lsp/index.ts +44 -11
- package/src/main.ts +9 -1
- package/src/mcp/config-writer.test.ts +43 -0
- package/src/mcp/config-writer.ts +109 -82
- package/src/mcp/manager.ts +39 -8
- package/src/mcp/oauth-discovery.ts +10 -2
- package/src/mcp/render.ts +94 -35
- package/src/mcp/smithery-auth.test.ts +29 -0
- package/src/mcp/smithery-auth.ts +3 -2
- package/src/mcp/tool-bridge.ts +107 -11
- package/src/mcp/types.ts +7 -0
- package/src/memories/index.ts +40 -20
- package/src/memory-backend/tool-names.ts +2 -0
- package/src/mnemopi/backend.ts +24 -7
- package/src/modes/acp/acp-agent.ts +56 -10
- package/src/modes/acp/acp-event-mapper.ts +8 -1
- package/src/modes/components/agent-hub.ts +27 -10
- package/src/modes/components/login-dialog.ts +14 -4
- package/src/modes/components/oauth-selector.ts +24 -7
- package/src/modes/components/plan-review-overlay.ts +350 -35
- package/src/modes/components/settings-defs.ts +28 -3
- package/src/modes/components/settings-selector.ts +178 -6
- package/src/modes/components/status-line/component.jj-cache.test.ts +229 -0
- package/src/modes/components/status-line/component.ts +123 -2
- package/src/modes/components/tool-execution.test.ts +63 -2
- package/src/modes/components/tool-execution.ts +11 -2
- package/src/modes/controllers/command-controller.ts +70 -22
- package/src/modes/controllers/event-controller.ts +111 -16
- package/src/modes/controllers/extension-ui-controller.test.ts +1 -0
- package/src/modes/controllers/extension-ui-controller.ts +20 -4
- package/src/modes/controllers/live-command-controller.ts +178 -0
- package/src/modes/controllers/mcp-command-controller.ts +80 -41
- package/src/modes/controllers/omfg-controller.ts +44 -40
- package/src/modes/controllers/selector-controller.ts +18 -10
- package/src/modes/controllers/session-focus-controller.ts +6 -1
- package/src/modes/interactive-mode.ts +160 -38
- package/src/modes/rpc/rpc-client.ts +94 -3
- package/src/modes/rpc/rpc-frame.ts +164 -4
- package/src/modes/rpc/rpc-messages.ts +127 -0
- package/src/modes/rpc/rpc-mode.ts +79 -7
- package/src/modes/rpc/rpc-types.ts +34 -2
- package/src/modes/runtime-init.ts +2 -0
- package/src/modes/setup-wizard/scenes/model.ts +5 -7
- package/src/modes/setup-wizard/scenes/providers.ts +3 -2
- package/src/modes/setup-wizard/scenes/sign-in.ts +8 -2
- package/src/modes/setup-wizard/scenes/theme.ts +13 -3
- package/src/modes/setup-wizard/scenes/types.ts +9 -1
- package/src/modes/setup-wizard/scenes/web-search.ts +23 -10
- package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
- package/src/modes/theme/theme.ts +1 -1
- package/src/modes/types.ts +3 -1
- package/src/modes/utils/context-usage.ts +23 -7
- package/src/modes/utils/ui-helpers.ts +10 -5
- package/src/plan-mode/plan-files.ts +40 -0
- package/src/prompts/bench/cache-prefix-chunk.md +1 -0
- package/src/prompts/bench/cache-prefix.md +3 -0
- package/src/prompts/bench/cache-suffix.md +1 -0
- package/src/prompts/goals/guided-goal-system.md +24 -3
- package/src/prompts/system/custom-system-prompt.md +1 -1
- package/src/prompts/system/project-prompt.md +8 -1
- package/src/prompts/system/subagent-async-pending.md +6 -0
- package/src/prompts/system/system-prompt.md +1 -1
- package/src/prompts/system/workflow-notice.md +48 -40
- package/src/prompts/system/xdev-mount-notice.md +4 -0
- package/src/prompts/tools/task.md +12 -2
- package/src/prompts/tools/todo.md +3 -1
- package/src/registry/agent-lifecycle.ts +116 -46
- package/src/registry/agent-registry.ts +35 -8
- package/src/registry/persisted-agents.ts +26 -2
- package/src/sdk.ts +255 -139
- package/src/secrets/index.ts +127 -4
- package/src/secrets/obfuscator.ts +2328 -105
- package/src/session/acp-permission-gate.ts +165 -0
- package/src/session/agent-session-error-log.test.ts +1 -1
- package/src/session/agent-session-events.ts +66 -0
- package/src/session/agent-session-types.ts +334 -0
- package/src/session/agent-session.ts +1910 -12213
- package/src/session/artifacts.ts +6 -5
- package/src/session/async-job-delivery.ts +74 -0
- package/src/session/bash-runner.ts +326 -0
- package/src/session/blob-store.test.ts +56 -0
- package/src/session/blob-store.ts +18 -2
- package/src/session/checkpoint-entries.ts +81 -0
- package/src/session/eval-runner.ts +212 -0
- package/src/session/indexed-session-storage.ts +9 -2
- package/src/session/irc-bridge.ts +203 -0
- package/src/session/messages.ts +263 -1
- package/src/session/model-controls.ts +714 -0
- package/src/session/prewalk.ts +252 -0
- package/src/session/queued-messages.ts +93 -0
- package/src/session/redis-session-storage.ts +51 -11
- package/src/session/retry-fallback-chains.ts +455 -0
- package/src/session/role-models.ts +85 -0
- package/src/session/session-advisors.ts +1679 -0
- package/src/session/session-context.test.ts +224 -1
- package/src/session/session-context.ts +47 -5
- package/src/session/session-entries.ts +8 -0
- package/src/session/session-handoff.ts +308 -0
- package/src/session/session-history-format.ts +20 -9
- package/src/session/session-loader.ts +10 -51
- package/src/session/session-maintenance.ts +2983 -0
- package/src/session/session-manager.ts +390 -30
- package/src/session/session-memory.ts +222 -0
- package/src/session/session-provider-boundary.ts +307 -0
- package/src/session/session-stats.ts +293 -0
- package/src/session/session-tools.ts +943 -0
- package/src/session/session-workspace.ts +53 -0
- package/src/session/stream-guards.ts +417 -0
- package/src/session/todo-tracker.ts +380 -0
- package/src/session/ttsr-coordinator.ts +496 -0
- package/src/session/turn-recovery.ts +1629 -0
- package/src/slash-commands/builtin-registry.ts +92 -11
- package/src/slash-commands/helpers/usage-report.ts +25 -4
- package/src/system-prompt.ts +41 -17
- package/src/task/executor.ts +288 -70
- package/src/task/index.ts +148 -111
- package/src/task/output-manager.ts +25 -3
- package/src/task/persisted-revive.ts +4 -3
- package/src/task/structured-subagent.ts +4 -1
- package/src/task/types.ts +16 -0
- package/src/tools/approval.ts +55 -10
- package/src/tools/bash-interactive.ts +26 -0
- package/src/tools/bash-skill-urls.ts +28 -2
- package/src/tools/bash.ts +339 -123
- package/src/tools/browser/launch.ts +9 -1
- package/src/tools/browser/tab-supervisor.ts +8 -5
- package/src/tools/browser.ts +94 -47
- package/src/tools/hub/index.ts +1 -1
- package/src/tools/hub/jobs.ts +67 -8
- package/src/tools/image-gen.ts +20 -28
- package/src/tools/image-providers.ts +50 -0
- package/src/tools/index.ts +12 -0
- package/src/tools/path-utils.ts +49 -2
- package/src/tools/read.ts +156 -88
- package/src/tools/renderers.ts +7 -1
- package/src/tools/report-tool-issue.ts +79 -28
- package/src/tools/todo.ts +101 -11
- package/src/tools/vibe.ts +1 -2
- package/src/tools/write.ts +51 -1
- package/src/tools/xdev.ts +67 -3
- package/src/tts/streaming-player.ts +62 -4
- package/src/tts/vocalizer.ts +18 -1
- package/src/utils/jj.ts +125 -4
- package/src/utils/lang-from-path.ts +7 -0
- package/src/utils/title-generator.ts +137 -1
- package/src/vibe/runtime.ts +852 -72
- package/src/web/search/index.ts +3 -6
- package/src/web/search/provider.ts +31 -16
- package/src/web/search/providers/firecrawl.ts +46 -13
- package/src/web/search/providers/xai.ts +7 -1
- package/src/web/search/types.ts +8 -1
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { logger } from "@oh-my-pi/pi-utils";
|
|
2
|
+
import { LiveSessionController } from "../../live/controller";
|
|
3
|
+
import { LiveVisualizer } from "../../live/visualizer";
|
|
4
|
+
import { vocalizer } from "../../tts/vocalizer";
|
|
5
|
+
import type { CustomEditor } from "../components/custom-editor";
|
|
6
|
+
import type { InteractiveModeContext } from "../types";
|
|
7
|
+
|
|
8
|
+
const ANIMATION_INTERVAL_MS = 80;
|
|
9
|
+
|
|
10
|
+
function errorFrom(cause: unknown): Error {
|
|
11
|
+
return cause instanceof Error ? cause : new Error(String(cause));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Owns the editor-replacing visualizer and realtime session lifecycle for `/live`. */
|
|
15
|
+
export class LiveCommandController {
|
|
16
|
+
readonly #ctx: InteractiveModeContext;
|
|
17
|
+
|
|
18
|
+
#session: LiveSessionController | undefined;
|
|
19
|
+
#settling: Promise<void> | undefined;
|
|
20
|
+
#visualizer: LiveVisualizer | undefined;
|
|
21
|
+
#detachedEditor: CustomEditor | undefined;
|
|
22
|
+
#animationInterval: NodeJS.Timeout | undefined;
|
|
23
|
+
#previousShowHardwareCursor: boolean | undefined;
|
|
24
|
+
#previousUseTerminalCursor: boolean | undefined;
|
|
25
|
+
#resumeVocalizer: (() => void) | undefined;
|
|
26
|
+
|
|
27
|
+
constructor(ctx: InteractiveModeContext) {
|
|
28
|
+
this.#ctx = ctx;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Whether a live session is connected, connecting, or closing. */
|
|
32
|
+
get active(): boolean {
|
|
33
|
+
return this.#session !== undefined || this.#settling !== undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Start live mode, or stop the currently active session. */
|
|
37
|
+
async handleCommand(): Promise<void> {
|
|
38
|
+
if (this.#session) {
|
|
39
|
+
await this.stop();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (this.#settling) await this.#settling;
|
|
43
|
+
await this.#start();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Stop the active live session and restore the editor. */
|
|
47
|
+
async stop(): Promise<void> {
|
|
48
|
+
const session = this.#session;
|
|
49
|
+
if (!session) {
|
|
50
|
+
if (this.#settling) await this.#settling;
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
await session.stop();
|
|
55
|
+
} catch (cause) {
|
|
56
|
+
this.#finish(session, errorFrom(cause));
|
|
57
|
+
} finally {
|
|
58
|
+
this.#finish(session);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Release UI resources during synchronous InteractiveMode teardown. */
|
|
63
|
+
dispose(): void {
|
|
64
|
+
const session = this.#session;
|
|
65
|
+
if (session) {
|
|
66
|
+
this.#finish(session);
|
|
67
|
+
void session.stop().catch(cause => {
|
|
68
|
+
logger.debug("Live session teardown failed", { error: errorFrom(cause).message });
|
|
69
|
+
});
|
|
70
|
+
} else {
|
|
71
|
+
this.#restoreEditor();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async #start(): Promise<void> {
|
|
76
|
+
const visualizer = new LiveVisualizer({
|
|
77
|
+
onStop: () => {
|
|
78
|
+
void this.stop().catch(cause => this.#ctx.showError(errorFrom(cause).message));
|
|
79
|
+
},
|
|
80
|
+
onToggleMute: () => this.#session?.toggleMute(),
|
|
81
|
+
});
|
|
82
|
+
this.#mountVisualizer(visualizer);
|
|
83
|
+
|
|
84
|
+
let session: LiveSessionController;
|
|
85
|
+
session = new LiveSessionController({
|
|
86
|
+
session: this.#ctx.session,
|
|
87
|
+
extractAssistantText: message => this.#ctx.extractAssistantText(message),
|
|
88
|
+
callbacks: {
|
|
89
|
+
onPhase: phase => {
|
|
90
|
+
if (this.#visualizer !== visualizer) return;
|
|
91
|
+
visualizer.setPhase(phase);
|
|
92
|
+
this.#ctx.ui.requestComponentRender(visualizer);
|
|
93
|
+
},
|
|
94
|
+
onLevels: (input, output) => {
|
|
95
|
+
if (this.#visualizer !== visualizer) return;
|
|
96
|
+
visualizer.setLevels(input, output);
|
|
97
|
+
this.#ctx.ui.requestComponentRender(visualizer);
|
|
98
|
+
},
|
|
99
|
+
onTranscript: transcript => {
|
|
100
|
+
if (this.#visualizer !== visualizer) return;
|
|
101
|
+
visualizer.setTranscript(transcript);
|
|
102
|
+
this.#ctx.ui.requestComponentRender(visualizer);
|
|
103
|
+
},
|
|
104
|
+
onTerminal: error => this.#finish(session, error),
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
this.#session = session;
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
await session.start();
|
|
111
|
+
} catch (cause) {
|
|
112
|
+
if (this.#session === session) {
|
|
113
|
+
await session.stop();
|
|
114
|
+
this.#finish(session, errorFrom(cause));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
#mountVisualizer(visualizer: LiveVisualizer): void {
|
|
120
|
+
this.#visualizer = visualizer;
|
|
121
|
+
this.#detachedEditor = this.#ctx.editor;
|
|
122
|
+
this.#previousShowHardwareCursor = this.#ctx.ui.getShowHardwareCursor();
|
|
123
|
+
this.#previousUseTerminalCursor = this.#ctx.editor.getUseTerminalCursor();
|
|
124
|
+
this.#ctx.ui.setShowHardwareCursor(false);
|
|
125
|
+
this.#ctx.editor.setUseTerminalCursor(false);
|
|
126
|
+
this.#ctx.editorContainer.clear();
|
|
127
|
+
this.#ctx.editorContainer.addChild(visualizer);
|
|
128
|
+
this.#ctx.ui.setFocus(visualizer);
|
|
129
|
+
this.#resumeVocalizer = vocalizer.suspend();
|
|
130
|
+
let frame = 0;
|
|
131
|
+
this.#animationInterval = setInterval(() => {
|
|
132
|
+
if (this.#visualizer !== visualizer) return;
|
|
133
|
+
frame += 1;
|
|
134
|
+
visualizer.setFrame(frame);
|
|
135
|
+
this.#ctx.ui.requestComponentRender(visualizer);
|
|
136
|
+
}, ANIMATION_INTERVAL_MS);
|
|
137
|
+
this.#ctx.ui.requestRender();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
#finish(session: LiveSessionController, error?: Error): void {
|
|
141
|
+
if (this.#session !== session) return;
|
|
142
|
+
this.#session = undefined;
|
|
143
|
+
this.#restoreEditor();
|
|
144
|
+
if (error) this.#ctx.showError(error.message);
|
|
145
|
+
const settling = session.stop().catch(cause => {
|
|
146
|
+
logger.debug("Live session cleanup failed", { error: errorFrom(cause).message });
|
|
147
|
+
});
|
|
148
|
+
this.#settling = settling;
|
|
149
|
+
void settling.finally(() => {
|
|
150
|
+
if (this.#settling === settling) this.#settling = undefined;
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#restoreEditor(): void {
|
|
155
|
+
if (this.#animationInterval) {
|
|
156
|
+
clearInterval(this.#animationInterval);
|
|
157
|
+
this.#animationInterval = undefined;
|
|
158
|
+
}
|
|
159
|
+
this.#resumeVocalizer?.();
|
|
160
|
+
this.#resumeVocalizer = undefined;
|
|
161
|
+
const editor = this.#detachedEditor;
|
|
162
|
+
this.#detachedEditor = undefined;
|
|
163
|
+
this.#visualizer = undefined;
|
|
164
|
+
if (!editor) return;
|
|
165
|
+
this.#ctx.editorContainer.clear();
|
|
166
|
+
this.#ctx.editorContainer.addChild(editor);
|
|
167
|
+
if (this.#previousShowHardwareCursor !== undefined) {
|
|
168
|
+
this.#ctx.ui.setShowHardwareCursor(this.#previousShowHardwareCursor);
|
|
169
|
+
}
|
|
170
|
+
if (this.#previousUseTerminalCursor !== undefined) {
|
|
171
|
+
editor.setUseTerminalCursor(this.#previousUseTerminalCursor);
|
|
172
|
+
}
|
|
173
|
+
this.#previousShowHardwareCursor = undefined;
|
|
174
|
+
this.#previousUseTerminalCursor = undefined;
|
|
175
|
+
this.#ctx.ui.setFocus(editor);
|
|
176
|
+
this.#ctx.ui.requestRender();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
getSmitheryApiKey,
|
|
39
39
|
getSmitheryLoginUrl,
|
|
40
40
|
pollSmitheryCliAuthSession,
|
|
41
|
+
type SmitheryCliPollResponse,
|
|
41
42
|
saveSmitheryApiKey,
|
|
42
43
|
} from "../../mcp/smithery-auth";
|
|
43
44
|
import { SmitheryConnectError } from "../../mcp/smithery-connect";
|
|
@@ -47,10 +48,11 @@ import {
|
|
|
47
48
|
searchSmitheryRegistry,
|
|
48
49
|
toConfigName,
|
|
49
50
|
} from "../../mcp/smithery-registry";
|
|
50
|
-
import type { MCPAuthConfig, MCPServerConfig, MCPServerConnection } from "../../mcp/types";
|
|
51
|
+
import type { MCPAuthChallenge, MCPAuthConfig, MCPServerConfig, MCPServerConnection } from "../../mcp/types";
|
|
51
52
|
import { shortenPath } from "../../tools/render-utils";
|
|
52
53
|
import { urlHyperlinkAlways } from "../../tui";
|
|
53
54
|
import { copyToClipboard } from "../../utils/clipboard";
|
|
55
|
+
import { isTimeoutError } from "../../utils/fetch-timeout";
|
|
54
56
|
import { openPath } from "../../utils/open";
|
|
55
57
|
import { ChatBlock } from "../components/chat-block";
|
|
56
58
|
import { MCPAddWizard } from "../components/mcp-add-wizard";
|
|
@@ -1042,7 +1044,10 @@ export class MCPCommandController {
|
|
|
1042
1044
|
return next;
|
|
1043
1045
|
}
|
|
1044
1046
|
|
|
1045
|
-
async #resolveOAuthEndpointsFromServer(
|
|
1047
|
+
async #resolveOAuthEndpointsFromServer(
|
|
1048
|
+
config: MCPServerConfig,
|
|
1049
|
+
authChallenge?: MCPAuthChallenge,
|
|
1050
|
+
): Promise<OAuthEndpoints> {
|
|
1046
1051
|
// Stdio servers manage credentials inside the child process; OMP's OAuth
|
|
1047
1052
|
// flow only applies to http/sse transports. Without this guard the
|
|
1048
1053
|
// unauthenticated preflight below spawns the child, which happily reuses
|
|
@@ -1068,13 +1073,20 @@ export class MCPCommandController {
|
|
|
1068
1073
|
connectionError = error as Error;
|
|
1069
1074
|
}
|
|
1070
1075
|
|
|
1071
|
-
// Server connected fine without auth — reauth is not needed
|
|
1072
|
-
|
|
1076
|
+
// Server connected fine without auth — reauth is not needed. A tool-level
|
|
1077
|
+
// challenge overrides this: servers may allow the anonymous handshake yet
|
|
1078
|
+
// protect individual tool calls with `_meta["mcp/www_authenticate"]`.
|
|
1079
|
+
if (connectionSucceeded && !authChallenge) {
|
|
1073
1080
|
throw new Error("Server connection succeeded without OAuth; reauthorization is not required.");
|
|
1074
1081
|
}
|
|
1075
1082
|
|
|
1076
|
-
//
|
|
1077
|
-
|
|
1083
|
+
// Tool calls can carry richer RFC 6750/RFC 9728 hints than the original
|
|
1084
|
+
// connection error. Feed those hints through the same analyzer so
|
|
1085
|
+
// resource_metadata and scope reach protected-resource discovery.
|
|
1086
|
+
const authError = authChallenge
|
|
1087
|
+
? new Error(`${connectionError?.message ?? "HTTP 401"}\n${authChallenge.wwwAuthenticate.join("\n")}`)
|
|
1088
|
+
: connectionError!;
|
|
1089
|
+
const authResult = analyzeAuthError(authError, "url" in config ? config.url : undefined);
|
|
1078
1090
|
let oauth = authResult.authType === "oauth" ? (authResult.oauth ?? null) : null;
|
|
1079
1091
|
|
|
1080
1092
|
if (!oauth && (config.type === "http" || config.type === "sse") && config.url) {
|
|
@@ -1678,21 +1690,29 @@ export class MCPCommandController {
|
|
|
1678
1690
|
}
|
|
1679
1691
|
}
|
|
1680
1692
|
|
|
1681
|
-
|
|
1693
|
+
/** Reauthorize a server after a tool-level OAuth challenge. */
|
|
1694
|
+
async handleMCPAuthChallenge(name: string, challenge: MCPAuthChallenge): Promise<MCPServerConfig | undefined> {
|
|
1695
|
+
return this.#handleReauth(name, { silent: true, reload: false, authChallenge: challenge });
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
async #handleReauth(
|
|
1699
|
+
name: string | undefined,
|
|
1700
|
+
options: { silent?: boolean; reload?: boolean; authChallenge?: MCPAuthChallenge } = {},
|
|
1701
|
+
): Promise<MCPServerConfig | undefined> {
|
|
1682
1702
|
if (!name) {
|
|
1683
|
-
this.ctx.showError("Server name required. Usage: /mcp reauth <name>");
|
|
1703
|
+
if (!options.silent) this.ctx.showError("Server name required. Usage: /mcp reauth <name>");
|
|
1684
1704
|
return;
|
|
1685
1705
|
}
|
|
1686
1706
|
|
|
1687
1707
|
try {
|
|
1688
1708
|
const found = await this.#resolveServerForAuth(name);
|
|
1689
1709
|
if (!found) {
|
|
1690
|
-
this.ctx.showError(`Server "${name}" not found.`);
|
|
1710
|
+
if (!options.silent) this.ctx.showError(`Server "${name}" not found.`);
|
|
1691
1711
|
return;
|
|
1692
1712
|
}
|
|
1693
1713
|
|
|
1694
1714
|
if (found.config.enabled === false) {
|
|
1695
|
-
this.ctx.showError(`Server "${name}" is disabled. Run /mcp enable ${name} first.`);
|
|
1715
|
+
if (!options.silent) this.ctx.showError(`Server "${name}" is disabled. Run /mcp enable ${name} first.`);
|
|
1696
1716
|
return;
|
|
1697
1717
|
}
|
|
1698
1718
|
|
|
@@ -1705,7 +1725,7 @@ export class MCPCommandController {
|
|
|
1705
1725
|
// happened yet if the server turns out not to need (or support) OAuth.
|
|
1706
1726
|
// Use the same env-expanded config shape runtime discovery passes to
|
|
1707
1727
|
// MCPManager; the raw file value may contain `${...}` placeholders.
|
|
1708
|
-
const oauth = await this.#resolveOAuthEndpointsFromServer(runtimeBaseConfig);
|
|
1728
|
+
const oauth = await this.#resolveOAuthEndpointsFromServer(runtimeBaseConfig, options.authChallenge);
|
|
1709
1729
|
const serverUrl =
|
|
1710
1730
|
runtimeBaseConfig.type === "http" || runtimeBaseConfig.type === "sse" ? runtimeBaseConfig.url : undefined;
|
|
1711
1731
|
// A user-supplied client secret may live in either block (the wizard
|
|
@@ -1719,7 +1739,9 @@ export class MCPCommandController {
|
|
|
1719
1739
|
const userClientSecret = found.config.oauth?.clientSecret ?? currentAuth?.clientSecret;
|
|
1720
1740
|
const flowClientSecret = userClientSecret ?? storedClientSecret ?? "";
|
|
1721
1741
|
|
|
1722
|
-
|
|
1742
|
+
if (!options.silent) {
|
|
1743
|
+
this.#showMessage(["", theme.fg("muted", `Reauthorizing "${name}"...`), ""].join("\n"));
|
|
1744
|
+
}
|
|
1723
1745
|
|
|
1724
1746
|
const currentAuthResource = currentAuth?.resource ? expandEnvVarsDeep(currentAuth.resource) : undefined;
|
|
1725
1747
|
const oauthResource =
|
|
@@ -1755,39 +1777,49 @@ export class MCPCommandController {
|
|
|
1755
1777
|
// Definition-only entries resolve through the url-keyed binding alone;
|
|
1756
1778
|
// skip the write-back so a committed project mcp.json stays clean.
|
|
1757
1779
|
const urlKeyedId = serverUrl ? mcpOAuthCredentialId(serverUrl) : undefined;
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1780
|
+
const shouldPersist = currentAuth || oauthResult.credentialId !== urlKeyedId;
|
|
1781
|
+
const updatedConfig = shouldPersist
|
|
1782
|
+
? this.#persistOAuthResult(baseConfig, oauthResult, {
|
|
1783
|
+
tokenUrl: oauth.tokenUrl,
|
|
1784
|
+
clientId: oauth.clientId,
|
|
1785
|
+
userClientSecret,
|
|
1786
|
+
resource: oauthResource,
|
|
1787
|
+
stripSameOriginResource: oauthResourceIsFallback,
|
|
1788
|
+
})
|
|
1789
|
+
: baseConfig;
|
|
1790
|
+
if (shouldPersist) {
|
|
1791
|
+
await updateMCPServer(found.filePath, name, updatedConfig);
|
|
1792
|
+
}
|
|
1793
|
+
if (options.reload !== false) {
|
|
1794
|
+
await this.#reloadMCP();
|
|
1795
|
+
const state = await this.#waitForServerConnectionWithAnimation(name);
|
|
1770
1796
|
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1797
|
+
const lines = [
|
|
1798
|
+
"",
|
|
1799
|
+
theme.fg("success", `✓ Reauthorized "${name}" (${found.scope} config)`),
|
|
1800
|
+
"",
|
|
1801
|
+
` Status: ${
|
|
1802
|
+
state === "connected"
|
|
1803
|
+
? theme.fg("success", "connected")
|
|
1804
|
+
: state === "connecting"
|
|
1805
|
+
? theme.fg("muted", "connecting")
|
|
1806
|
+
: theme.fg("warning", "not connected")
|
|
1807
|
+
}`,
|
|
1808
|
+
"",
|
|
1809
|
+
];
|
|
1810
|
+
this.#showMessage(lines.join("\n"));
|
|
1811
|
+
}
|
|
1812
|
+
return updatedConfig;
|
|
1785
1813
|
} catch (error) {
|
|
1786
1814
|
if (error instanceof MCPOAuthCancelledError) {
|
|
1787
|
-
this.ctx.showStatus(`Reauthorization cancelled for "${name}"`);
|
|
1815
|
+
if (!options.silent) this.ctx.showStatus(`Reauthorization cancelled for "${name}"`);
|
|
1788
1816
|
return;
|
|
1789
1817
|
}
|
|
1790
|
-
|
|
1818
|
+
if (!options.silent) {
|
|
1819
|
+
this.ctx.showError(
|
|
1820
|
+
`Failed to reauthorize server: ${error instanceof Error ? error.message : String(error)}`,
|
|
1821
|
+
);
|
|
1822
|
+
}
|
|
1791
1823
|
}
|
|
1792
1824
|
}
|
|
1793
1825
|
|
|
@@ -2091,7 +2123,14 @@ export class MCPCommandController {
|
|
|
2091
2123
|
if (Date.now() - startedAt >= timeoutMs) {
|
|
2092
2124
|
throw new Error("Smithery authorization timed out after 5 minutes.");
|
|
2093
2125
|
}
|
|
2094
|
-
|
|
2126
|
+
let response: SmitheryCliPollResponse;
|
|
2127
|
+
try {
|
|
2128
|
+
response = await pollSmitheryCliAuthSession(sessionId, signal);
|
|
2129
|
+
} catch (error) {
|
|
2130
|
+
// A single hung/slow poll aborts with TimeoutError; retry until the deadline.
|
|
2131
|
+
if (isTimeoutError(error)) continue;
|
|
2132
|
+
throw error;
|
|
2133
|
+
}
|
|
2095
2134
|
if (response.status === "success" && response.apiKey) {
|
|
2096
2135
|
return response.apiKey;
|
|
2097
2136
|
}
|
|
@@ -192,56 +192,60 @@ export class OmfgController {
|
|
|
192
192
|
|
|
193
193
|
async #saveCandidate(request: OmfgRequest, candidate: OmfgCandidate): Promise<SaveCandidateResult> {
|
|
194
194
|
if (this.#shouldStop(request)) return { kind: "aborted" };
|
|
195
|
-
request.component.setStatus("saving", "Choose where to save or amend the TTSR rule…");
|
|
196
|
-
const location = await this.ctx.showHookSelector("Save TTSR rule where?", [
|
|
197
|
-
PROJECT_OPTION,
|
|
198
|
-
GLOBAL_OPTION,
|
|
199
|
-
AMEND_OPTION,
|
|
200
|
-
]);
|
|
201
|
-
if (!this.#isActiveRequest(request)) return { kind: "aborted" };
|
|
202
|
-
if (!location) {
|
|
203
|
-
request.component.markAborted();
|
|
204
|
-
this.#closeActiveRequest({ abort: false });
|
|
205
|
-
return { kind: "aborted" };
|
|
206
|
-
}
|
|
207
195
|
|
|
208
|
-
|
|
209
|
-
request.component.setStatus("
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
196
|
+
for (;;) {
|
|
197
|
+
request.component.setStatus("saving", "Choose where to save or amend the TTSR rule…");
|
|
198
|
+
const location = await this.ctx.showHookSelector("Save TTSR rule where?", [
|
|
199
|
+
PROJECT_OPTION,
|
|
200
|
+
GLOBAL_OPTION,
|
|
201
|
+
AMEND_OPTION,
|
|
202
|
+
]);
|
|
214
203
|
if (!this.#isActiveRequest(request)) return { kind: "aborted" };
|
|
215
|
-
|
|
216
|
-
if (!feedback) {
|
|
204
|
+
if (!location) {
|
|
217
205
|
request.component.markAborted();
|
|
218
206
|
this.#closeActiveRequest({ abort: false });
|
|
219
207
|
return { kind: "aborted" };
|
|
220
208
|
}
|
|
221
|
-
return { kind: "amend", feedback };
|
|
222
|
-
}
|
|
223
209
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
return { kind: "
|
|
210
|
+
if (location === AMEND_OPTION) {
|
|
211
|
+
request.component.setStatus("confirming", "Describe how to amend the rule…");
|
|
212
|
+
const amendment = await this.ctx.showHookInput(
|
|
213
|
+
"Amend TTSR rule",
|
|
214
|
+
"e.g. Make it specific to Ruby string eval in tool:write(*.rb)",
|
|
215
|
+
);
|
|
216
|
+
if (!this.#isActiveRequest(request)) return { kind: "aborted" };
|
|
217
|
+
const feedback = amendment?.trim();
|
|
218
|
+
if (!feedback) continue;
|
|
219
|
+
return { kind: "amend", feedback };
|
|
234
220
|
}
|
|
235
|
-
}
|
|
236
221
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
222
|
+
const target = this.#resolveTarget(location, candidate.rule.name);
|
|
223
|
+
if (await Bun.file(target.filePath).exists()) {
|
|
224
|
+
const shouldOverwrite = await this.ctx.showHookConfirm(
|
|
225
|
+
"Overwrite TTSR rule?",
|
|
226
|
+
`${shortenPath(target.filePath)} already exists. Overwrite it?`,
|
|
227
|
+
);
|
|
228
|
+
if (!this.#isActiveRequest(request)) return { kind: "aborted" };
|
|
229
|
+
if (!shouldOverwrite) {
|
|
230
|
+
request.component.markRejected();
|
|
231
|
+
return { kind: "rejected" };
|
|
232
|
+
}
|
|
233
|
+
}
|
|
240
234
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
235
|
+
request.component.setStatus("saving", `Saving ${candidate.rule.name}…`);
|
|
236
|
+
await Bun.write(target.filePath, candidate.fileContent);
|
|
237
|
+
if (!this.#isActiveRequest(request)) return { kind: "aborted" };
|
|
238
|
+
|
|
239
|
+
const savedRule = buildOmfgRuleForPath(
|
|
240
|
+
candidate.rule.name,
|
|
241
|
+
candidate.fileContent,
|
|
242
|
+
target.filePath,
|
|
243
|
+
target.level,
|
|
244
|
+
);
|
|
245
|
+
this.#registerLive(savedRule);
|
|
246
|
+
request.component.markSaved(shortenPath(target.filePath));
|
|
247
|
+
return { kind: "saved" };
|
|
248
|
+
}
|
|
245
249
|
}
|
|
246
250
|
|
|
247
251
|
#resolveTarget(location: string, ruleName: string): { filePath: string; level: OmfgRuleSourceLevel } {
|
|
@@ -57,12 +57,10 @@ import {
|
|
|
57
57
|
parseConfiguredThinkingLevel,
|
|
58
58
|
} from "../../thinking";
|
|
59
59
|
import {
|
|
60
|
-
isImageProviderPreference,
|
|
61
60
|
isSearchProviderId,
|
|
62
|
-
isSearchProviderPreference,
|
|
63
61
|
setExcludedSearchProviders,
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
setImageProviderOrder,
|
|
63
|
+
setSearchProviderOrder,
|
|
66
64
|
type ToolSession,
|
|
67
65
|
} from "../../tools";
|
|
68
66
|
import { AskTool, type AskToolDetails, type AskToolInput } from "../../tools/ask";
|
|
@@ -439,6 +437,16 @@ export class SelectorController {
|
|
|
439
437
|
this.ctx.showError(`Failed to apply personality: ${err}`);
|
|
440
438
|
});
|
|
441
439
|
break;
|
|
440
|
+
case "tools.xdevDocs":
|
|
441
|
+
void this.ctx.session.refreshBaseSystemPrompt().catch(err => {
|
|
442
|
+
this.ctx.showError(`Failed to apply xd:// prompt docs setting: ${err}`);
|
|
443
|
+
});
|
|
444
|
+
break;
|
|
445
|
+
case "memory.backend":
|
|
446
|
+
void this.ctx.session.applyMemoryBackend().catch(err => {
|
|
447
|
+
this.ctx.showError(`Failed to apply memory backend: ${err}`);
|
|
448
|
+
});
|
|
449
|
+
break;
|
|
442
450
|
|
|
443
451
|
case "autocompleteMaxVisible":
|
|
444
452
|
this.ctx.editor.setAutocompleteMaxVisible(typeof value === "number" ? value : Number(value));
|
|
@@ -609,9 +617,9 @@ export class SelectorController {
|
|
|
609
617
|
}
|
|
610
618
|
|
|
611
619
|
// Provider settings - update runtime preferences
|
|
612
|
-
case "providers.
|
|
613
|
-
if (
|
|
614
|
-
|
|
620
|
+
case "providers.webSearchOrder":
|
|
621
|
+
if (Array.isArray(value)) {
|
|
622
|
+
setSearchProviderOrder(value.filter(isSearchProviderId));
|
|
615
623
|
}
|
|
616
624
|
break;
|
|
617
625
|
case "providers.webSearchExclude":
|
|
@@ -619,9 +627,9 @@ export class SelectorController {
|
|
|
619
627
|
setExcludedSearchProviders(value.filter(isSearchProviderId));
|
|
620
628
|
}
|
|
621
629
|
break;
|
|
622
|
-
case "providers.
|
|
623
|
-
if (
|
|
624
|
-
|
|
630
|
+
case "providers.imageOrder":
|
|
631
|
+
if (Array.isArray(value)) {
|
|
632
|
+
setImageProviderOrder(value.filter((entry): entry is string => typeof entry === "string"));
|
|
625
633
|
}
|
|
626
634
|
break;
|
|
627
635
|
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { AgentLifecycleManager } from "../../registry/agent-lifecycle";
|
|
13
13
|
import { AgentRegistry, MAIN_AGENT_ID, type RegistryEvent } from "../../registry/agent-registry";
|
|
14
14
|
import type { AgentSession } from "../../session/agent-session";
|
|
15
|
+
import { setTerminalTitleState } from "../../utils/title-generator";
|
|
15
16
|
import type { InteractiveModeContext } from "../types";
|
|
16
17
|
|
|
17
18
|
export class SessionFocusController {
|
|
@@ -104,8 +105,12 @@ export class SessionFocusController {
|
|
|
104
105
|
});
|
|
105
106
|
this.ctx.statusLine.setSession(target, this.#focusedAgentId);
|
|
106
107
|
this.ctx.renderInitialMessages({ clearTerminalHistory: true });
|
|
107
|
-
//
|
|
108
|
+
// Sync the run-state title to the attached target: a streaming target has no
|
|
109
|
+
// agent_start incoming, so arm the loader/working title manually; an idle
|
|
110
|
+
// target would otherwise inherit the previous session's stuck spinner, so
|
|
111
|
+
// reset it to idle (agent_end teardown already ran via clearTransientSessionUi).
|
|
108
112
|
if (target.isStreaming) await this.ctx.eventController.handleEvent({ type: "agent_start" });
|
|
113
|
+
else setTerminalTitleState("idle");
|
|
109
114
|
this.ctx.updateEditorBorderColor();
|
|
110
115
|
this.ctx.ui.requestRender();
|
|
111
116
|
}
|