@oh-my-pi/pi-coding-agent 17.0.9 → 17.1.1
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 +78 -0
- package/README.md +1 -1
- package/dist/cli.js +4685 -4614
- 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/model-registry.d.ts +3 -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 +374 -47
- 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 +3 -0
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +13 -0
- package/dist/types/live/attestation.d.ts +2 -0
- package/dist/types/live/controller.d.ts +48 -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 +35 -0
- package/dist/types/live/visualizer.d.ts +30 -0
- package/dist/types/lsp/client.d.ts +16 -1
- package/dist/types/mcp/config-writer.test.d.ts +1 -0
- package/dist/types/mcp/oauth-discovery.d.ts +2 -0
- package/dist/types/mcp/smithery-auth.d.ts +1 -1
- package/dist/types/mcp/smithery-auth.test.d.ts +1 -0
- package/dist/types/memory-backend/tool-names.d.ts +2 -0
- package/dist/types/modes/components/assistant-message.d.ts +1 -0
- package/dist/types/modes/components/custom-message.d.ts +1 -1
- package/dist/types/modes/components/login-dialog.d.ts +2 -2
- package/dist/types/modes/components/message-frame.d.ts +8 -4
- package/dist/types/modes/components/plan-review-overlay.d.ts +26 -0
- package/dist/types/modes/components/session-account-selector.d.ts +11 -0
- package/dist/types/modes/components/settings-defs.d.ts +7 -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/selector-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +6 -0
- package/dist/types/modes/theme/theme.d.ts +1 -1
- package/dist/types/modes/types.d.ts +4 -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 +321 -0
- package/dist/types/session/agent-session.d.ts +135 -753
- package/dist/types/session/async-job-delivery.d.ts +28 -0
- package/dist/types/session/auth-storage.d.ts +1 -1
- 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 +51 -0
- package/dist/types/session/irc-bridge.d.ts +46 -0
- package/dist/types/session/messages.d.ts +24 -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-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 +158 -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/streaming-output.d.ts +8 -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/slash-commands/helpers/session-pin.d.ts +9 -0
- package/dist/types/stt/index.d.ts +0 -2
- package/dist/types/stt/stt-controller.d.ts +7 -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/tiny/title-client.d.ts +10 -0
- package/dist/types/tools/approval.d.ts +1 -0
- package/dist/types/tools/browser/launch.d.ts +5 -0
- package/dist/types/tools/builtin-names.d.ts +1 -1
- package/dist/types/tools/computer/protocol.d.ts +43 -0
- package/dist/types/tools/computer/supervisor.d.ts +32 -0
- package/dist/types/tools/computer/worker-entry.d.ts +1 -0
- package/dist/types/tools/computer/worker.d.ts +15 -0
- package/dist/types/tools/computer-renderer.d.ts +22 -0
- package/dist/types/tools/computer.d.ts +71 -0
- package/dist/types/tools/context.d.ts +2 -0
- package/dist/types/tools/default-renderer.d.ts +21 -0
- 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 +7 -0
- package/dist/types/tools/path-utils.d.ts +8 -0
- 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 +10 -29
- 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/utils/tools-manager.d.ts +1 -2
- 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/types.d.ts +94 -0
- package/package.json +12 -12
- package/scripts/generate-share-viewer.ts +4 -6
- 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 +3 -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/setup-cli.ts +2 -14
- package/src/cli/usage-cli.ts +10 -1
- package/src/cli.ts +8 -0
- package/src/collab/host.ts +3 -2
- package/src/commands/bench.ts +18 -4
- package/src/commands/launch.ts +4 -0
- package/src/config/model-registry.ts +16 -2
- 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 +270 -51
- package/src/config/settings.ts +81 -2
- package/src/dap/client.ts +37 -4
- package/src/edit/index.ts +49 -12
- package/src/eval/executor-base.ts +1 -0
- package/src/eval/js/executor.ts +2 -0
- package/src/eval/py/executor.ts +103 -33
- package/src/exec/bash-executor.ts +90 -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/extensions/wrapper.ts +68 -12
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +7 -1
- package/src/extensibility/plugins/legacy-pi-compat.ts +19 -1
- 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/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/attestation.ts +91 -0
- package/src/live/controller.ts +517 -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 +422 -0
- package/src/live/visualizer.ts +214 -0
- package/src/lsp/client.ts +29 -9
- package/src/lsp/index.ts +19 -4
- package/src/main.ts +8 -1
- package/src/mcp/config-writer.test.ts +43 -0
- package/src/mcp/config-writer.ts +109 -82
- package/src/mcp/oauth-discovery.ts +10 -2
- package/src/mcp/smithery-auth.test.ts +29 -0
- package/src/mcp/smithery-auth.ts +3 -2
- 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 +1 -1
- package/src/modes/components/assistant-message.ts +7 -2
- package/src/modes/components/custom-message.ts +4 -1
- package/src/modes/components/login-dialog.ts +14 -4
- package/src/modes/components/message-frame.ts +14 -8
- package/src/modes/components/plan-review-overlay.ts +350 -35
- package/src/modes/components/session-account-selector.ts +62 -0
- package/src/modes/components/settings-defs.ts +23 -1
- package/src/modes/components/settings-selector.ts +169 -1
- 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.ts +28 -112
- package/src/modes/controllers/command-controller.ts +56 -15
- 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/input-controller.ts +47 -39
- package/src/modes/controllers/live-command-controller.ts +255 -0
- package/src/modes/controllers/mcp-command-controller.ts +10 -1
- package/src/modes/controllers/omfg-controller.ts +44 -40
- package/src/modes/controllers/selector-controller.ts +80 -10
- package/src/modes/controllers/session-focus-controller.ts +6 -1
- package/src/modes/interactive-mode.ts +176 -38
- package/src/modes/runtime-init.ts +2 -0
- package/src/modes/setup-wizard/scenes/web-search.ts +17 -9
- package/src/modes/theme/theme.ts +1 -1
- package/src/modes/types.ts +4 -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/system/computer-safety.md +14 -0
- 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/computer.md +26 -0
- 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 +215 -136
- 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 +343 -0
- package/src/session/agent-session.ts +1940 -12218
- package/src/session/artifacts.ts +6 -5
- package/src/session/async-job-delivery.ts +74 -0
- package/src/session/auth-storage.ts +1 -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 +217 -0
- package/src/session/indexed-session-storage.ts +9 -2
- package/src/session/irc-bridge.ts +203 -0
- package/src/session/messages.ts +266 -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.ts +6 -3
- 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 +0 -46
- 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 +980 -0
- package/src/session/session-workspace.ts +53 -0
- package/src/session/stream-guards.ts +417 -0
- package/src/session/streaming-output.ts +52 -5
- 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 +257 -20
- package/src/slash-commands/helpers/session-pin.ts +44 -0
- package/src/slash-commands/helpers/usage-report.ts +22 -3
- package/src/stt/downloader.ts +0 -2
- package/src/stt/index.ts +0 -2
- package/src/stt/stt-controller.ts +57 -146
- package/src/system-prompt.ts +45 -17
- package/src/task/executor.ts +285 -70
- package/src/task/index.ts +98 -105
- package/src/task/output-manager.ts +25 -3
- package/src/task/persisted-revive.ts +4 -3
- package/src/task/structured-subagent.ts +1 -0
- package/src/tiny/title-client.ts +22 -0
- package/src/tools/approval.ts +55 -10
- package/src/tools/bash-interactive.ts +116 -86
- 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/builtin-names.ts +1 -0
- package/src/tools/computer/protocol.ts +28 -0
- package/src/tools/computer/supervisor.ts +258 -0
- package/src/tools/computer/worker-entry.ts +25 -0
- package/src/tools/computer/worker.ts +135 -0
- package/src/tools/computer-renderer.ts +108 -0
- package/src/tools/computer.ts +433 -0
- package/src/tools/context.ts +2 -0
- package/src/tools/default-renderer.ts +139 -0
- package/src/tools/essential-tools.ts +1 -0
- package/src/tools/image-gen.ts +20 -28
- package/src/tools/image-providers.ts +50 -0
- package/src/tools/index.ts +14 -0
- package/src/tools/path-utils.ts +49 -2
- package/src/tools/read.ts +156 -88
- package/src/tools/renderers.ts +9 -1
- 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 +121 -29
- package/src/tts/streaming-player.ts +82 -283
- package/src/tts/vocalizer.ts +18 -1
- package/src/utils/clipboard.ts +1 -30
- package/src/utils/jj.ts +125 -4
- package/src/utils/lang-from-path.ts +7 -0
- package/src/utils/mac-file-urls.applescript +37 -0
- package/src/utils/title-generator.ts +137 -1
- package/src/utils/tool-choice.ts +14 -0
- package/src/utils/tools-manager.ts +1 -19
- 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/xai.ts +7 -1
- package/src/web/search/types.ts +3 -0
- package/dist/types/stt/recorder.d.ts +0 -30
- package/dist/types/stt/transcriber.d.ts +0 -14
- package/dist/types/stt/wav.d.ts +0 -29
- package/dist/types/tts/player.d.ts +0 -32
- package/src/stt/recorder.ts +0 -551
- package/src/stt/transcriber.ts +0 -60
- package/src/stt/wav.ts +0 -173
- package/src/tts/player.ts +0 -137
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
} from "@oh-my-pi/pi-tui";
|
|
40
40
|
import { isInsideTerminalMultiplexer } from "@oh-my-pi/pi-tui/terminal-capabilities";
|
|
41
41
|
import {
|
|
42
|
+
$env,
|
|
42
43
|
APP_NAME,
|
|
43
44
|
adjustHsv,
|
|
44
45
|
formatNumber,
|
|
@@ -55,7 +56,7 @@ import { reset as resetCapabilities } from "../capability";
|
|
|
55
56
|
import type { CollabGuestLink } from "../collab/guest";
|
|
56
57
|
import type { CollabHost } from "../collab/host";
|
|
57
58
|
import { KeybindingsManager } from "../config/keybindings";
|
|
58
|
-
import type
|
|
59
|
+
import { formatModelString, type ResolvedModelRoleValue } from "../config/model-resolver";
|
|
59
60
|
import { applyProviderGlobalsFromSettings } from "../config/provider-globals";
|
|
60
61
|
import {
|
|
61
62
|
isSettingsInitialized,
|
|
@@ -113,6 +114,7 @@ import { STTController, type SttState } from "../stt";
|
|
|
113
114
|
import { discoverTitleSystemPromptFile, resolvePromptInput } from "../system-prompt";
|
|
114
115
|
import { formatTaskId } from "../task/render";
|
|
115
116
|
import type { ConfiguredThinkingLevel } from "../thinking";
|
|
117
|
+
import { tinyTitleClient } from "../tiny/title-client";
|
|
116
118
|
import type { LspStartupServerInfo } from "../tools";
|
|
117
119
|
import { normalizeLocalScheme } from "../tools/path-utils";
|
|
118
120
|
import { replaceTabs, TRUNCATE_LENGTHS, truncateToWidth } from "../tools/render-utils";
|
|
@@ -130,8 +132,19 @@ import type { EventBus } from "../utils/event-bus";
|
|
|
130
132
|
import { getEditorCommand, openInEditor } from "../utils/external-editor";
|
|
131
133
|
import { getSessionAccentAnsi, getSessionAccentHex } from "../utils/session-color";
|
|
132
134
|
import { messageHasDisplayableThinking } from "../utils/thinking-display";
|
|
133
|
-
import {
|
|
134
|
-
|
|
135
|
+
import {
|
|
136
|
+
disposeTerminalTitleState,
|
|
137
|
+
popTerminalTitle,
|
|
138
|
+
pushTerminalTitle,
|
|
139
|
+
setSessionTerminalTitle,
|
|
140
|
+
setTerminalTitleStateEnabled,
|
|
141
|
+
} from "../utils/title-generator";
|
|
142
|
+
import {
|
|
143
|
+
aggregateVibeWorkerTokensPerSecond,
|
|
144
|
+
type VibeOwnerScope,
|
|
145
|
+
type VibeParentSession,
|
|
146
|
+
VibeSessionRegistry,
|
|
147
|
+
} from "../vibe/runtime";
|
|
135
148
|
import type { AssistantMessageComponent } from "./components/assistant-message";
|
|
136
149
|
import type { BashExecutionComponent } from "./components/bash-execution";
|
|
137
150
|
import { ChatBlock, type ChatBlockHost } from "./components/chat-block";
|
|
@@ -142,7 +155,7 @@ import type { EvalExecutionComponent } from "./components/eval-execution";
|
|
|
142
155
|
import type { HookEditorComponent } from "./components/hook-editor";
|
|
143
156
|
import type { HookInputComponent } from "./components/hook-input";
|
|
144
157
|
import type { HookSelectorComponent, HookSelectorSlider } from "./components/hook-selector";
|
|
145
|
-
import { PlanReviewOverlay } from "./components/plan-review-overlay";
|
|
158
|
+
import { type PlanReviewAnnotationState, PlanReviewOverlay } from "./components/plan-review-overlay";
|
|
146
159
|
import { StatusLineComponent } from "./components/status-line";
|
|
147
160
|
import type { ToolExecutionHandle } from "./components/tool-execution";
|
|
148
161
|
import { TranscriptContainer } from "./components/transcript-container";
|
|
@@ -152,6 +165,7 @@ import { CommandController } from "./controllers/command-controller";
|
|
|
152
165
|
import { EventController } from "./controllers/event-controller";
|
|
153
166
|
import { ExtensionUiController } from "./controllers/extension-ui-controller";
|
|
154
167
|
import { InputController } from "./controllers/input-controller";
|
|
168
|
+
import { LiveCommandController } from "./controllers/live-command-controller";
|
|
155
169
|
import { MCPCommandController } from "./controllers/mcp-command-controller";
|
|
156
170
|
import { OmfgController } from "./controllers/omfg-controller";
|
|
157
171
|
import { SelectorController } from "./controllers/selector-controller";
|
|
@@ -543,6 +557,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
543
557
|
#planModePreviousTools: string[] | undefined;
|
|
544
558
|
#goalModePreviousTools: string[] | undefined;
|
|
545
559
|
#vibeModePreviousTools: string[] | undefined;
|
|
560
|
+
#vibeModeOwnerScope: VibeOwnerScope | undefined;
|
|
561
|
+
#vibeScopeSuspendedForSwitch = false;
|
|
546
562
|
#goalContinuationTimer: NodeJS.Timeout | undefined;
|
|
547
563
|
#goalTurnHadToolCalls = false;
|
|
548
564
|
#goalContinuationTurnInFlight = false;
|
|
@@ -555,6 +571,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
555
571
|
#planReviewOverlay: PlanReviewOverlay | undefined;
|
|
556
572
|
#planReviewOverlayHandle: OverlayHandle | undefined;
|
|
557
573
|
#planReviewCancel: (() => void) | undefined;
|
|
574
|
+
/** Serializable review annotations keyed by the resolved plan file path. */
|
|
575
|
+
#planReviewAnnotationState = new Map<string, PlanReviewAnnotationState>();
|
|
576
|
+
/** Annotation state held until the associated queued refinement actually starts. */
|
|
577
|
+
#planReviewAnnotationStateBySubmission = new WeakMap<SubmittedUserInput, string>();
|
|
558
578
|
readonly lspServers: LspStartupServerInfo[] | undefined = undefined;
|
|
559
579
|
mcpManager?: MCPManager;
|
|
560
580
|
readonly #toolUiContextSetter: (uiContext: ExtensionUIContext, hasUI: boolean) => void;
|
|
@@ -564,6 +584,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
564
584
|
readonly #omfgController: OmfgController;
|
|
565
585
|
readonly #commandController: CommandController;
|
|
566
586
|
readonly #todoCommandController: TodoCommandController;
|
|
587
|
+
readonly #liveCommandController: LiveCommandController;
|
|
567
588
|
readonly #eventController: EventController;
|
|
568
589
|
get eventController(): EventController {
|
|
569
590
|
return this.#eventController;
|
|
@@ -773,6 +794,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
773
794
|
this.#eventController = new EventController(this);
|
|
774
795
|
this.#commandController = new CommandController(this);
|
|
775
796
|
this.#todoCommandController = new TodoCommandController(this);
|
|
797
|
+
this.#liveCommandController = new LiveCommandController(this);
|
|
776
798
|
this.#selectorController = new SelectorController(this);
|
|
777
799
|
this.#focusController = new SessionFocusController(this);
|
|
778
800
|
this.#inputController = new InputController(this);
|
|
@@ -976,6 +998,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
976
998
|
// the initial welcome frame does not append over the previous run's scrollback.
|
|
977
999
|
this.ui.start({ clearScrollback: options.clearInitialTerminalHistory === true });
|
|
978
1000
|
pushTerminalTitle();
|
|
1001
|
+
setTerminalTitleStateEnabled(this.settings.get("tui.titleState"));
|
|
979
1002
|
setSessionTerminalTitle(this.sessionManager.getSessionName(), this.sessionManager.getCwd());
|
|
980
1003
|
this.updateEditorBorderColor();
|
|
981
1004
|
// Single side-effect point for title changes: every setSessionName caller
|
|
@@ -993,10 +1016,27 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
993
1016
|
this.isInitialized = true;
|
|
994
1017
|
this.ui.requestRender(true);
|
|
995
1018
|
|
|
1019
|
+
// Prewarm the local tiny-title worker off the submit hot path: spawn it
|
|
1020
|
+
// now, idle and unref'd, so the first submit reuses a live subprocess
|
|
1021
|
+
// instead of paying spawn latency ahead of the first frame (issue #6462).
|
|
1022
|
+
// No-ops for the online default and for already-named sessions that will
|
|
1023
|
+
// not be titled. Deferred via setImmediate so it runs AFTER the render
|
|
1024
|
+
// callback requestRender(true) queued above (immediates are FIFO) — the
|
|
1025
|
+
// spawn syscall never lands in the same loop turn ahead of the first paint.
|
|
1026
|
+
setImmediate(() => {
|
|
1027
|
+
if (!$env.PI_NO_TITLE && !this.sessionManager.getSessionName()) {
|
|
1028
|
+
tinyTitleClient.prewarm(this.settings.get("providers.tinyModel"));
|
|
1029
|
+
}
|
|
1030
|
+
});
|
|
1031
|
+
|
|
996
1032
|
// Initialize hooks with TUI-based UI context
|
|
997
1033
|
await this.initHooksAndCustomTools();
|
|
998
1034
|
|
|
999
1035
|
// Restore mode from session (e.g. plan mode on resume)
|
|
1036
|
+
this.session.setSessionBeforeSwitchReconciler?.(async () => {
|
|
1037
|
+
await this.#liveCommandController.stop();
|
|
1038
|
+
await this.#quiesceVibeForSessionSwitch();
|
|
1039
|
+
});
|
|
1000
1040
|
this.session.setSessionSwitchReconciler?.(() => this.#reconcileModeFromSession({ preserveActiveGoal: true }));
|
|
1001
1041
|
await this.#reconcileModeFromSession();
|
|
1002
1042
|
|
|
@@ -1566,6 +1606,11 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1566
1606
|
return false;
|
|
1567
1607
|
}
|
|
1568
1608
|
input.started = true;
|
|
1609
|
+
const annotationStateKey = this.#planReviewAnnotationStateBySubmission.get(input);
|
|
1610
|
+
if (annotationStateKey) {
|
|
1611
|
+
this.#planReviewAnnotationStateBySubmission.delete(input);
|
|
1612
|
+
this.#planReviewAnnotationState.delete(annotationStateKey);
|
|
1613
|
+
}
|
|
1569
1614
|
return true;
|
|
1570
1615
|
}
|
|
1571
1616
|
|
|
@@ -1756,6 +1801,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1756
1801
|
return theme.fg("accent", `${prefix}${checkbox.unchecked} ${todo.content}`) + marker;
|
|
1757
1802
|
case "abandoned":
|
|
1758
1803
|
return theme.fg("error", `${prefix}${checkbox.unchecked} ${chalk.strikethrough(todo.content)}`) + marker;
|
|
1804
|
+
case "blocked":
|
|
1805
|
+
return theme.fg("warning", `${prefix}${checkbox.unchecked} ${todo.content} (blocked)`) + marker;
|
|
1759
1806
|
default:
|
|
1760
1807
|
if (matched) return theme.fg("accent", `${prefix}${checkbox.unchecked} ${todo.content}`) + marker;
|
|
1761
1808
|
return theme.fg("dim", `${prefix}${checkbox.unchecked} ${todo.content}`) + marker;
|
|
@@ -1775,12 +1822,15 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1775
1822
|
}
|
|
1776
1823
|
|
|
1777
1824
|
/**
|
|
1778
|
-
* Auto-complete any pending/in_progress
|
|
1779
|
-
* subagent that has finished successfully. Fires on every observer
|
|
1825
|
+
* Auto-complete any open todo (pending/in_progress/blocked) whose content
|
|
1826
|
+
* matches a subagent that has finished successfully. Fires on every observer
|
|
1780
1827
|
* `onChange` so the visual state stays in sync with subagent lifecycle
|
|
1781
|
-
* without requiring the agent to issue a follow-up `todo`.
|
|
1782
|
-
*
|
|
1783
|
-
*
|
|
1828
|
+
* without requiring the agent to issue a follow-up `todo`. A todo `block`ed
|
|
1829
|
+
* while waiting on a detached subagent is included: that subagent completing
|
|
1830
|
+
* is exactly the unblock signal, and blocked todos are excluded from the stop
|
|
1831
|
+
* reminder, so leaving it blocked would strand it silently. Failed and aborted
|
|
1832
|
+
* subagents are intentionally NOT auto-completed — those stay open so the user
|
|
1833
|
+
* (or the next agent turn) can decide what to do.
|
|
1784
1834
|
*
|
|
1785
1835
|
* Idempotent: only flips open tasks, never re-touches completed ones.
|
|
1786
1836
|
*/
|
|
@@ -1799,10 +1849,14 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1799
1849
|
const next: TodoPhase[] = this.todoPhases.map(phase => ({
|
|
1800
1850
|
name: phase.name,
|
|
1801
1851
|
tasks: phase.tasks.map(task => {
|
|
1802
|
-
if (task.status !== "pending" && task.status !== "in_progress"
|
|
1852
|
+
if (task.status !== "pending" && task.status !== "in_progress" && task.status !== "blocked") {
|
|
1853
|
+
return task;
|
|
1854
|
+
}
|
|
1803
1855
|
if (!todoMatchesAnyDescription(task.content, completedDescs)) return task;
|
|
1804
1856
|
mutated = true;
|
|
1805
|
-
|
|
1857
|
+
// Drop any blocker note along with the blocked status — the wait the
|
|
1858
|
+
// note described is over.
|
|
1859
|
+
return { content: task.content, status: "completed" as const };
|
|
1806
1860
|
}),
|
|
1807
1861
|
}));
|
|
1808
1862
|
if (!mutated) return;
|
|
@@ -2058,6 +2112,29 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2058
2112
|
this.ui.requestRender();
|
|
2059
2113
|
}
|
|
2060
2114
|
|
|
2115
|
+
#vibeParentSession(): VibeParentSession {
|
|
2116
|
+
return {
|
|
2117
|
+
getAgentId: () => this.session.getAgentId() ?? null,
|
|
2118
|
+
getSessionId: () => this.sessionManager.getSessionId(),
|
|
2119
|
+
getSessionFile: () => this.sessionManager.getSessionFile() ?? null,
|
|
2120
|
+
sessionManager: this.sessionManager,
|
|
2121
|
+
asyncJobManager: this.session.asyncJobManager,
|
|
2122
|
+
settings: this.session.settings,
|
|
2123
|
+
// Resolve restored/switched-to workers against this session's active model
|
|
2124
|
+
// (same as the spawn-path ToolSession), not the settings default. This is
|
|
2125
|
+
// the primary fallback in resolveAgentModelPatterns, so the `good` worker's
|
|
2126
|
+
// pi/task inheritance tracks the reopened session's model.
|
|
2127
|
+
getActiveModelString: () => (this.session.model ? formatModelString(this.session.model) : undefined),
|
|
2128
|
+
};
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
async #quiesceVibeForSessionSwitch(): Promise<void> {
|
|
2132
|
+
const ownerScope = this.#vibeModeOwnerScope;
|
|
2133
|
+
if (!this.vibeModeEnabled || !ownerScope) return;
|
|
2134
|
+
await VibeSessionRegistry.global().suspendScope(ownerScope, this.session.asyncJobManager);
|
|
2135
|
+
this.#vibeScopeSuspendedForSwitch = true;
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2061
2138
|
#updateGoalModeStatus(): void {
|
|
2062
2139
|
const status =
|
|
2063
2140
|
this.goalModeEnabled || this.goalModePaused
|
|
@@ -2241,7 +2318,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2241
2318
|
}
|
|
2242
2319
|
}
|
|
2243
2320
|
|
|
2244
|
-
async #clearTransientModeState(
|
|
2321
|
+
async #clearTransientModeState(options?: {
|
|
2322
|
+
preserveVibe?: boolean;
|
|
2323
|
+
vibeScopeAlreadySuspended?: boolean;
|
|
2324
|
+
}): Promise<void> {
|
|
2245
2325
|
if (this.planModeEnabled || this.planModePaused) {
|
|
2246
2326
|
this.session.setPlanModeState(undefined);
|
|
2247
2327
|
try {
|
|
@@ -2277,23 +2357,40 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2277
2357
|
this.#updateGoalModeStatus();
|
|
2278
2358
|
}
|
|
2279
2359
|
|
|
2280
|
-
if (this.vibeModeEnabled) {
|
|
2281
|
-
|
|
2360
|
+
if (this.vibeModeEnabled && !options?.preserveVibe) {
|
|
2361
|
+
const ownerScope = this.#vibeModeOwnerScope;
|
|
2362
|
+
// This runs only from #reconcileModeFromSession, i.e. after switchSession
|
|
2363
|
+
// already loaded and restored the target session's active tools. The
|
|
2364
|
+
// #vibeModePreviousTools snapshot belongs to the SOURCE session, so
|
|
2365
|
+
// applying it here would clobber the target's tools — strip only the
|
|
2366
|
+
// transient vibe tools and keep the target's active set intact.
|
|
2367
|
+
await this.session.removeVibeToolsPreservingActive();
|
|
2282
2368
|
this.session.setVibeModeState(undefined);
|
|
2283
2369
|
this.vibeModeEnabled = false;
|
|
2284
2370
|
this.#vibeModePreviousTools = undefined;
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
this.session.asyncJobManager
|
|
2288
|
-
|
|
2371
|
+
this.#vibeModeOwnerScope = undefined;
|
|
2372
|
+
if (ownerScope && !options?.vibeScopeAlreadySuspended) {
|
|
2373
|
+
await VibeSessionRegistry.global().suspendScope(ownerScope, this.session.asyncJobManager);
|
|
2374
|
+
}
|
|
2289
2375
|
this.#updateVibeModeStatus();
|
|
2290
2376
|
}
|
|
2291
2377
|
}
|
|
2292
2378
|
|
|
2293
2379
|
/** Reconcile mode state from session entries on resume/switch. */
|
|
2294
2380
|
async #reconcileModeFromSession(options?: { preserveActiveGoal?: boolean }): Promise<void> {
|
|
2295
|
-
|
|
2381
|
+
const vibeScopeAlreadySuspended = this.#vibeScopeSuspendedForSwitch;
|
|
2382
|
+
this.#vibeScopeSuspendedForSwitch = false;
|
|
2296
2383
|
const sessionContext = this.sessionManager.buildSessionContext();
|
|
2384
|
+
const vibeSession = this.#vibeParentSession();
|
|
2385
|
+
const targetVibeScope = VibeSessionRegistry.global().ownerScope(vibeSession);
|
|
2386
|
+
const preserveVibe =
|
|
2387
|
+
this.vibeModeEnabled &&
|
|
2388
|
+
sessionContext.mode === "vibe" &&
|
|
2389
|
+
this.#vibeModeOwnerScope?.ownerId === targetVibeScope.ownerId &&
|
|
2390
|
+
this.#vibeModeOwnerScope.parentSessionId === targetVibeScope.parentSessionId &&
|
|
2391
|
+
this.#vibeModeOwnerScope.parentSessionFile === targetVibeScope.parentSessionFile;
|
|
2392
|
+
await this.#clearTransientModeState({ preserveVibe, vibeScopeAlreadySuspended });
|
|
2393
|
+
await VibeSessionRegistry.global().rehydrate(vibeSession);
|
|
2297
2394
|
const goalEnabled = this.session.settings.get("goal.enabled");
|
|
2298
2395
|
if (!goalEnabled && (sessionContext.mode === "goal" || sessionContext.mode === "goal_paused")) {
|
|
2299
2396
|
this.session.goalRuntime.clearAccounting();
|
|
@@ -2328,7 +2425,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2328
2425
|
}
|
|
2329
2426
|
this.session.goalRuntime.clearAccounting();
|
|
2330
2427
|
if (sessionContext.mode === "vibe") {
|
|
2331
|
-
await this.#enterVibeMode();
|
|
2428
|
+
if (!preserveVibe) await this.#enterVibeMode({ persistModeChange: false });
|
|
2332
2429
|
return;
|
|
2333
2430
|
}
|
|
2334
2431
|
if (!this.session.settings.get("plan.enabled")) {
|
|
@@ -2646,6 +2743,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2646
2743
|
onExternalEditor?: () => void;
|
|
2647
2744
|
onPlanEdited?: (content: string) => void;
|
|
2648
2745
|
onFeedbackChange?: (feedback: string) => void;
|
|
2746
|
+
annotationState?: PlanReviewAnnotationState;
|
|
2747
|
+
onAnnotationStateChange?: (state: PlanReviewAnnotationState) => void;
|
|
2649
2748
|
initialIndex?: number;
|
|
2650
2749
|
},
|
|
2651
2750
|
extra?: { slider?: HookSelectorSlider },
|
|
@@ -2669,6 +2768,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2669
2768
|
initialIndex: dialogOptions?.initialIndex,
|
|
2670
2769
|
slider: extra?.slider,
|
|
2671
2770
|
externalEditorLabel: this.keybindings.getDisplayString("app.editor.external") || undefined,
|
|
2771
|
+
annotationState: dialogOptions?.annotationState,
|
|
2672
2772
|
},
|
|
2673
2773
|
{
|
|
2674
2774
|
onPick: choice => finish(choice),
|
|
@@ -2678,6 +2778,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2678
2778
|
onAnnotationExternalEditor: (draft, commit) => void this.#openPlanAnnotationInExternalEditor(draft, commit),
|
|
2679
2779
|
onPlanEdited: dialogOptions?.onPlanEdited,
|
|
2680
2780
|
onFeedbackChange: dialogOptions?.onFeedbackChange,
|
|
2781
|
+
onAnnotationStateChange: dialogOptions?.onAnnotationStateChange,
|
|
2681
2782
|
},
|
|
2682
2783
|
);
|
|
2683
2784
|
this.#planReviewOverlay = overlay;
|
|
@@ -2907,7 +3008,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2907
3008
|
compactBeforeExecute?: boolean;
|
|
2908
3009
|
executionModel?: ResolvedRoleModel;
|
|
2909
3010
|
},
|
|
2910
|
-
): Promise<
|
|
3011
|
+
): Promise<boolean> {
|
|
2911
3012
|
const previousTools = this.#planModePreviousTools ?? this.session.getEnabledToolNames();
|
|
2912
3013
|
|
|
2913
3014
|
// Mark the pending abort caused by the plan-mode → compaction transition as
|
|
@@ -3006,7 +3107,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3006
3107
|
this.showWarning(
|
|
3007
3108
|
"Plan approved, but compaction was cancelled — execution not dispatched. Submit a turn to continue.",
|
|
3008
3109
|
);
|
|
3009
|
-
return;
|
|
3110
|
+
return false;
|
|
3010
3111
|
}
|
|
3011
3112
|
|
|
3012
3113
|
// Approved plans land in a fresh (or compacted) session whose first user-visible
|
|
@@ -3048,14 +3149,15 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3048
3149
|
// noted below), catch `AgentBusyError` and fall back to the same queue.
|
|
3049
3150
|
if (this.session.isStreaming) {
|
|
3050
3151
|
await this.session.followUp(planModePrompt, undefined, { synthetic: true });
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3152
|
+
} else {
|
|
3153
|
+
try {
|
|
3154
|
+
await this.session.prompt(planModePrompt, { synthetic: true });
|
|
3155
|
+
} catch (error) {
|
|
3156
|
+
if (!(error instanceof AgentBusyError)) throw error;
|
|
3157
|
+
await this.session.followUp(planModePrompt, undefined, { synthetic: true });
|
|
3158
|
+
}
|
|
3058
3159
|
}
|
|
3160
|
+
return true;
|
|
3059
3161
|
}
|
|
3060
3162
|
async #abortPlanApprovalTurnSilently(): Promise<void> {
|
|
3061
3163
|
this.session.markPlanInternalAbortPending();
|
|
@@ -3135,7 +3237,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3135
3237
|
}
|
|
3136
3238
|
}
|
|
3137
3239
|
|
|
3138
|
-
async #enterVibeMode(): Promise<void> {
|
|
3240
|
+
async #enterVibeMode(options?: { persistModeChange?: boolean }): Promise<void> {
|
|
3139
3241
|
if (this.vibeModeEnabled) {
|
|
3140
3242
|
return;
|
|
3141
3243
|
}
|
|
@@ -3148,9 +3250,13 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3148
3250
|
return;
|
|
3149
3251
|
}
|
|
3150
3252
|
|
|
3253
|
+
const vibeRegistry = VibeSessionRegistry.global();
|
|
3254
|
+
const ownerScope = vibeRegistry.ownerScope(this.#vibeParentSession());
|
|
3255
|
+
vibeRegistry.activateScope(ownerScope);
|
|
3151
3256
|
const previousTools = this.session.getEnabledToolNames();
|
|
3152
3257
|
await this.session.activateVibeTools(["read"]);
|
|
3153
3258
|
this.#vibeModePreviousTools = previousTools;
|
|
3259
|
+
this.#vibeModeOwnerScope = ownerScope;
|
|
3154
3260
|
this.vibeModeEnabled = true;
|
|
3155
3261
|
// Suppress cache-miss marker on the next turn: vibe mode changes the
|
|
3156
3262
|
// injected context, which predictably invalidates the cache.
|
|
@@ -3160,7 +3266,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3160
3266
|
await this.session.sendVibeModeContext({ deliverAs: "steer" });
|
|
3161
3267
|
}
|
|
3162
3268
|
this.#updateVibeModeStatus();
|
|
3163
|
-
this.sessionManager.appendModeChange("vibe");
|
|
3269
|
+
if (options?.persistModeChange !== false) this.sessionManager.appendModeChange("vibe");
|
|
3164
3270
|
this.showStatus("Vibe mode enabled. You direct fast/good worker sessions; toolset is read + vibe tools.");
|
|
3165
3271
|
}
|
|
3166
3272
|
|
|
@@ -3168,17 +3274,15 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3168
3274
|
if (!this.vibeModeEnabled) {
|
|
3169
3275
|
return;
|
|
3170
3276
|
}
|
|
3277
|
+
const ownerScope = this.#vibeModeOwnerScope;
|
|
3278
|
+
const killed = await VibeSessionRegistry.global().killAll(this.#vibeParentSession(), ownerScope);
|
|
3171
3279
|
await this.session.deactivateVibeTools(this.#vibeModePreviousTools ?? []);
|
|
3172
3280
|
this.session.setVibeModeState(undefined);
|
|
3173
3281
|
this.vibeModeEnabled = false;
|
|
3174
3282
|
this.#vibeModePreviousTools = undefined;
|
|
3283
|
+
this.#vibeModeOwnerScope = undefined;
|
|
3175
3284
|
this.lastAssistantUsage = undefined;
|
|
3176
|
-
const killed = await VibeSessionRegistry.global().killAll(
|
|
3177
|
-
this.session.getAgentId() ?? MAIN_AGENT_ID,
|
|
3178
|
-
this.session.asyncJobManager,
|
|
3179
|
-
);
|
|
3180
3285
|
this.#updateVibeModeStatus();
|
|
3181
|
-
this.sessionManager.appendModeChange("none");
|
|
3182
3286
|
this.showStatus(
|
|
3183
3287
|
killed > 0
|
|
3184
3288
|
? `Vibe mode disabled. Killed ${killed} worker session${killed === 1 ? "" : "s"}.`
|
|
@@ -3582,6 +3686,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3582
3686
|
// that the Refine branch re-prompts the model with.
|
|
3583
3687
|
let editedContent: string | undefined;
|
|
3584
3688
|
let feedback = "";
|
|
3689
|
+
const annotationStateKey = this.#resolvePlanFilePath(planFilePath);
|
|
3585
3690
|
|
|
3586
3691
|
const choice = await this.showPlanReview(
|
|
3587
3692
|
planContent,
|
|
@@ -3597,6 +3702,11 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3597
3702
|
onFeedbackChange: value => {
|
|
3598
3703
|
feedback = value;
|
|
3599
3704
|
},
|
|
3705
|
+
annotationState: this.#planReviewAnnotationState.get(annotationStateKey),
|
|
3706
|
+
onAnnotationStateChange: state => {
|
|
3707
|
+
if (state.annotations.length > 0) this.#planReviewAnnotationState.set(annotationStateKey, state);
|
|
3708
|
+
else this.#planReviewAnnotationState.delete(annotationStateKey);
|
|
3709
|
+
},
|
|
3600
3710
|
disabledIndices: keepContextDisabled ? [PLAN_KEEP_CONTEXT_OPTION_INDEX] : undefined,
|
|
3601
3711
|
},
|
|
3602
3712
|
{ slider },
|
|
@@ -3648,13 +3758,14 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3648
3758
|
: -1;
|
|
3649
3759
|
const executionModel =
|
|
3650
3760
|
slider && cycle && selectedTierIndex !== restoredIndex ? cycle.models[selectedTierIndex] : undefined;
|
|
3651
|
-
await this.#approvePlan(latestPlanContent, {
|
|
3761
|
+
const executionDispatched = await this.#approvePlan(latestPlanContent, {
|
|
3652
3762
|
planFilePath,
|
|
3653
3763
|
title: details.title,
|
|
3654
3764
|
preserveContext: choice !== "Approve and execute",
|
|
3655
3765
|
compactBeforeExecute: choice === "Approve and compact context",
|
|
3656
3766
|
executionModel,
|
|
3657
3767
|
});
|
|
3768
|
+
if (executionDispatched) this.#planReviewAnnotationState.delete(annotationStateKey);
|
|
3658
3769
|
} catch (error) {
|
|
3659
3770
|
this.showError(
|
|
3660
3771
|
`Failed to finalize approved plan: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -3669,9 +3780,12 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3669
3780
|
try {
|
|
3670
3781
|
if (refinement) {
|
|
3671
3782
|
if (this.onInputCallback) {
|
|
3672
|
-
this.
|
|
3783
|
+
const input = this.startPendingSubmission({ text: feedback });
|
|
3784
|
+
this.#planReviewAnnotationStateBySubmission.set(input, annotationStateKey);
|
|
3785
|
+
this.onInputCallback(input);
|
|
3673
3786
|
} else {
|
|
3674
3787
|
await this.session.prompt(feedback);
|
|
3788
|
+
this.#planReviewAnnotationState.delete(annotationStateKey);
|
|
3675
3789
|
}
|
|
3676
3790
|
} else {
|
|
3677
3791
|
this.showStatus("Refine plan: enter a follow-up prompt.");
|
|
@@ -3746,6 +3860,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3746
3860
|
this.#stopLoadingAnimation(false);
|
|
3747
3861
|
}
|
|
3748
3862
|
this.#cleanupMicAnimation();
|
|
3863
|
+
this.#liveCommandController.dispose();
|
|
3749
3864
|
this.#cancelTodoAutoClearTimer();
|
|
3750
3865
|
this.#cancelObserverUiSyncTimer();
|
|
3751
3866
|
this.#cancelGoalContinuation();
|
|
@@ -3788,6 +3903,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3788
3903
|
if (this.#isShuttingDown) return;
|
|
3789
3904
|
this.#isShuttingDown = true;
|
|
3790
3905
|
|
|
3906
|
+
await this.#liveCommandController.stop();
|
|
3907
|
+
|
|
3791
3908
|
this.#btwController.dispose();
|
|
3792
3909
|
this.#omfgController.dispose();
|
|
3793
3910
|
this.#focusController.dispose();
|
|
@@ -3825,6 +3942,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3825
3942
|
// Drain any in-flight Kitty key release events before stopping.
|
|
3826
3943
|
// This prevents escape sequences from leaking to the parent shell over slow SSH.
|
|
3827
3944
|
await this.ui.terminal.drainInput(1000);
|
|
3945
|
+
// Stop the run-state spinner interval BEFORE restoring the shell title, so a
|
|
3946
|
+
// pending tick cannot re-emit an OSC title after `popTerminalTitle` hands the
|
|
3947
|
+
// terminal back (which would leave the parent shell with a `π ⠋ …` tab).
|
|
3948
|
+
disposeTerminalTitleState();
|
|
3828
3949
|
popTerminalTitle();
|
|
3829
3950
|
this.stop();
|
|
3830
3951
|
|
|
@@ -4297,6 +4418,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
4297
4418
|
}
|
|
4298
4419
|
|
|
4299
4420
|
async handleSTTToggle(): Promise<void> {
|
|
4421
|
+
if (this.#liveCommandController.active) {
|
|
4422
|
+
this.showWarning("End live mode before using push-to-talk speech input.");
|
|
4423
|
+
return;
|
|
4424
|
+
}
|
|
4300
4425
|
if (!settings.get("stt.enabled")) {
|
|
4301
4426
|
this.showWarning("Speech-to-text is disabled. Enable it in settings: stt.enabled");
|
|
4302
4427
|
return;
|
|
@@ -4329,6 +4454,15 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
4329
4454
|
});
|
|
4330
4455
|
}
|
|
4331
4456
|
|
|
4457
|
+
/** Start or stop the Codex-backed realtime voice surface. */
|
|
4458
|
+
async handleLiveCommand(): Promise<void> {
|
|
4459
|
+
if (this.#sttController && this.#sttController.state !== "idle") {
|
|
4460
|
+
this.showWarning("Finish the current speech-to-text capture before starting live mode.");
|
|
4461
|
+
return;
|
|
4462
|
+
}
|
|
4463
|
+
await this.#liveCommandController.handleCommand();
|
|
4464
|
+
}
|
|
4465
|
+
|
|
4332
4466
|
#setMicCursor(color: { r: number; g: number; b: number }): void {
|
|
4333
4467
|
this.editor.cursorOverride = `\x1b[38;2;${color.r};${color.g};${color.b}m${theme.icon.mic}\x1b[0m`;
|
|
4334
4468
|
// Theme symbols can be wide (for example, 🎤), so measure the rendered override.
|
|
@@ -4505,6 +4639,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
4505
4639
|
return this.#selectorController.showOAuthSelector(mode, providerId);
|
|
4506
4640
|
}
|
|
4507
4641
|
|
|
4642
|
+
showSessionPinSelector(): Promise<void> {
|
|
4643
|
+
return this.#selectorController.showSessionPinSelector();
|
|
4644
|
+
}
|
|
4645
|
+
|
|
4508
4646
|
showResetUsageSelector(): Promise<void> {
|
|
4509
4647
|
return this.#selectorController.showResetUsageSelector();
|
|
4510
4648
|
}
|
|
@@ -90,6 +90,8 @@ export async function initializeExtensions(session: AgentSession, options: Initi
|
|
|
90
90
|
setModel: model => runExtensionSetModel(session, model),
|
|
91
91
|
getThinkingLevel: () => session.thinkingLevel,
|
|
92
92
|
setThinkingLevel: level => session.setThinkingLevel(level),
|
|
93
|
+
getServiceTiers: () => session.serviceTierByFamily,
|
|
94
|
+
setServiceTier: (family, tier) => session.setServiceTierFamily(family, tier),
|
|
93
95
|
getSessionName: () => session.sessionManager.getSessionName(),
|
|
94
96
|
setSessionName: async name => {
|
|
95
97
|
await session.sessionManager.setSessionName(name, "user");
|
|
@@ -5,16 +5,20 @@ import {
|
|
|
5
5
|
type SgrMouseEvent,
|
|
6
6
|
truncateToWidth,
|
|
7
7
|
} from "@oh-my-pi/pi-tui";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
8
|
+
import { getSearchProvider, setSearchProviderOrder } from "../../../web/search/provider";
|
|
9
|
+
import {
|
|
10
|
+
isSearchProviderId,
|
|
11
|
+
SEARCH_PROVIDER_OPTIONS,
|
|
12
|
+
SEARCH_PROVIDER_ORDER,
|
|
13
|
+
type SearchProviderId,
|
|
14
|
+
} from "../../../web/search/types";
|
|
11
15
|
import { getSelectListTheme, theme } from "../../theme/theme";
|
|
12
16
|
import type { SetupSceneHost, SetupTab } from "./types";
|
|
13
17
|
|
|
14
18
|
const MAX_VISIBLE = 8;
|
|
15
19
|
|
|
16
|
-
/** Reuse the
|
|
17
|
-
const WEB_SEARCH_ITEMS: readonly SelectItem[] =
|
|
20
|
+
/** Reuse the shared provider options as the single source of truth for labels/descriptions. */
|
|
21
|
+
const WEB_SEARCH_ITEMS: readonly SelectItem[] = SEARCH_PROVIDER_OPTIONS.map(option => ({
|
|
18
22
|
value: option.value,
|
|
19
23
|
label: option.label,
|
|
20
24
|
description: option.description,
|
|
@@ -42,7 +46,8 @@ export class WebSearchTab implements SetupTab {
|
|
|
42
46
|
|
|
43
47
|
constructor(private readonly host: SetupSceneHost) {
|
|
44
48
|
this.#list = new SelectList(WEB_SEARCH_ITEMS, MAX_VISIBLE, getSelectListTheme());
|
|
45
|
-
const
|
|
49
|
+
const order = host.ctx.settings.get("providers.webSearchOrder");
|
|
50
|
+
const current = Array.isArray(order) && typeof order[0] === "string" ? order[0] : "auto";
|
|
46
51
|
const index = WEB_SEARCH_ITEMS.findIndex(item => item.value === current);
|
|
47
52
|
if (index >= 0) this.#list.setSelectedIndex(index);
|
|
48
53
|
this.#list.onSelectionChange = item => this.#onHighlight(item.value);
|
|
@@ -119,9 +124,12 @@ export class WebSearchTab implements SetupTab {
|
|
|
119
124
|
}
|
|
120
125
|
|
|
121
126
|
#apply(value: string): void {
|
|
122
|
-
if (!
|
|
123
|
-
|
|
124
|
-
|
|
127
|
+
if (value !== "auto" && !isSearchProviderId(value)) return;
|
|
128
|
+
// The wizard picks one favorite; persist it as the head of the priority
|
|
129
|
+
// list with the remaining providers in their built-in order (auto = reset).
|
|
130
|
+
const order = value === "auto" ? [] : [value, ...SEARCH_PROVIDER_ORDER.filter(id => id !== value)];
|
|
131
|
+
this.host.ctx.settings.set("providers.webSearchOrder", order);
|
|
132
|
+
setSearchProviderOrder(order);
|
|
125
133
|
const label = WEB_SEARCH_ITEMS.find(item => item.value === value)?.label ?? value;
|
|
126
134
|
this.#status = [theme.fg("success", `${theme.status.success} Web search set to ${label}`)];
|
|
127
135
|
if (value !== "auto" && this.#availability.get(value as SearchProviderId) === false) {
|
package/src/modes/theme/theme.ts
CHANGED
|
@@ -20,7 +20,7 @@ import { defaultThemes } from "./defaults";
|
|
|
20
20
|
import lightThemeJson from "./light.json" with { type: "json" };
|
|
21
21
|
import { resolveMermaidAscii } from "./mermaid-cache";
|
|
22
22
|
|
|
23
|
-
export { getLanguageFromPath } from "../../utils/lang-from-path";
|
|
23
|
+
export { getLanguageFromPath, isMarkdownPath } from "../../utils/lang-from-path";
|
|
24
24
|
|
|
25
25
|
// ============================================================================
|
|
26
26
|
// Symbol Presets
|
package/src/modes/types.ts
CHANGED
|
@@ -71,7 +71,7 @@ export type SubmittedUserInput = {
|
|
|
71
71
|
started: boolean;
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
-
export type TodoStatus = "pending" | "in_progress" | "completed" | "abandoned";
|
|
74
|
+
export type TodoStatus = "pending" | "in_progress" | "completed" | "abandoned" | "blocked";
|
|
75
75
|
|
|
76
76
|
export type TodoItem = {
|
|
77
77
|
content: string;
|
|
@@ -356,6 +356,8 @@ export interface InteractiveModeContext {
|
|
|
356
356
|
handleRenameCommand(title: string): Promise<void>;
|
|
357
357
|
handleMemoryCommand(text: string): Promise<void>;
|
|
358
358
|
handleSTTToggle(): Promise<void>;
|
|
359
|
+
/** Start or stop the Codex-backed realtime voice session. */
|
|
360
|
+
handleLiveCommand(): Promise<void>;
|
|
359
361
|
executeCompaction(
|
|
360
362
|
customInstructionsOrOptions?: string | CompactOptions,
|
|
361
363
|
isAuto?: boolean,
|
|
@@ -381,6 +383,7 @@ export interface InteractiveModeContext {
|
|
|
381
383
|
handleResumeSession(sessionPath: string): Promise<void>;
|
|
382
384
|
handleSessionDeleteCommand(): Promise<void>;
|
|
383
385
|
showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void>;
|
|
386
|
+
showSessionPinSelector(): Promise<void>;
|
|
384
387
|
showResetUsageSelector(): Promise<void>;
|
|
385
388
|
showProviderSetup(): Promise<void>;
|
|
386
389
|
showHookConfirm(title: string, message: string): Promise<boolean>;
|