@oh-my-pi/pi-coding-agent 17.2.4 → 17.2.6
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 +69 -0
- package/dist/{CHANGELOG-bpmhv26t.md → CHANGELOG-gs76k6wc.md} +69 -0
- package/dist/cli.js +4438 -3962
- package/dist/{template-8vdv6xb4.js → template-c2hyaytt.js} +8 -26
- package/dist/types/cli/args.d.ts +4 -1
- package/dist/types/cli/browser-relay-cli.d.ts +15 -0
- package/dist/types/cli/command-help.d.ts +99 -0
- package/dist/types/cli/gc-cli.d.ts +1 -0
- package/dist/types/cli/help-extra.d.ts +2 -0
- package/dist/types/cli/thinking-levels.d.ts +5 -0
- package/dist/types/cli/update-cli.d.ts +13 -0
- package/dist/types/commands/browser-relay.d.ts +38 -0
- package/dist/types/commands/commit.d.ts +3 -0
- package/dist/types/commands/complete.d.ts +1 -1
- package/dist/types/commands/completions.d.ts +6 -0
- package/dist/types/commands/grep.d.ts +3 -0
- package/dist/types/commands/join.d.ts +4 -0
- package/dist/types/commands/launch-help.d.ts +171 -0
- package/dist/types/commands/launch.d.ts +5 -1
- package/dist/types/commands/models.d.ts +3 -0
- package/dist/types/commands/say.d.ts +10 -0
- package/dist/types/commands/worktree.d.ts +3 -0
- package/dist/types/config/keybindings.d.ts +5 -0
- package/dist/types/config/model-discovery.d.ts +2 -2
- package/dist/types/config/models-config-schema-bundle.d.ts +3 -0
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/models-config.d.ts +1 -0
- package/dist/types/config/service-tier.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +69 -21
- package/dist/types/cursor-bridge-tools.d.ts +1 -1
- package/dist/types/cursor.d.ts +7 -4
- package/dist/types/edit/index.d.ts +3 -3
- package/dist/types/edit/modes/replace.d.ts +22 -15
- package/dist/types/edit/renderer.d.ts +1 -1
- package/dist/types/eval/py/kernel.d.ts +3 -1
- package/dist/types/eval/py/spawn-options.d.ts +12 -16
- package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +8 -1
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -1
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +2 -0
- package/dist/types/launch/broker.d.ts +1 -1
- package/dist/types/launch/client.d.ts +15 -4
- package/dist/types/launch/ensure.d.ts +8 -0
- package/dist/types/launch/paths.d.ts +1 -1
- package/dist/types/launch/protocol.d.ts +19 -2
- package/dist/types/lsp/client.d.ts +2 -0
- package/dist/types/lsp/mux/daemon.d.ts +15 -0
- package/dist/types/lsp/mux/protocol.d.ts +57 -0
- package/dist/types/lsp/mux/server.d.ts +18 -0
- package/dist/types/lsp/types.d.ts +22 -2
- package/dist/types/main.d.ts +2 -0
- package/dist/types/mnemopi/embed-client.d.ts +1 -1
- package/dist/types/mnemopi/state.d.ts +0 -23
- package/dist/types/modes/components/assistant-message.d.ts +2 -0
- package/dist/types/modes/components/btw-panel.d.ts +3 -0
- package/dist/types/modes/components/custom-editor.d.ts +2 -1
- package/dist/types/modes/components/read-tool-group.d.ts +2 -0
- package/dist/types/modes/components/stripped-tool-calls-placeholder.d.ts +12 -0
- package/dist/types/modes/components/tool-execution.d.ts +2 -0
- package/dist/types/modes/controllers/btw-controller.d.ts +2 -0
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +5 -1
- package/dist/types/modes/types.d.ts +4 -1
- package/dist/types/modes/workflow.d.ts +2 -1
- package/dist/types/sdk.d.ts +3 -1
- package/dist/types/secrets/index.d.ts +1 -1
- package/dist/types/security/contracts/schemas.d.ts +405 -403
- package/dist/types/session/agent-session-types.d.ts +8 -1
- package/dist/types/session/agent-session.d.ts +26 -2
- package/dist/types/session/indexed-session-storage.d.ts +1 -0
- package/dist/types/session/launch-completion.d.ts +10 -0
- package/dist/types/session/session-advisors.d.ts +1 -1
- package/dist/types/session/session-context.d.ts +2 -1
- package/dist/types/session/session-entries.d.ts +15 -1
- package/dist/types/session/session-maintenance.d.ts +1 -0
- package/dist/types/session/session-manager.d.ts +23 -11
- package/dist/types/session/session-stats.d.ts +10 -0
- package/dist/types/session/session-storage.d.ts +15 -3
- package/dist/types/session/yield-queue.d.ts +6 -1
- package/dist/types/system-prompt.d.ts +4 -1
- package/dist/types/task/index.d.ts +2 -1
- package/dist/types/task/spawn-policy.d.ts +5 -0
- package/dist/types/thinking.d.ts +1 -7
- package/dist/types/tools/ast-grep.d.ts +1 -1
- package/dist/types/tools/browser/registry.d.ts +2 -1
- package/dist/types/tools/browser/relay/bridge.d.ts +35 -0
- package/dist/types/tools/browser/relay/daemon.d.ts +16 -0
- package/dist/types/tools/browser/relay/kind.d.ts +19 -0
- package/dist/types/tools/browser/relay/protocol.d.ts +97 -0
- package/dist/types/tools/browser/relay/server.d.ts +35 -0
- package/dist/types/tools/browser/render.d.ts +1 -0
- package/dist/types/tools/browser.d.ts +3 -0
- package/dist/types/tools/computer/exposure.d.ts +9 -7
- package/dist/types/tools/computer/protocol.d.ts +70 -17
- package/dist/types/tools/computer/supervisor.d.ts +23 -10
- package/dist/types/tools/computer/worker-entry.d.ts +1 -0
- package/dist/types/tools/computer/worker.d.ts +42 -7
- package/dist/types/tools/computer-renderer.d.ts +7 -5
- package/dist/types/tools/computer.d.ts +25 -44
- package/dist/types/tools/context.d.ts +3 -0
- package/dist/types/tools/glob.d.ts +1 -1
- package/dist/types/tools/grep.d.ts +1 -1
- package/dist/types/tools/index.d.ts +9 -0
- package/dist/types/tools/render-utils.d.ts +2 -0
- package/dist/types/tools/{browser/run-cancellation.d.ts → run-scope.d.ts} +8 -8
- package/dist/types/tools/tool-timeouts.d.ts +5 -0
- package/dist/types/tools/xdev.d.ts +8 -0
- package/dist/types/utils/clipboard.d.ts +2 -2
- package/dist/types/web/kagi.d.ts +1 -0
- package/dist/types/web/search/index.d.ts +1 -1
- package/dist/types/web/search/providers/anthropic.d.ts +1 -0
- package/dist/types/web/search/providers/base.d.ts +2 -0
- package/dist/types/web/search/providers/brave.d.ts +1 -0
- package/dist/types/web/search/providers/browser-page.d.ts +1 -0
- package/dist/types/web/search/providers/codex.d.ts +1 -0
- package/dist/types/web/search/providers/exa.d.ts +1 -0
- package/dist/types/web/search/providers/firecrawl.d.ts +1 -0
- package/dist/types/web/search/providers/gemini.d.ts +1 -0
- package/dist/types/web/search/providers/jina.d.ts +1 -0
- package/dist/types/web/search/providers/kagi.d.ts +1 -0
- package/dist/types/web/search/providers/kimi.d.ts +1 -0
- package/dist/types/web/search/providers/parallel.d.ts +1 -0
- package/dist/types/web/search/providers/perplexity.d.ts +1 -0
- package/dist/types/web/search/providers/searxng.d.ts +1 -0
- package/dist/types/web/search/providers/tavily.d.ts +1 -0
- package/dist/types/web/search/providers/tinyfish.d.ts +1 -0
- package/dist/types/web/search/providers/utils.d.ts +6 -9
- package/dist/types/web/search/providers/zai.d.ts +1 -0
- package/dist/types/web/search/types.d.ts +4 -0
- package/package.json +12 -12
- package/src/cli/args.ts +7 -87
- package/src/cli/browser-relay-cli.ts +119 -0
- package/src/cli/command-help.ts +103 -0
- package/src/cli/completion-gen.ts +5 -5
- package/src/cli/flag-tables.ts +9 -0
- package/src/cli/gc-cli.ts +641 -21
- package/src/cli/help-extra.ts +89 -0
- package/src/cli/setup-cli.ts +13 -21
- package/src/cli/thinking-levels.ts +7 -0
- package/src/cli/update-cli.ts +26 -7
- package/src/cli-commands.ts +170 -33
- package/src/cli.ts +17 -5
- package/src/commands/acp.ts +3 -1
- package/src/commands/agents.ts +3 -2
- package/src/commands/auth-broker.ts +3 -2
- package/src/commands/auth-gateway.ts +3 -2
- package/src/commands/bench.ts +2 -3
- package/src/commands/browser-relay.ts +53 -0
- package/src/commands/cleanse.ts +2 -2
- package/src/commands/commit.ts +3 -2
- package/src/commands/complete.ts +2 -1
- package/src/commands/completions.ts +3 -2
- package/src/commands/config.ts +3 -2
- package/src/commands/dry-balance.ts +2 -2
- package/src/commands/gallery.ts +3 -2
- package/src/commands/gc.ts +3 -2
- package/src/commands/grep.ts +3 -2
- package/src/commands/grievances.ts +3 -2
- package/src/commands/install.ts +2 -2
- package/src/commands/join.ts +3 -2
- package/src/commands/launch-help.ts +116 -0
- package/src/commands/launch.ts +7 -191
- package/src/commands/models.ts +3 -2
- package/src/commands/plugin.ts +3 -2
- package/src/commands/read.ts +3 -2
- package/src/commands/say.ts +3 -2
- package/src/commands/setup.ts +3 -2
- package/src/commands/shell.ts +3 -2
- package/src/commands/ssh.ts +3 -2
- package/src/commands/stats.ts +3 -2
- package/src/commands/tiny-models.ts +2 -2
- package/src/commands/token.ts +2 -2
- package/src/commands/ttsr.ts +2 -2
- package/src/commands/update.ts +3 -2
- package/src/commands/usage.ts +3 -2
- package/src/commands/web-search.ts +3 -2
- package/src/commands/worktree.ts +3 -2
- package/src/config/keybindings.ts +5 -0
- package/src/config/model-discovery.ts +44 -27
- package/src/config/model-registry.ts +19 -13
- package/src/config/models-config-schema-bundle.ts +9 -0
- package/src/config/resolve-config-value.ts +2 -1
- package/src/config/service-tier.ts +5 -0
- package/src/config/settings-schema.ts +72 -20
- package/src/config/settings.ts +1 -1
- package/src/cursor-bridge-tools.ts +1 -1
- package/src/cursor.ts +10 -14
- package/src/edit/diff.ts +17 -8
- package/src/edit/index.ts +20 -7
- package/src/edit/modes/replace.ts +93 -40
- package/src/edit/renderer.ts +1 -1
- package/src/edit/streaming.ts +14 -17
- package/src/eval/py/kernel.ts +2 -1
- package/src/eval/py/spawn-options.ts +24 -29
- package/src/export/html/index.ts +10 -3
- package/src/export/html/template.js +8 -26
- package/src/export/share.ts +4 -0
- package/src/extensibility/extensions/wrapper.ts +1 -0
- package/src/extensibility/legacy-pi-ai-shim.ts +22 -1
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +7 -6
- package/src/extensibility/plugins/legacy-pi-compat.ts +124 -57
- package/src/extensibility/skills.ts +11 -0
- package/src/extensibility/utils.ts +10 -2
- package/src/launch/broker.ts +223 -7
- package/src/launch/client.ts +192 -21
- package/src/launch/ensure.ts +73 -0
- package/src/launch/paths.ts +1 -1
- package/src/launch/protocol.ts +54 -2
- package/src/lsp/client.ts +23 -2
- package/src/lsp/index.ts +8 -0
- package/src/lsp/mux/daemon.ts +348 -0
- package/src/lsp/mux/protocol.ts +96 -0
- package/src/lsp/mux/server.ts +797 -0
- package/src/lsp/types.ts +28 -2
- package/src/main.ts +20 -8
- package/src/mcp/config-writer.ts +1 -1
- package/src/mcp/oauth-flow.ts +11 -1
- package/src/mnemopi/embed-client.ts +49 -2
- package/src/mnemopi/state.ts +57 -23
- package/src/modes/components/assistant-message.ts +11 -0
- package/src/modes/components/btw-panel.ts +41 -4
- package/src/modes/components/chat-transcript-builder.ts +4 -0
- package/src/modes/components/custom-editor.ts +9 -0
- package/src/modes/components/read-tool-group.ts +10 -0
- package/src/modes/components/status-line/component.ts +1 -1
- package/src/modes/components/stripped-tool-calls-placeholder.ts +35 -0
- package/src/modes/components/tool-execution.ts +8 -0
- package/src/modes/components/tree-selector.ts +46 -48
- package/src/modes/controllers/btw-controller.ts +55 -7
- package/src/modes/controllers/command-controller.ts +31 -0
- package/src/modes/controllers/event-controller.ts +17 -0
- package/src/modes/controllers/input-controller.ts +63 -8
- package/src/modes/controllers/mcp-command-controller.ts +11 -5
- package/src/modes/controllers/selector-controller.ts +20 -0
- package/src/modes/interactive-mode.ts +18 -2
- package/src/modes/types.ts +9 -1
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/interactive-context-helpers.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +6 -10
- package/src/modes/workflow.ts +8 -2
- package/src/prompts/agents/init.md +1 -1
- package/src/prompts/session/launch-completion.md +1 -0
- package/src/prompts/system/plan-mode-active.md +2 -2
- package/src/prompts/system/system-prompt.md +26 -52
- package/src/prompts/system/workflow-notice.md +3 -3
- package/src/prompts/tools/ast-grep.md +1 -1
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/browser.md +1 -0
- package/src/prompts/tools/computer.md +21 -21
- package/src/prompts/tools/glob.md +1 -1
- package/src/prompts/tools/grep.md +1 -1
- package/src/prompts/tools/replace.md +5 -4
- package/src/prompts/tools/task.md +4 -4
- package/src/sdk.ts +49 -6
- package/src/secrets/index.ts +1 -1
- package/src/security/contracts/schemas.ts +205 -183
- package/src/security/contracts/validation.ts +5 -1
- package/src/security/store.ts +2 -2
- package/src/session/agent-session-types.ts +9 -1
- package/src/session/agent-session.ts +204 -15
- package/src/session/indexed-session-storage.ts +9 -0
- package/src/session/launch-completion.ts +37 -0
- package/src/session/prewalk.ts +24 -2
- package/src/session/session-advisors.ts +2 -2
- package/src/session/session-context.ts +42 -12
- package/src/session/session-dump-format.ts +1 -1
- package/src/session/session-entries.ts +17 -1
- package/src/session/session-maintenance.ts +38 -4
- package/src/session/session-manager.ts +123 -67
- package/src/session/session-paths.ts +118 -55
- package/src/session/session-stats.ts +48 -3
- package/src/session/session-storage.ts +30 -22
- package/src/session/stream-guards.ts +1 -1
- package/src/session/yield-queue.ts +121 -16
- package/src/slash-commands/builtin-registry.ts +37 -24
- package/src/system-prompt.ts +8 -3
- package/src/task/index.ts +23 -8
- package/src/task/spawn-policy.ts +14 -0
- package/src/thinking.ts +2 -8
- package/src/tools/ast-grep.ts +10 -4
- package/src/tools/browser/cmux/cmux-tab.ts +97 -14
- package/src/tools/browser/cmux/rpc.ts +2 -8
- package/src/tools/browser/registry.ts +53 -2
- package/src/tools/browser/relay/bridge.ts +945 -0
- package/src/tools/browser/relay/daemon.ts +117 -0
- package/src/tools/browser/relay/extension-assets/background.js.txt +242 -0
- package/src/tools/browser/relay/extension-assets/manifest.json.txt +14 -0
- package/src/tools/browser/relay/extension-assets/options.html.txt +53 -0
- package/src/tools/browser/relay/extension-assets/options.js.txt +23 -0
- package/src/tools/browser/relay/kind.ts +41 -0
- package/src/tools/browser/relay/protocol.ts +54 -0
- package/src/tools/browser/relay/server.ts +141 -0
- package/src/tools/browser/render.ts +4 -1
- package/src/tools/browser/shared-daemon.ts +7 -58
- package/src/tools/browser/tab-supervisor.ts +5 -4
- package/src/tools/browser/tab-worker.ts +33 -12
- package/src/tools/browser.ts +26 -1
- package/src/tools/computer/exposure.ts +11 -35
- package/src/tools/computer/protocol.ts +51 -10
- package/src/tools/computer/supervisor.ts +227 -124
- package/src/tools/computer/worker-entry.ts +11 -6
- package/src/tools/computer/worker.ts +695 -81
- package/src/tools/computer-renderer.ts +104 -65
- package/src/tools/computer.ts +134 -428
- package/src/tools/context.ts +3 -0
- package/src/tools/glob.ts +9 -2
- package/src/tools/grep.ts +12 -6
- package/src/tools/hub/launch.ts +122 -6
- package/src/tools/index.ts +9 -0
- package/src/tools/inspect-image.ts +32 -6
- package/src/tools/render-utils.ts +2 -0
- package/src/tools/{browser/run-cancellation.ts → run-scope.ts} +11 -11
- package/src/tools/tool-timeouts.ts +1 -0
- package/src/tools/xdev.ts +29 -2
- package/src/utils/clipboard.ts +40 -14
- package/src/utils/command-args.ts +26 -28
- package/src/utils/tool-choice.ts +0 -13
- package/src/web/kagi.ts +2 -1
- package/src/web/search/index.ts +18 -2
- package/src/web/search/providers/anthropic.ts +4 -1
- package/src/web/search/providers/base.ts +2 -0
- package/src/web/search/providers/brave.ts +3 -1
- package/src/web/search/providers/browser-page.ts +6 -4
- package/src/web/search/providers/codex.ts +4 -1
- package/src/web/search/providers/duckduckgo.ts +2 -1
- package/src/web/search/providers/ecosia.ts +2 -1
- package/src/web/search/providers/exa.ts +4 -2
- package/src/web/search/providers/firecrawl.ts +3 -1
- package/src/web/search/providers/gemini.ts +8 -2
- package/src/web/search/providers/google.ts +2 -1
- package/src/web/search/providers/jina.ts +12 -2
- package/src/web/search/providers/kagi.ts +3 -0
- package/src/web/search/providers/kimi.ts +5 -1
- package/src/web/search/providers/mojeek.ts +2 -1
- package/src/web/search/providers/parallel.ts +5 -1
- package/src/web/search/providers/perplexity.ts +6 -3
- package/src/web/search/providers/public.ts +1 -1
- package/src/web/search/providers/searxng.ts +11 -5
- package/src/web/search/providers/startpage.ts +10 -4
- package/src/web/search/providers/synthetic.ts +11 -5
- package/src/web/search/providers/tavily.ts +3 -1
- package/src/web/search/providers/tinyfish.ts +3 -1
- package/src/web/search/providers/utils.ts +12 -10
- package/src/web/search/providers/xai.ts +2 -2
- package/src/web/search/providers/zai.ts +18 -3
- package/src/web/search/types.ts +6 -0
- package/dist/types/config/file-lock.d.ts +0 -29
- package/src/config/file-lock.ts +0 -164
|
@@ -13,7 +13,13 @@ import {
|
|
|
13
13
|
} from "@oh-my-pi/pi-tui";
|
|
14
14
|
import type { TreeFilterMode } from "../../config/settings-schema";
|
|
15
15
|
import { theme } from "../../modes/theme/theme";
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
matchesAppInterrupt,
|
|
18
|
+
matchesSelectDown,
|
|
19
|
+
matchesSelectPageDown,
|
|
20
|
+
matchesSelectPageUp,
|
|
21
|
+
matchesSelectUp,
|
|
22
|
+
} from "../../modes/utils/keybinding-matchers";
|
|
17
23
|
import type { SessionTreeNode } from "../../session/session-entries";
|
|
18
24
|
import { toPathList } from "../../tools/path-utils";
|
|
19
25
|
import { shortenPath } from "../../tools/render-utils";
|
|
@@ -144,13 +150,12 @@ class TreeList implements Component {
|
|
|
144
150
|
const result: FlatNode[] = [];
|
|
145
151
|
this.#toolCallMap.clear();
|
|
146
152
|
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
// - At indent 2+: stay flat for single-child chains, +1 only if parent branches
|
|
153
|
+
// A real branch point adds one indentation level. Linear conversation
|
|
154
|
+
// chains retain that level so their text stays aligned with the branch
|
|
155
|
+
// head instead of drifting right after every fork.
|
|
151
156
|
|
|
152
|
-
// Stack items: [node, indent,
|
|
153
|
-
type StackItem = [SessionTreeNode, number, boolean, boolean,
|
|
157
|
+
// Stack items: [node, indent, showConnector, isLast, gutters, isVirtualRootChild]
|
|
158
|
+
type StackItem = [SessionTreeNode, number, boolean, boolean, GutterInfo[], boolean];
|
|
154
159
|
const stack: StackItem[] = [];
|
|
155
160
|
|
|
156
161
|
// Determine which subtrees contain the active leaf (to sort current branch first)
|
|
@@ -188,11 +193,11 @@ class TreeList implements Component {
|
|
|
188
193
|
const orderedRoots = [...roots].sort((a, b) => Number(containsActive.get(b)) - Number(containsActive.get(a)));
|
|
189
194
|
for (let i = orderedRoots.length - 1; i >= 0; i--) {
|
|
190
195
|
const isLast = i === orderedRoots.length - 1;
|
|
191
|
-
stack.push([orderedRoots[i], multipleRoots ? 1 : 0, multipleRoots,
|
|
196
|
+
stack.push([orderedRoots[i], multipleRoots ? 1 : 0, multipleRoots, isLast, [], multipleRoots]);
|
|
192
197
|
}
|
|
193
198
|
|
|
194
199
|
while (stack.length > 0) {
|
|
195
|
-
const [node, indent,
|
|
200
|
+
const [node, indent, showConnector, isLast, gutters, isVirtualRootChild] = stack.pop()!;
|
|
196
201
|
|
|
197
202
|
// Extract tool calls from assistant messages for later lookup
|
|
198
203
|
const entry = node.entry;
|
|
@@ -227,18 +232,10 @@ class TreeList implements Component {
|
|
|
227
232
|
return [...prioritized, ...rest];
|
|
228
233
|
})();
|
|
229
234
|
|
|
230
|
-
//
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
childIndent = indent + 1;
|
|
235
|
-
} else if (justBranched && indent > 0) {
|
|
236
|
-
// First generation after a branch: +1 for visual grouping
|
|
237
|
-
childIndent = indent + 1;
|
|
238
|
-
} else {
|
|
239
|
-
// Single-child chain: stay flat
|
|
240
|
-
childIndent = indent;
|
|
241
|
-
}
|
|
235
|
+
// Real branch points add visual depth, and a virtual root's direct
|
|
236
|
+
// children (the session roots) nest one level under the shared column-0
|
|
237
|
+
// root. Linear continuations otherwise stay aligned with their head.
|
|
238
|
+
const childIndent = multipleChildren || isVirtualRootChild ? indent + 1 : indent;
|
|
242
239
|
|
|
243
240
|
// Build gutters for children
|
|
244
241
|
// If this node showed a connector, add a gutter entry for descendants
|
|
@@ -255,15 +252,7 @@ class TreeList implements Component {
|
|
|
255
252
|
// Add children in reverse order
|
|
256
253
|
for (let i = orderedChildren.length - 1; i >= 0; i--) {
|
|
257
254
|
const childIsLast = i === orderedChildren.length - 1;
|
|
258
|
-
stack.push([
|
|
259
|
-
orderedChildren[i],
|
|
260
|
-
childIndent,
|
|
261
|
-
multipleChildren,
|
|
262
|
-
multipleChildren,
|
|
263
|
-
childIsLast,
|
|
264
|
-
childGutters,
|
|
265
|
-
false,
|
|
266
|
-
]);
|
|
255
|
+
stack.push([orderedChildren[i], childIndent, multipleChildren, childIsLast, childGutters, false]);
|
|
267
256
|
}
|
|
268
257
|
}
|
|
269
258
|
|
|
@@ -516,16 +505,8 @@ class TreeList implements Component {
|
|
|
516
505
|
const renderedIndent = Math.min(displayIndent, maxIndentLevels);
|
|
517
506
|
const scrollOffset = displayIndent - renderedIndent;
|
|
518
507
|
const connectorPositionDisplay = hasConnector ? renderedIndent - 1 : -1;
|
|
519
|
-
//
|
|
520
|
-
//
|
|
521
|
-
// suppressed gutter — the column where the row's own connector would
|
|
522
|
-
// sit, directly below the branch head's content. Drawing it in the
|
|
523
|
-
// `└─` column itself contradicts the corner and leaves dangling,
|
|
524
|
-
// drifting verticals once the chain branches deeper (#2298, #2325).
|
|
525
|
-
// Chains under `├─` heads need no extra anchor: the sibling line
|
|
526
|
-
// (`show: true` gutter) already ties them to their branch.
|
|
527
|
-
const nearestGutter = !hasConnector ? flatNode.gutters[flatNode.gutters.length - 1] : undefined;
|
|
528
|
-
const chainAnchorLevel = nearestGutter && !nearestGutter.show ? nearestGutter.position + 1 : -1;
|
|
508
|
+
// Linear rows reuse their branch head's depth. Existing sibling
|
|
509
|
+
// gutters remain visible; terminal gutters remain terminated.
|
|
529
510
|
|
|
530
511
|
// Build prefix char by char, placing gutters and connector at their positions
|
|
531
512
|
const totalChars = renderedIndent * 3;
|
|
@@ -545,9 +526,6 @@ class TreeList implements Component {
|
|
|
545
526
|
} else {
|
|
546
527
|
prefixChars.push(" ");
|
|
547
528
|
}
|
|
548
|
-
} else if (originalLevel === chainAnchorLevel) {
|
|
549
|
-
// Chain anchor for rows under a `└─` branch head.
|
|
550
|
-
prefixChars.push(posInLevel === 0 ? theme.tree.vertical : " ");
|
|
551
529
|
} else if (hasConnector && level === connectorPositionDisplay) {
|
|
552
530
|
// Connector at this level
|
|
553
531
|
if (posInLevel === 0) {
|
|
@@ -781,16 +759,36 @@ class TreeList implements Component {
|
|
|
781
759
|
}
|
|
782
760
|
}
|
|
783
761
|
|
|
762
|
+
#moveToAdjacentTurn(direction: -1 | 1): void {
|
|
763
|
+
for (
|
|
764
|
+
let index = this.#selectedIndex + direction;
|
|
765
|
+
index >= 0 && index < this.#filteredNodes.length;
|
|
766
|
+
index += direction
|
|
767
|
+
) {
|
|
768
|
+
const entry = this.#filteredNodes[index]?.node.entry;
|
|
769
|
+
if (entry?.type === "message" && (entry.message.role === "user" || entry.message.role === "assistant")) {
|
|
770
|
+
this.#selectedIndex = index;
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
784
776
|
handleInput(keyData: string): void {
|
|
785
777
|
if (matchesSelectUp(keyData)) {
|
|
786
778
|
this.#selectedIndex = this.#selectedIndex === 0 ? this.#filteredNodes.length - 1 : this.#selectedIndex - 1;
|
|
787
779
|
} else if (matchesSelectDown(keyData)) {
|
|
788
780
|
this.#selectedIndex = this.#selectedIndex === this.#filteredNodes.length - 1 ? 0 : this.#selectedIndex + 1;
|
|
789
|
-
} else if (matchesKey(keyData, "
|
|
790
|
-
|
|
781
|
+
} else if (matchesKey(keyData, "alt+up")) {
|
|
782
|
+
this.#moveToAdjacentTurn(-1);
|
|
783
|
+
} else if (matchesKey(keyData, "alt+down")) {
|
|
784
|
+
this.#moveToAdjacentTurn(1);
|
|
785
|
+
} else if (matchesKey(keyData, "home")) {
|
|
786
|
+
this.#selectedIndex = 0;
|
|
787
|
+
} else if (matchesKey(keyData, "end")) {
|
|
788
|
+
this.#selectedIndex = Math.max(0, this.#filteredNodes.length - 1);
|
|
789
|
+
} else if (matchesSelectPageUp(keyData) || matchesKey(keyData, "left")) {
|
|
791
790
|
this.#selectedIndex = Math.max(0, this.#selectedIndex - this.maxVisibleLines);
|
|
792
|
-
} else if (matchesKey(keyData, "right")) {
|
|
793
|
-
// Page down
|
|
791
|
+
} else if (matchesSelectPageDown(keyData) || matchesKey(keyData, "right")) {
|
|
794
792
|
this.#selectedIndex = Math.min(this.#filteredNodes.length - 1, this.#selectedIndex + this.maxVisibleLines);
|
|
795
793
|
} else if (matchesKey(keyData, "shift+enter") || matchesKey(keyData, "shift+return")) {
|
|
796
794
|
// Summarize-and-switch: fork with a branch summary without the extra prompt.
|
|
@@ -954,7 +952,7 @@ export class TreeSelectorComponent extends Container {
|
|
|
954
952
|
new TruncatedText(
|
|
955
953
|
theme.fg(
|
|
956
954
|
"muted",
|
|
957
|
-
"Enter: switch. Shift+Enter: summarize & switch. Shift+L: label. Ctrl+O: filter. Alt+D/T/U/L/A: filter. Type to search",
|
|
955
|
+
"Enter: switch. Alt+↑/↓: previous/next turn. PgUp/PgDn (←/→): page. Home/End: first/last item. Shift+Enter: summarize & switch. Shift+L: label. Ctrl+O: filter. Alt+D/T/U/L/A: filter. Type to search",
|
|
958
956
|
),
|
|
959
957
|
0,
|
|
960
958
|
0,
|
|
@@ -10,6 +10,7 @@ interface BtwRequest {
|
|
|
10
10
|
abortController: AbortController;
|
|
11
11
|
question: string;
|
|
12
12
|
leafId: string | null;
|
|
13
|
+
sessionId: string;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
function assistantMessageWithReplyText(assistantMessage: AssistantMessage, replyText: string): AssistantMessage {
|
|
@@ -39,6 +40,7 @@ export class BtwController {
|
|
|
39
40
|
#lastReplyText: string | undefined;
|
|
40
41
|
#lastAssistantMessage: AssistantMessage | undefined;
|
|
41
42
|
#lastLeafId: string | null | undefined;
|
|
43
|
+
#lastSessionId: string | undefined;
|
|
42
44
|
#branchInFlight = false;
|
|
43
45
|
#lastCopyText: string | undefined;
|
|
44
46
|
#copyInFlight = false;
|
|
@@ -50,17 +52,39 @@ export class BtwController {
|
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
canBranch(): boolean {
|
|
55
|
+
return this.#branchUnavailableReason() === undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Whether plain `b` is currently reserved for a completed or pending branch action. */
|
|
59
|
+
handlesBranchKey(): boolean {
|
|
60
|
+
if (this.#branchInFlight) return true;
|
|
61
|
+
if (this.#activeRequest?.component.isBranchable() !== true) return false;
|
|
53
62
|
return (
|
|
54
|
-
!this.#branchInFlight &&
|
|
55
|
-
this.#activeRequest?.component.isBranchable() === true &&
|
|
56
63
|
this.#lastQuestion !== undefined &&
|
|
57
64
|
this.#lastReplyText !== undefined &&
|
|
58
65
|
this.#lastAssistantMessage !== undefined &&
|
|
59
|
-
this.#lastLeafId !==
|
|
60
|
-
this.#
|
|
66
|
+
this.#lastLeafId !== undefined &&
|
|
67
|
+
this.#lastSessionId !== undefined
|
|
61
68
|
);
|
|
62
69
|
}
|
|
63
70
|
|
|
71
|
+
#branchUnavailableReason(): string | undefined {
|
|
72
|
+
if (this.#branchInFlight) return "a branch is already in progress";
|
|
73
|
+
if (this.#activeRequest?.component.isBranchable() !== true) return "the answer is not ready";
|
|
74
|
+
if (!this.#lastQuestion || !this.#lastReplyText || !this.#lastAssistantMessage) {
|
|
75
|
+
return "the answer is unavailable";
|
|
76
|
+
}
|
|
77
|
+
if (!this.#lastLeafId) return "the session has no branch point";
|
|
78
|
+
if (
|
|
79
|
+
this.#lastSessionId !== this.ctx.sessionManager.getSessionId() ||
|
|
80
|
+
this.#lastLeafId !== this.ctx.sessionManager.getLeafId()
|
|
81
|
+
) {
|
|
82
|
+
return "the session changed since /btw started";
|
|
83
|
+
}
|
|
84
|
+
if (this.ctx.session.isStreaming) return "a turn is still running";
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
64
88
|
canCopy(): boolean {
|
|
65
89
|
return (
|
|
66
90
|
!this.#copyInFlight && this.#activeRequest?.component.isCopyable() === true && this.#lastCopyText !== undefined
|
|
@@ -83,17 +107,34 @@ export class BtwController {
|
|
|
83
107
|
}
|
|
84
108
|
|
|
85
109
|
async handleBranch(): Promise<boolean> {
|
|
86
|
-
|
|
110
|
+
const unavailableReason = this.#branchUnavailableReason();
|
|
111
|
+
if (unavailableReason) {
|
|
112
|
+
this.ctx.showStatus(`/btw branch unavailable: ${unavailableReason}`, { dim: true });
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
const request = this.#activeRequest;
|
|
116
|
+
const question = this.#lastQuestion;
|
|
117
|
+
const assistantMessage = this.#lastAssistantMessage;
|
|
118
|
+
const leafId = this.#lastLeafId;
|
|
119
|
+
const sessionId = this.#lastSessionId;
|
|
120
|
+
if (!request || !question || !assistantMessage || !leafId || !sessionId) return false;
|
|
121
|
+
|
|
87
122
|
this.#branchInFlight = true;
|
|
123
|
+
request.component.markBranching();
|
|
88
124
|
try {
|
|
89
|
-
await this.ctx.handleBtwBranch(
|
|
125
|
+
await this.ctx.handleBtwBranch(question, assistantMessage, leafId, sessionId);
|
|
90
126
|
return true;
|
|
91
127
|
} finally {
|
|
92
128
|
this.#branchInFlight = false;
|
|
129
|
+
if (this.#activeRequest === request) request.component.markComplete();
|
|
93
130
|
}
|
|
94
131
|
}
|
|
95
132
|
|
|
96
133
|
handleEscape(): boolean {
|
|
134
|
+
if (this.#branchInFlight) {
|
|
135
|
+
this.ctx.showStatus("/btw branch is in progress", { dim: true });
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
97
138
|
if (!this.#activeRequest) return false;
|
|
98
139
|
this.#closeActiveRequest({ abort: this.#activeRequest.abortController.signal.aborted === false });
|
|
99
140
|
return true;
|
|
@@ -119,10 +160,15 @@ export class BtwController {
|
|
|
119
160
|
this.#closeActiveRequest({ abort: true });
|
|
120
161
|
|
|
121
162
|
const request: BtwRequest = {
|
|
122
|
-
component: new BtwPanelComponent({
|
|
163
|
+
component: new BtwPanelComponent({
|
|
164
|
+
question: trimmedQuestion,
|
|
165
|
+
tui: this.ctx.ui,
|
|
166
|
+
canBranch: () => this.canBranch(),
|
|
167
|
+
}),
|
|
123
168
|
abortController: new AbortController(),
|
|
124
169
|
question: trimmedQuestion,
|
|
125
170
|
leafId: this.ctx.sessionManager.getLeafId(),
|
|
171
|
+
sessionId: this.ctx.sessionManager.getSessionId(),
|
|
126
172
|
};
|
|
127
173
|
this.ctx.btwContainer.clear();
|
|
128
174
|
this.ctx.btwContainer.addChild(request.component);
|
|
@@ -156,6 +202,7 @@ export class BtwController {
|
|
|
156
202
|
this.#lastCopyText = copyText;
|
|
157
203
|
this.#lastAssistantMessage = assistantMessageWithReplyText(assistantMessage, replyText);
|
|
158
204
|
this.#lastLeafId = request.leafId;
|
|
205
|
+
this.#lastSessionId = request.sessionId;
|
|
159
206
|
} else {
|
|
160
207
|
this.#clearCompletedState();
|
|
161
208
|
}
|
|
@@ -190,6 +237,7 @@ export class BtwController {
|
|
|
190
237
|
this.#lastAssistantMessage = undefined;
|
|
191
238
|
this.#lastCopyText = undefined;
|
|
192
239
|
this.#lastLeafId = undefined;
|
|
240
|
+
this.#lastSessionId = undefined;
|
|
193
241
|
}
|
|
194
242
|
|
|
195
243
|
#isActiveRequest(request: BtwRequest): boolean {
|
|
@@ -961,6 +961,37 @@ export class CommandController {
|
|
|
961
961
|
this.ctx.showStatus(`Fresh provider session started (${result.closedProviderSessions} ${stateLabel} pruned).`);
|
|
962
962
|
}
|
|
963
963
|
|
|
964
|
+
async handleResetContextCommand(): Promise<void> {
|
|
965
|
+
if (this.ctx.session.isCompacting) {
|
|
966
|
+
this.ctx.session.abortCompaction();
|
|
967
|
+
while (this.ctx.session.isCompacting) {
|
|
968
|
+
await Bun.sleep(10);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
const result = await this.ctx.session.resetSessionContext();
|
|
972
|
+
if (!result) {
|
|
973
|
+
this.ctx.showWarning("Wait for the current response to finish or abort it before resetting the context.");
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
// Drop the rendered transcript so the UI matches the now-empty model
|
|
977
|
+
// context (mirrors #runNewSessionFlow's teardown, minus the new session —
|
|
978
|
+
// the session id, title, and transcript file all survive).
|
|
979
|
+
this.ctx.clearTransientSessionUi();
|
|
980
|
+
this.ctx.resetTranscript();
|
|
981
|
+
this.ctx.statusLine.invalidate();
|
|
982
|
+
this.ctx.updateEditorBorderColor();
|
|
983
|
+
const noun = result.droppedCount === 1 ? "message" : "messages";
|
|
984
|
+
this.ctx.present([
|
|
985
|
+
new Spacer(1),
|
|
986
|
+
new Text(
|
|
987
|
+
`${theme.fg("accent", `${theme.status.success} Context reset — ${result.droppedCount} ${noun} dropped; session continues.`)}`,
|
|
988
|
+
1,
|
|
989
|
+
1,
|
|
990
|
+
),
|
|
991
|
+
]);
|
|
992
|
+
this.ctx.ui.requestRender(true, { clearScrollback: true });
|
|
993
|
+
}
|
|
994
|
+
|
|
964
995
|
async handleDropCommand(): Promise<void> {
|
|
965
996
|
if (!this.ctx.sessionManager.getSessionFile()) {
|
|
966
997
|
this.ctx.showError("Nothing to drop (in-memory session)");
|
|
@@ -276,6 +276,7 @@ export class EventController {
|
|
|
276
276
|
showContentPreview: this.ctx.settings.get("read.toolResultPreview"),
|
|
277
277
|
});
|
|
278
278
|
group.setExpanded(this.ctx.toolOutputExpanded);
|
|
279
|
+
group.setToolActivityVisible(!this.ctx.hideToolActivity);
|
|
279
280
|
this.ctx.chatContainer.addChild(group);
|
|
280
281
|
this.#lastReadGroup = group;
|
|
281
282
|
}
|
|
@@ -927,6 +928,7 @@ export class EventController {
|
|
|
927
928
|
content.id,
|
|
928
929
|
);
|
|
929
930
|
component.setExpanded(this.ctx.toolOutputExpanded);
|
|
931
|
+
component.setToolActivityVisible(!this.ctx.hideToolActivity);
|
|
930
932
|
this.ctx.chatContainer.addChild(component);
|
|
931
933
|
this.ctx.pendingTools.set(content.id, component);
|
|
932
934
|
this.#toolTimelineComponents.set(content.id, component);
|
|
@@ -1176,6 +1178,7 @@ export class EventController {
|
|
|
1176
1178
|
event.toolCallId,
|
|
1177
1179
|
);
|
|
1178
1180
|
component.setExpanded(this.ctx.toolOutputExpanded);
|
|
1181
|
+
component.setToolActivityVisible(!this.ctx.hideToolActivity);
|
|
1179
1182
|
this.ctx.chatContainer.addChild(component);
|
|
1180
1183
|
this.ctx.pendingTools.set(event.toolCallId, component);
|
|
1181
1184
|
this.#toolTimelineComponents.set(event.toolCallId, component);
|
|
@@ -1464,6 +1467,20 @@ export class EventController {
|
|
|
1464
1467
|
// the loader and finalizes it at its own agent_end (isStreaming === false by
|
|
1465
1468
|
// then). Mirrors the collab guest's !isStreaming loader reconciler.
|
|
1466
1469
|
if (this.ctx.session.isStreaming) return;
|
|
1470
|
+
// A non-terminal settle (`isTerminal: false`) is a scheduling pause, not the
|
|
1471
|
+
// end of the run: an unsuppressed async job (a `/vibe` worker turn, a bash
|
|
1472
|
+
// `async` job, etc.) will re-wake the loop when its result is delivered.
|
|
1473
|
+
// `AgentSession` tags this on the deferred event (see `#hasPendingAsyncWake`
|
|
1474
|
+
// in agent-session.ts). Skip the idle title/loader teardown so the tab keeps
|
|
1475
|
+
// reading "working"; the later terminal `agent_end` performs it. Still flush
|
|
1476
|
+
// a deferred model switch — the plan-mode reconciler queues it to apply once
|
|
1477
|
+
// the current stream ends, and `#finishAgentEnd` is otherwise its only flush
|
|
1478
|
+
// site, so the automatic continuation would otherwise run on the old
|
|
1479
|
+
// model/thinking level until the terminal settle.
|
|
1480
|
+
if (event.isTerminal === false) {
|
|
1481
|
+
await this.ctx.flushPendingModelSwitch();
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1467
1484
|
setTerminalTitleState("idle");
|
|
1468
1485
|
|
|
1469
1486
|
await this.#finishAgentEnd(event);
|
|
@@ -8,8 +8,11 @@ import { isSettingsInitialized, settings } from "../../config/settings";
|
|
|
8
8
|
import { resolveLocalRoot } from "../../internal-urls";
|
|
9
9
|
import { AssistantMessageComponent } from "../../modes/components/assistant-message";
|
|
10
10
|
import { extractImagePathFromText } from "../../modes/components/custom-editor";
|
|
11
|
+
import { ReadToolGroupComponent } from "../../modes/components/read-tool-group";
|
|
11
12
|
import { renderSegmentTrack } from "../../modes/components/segment-track";
|
|
13
|
+
import { StrippedToolCallsPlaceholder } from "../../modes/components/stripped-tool-calls-placeholder";
|
|
12
14
|
import { TinyTitleDownloadProgressComponent } from "../../modes/components/tiny-title-download-progress";
|
|
15
|
+
import { ToolExecutionComponent } from "../../modes/components/tool-execution";
|
|
13
16
|
import { expandEmoticons } from "../../modes/emoji-autocomplete";
|
|
14
17
|
import { materializeImageReferenceLinks, shiftImageMarkers } from "../../modes/image-references";
|
|
15
18
|
import { createPromptActionAutocompleteProvider } from "../../modes/prompt-action-autocomplete";
|
|
@@ -247,7 +250,7 @@ export class InputController {
|
|
|
247
250
|
this.#btwBranchListenerInstalled = true;
|
|
248
251
|
this.ctx.ui.addInputListener(data => {
|
|
249
252
|
if (!matchesKey(data, "b")) return undefined;
|
|
250
|
-
if (!this.ctx.
|
|
253
|
+
if (!this.ctx.handlesBtwBranchKey()) return undefined;
|
|
251
254
|
if (this.ctx.ui.getFocused() !== this.ctx.editor) return undefined;
|
|
252
255
|
if (this.ctx.editor.getText().trim()) return undefined;
|
|
253
256
|
void this.ctx.handleBtwBranchKey();
|
|
@@ -327,10 +330,10 @@ export class InputController {
|
|
|
327
330
|
}
|
|
328
331
|
|
|
329
332
|
if (this.ctx.loopModeEnabled) {
|
|
330
|
-
this.ctx.pauseLoop();
|
|
331
333
|
if (this.ctx.session.isStreaming) {
|
|
332
334
|
this.#abortStreamingTurn();
|
|
333
335
|
} else {
|
|
336
|
+
this.ctx.pauseLoop();
|
|
334
337
|
this.ctx.cancelPendingSubmission();
|
|
335
338
|
}
|
|
336
339
|
return;
|
|
@@ -455,6 +458,11 @@ export class InputController {
|
|
|
455
458
|
this.ctx.editor.onCopyPrompt = () => this.handleCopyPrompt();
|
|
456
459
|
this.ctx.editor.setActionKeys("app.tools.expand", this.ctx.keybindings.getKeys("app.tools.expand"));
|
|
457
460
|
this.ctx.editor.onExpandTools = () => this.toggleToolOutputExpansion();
|
|
461
|
+
this.ctx.editor.setActionKeys(
|
|
462
|
+
"app.tools.toggleVisibility",
|
|
463
|
+
this.ctx.keybindings.getKeys("app.tools.toggleVisibility"),
|
|
464
|
+
);
|
|
465
|
+
this.ctx.editor.onToggleToolActivity = () => this.toggleToolActivityVisibility();
|
|
458
466
|
this.ctx.editor.setActionKeys("app.message.dequeue", this.ctx.keybindings.getKeys("app.message.dequeue"));
|
|
459
467
|
this.ctx.editor.onDequeue = () => this.handleDequeue();
|
|
460
468
|
this.ctx.editor.setActionKeys("app.retry", this.ctx.keybindings.getKeys("app.retry"));
|
|
@@ -793,6 +801,19 @@ export class InputController {
|
|
|
793
801
|
this.ctx.queueCompactionMessage(text, "steer", images);
|
|
794
802
|
return;
|
|
795
803
|
}
|
|
804
|
+
// Extension commands are local actions. Execute them before the normal
|
|
805
|
+
// submission path creates an optimistic user message; otherwise a
|
|
806
|
+
// consumed command remains rendered like a prompt sent to the model.
|
|
807
|
+
if (this.#isLocalExtensionCommand(text)) {
|
|
808
|
+
this.ctx.editor.clearDraft(text);
|
|
809
|
+
try {
|
|
810
|
+
await this.ctx.session.prompt(text, { images: inputImages });
|
|
811
|
+
} catch (error) {
|
|
812
|
+
this.ctx.editor.setText(text);
|
|
813
|
+
this.ctx.showError(error instanceof Error ? error.message : String(error));
|
|
814
|
+
}
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
796
817
|
|
|
797
818
|
// If streaming, use prompt() with steer behavior
|
|
798
819
|
// This handles extension commands (execute immediately), prompt template expansion, and queueing
|
|
@@ -906,14 +927,18 @@ export class InputController {
|
|
|
906
927
|
* Local extension commands are consumed before reaching the shared session
|
|
907
928
|
* title gate and must not name the conversation.
|
|
908
929
|
*/
|
|
909
|
-
#
|
|
910
|
-
const runner = this.ctx.session.extensionRunner;
|
|
930
|
+
#isLocalExtensionCommand(text: string): boolean {
|
|
911
931
|
const extensionCommandSpace = text.indexOf(" ");
|
|
912
|
-
|
|
932
|
+
return (
|
|
913
933
|
text.startsWith("/") &&
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
934
|
+
this.ctx.session.extensionRunner?.getCommand(
|
|
935
|
+
extensionCommandSpace === -1 ? text.slice(1) : text.slice(1, extensionCommandSpace),
|
|
936
|
+
) !== undefined
|
|
937
|
+
);
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
#maybeStartTitleGeneration(text: string): void {
|
|
941
|
+
if (this.#isLocalExtensionCommand(text)) {
|
|
917
942
|
return;
|
|
918
943
|
}
|
|
919
944
|
this.ctx.session.maybeStartTitleGeneration(text, () => {
|
|
@@ -1845,9 +1870,39 @@ export class InputController {
|
|
|
1845
1870
|
}
|
|
1846
1871
|
|
|
1847
1872
|
toggleToolOutputExpansion(): void {
|
|
1873
|
+
if (this.ctx.hideToolActivity) {
|
|
1874
|
+
const visibilityKey = this.ctx.keybindings.getDisplayString("app.tools.toggleVisibility");
|
|
1875
|
+
const visibilityHint = visibilityKey ? `${visibilityKey} or /settings` : "/settings";
|
|
1876
|
+
this.ctx.showStatus(`Tool activity is hidden — show it with ${visibilityHint} before expanding`);
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1848
1879
|
this.setToolsExpanded(!this.ctx.toolOutputExpanded);
|
|
1849
1880
|
}
|
|
1850
1881
|
|
|
1882
|
+
toggleToolActivityVisibility(): void {
|
|
1883
|
+
this.ctx.hideToolActivity = !this.ctx.hideToolActivity;
|
|
1884
|
+
this.ctx.settings.set("display.hideToolActivity", this.ctx.hideToolActivity);
|
|
1885
|
+
|
|
1886
|
+
if (!this.ctx.hideToolActivity) {
|
|
1887
|
+
this.ctx.toolOutputExpanded = false;
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
for (const child of this.ctx.chatContainer.children) {
|
|
1891
|
+
if (child instanceof ToolExecutionComponent || child instanceof ReadToolGroupComponent) {
|
|
1892
|
+
if (!this.ctx.hideToolActivity) child.setExpanded(false);
|
|
1893
|
+
child.setToolActivityVisible(!this.ctx.hideToolActivity);
|
|
1894
|
+
} else if (child instanceof AssistantMessageComponent) {
|
|
1895
|
+
child.setToolResultImagesVisible(!this.ctx.hideToolActivity);
|
|
1896
|
+
} else if (child instanceof StrippedToolCallsPlaceholder) {
|
|
1897
|
+
child.setToolActivityVisible(!this.ctx.hideToolActivity);
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
if (this.ctx.hideToolActivity) this.ctx.ui.clearInlineImages();
|
|
1902
|
+
this.ctx.ui.resetDisplay();
|
|
1903
|
+
this.ctx.showStatus(`Tool activity: ${this.ctx.hideToolActivity ? "hidden" : "visible"}`);
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1851
1906
|
setToolsExpanded(expanded: boolean): void {
|
|
1852
1907
|
this.ctx.toolOutputExpanded = expanded;
|
|
1853
1908
|
for (const child of this.ctx.chatContainer.children) {
|
|
@@ -1793,16 +1793,22 @@ export class MCPCommandController {
|
|
|
1793
1793
|
const oauth = await this.#resolveOAuthEndpointsFromServer(runtimeBaseConfig, options.authChallenge);
|
|
1794
1794
|
const serverUrl =
|
|
1795
1795
|
runtimeBaseConfig.type === "http" || runtimeBaseConfig.type === "sse" ? runtimeBaseConfig.url : undefined;
|
|
1796
|
-
//
|
|
1797
|
-
//
|
|
1798
|
-
//
|
|
1799
|
-
|
|
1796
|
+
// Client credentials drive the token exchange, so they must come from the
|
|
1797
|
+
// env-expanded runtime config; `found.config`/`currentAuth` may still hold
|
|
1798
|
+
// `${...}` placeholders (the wizard writes the secret to auth.clientSecret).
|
|
1799
|
+
// DCR secrets are embedded in the stored credential and never echoed back
|
|
1800
|
+
// into config files.
|
|
1801
|
+
const runtimeAuth = currentAuth ? expandEnvVarsDeep(currentAuth) : undefined;
|
|
1802
|
+
const configuredClientId = runtimeBaseConfig.oauth?.clientId ?? runtimeAuth?.clientId;
|
|
1800
1803
|
const existingCredential = lookupMcpOAuthCredentialForServer(authStorage, currentAuth, serverUrl)?.credential;
|
|
1801
1804
|
const flowClientId = oauth.clientId ?? configuredClientId ?? existingCredential?.clientId ?? "";
|
|
1802
1805
|
const storedClientSecret =
|
|
1803
1806
|
existingCredential?.clientId === flowClientId ? existingCredential.clientSecret : undefined;
|
|
1807
|
+
const flowClientSecret =
|
|
1808
|
+
runtimeBaseConfig.oauth?.clientSecret ?? runtimeAuth?.clientSecret ?? storedClientSecret ?? "";
|
|
1809
|
+
// Persisted separately below: keep the raw `${...}` placeholder in the file
|
|
1810
|
+
// rather than writing the resolved secret back to (possibly shared) config.
|
|
1804
1811
|
const userClientSecret = found.config.oauth?.clientSecret ?? currentAuth?.clientSecret;
|
|
1805
|
-
const flowClientSecret = userClientSecret ?? storedClientSecret ?? "";
|
|
1806
1812
|
|
|
1807
1813
|
if (!options.silent) {
|
|
1808
1814
|
this.#showMessage(["", theme.fg("muted", `Reauthorizing "${name}"...`), ""].join("\n"));
|
|
@@ -92,11 +92,13 @@ import { ModelHubComponent, type ModelRoleSelectionScope } from "../components/m
|
|
|
92
92
|
import { ModelPickerComponent } from "../components/model-picker";
|
|
93
93
|
import { OAuthSelectorComponent } from "../components/oauth-selector";
|
|
94
94
|
import { PluginSelectorComponent } from "../components/plugin-selector";
|
|
95
|
+
import { ReadToolGroupComponent } from "../components/read-tool-group";
|
|
95
96
|
import { ResetUsageSelectorComponent } from "../components/reset-usage-selector";
|
|
96
97
|
import { renderSegmentTrack } from "../components/segment-track";
|
|
97
98
|
import { SessionAccountSelectorComponent } from "../components/session-account-selector";
|
|
98
99
|
import { SessionSelectorComponent, type SessionSelectorOptions } from "../components/session-selector";
|
|
99
100
|
import { SettingsSelectorComponent } from "../components/settings-selector";
|
|
101
|
+
import { StrippedToolCallsPlaceholder } from "../components/stripped-tool-calls-placeholder";
|
|
100
102
|
import { ToolExecutionComponent } from "../components/tool-execution";
|
|
101
103
|
import { TranscriptBlock } from "../components/transcript-container";
|
|
102
104
|
import { TreeSelectorComponent } from "../components/tree-selector";
|
|
@@ -474,6 +476,24 @@ export class SelectorController {
|
|
|
474
476
|
break;
|
|
475
477
|
|
|
476
478
|
// Settings with UI side effects
|
|
479
|
+
case "display.hideToolActivity": {
|
|
480
|
+
const hidden = value as boolean;
|
|
481
|
+
this.ctx.hideToolActivity = hidden;
|
|
482
|
+
if (!hidden) this.ctx.toolOutputExpanded = false;
|
|
483
|
+
for (const child of this.ctx.chatContainer.children) {
|
|
484
|
+
if (child instanceof ToolExecutionComponent || child instanceof ReadToolGroupComponent) {
|
|
485
|
+
if (!hidden) child.setExpanded(false);
|
|
486
|
+
child.setToolActivityVisible(!hidden);
|
|
487
|
+
} else if (child instanceof AssistantMessageComponent) {
|
|
488
|
+
child.setToolResultImagesVisible(!hidden);
|
|
489
|
+
} else if (child instanceof StrippedToolCallsPlaceholder) {
|
|
490
|
+
child.setToolActivityVisible(!hidden);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
if (hidden) this.ctx.ui.clearInlineImages();
|
|
494
|
+
this.ctx.ui.resetDisplay();
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
477
497
|
case "terminal.showImages":
|
|
478
498
|
case "showImages": {
|
|
479
499
|
const visible = value as boolean;
|
|
@@ -460,6 +460,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
460
460
|
initialChatRendered = false;
|
|
461
461
|
isBashMode = false;
|
|
462
462
|
toolOutputExpanded = false;
|
|
463
|
+
hideToolActivity = false;
|
|
463
464
|
todoExpanded = false;
|
|
464
465
|
planModeEnabled = false;
|
|
465
466
|
planModePaused = false;
|
|
@@ -778,6 +779,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
778
779
|
// hot path where the render never gets to paint the result.
|
|
779
780
|
this.editor.setTopBorderProvider(availableWidth => this.statusLine.getTopBorder(availableWidth));
|
|
780
781
|
|
|
782
|
+
this.hideToolActivity = settings.get("display.hideToolActivity");
|
|
781
783
|
this.hideThinkingBlock = settings.get("hideThinkingBlock");
|
|
782
784
|
this.proseOnlyThinking = settings.get("proseOnlyThinking");
|
|
783
785
|
|
|
@@ -4511,6 +4513,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
4511
4513
|
return this.#commandController.handleFreshCommand();
|
|
4512
4514
|
}
|
|
4513
4515
|
|
|
4516
|
+
handleResetContextCommand(): Promise<void> {
|
|
4517
|
+
return this.#commandController.handleResetContextCommand();
|
|
4518
|
+
}
|
|
4519
|
+
|
|
4514
4520
|
async handleDropCommand(): Promise<void> {
|
|
4515
4521
|
if (this.#vibeSessionTransitionBlocked()) return;
|
|
4516
4522
|
this.#prepareSessionSwitch();
|
|
@@ -4842,6 +4848,11 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
4842
4848
|
return this.#btwController.canBranch();
|
|
4843
4849
|
}
|
|
4844
4850
|
|
|
4851
|
+
/** Reserves plain `b` only after /btw has a completed branch action to handle. */
|
|
4852
|
+
handlesBtwBranchKey(): boolean {
|
|
4853
|
+
return this.#btwController.handlesBranchKey();
|
|
4854
|
+
}
|
|
4855
|
+
|
|
4845
4856
|
handleBtwBranchKey(): Promise<boolean> {
|
|
4846
4857
|
return this.#btwController.handleBranch();
|
|
4847
4858
|
}
|
|
@@ -4854,9 +4865,14 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
4854
4865
|
return this.#btwController.handleCopy();
|
|
4855
4866
|
}
|
|
4856
4867
|
|
|
4857
|
-
async handleBtwBranch(
|
|
4868
|
+
async handleBtwBranch(
|
|
4869
|
+
question: string,
|
|
4870
|
+
assistantMessage: AssistantMessage,
|
|
4871
|
+
leafId: string,
|
|
4872
|
+
sessionId: string,
|
|
4873
|
+
): Promise<void> {
|
|
4858
4874
|
try {
|
|
4859
|
-
const result = await this.session.branchFromBtw(question, assistantMessage);
|
|
4875
|
+
const result = await this.session.branchFromBtw(question, assistantMessage, leafId, sessionId);
|
|
4860
4876
|
if (result.cancelled) {
|
|
4861
4877
|
this.showStatus("/btw branch cancelled", { dim: true });
|
|
4862
4878
|
return;
|
package/src/modes/types.ts
CHANGED
|
@@ -162,6 +162,7 @@ export interface InteractiveModeContext {
|
|
|
162
162
|
initialChatRendered: boolean;
|
|
163
163
|
isBashMode: boolean;
|
|
164
164
|
toolOutputExpanded: boolean;
|
|
165
|
+
hideToolActivity: boolean;
|
|
165
166
|
todoExpanded: boolean;
|
|
166
167
|
planModeEnabled: boolean;
|
|
167
168
|
vibeModeEnabled: boolean;
|
|
@@ -349,6 +350,7 @@ export interface InteractiveModeContext {
|
|
|
349
350
|
handleDebugTranscriptCommand(): Promise<void>;
|
|
350
351
|
handleClearCommand(): Promise<void>;
|
|
351
352
|
handleFreshCommand(): Promise<void>;
|
|
353
|
+
handleResetContextCommand(): Promise<void>;
|
|
352
354
|
handleDropCommand(): Promise<void>;
|
|
353
355
|
handleForkCommand(): Promise<void>;
|
|
354
356
|
handleBashCommand(command: string, excludeFromContext?: boolean): Promise<void>;
|
|
@@ -417,9 +419,15 @@ export interface InteractiveModeContext {
|
|
|
417
419
|
handleBtwEscape(): boolean;
|
|
418
420
|
handleBtwBranchKey(): Promise<boolean>;
|
|
419
421
|
canBranchBtw(): boolean;
|
|
422
|
+
handlesBtwBranchKey(): boolean;
|
|
420
423
|
canCopyBtw(): boolean;
|
|
421
424
|
handleBtwCopyKey(): Promise<boolean>;
|
|
422
|
-
handleBtwBranch(
|
|
425
|
+
handleBtwBranch(
|
|
426
|
+
question: string,
|
|
427
|
+
assistantMessage: AssistantMessage,
|
|
428
|
+
leafId: string,
|
|
429
|
+
sessionId: string,
|
|
430
|
+
): Promise<void>;
|
|
423
431
|
handleOmfgCommand(complaint: string): Promise<void>;
|
|
424
432
|
hasActiveOmfg(): boolean;
|
|
425
433
|
handleOmfgEscape(): boolean;
|