@oh-my-pi/pi-coding-agent 17.2.3 → 17.2.5
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 +92 -0
- package/dist/{CHANGELOG-c5hpqt9r.md → CHANGELOG-q2w43aw3.md} +92 -0
- package/dist/cli.js +3979 -3548
- package/dist/{template-8vdv6xb4.js → template-c2hyaytt.js} +8 -26
- package/dist/types/advisor/advise-tool.d.ts +6 -0
- package/dist/types/advisor/runtime.d.ts +4 -4
- package/dist/types/capability/mcp.d.ts +9 -0
- 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/help-extra.d.ts +2 -0
- package/dist/types/cli/models-cli.d.ts +1 -1
- 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 +6 -1
- 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 +70 -22
- package/dist/types/cursor-bridge-tools.d.ts +1 -1
- package/dist/types/cursor.d.ts +7 -4
- package/dist/types/discovery/helpers.d.ts +6 -0
- package/dist/types/discovery/omp-extension-roots.d.ts +21 -2
- 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/extensions/loader.d.ts +6 -2
- 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/extensibility/plugins/marketplace/registry.d.ts +2 -2
- package/dist/types/launch/broker.d.ts +1 -1
- package/dist/types/launch/client.d.ts +6 -3
- package/dist/types/launch/ensure.d.ts +8 -0
- package/dist/types/launch/paths.d.ts +3 -2
- package/dist/types/launch/protocol.d.ts +2 -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/mcp/request-id.d.ts +19 -0
- package/dist/types/mcp/types.d.ts +14 -0
- package/dist/types/memory-backend/index.d.ts +1 -0
- package/dist/types/memory-backend/messages.d.ts +15 -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/custom-editor.d.ts +2 -1
- package/dist/types/modes/components/model-browser.d.ts +7 -5
- package/dist/types/modes/components/model-picker.d.ts +9 -3
- package/dist/types/modes/components/read-tool-group.d.ts +11 -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/input-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/types.d.ts +2 -1
- package/dist/types/modes/workflow.d.ts +2 -1
- package/dist/types/registry/agent-lifecycle.d.ts +14 -5
- package/dist/types/registry/agent-registry.d.ts +4 -3
- package/dist/types/sdk.d.ts +4 -2
- package/dist/types/secrets/index.d.ts +7 -9
- package/dist/types/session/agent-session-types.d.ts +3 -1
- package/dist/types/session/agent-session.d.ts +6 -1
- package/dist/types/session/indexed-session-storage.d.ts +1 -0
- package/dist/types/session/model-controls.d.ts +0 -1
- package/dist/types/session/session-advisors.d.ts +8 -1
- package/dist/types/session/session-context.d.ts +2 -1
- package/dist/types/session/session-maintenance.d.ts +2 -0
- package/dist/types/session/session-manager.d.ts +16 -5
- package/dist/types/session/session-stats.d.ts +10 -0
- package/dist/types/session/session-storage.d.ts +15 -3
- package/dist/types/system-prompt.d.ts +6 -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/default-renderer.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/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/scripts/legacy-pi-virtual-module.ts +12 -2
- package/src/advisor/advise-tool.ts +18 -0
- package/src/advisor/runtime.ts +6 -6
- package/src/capability/mcp.ts +7 -0
- 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/help-extra.ts +89 -0
- package/src/cli/models-cli.ts +13 -16
- 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/collab/host.ts +1 -1
- 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 +19 -9
- package/src/config/mcp-schema.json +5 -0
- package/src/config/model-discovery.ts +30 -13
- package/src/config/model-registry.ts +16 -6
- 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 +73 -21
- package/src/cursor-bridge-tools.ts +1 -1
- package/src/cursor.ts +10 -14
- package/src/discovery/builtin.ts +10 -0
- package/src/discovery/helpers.ts +10 -0
- package/src/discovery/mcp-json.ts +11 -1
- package/src/discovery/omp-extension-roots.ts +79 -20
- package/src/discovery/omp-plugins.ts +10 -1
- 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/template.js +8 -26
- package/src/extensibility/extensions/loader.ts +66 -28
- 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/plugins/marketplace/registry.ts +4 -8
- package/src/extensibility/skills.ts +11 -0
- package/src/extensibility/utils.ts +10 -2
- package/src/launch/broker.ts +1 -1
- package/src/launch/client.ts +32 -13
- package/src/launch/ensure.ts +73 -0
- package/src/launch/paths.ts +3 -6
- package/src/launch/protocol.ts +2 -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 +31 -24
- package/src/mcp/config.ts +1 -0
- package/src/mcp/oauth-flow.ts +11 -1
- package/src/mcp/request-id.ts +24 -0
- package/src/mcp/transports/http.ts +4 -2
- package/src/mcp/transports/sse.ts +4 -2
- package/src/mcp/transports/stdio.ts +4 -2
- package/src/mcp/types.ts +15 -0
- package/src/memory-backend/index.ts +1 -0
- package/src/memory-backend/messages.ts +19 -0
- package/src/mnemopi/embed-client.ts +49 -2
- package/src/mnemopi/state.ts +57 -23
- package/src/modes/components/agent-hub.ts +1 -1
- package/src/modes/components/assistant-message.ts +11 -0
- package/src/modes/components/chat-transcript-builder.ts +4 -0
- package/src/modes/components/custom-editor.ts +10 -1
- package/src/modes/components/model-browser.ts +25 -17
- package/src/modes/components/model-picker.ts +10 -6
- package/src/modes/components/read-tool-group.ts +36 -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 +85 -20
- package/src/modes/components/tree-selector.ts +46 -48
- package/src/modes/controllers/command-controller.ts +2 -2
- package/src/modes/controllers/event-controller.ts +199 -10
- package/src/modes/controllers/input-controller.ts +39 -1
- package/src/modes/controllers/mcp-command-controller.ts +11 -5
- package/src/modes/controllers/selector-controller.ts +47 -6
- package/src/modes/interactive-mode.ts +2 -0
- package/src/modes/types.ts +6 -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/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/registry/agent-lifecycle.ts +36 -11
- package/src/registry/agent-registry.ts +12 -5
- package/src/sdk.ts +102 -35
- package/src/secrets/index.ts +16 -18
- package/src/session/agent-session-types.ts +3 -1
- package/src/session/agent-session.ts +23 -2
- package/src/session/agent-storage.ts +6 -4
- package/src/session/history-storage.ts +4 -2
- package/src/session/indexed-session-storage.ts +9 -0
- package/src/session/messages.ts +31 -7
- package/src/session/model-controls.ts +0 -1
- package/src/session/prewalk.ts +24 -2
- package/src/session/session-advisors.ts +21 -3
- package/src/session/session-context.ts +16 -12
- package/src/session/session-dump-format.ts +1 -1
- package/src/session/session-maintenance.ts +41 -4
- package/src/session/session-manager.ts +181 -94
- 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/session-tools.ts +25 -23
- package/src/session/stream-guards.ts +1 -1
- package/src/slash-commands/builtin-registry.ts +29 -26
- package/src/system-prompt.ts +14 -4
- package/src/task/executor.ts +8 -1
- package/src/task/index.ts +23 -8
- package/src/task/spawn-policy.ts +14 -0
- package/src/thinking.ts +2 -8
- package/src/tiny/text.ts +12 -0
- package/src/tools/ast-grep.ts +10 -4
- package/src/tools/browser/cmux/cmux-tab.ts +5 -10
- 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/default-renderer.ts +19 -4
- package/src/tools/glob.ts +9 -2
- package/src/tools/grep.ts +12 -6
- package/src/tools/index.ts +10 -6
- 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 +7 -2
- 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
|
@@ -190,6 +190,7 @@ export class ChatTranscriptBuilder {
|
|
|
190
190
|
this.#readGroup = new ReadToolGroupComponent({
|
|
191
191
|
showContentPreview: settings.get("read.toolResultPreview"),
|
|
192
192
|
});
|
|
193
|
+
this.#readGroup.setToolActivityVisible(!settings.get("display.hideToolActivity"));
|
|
193
194
|
this.#trackExpandable(this.#readGroup);
|
|
194
195
|
this.container.addChild(this.#readGroup);
|
|
195
196
|
}
|
|
@@ -321,6 +322,7 @@ export class ChatTranscriptBuilder {
|
|
|
321
322
|
proseOnlyThinking,
|
|
322
323
|
);
|
|
323
324
|
assistantComponent.setImagesVisible(settings.get("terminal.showImages"));
|
|
325
|
+
assistantComponent.setToolResultImagesVisible(!settings.get("display.hideToolActivity"));
|
|
324
326
|
this.#trackExpandable(assistantComponent);
|
|
325
327
|
this.container.addChild(assistantComponent);
|
|
326
328
|
|
|
@@ -353,6 +355,7 @@ export class ChatTranscriptBuilder {
|
|
|
353
355
|
proseOnlyThinking,
|
|
354
356
|
);
|
|
355
357
|
component.setImagesVisible(settings.get("terminal.showImages"));
|
|
358
|
+
component.setToolResultImagesVisible(!settings.get("display.hideToolActivity"));
|
|
356
359
|
this.#trackExpandable(component);
|
|
357
360
|
this.container.addChild(component);
|
|
358
361
|
};
|
|
@@ -401,6 +404,7 @@ export class ChatTranscriptBuilder {
|
|
|
401
404
|
this.deps.cwd,
|
|
402
405
|
content.id,
|
|
403
406
|
);
|
|
407
|
+
component.setToolActivityVisible(!settings.get("display.hideToolActivity"));
|
|
404
408
|
this.#trackExpandable(component);
|
|
405
409
|
this.container.addChild(component);
|
|
406
410
|
|
|
@@ -31,6 +31,7 @@ type ConfigurableEditorAction = Extract<
|
|
|
31
31
|
| "app.model.select"
|
|
32
32
|
| "app.model.selectTemporary"
|
|
33
33
|
| "app.tools.expand"
|
|
34
|
+
| "app.tools.toggleVisibility"
|
|
34
35
|
| "app.thinking.toggle"
|
|
35
36
|
| "app.editor.external"
|
|
36
37
|
| "app.history.search"
|
|
@@ -53,10 +54,11 @@ const DEFAULT_ACTION_KEYS: Record<ConfigurableEditorAction, KeyId[]> = {
|
|
|
53
54
|
"app.model.select": ["alt+m"],
|
|
54
55
|
"app.model.selectTemporary": ["alt+p"],
|
|
55
56
|
"app.tools.expand": ["ctrl+o"],
|
|
57
|
+
"app.tools.toggleVisibility": ["ctrl+shift+o"],
|
|
56
58
|
"app.thinking.toggle": ["ctrl+t"],
|
|
57
59
|
"app.editor.external": ["ctrl+g"],
|
|
58
60
|
"app.history.search": ["ctrl+r"],
|
|
59
|
-
"app.message.dequeue": ["alt+up"],
|
|
61
|
+
"app.message.dequeue": ["alt+up", "shift+up"],
|
|
60
62
|
"app.retry": ["alt+r"],
|
|
61
63
|
"app.clipboard.pasteImage": ["ctrl+v"],
|
|
62
64
|
"app.clipboard.pasteTextRaw": ["ctrl+shift+v", "alt+shift+v"],
|
|
@@ -550,6 +552,7 @@ export class CustomEditor extends Editor {
|
|
|
550
552
|
onCycleModelBackward?: () => void;
|
|
551
553
|
onSelectModel?: () => void;
|
|
552
554
|
onExpandTools?: () => void;
|
|
555
|
+
onToggleToolActivity?: () => void;
|
|
553
556
|
onToggleThinking?: () => void;
|
|
554
557
|
onExternalEditor?: () => void;
|
|
555
558
|
onHistorySearch?: () => void;
|
|
@@ -910,6 +913,12 @@ export class CustomEditor extends Editor {
|
|
|
910
913
|
return;
|
|
911
914
|
}
|
|
912
915
|
|
|
916
|
+
// Intercept configured tool activity visibility toggle
|
|
917
|
+
if (this.#matchesAction(canonical, "app.tools.toggleVisibility") && this.onToggleToolActivity) {
|
|
918
|
+
this.onToggleToolActivity();
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
|
|
913
922
|
// Intercept configured backward model cycling (check before forward cycling)
|
|
914
923
|
if (this.#matchesAction(canonical, "app.model.cycleBackward") && this.onCycleModelBackward) {
|
|
915
924
|
this.onCycleModelBackward();
|
|
@@ -314,10 +314,10 @@ function padLeftVisible(text: string, width: number): string {
|
|
|
314
314
|
export interface ModelBrowserOptions {
|
|
315
315
|
/** Render the dim `provider/` prefix before model ids. Default true. */
|
|
316
316
|
showProvider?: boolean;
|
|
317
|
-
/** Session token count used to
|
|
317
|
+
/** Session token count used to flag models whose context window is exceeded. */
|
|
318
318
|
currentContextTokens?: number;
|
|
319
|
-
/** When true, rows
|
|
320
|
-
|
|
319
|
+
/** When true, over-context rows render grayed; picking one compacts first (session-switch mode). */
|
|
320
|
+
markOverContext?: boolean;
|
|
321
321
|
/** Host-provided empty-state text (e.g. provider discovery status). */
|
|
322
322
|
emptyText?: () => string | undefined;
|
|
323
323
|
}
|
|
@@ -351,7 +351,7 @@ export class ModelBrowser implements Component {
|
|
|
351
351
|
#maxVisible = 10;
|
|
352
352
|
#showProvider: boolean;
|
|
353
353
|
#currentContextTokens: number;
|
|
354
|
-
#
|
|
354
|
+
#markOverContext: boolean;
|
|
355
355
|
#emptyText?: () => string | undefined;
|
|
356
356
|
/** Keep role-like virtual rows in their host-defined order during search. */
|
|
357
357
|
#preserveQueryOrder = false;
|
|
@@ -375,7 +375,7 @@ export class ModelBrowser implements Component {
|
|
|
375
375
|
this.#showProvider = options.showProvider ?? true;
|
|
376
376
|
const tokens = options.currentContextTokens ?? 0;
|
|
377
377
|
this.#currentContextTokens = Number.isFinite(tokens) && tokens > 0 ? Math.floor(tokens) : 0;
|
|
378
|
-
this.#
|
|
378
|
+
this.#markOverContext = options.markOverContext ?? false;
|
|
379
379
|
this.#emptyText = options.emptyText;
|
|
380
380
|
}
|
|
381
381
|
|
|
@@ -420,9 +420,9 @@ export class ModelBrowser implements Component {
|
|
|
420
420
|
setPreserveQueryOrder(preserve: boolean): void {
|
|
421
421
|
this.#preserveQueryOrder = preserve;
|
|
422
422
|
}
|
|
423
|
-
/** Allow hosts to toggle context-window
|
|
424
|
-
|
|
425
|
-
this.#
|
|
423
|
+
/** Allow hosts to toggle context-window flagging between browser modes. */
|
|
424
|
+
setMarkOverContext(mark: boolean): void {
|
|
425
|
+
this.#markOverContext = mark;
|
|
426
426
|
}
|
|
427
427
|
/** Focused: accent cursor + selected-row background band. Unfocused: dim cursor, no band. */
|
|
428
428
|
setFocused(focused: boolean): void {
|
|
@@ -461,8 +461,13 @@ export class ModelBrowser implements Component {
|
|
|
461
461
|
}
|
|
462
462
|
|
|
463
463
|
#isDisabled(item: ModelBrowserItem): boolean {
|
|
464
|
-
|
|
465
|
-
|
|
464
|
+
return item.id === "separator";
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/** True when `item`'s context window is smaller than the live session token count (grayed row; hosts compact before switching). */
|
|
468
|
+
isOverContext(item: ModelBrowserItem): boolean {
|
|
469
|
+
if (item.id === "separator") return false;
|
|
470
|
+
if (!this.#markOverContext || this.#currentContextTokens <= 0) return false;
|
|
466
471
|
const contextWindow = item.model.contextWindow ?? 0;
|
|
467
472
|
return contextWindow > 0 && this.#currentContextTokens > contextWindow;
|
|
468
473
|
}
|
|
@@ -718,7 +723,7 @@ export class ModelBrowser implements Component {
|
|
|
718
723
|
const line = theme.fg("muted", "─".repeat(dashCount));
|
|
719
724
|
return ` ${line} `;
|
|
720
725
|
}
|
|
721
|
-
const
|
|
726
|
+
const overContext = this.isOverContext(item);
|
|
722
727
|
const prefix = selected && this.#focused ? `${theme.fg("accent", theme.nav.cursor)} ` : " ";
|
|
723
728
|
const providerPrefix = this.#showProvider ? theme.fg("dim", `${item.provider}/`) : "";
|
|
724
729
|
const name = item.labelColor
|
|
@@ -728,7 +733,7 @@ export class ModelBrowser implements Component {
|
|
|
728
733
|
: item.id;
|
|
729
734
|
const currentMark =
|
|
730
735
|
item.selector === this.#currentSelector ? ` ${theme.fg("success", theme.status.enabled)}` : "";
|
|
731
|
-
const overLimit =
|
|
736
|
+
const overLimit = overContext
|
|
732
737
|
? ` ${theme.status.disabled} context>${formatNumber(item.model.contextWindow ?? 0).toLowerCase()}`
|
|
733
738
|
: "";
|
|
734
739
|
let left = `${prefix}${providerPrefix}${name}${currentMark}${overLimit}`;
|
|
@@ -743,12 +748,15 @@ export class ModelBrowser implements Component {
|
|
|
743
748
|
const gap = Math.max(0, available - visibleWidth(left));
|
|
744
749
|
|
|
745
750
|
let line = `${left}${" ".repeat(gap)} ${meta}`;
|
|
746
|
-
if (
|
|
747
|
-
|
|
751
|
+
if (overContext) {
|
|
752
|
+
// Gray the whole row but keep the selection cursor visible: over-context
|
|
753
|
+
// models stay selectable (the host compacts before switching).
|
|
754
|
+
const plainPrefix = Bun.stripANSI(prefix);
|
|
755
|
+
line = `${prefix}${theme.fg("dim", Bun.stripANSI(line).slice(plainPrefix.length))}`;
|
|
748
756
|
}
|
|
749
757
|
// The bg band is reserved for the mouse: it marks hover, nothing else.
|
|
750
758
|
// Keyboard selection is the cursor glyph + accent name.
|
|
751
|
-
if (hovered
|
|
759
|
+
if (hovered) {
|
|
752
760
|
line = theme.bg("selectedBg", line);
|
|
753
761
|
}
|
|
754
762
|
return line;
|
|
@@ -772,8 +780,8 @@ export class ModelBrowser implements Component {
|
|
|
772
780
|
}
|
|
773
781
|
const line1 = truncateToWidth(theme.fg("muted", ` ${facts.join(" · ")}`), width);
|
|
774
782
|
|
|
775
|
-
if (this
|
|
776
|
-
const warning = ` ${theme.status.disabled}
|
|
783
|
+
if (this.isOverContext(selected)) {
|
|
784
|
+
const warning = ` ${theme.status.disabled} context ${formatNumber(this.#currentContextTokens).toLowerCase()} exceeds ${formatNumber(model.contextWindow ?? 0).toLowerCase()} limit · compacts with current model, then switches`;
|
|
777
785
|
return [line1, truncateToWidth(theme.fg("warning", warning), width)];
|
|
778
786
|
}
|
|
779
787
|
|
|
@@ -22,8 +22,12 @@ import { bottomBorder, row, topBorder } from "./overlay-box";
|
|
|
22
22
|
import { resolveSegmentPalette } from "./segment-track";
|
|
23
23
|
|
|
24
24
|
export interface ModelPickerCallbacks {
|
|
25
|
-
/**
|
|
26
|
-
|
|
25
|
+
/**
|
|
26
|
+
* A model was chosen for a session-only switch. `selector` is `provider/id`.
|
|
27
|
+
* `overContext` is true when the session transcript exceeds the model's
|
|
28
|
+
* context window — the host must compact before switching.
|
|
29
|
+
*/
|
|
30
|
+
onPick: (model: Model, selector: string, meta: { overContext: boolean }) => void;
|
|
27
31
|
/** A configured ctrl+p quick role was chosen. */
|
|
28
32
|
onPickRole?: (entry: ResolvedRoleModel) => void;
|
|
29
33
|
/** The picker was dismissed. */
|
|
@@ -31,7 +35,7 @@ export interface ModelPickerCallbacks {
|
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
export interface ModelPickerOptions {
|
|
34
|
-
/** Session token count; models with smaller context windows are
|
|
38
|
+
/** Session token count; models with smaller context windows are grayed and compact-first on pick. */
|
|
35
39
|
currentContextTokens?: number;
|
|
36
40
|
/** `provider/id` of the session's active model; highlighted and preselected. */
|
|
37
41
|
currentSelector?: string;
|
|
@@ -97,7 +101,7 @@ export class ModelPickerComponent implements Component {
|
|
|
97
101
|
|
|
98
102
|
this.#browser = new ModelBrowser(settings, {
|
|
99
103
|
currentContextTokens: options.currentContextTokens,
|
|
100
|
-
|
|
104
|
+
markOverContext: true,
|
|
101
105
|
emptyText: () => (this.#roleMode ? " No quick roles in the Ctrl+P cycle" : undefined),
|
|
102
106
|
});
|
|
103
107
|
this.#browser.onActivate = item => {
|
|
@@ -106,7 +110,7 @@ export class ModelPickerComponent implements Component {
|
|
|
106
110
|
callbacks.onPickRole?.(quickRole);
|
|
107
111
|
return;
|
|
108
112
|
}
|
|
109
|
-
callbacks.onPick(item.model, item.selector);
|
|
113
|
+
callbacks.onPick(item.model, item.selector, { overContext: this.#browser.isOverContext(item) });
|
|
110
114
|
};
|
|
111
115
|
this.#browser.onCancel = () => callbacks.onCancel();
|
|
112
116
|
this.#browser.onQueryChange = query => this.#syncItemsForQuery(query);
|
|
@@ -193,7 +197,7 @@ export class ModelPickerComponent implements Component {
|
|
|
193
197
|
|
|
194
198
|
this.#roleMode = roleMode;
|
|
195
199
|
this.#browser.setShowProvider(!roleMode);
|
|
196
|
-
this.#browser.
|
|
200
|
+
this.#browser.setMarkOverContext(!roleMode);
|
|
197
201
|
this.#browser.setPreserveQueryOrder(roleMode);
|
|
198
202
|
const currentSelector = roleMode ? this.#currentQuickRoleSelector : this.#currentSelector;
|
|
199
203
|
this.#browser.setCurrentSelector(currentSelector);
|
|
@@ -332,6 +332,7 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
|
|
332
332
|
#usageBatchByToolCallId = new Map<string, string>();
|
|
333
333
|
#text: Text;
|
|
334
334
|
#expanded = false;
|
|
335
|
+
#toolActivityVisible = true;
|
|
335
336
|
#showContentPreview: boolean;
|
|
336
337
|
// A read group accretes entries across multiple assistant completions for as
|
|
337
338
|
// long as the run of reads is uninterrupted. While it is the active group it
|
|
@@ -353,6 +354,10 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
|
|
353
354
|
this.#updateDisplay();
|
|
354
355
|
}
|
|
355
356
|
|
|
357
|
+
override render(width: number): readonly string[] {
|
|
358
|
+
if (!this.#toolActivityVisible) return [];
|
|
359
|
+
return super.render(width);
|
|
360
|
+
}
|
|
356
361
|
isTranscriptBlockFinalized(): boolean {
|
|
357
362
|
if (this.#sealed) return true;
|
|
358
363
|
if (!this.#finalized) return false;
|
|
@@ -397,6 +402,32 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
|
|
397
402
|
this.#updateDisplay();
|
|
398
403
|
}
|
|
399
404
|
|
|
405
|
+
/**
|
|
406
|
+
* Re-key an entry whose streamed tool-call id changed mid-stream (a provider
|
|
407
|
+
* rewriting the id across deltas; see EventController's
|
|
408
|
+
* `#streamedToolCallIdByIndex`). Preserves row order so a sibling read run is
|
|
409
|
+
* not visibly reshuffled, and no-ops when the rename would collide.
|
|
410
|
+
*/
|
|
411
|
+
renameEntry(oldId: string, newId: string): void {
|
|
412
|
+
if (oldId === newId || !newId) return;
|
|
413
|
+
const entry = this.#entries.get(oldId);
|
|
414
|
+
if (!entry || this.#entries.has(newId)) return;
|
|
415
|
+
entry.toolCallId = newId;
|
|
416
|
+
const reordered = [...this.#entries].map(([key, value]): [string, ReadEntry] => [
|
|
417
|
+
key === oldId ? newId : key,
|
|
418
|
+
value,
|
|
419
|
+
]);
|
|
420
|
+
this.#entries.clear();
|
|
421
|
+
for (const [key, value] of reordered) this.#entries.set(key, value);
|
|
422
|
+
this.#updateDisplay();
|
|
423
|
+
}
|
|
424
|
+
/** Remove one call without discarding successful siblings in the shared group. */
|
|
425
|
+
removeEntry(toolCallId: string): boolean {
|
|
426
|
+
if (!this.#entries.delete(toolCallId)) return this.#entries.size === 0;
|
|
427
|
+
this.#updateDisplay();
|
|
428
|
+
return this.#entries.size === 0;
|
|
429
|
+
}
|
|
430
|
+
|
|
400
431
|
updateResult(
|
|
401
432
|
result: { content: Array<{ type: string; text?: string }>; details?: unknown; isError?: boolean },
|
|
402
433
|
isPartial = false,
|
|
@@ -470,6 +501,11 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
|
|
470
501
|
this.#updateDisplay();
|
|
471
502
|
}
|
|
472
503
|
|
|
504
|
+
setToolActivityVisible(visible: boolean): void {
|
|
505
|
+
this.#toolActivityVisible = visible;
|
|
506
|
+
super.invalidate();
|
|
507
|
+
}
|
|
508
|
+
|
|
473
509
|
getComponent(): Component {
|
|
474
510
|
return this;
|
|
475
511
|
}
|
|
@@ -1785,7 +1785,7 @@ export class StatusLineComponent implements Component {
|
|
|
1785
1785
|
: separatorDef.endCaps.left
|
|
1786
1786
|
: "";
|
|
1787
1787
|
const capPrefix = separatorDef.endCaps?.useBgAsFg ? bgAnsi.replace("\x1b[48;", "\x1b[38;") : bgAnsi + sepAnsi;
|
|
1788
|
-
const capText = cap ? `${capPrefix}${cap}\x1b[0m` : "";
|
|
1788
|
+
const capText = cap ? `${capPrefix}${this.#focusedAgentId ? "\x1b[22m" : ""}${cap}\x1b[0m` : "";
|
|
1789
1789
|
|
|
1790
1790
|
let content = bgAnsi + fgAnsi;
|
|
1791
1791
|
content += ` ${parts.join(` ${sepAnsi}${sep}${fgAnsi} `)} `;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Text } from "@oh-my-pi/pi-tui";
|
|
2
|
+
import { theme } from "../../modes/theme/theme";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Dim transcript marker for tool calls stripped from the resolved branch
|
|
6
|
+
* (failed/retried turns, results on sibling branches). It is tool activity,
|
|
7
|
+
* so it hides and reappears with the `display.hideToolActivity` toggle.
|
|
8
|
+
*/
|
|
9
|
+
export class StrippedToolCallsPlaceholder extends Text {
|
|
10
|
+
#toolActivityVisible: boolean;
|
|
11
|
+
|
|
12
|
+
constructor(strippedToolCalls: number, toolActivityVisible: boolean) {
|
|
13
|
+
super(
|
|
14
|
+
theme.fg(
|
|
15
|
+
"dim",
|
|
16
|
+
theme.italic(
|
|
17
|
+
`${strippedToolCalls} tool call${strippedToolCalls === 1 ? "" : "s"} elided — no result on this branch`,
|
|
18
|
+
),
|
|
19
|
+
),
|
|
20
|
+
1,
|
|
21
|
+
0,
|
|
22
|
+
);
|
|
23
|
+
this.#toolActivityVisible = toolActivityVisible;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
setToolActivityVisible(visible: boolean): void {
|
|
27
|
+
this.#toolActivityVisible = visible;
|
|
28
|
+
this.invalidate();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
override render(width: number): readonly string[] {
|
|
32
|
+
if (!this.#toolActivityVisible) return [];
|
|
33
|
+
return super.render(width);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -246,6 +246,7 @@ export interface ToolExecutionHandle extends Component {
|
|
|
246
246
|
): void;
|
|
247
247
|
setArgsComplete(toolCallId?: string): void;
|
|
248
248
|
setExpanded(expanded: boolean): void;
|
|
249
|
+
setToolActivityVisible(visible: boolean): void;
|
|
249
250
|
/** Freeze the block as final history: stop spinners and let it commit to scrollback. */
|
|
250
251
|
seal(): void;
|
|
251
252
|
}
|
|
@@ -276,6 +277,9 @@ let toolExecutionInstanceSeq = 0;
|
|
|
276
277
|
export class ToolExecutionComponent extends Container implements NativeScrollbackLiveRegion {
|
|
277
278
|
#contentBox: Box; // Used for custom tools and bash visual truncation
|
|
278
279
|
#contentText: WidthAwareText; // Generic fallback (no custom/built-in renderer)
|
|
280
|
+
// Which container the constructor mounted: bespoke/built-in renderers use
|
|
281
|
+
// #contentBox, everything else the generic #contentText fallback.
|
|
282
|
+
#usesContentBox = false;
|
|
279
283
|
#multiFileBoxes: (Box | Spacer)[] = []; // Extra boxes for multi-file edit results
|
|
280
284
|
#imageComponents: Image[] = [];
|
|
281
285
|
#imageSpacers: Spacer[] = [];
|
|
@@ -284,6 +288,7 @@ export class ToolExecutionComponent extends Container implements NativeScrollbac
|
|
|
284
288
|
#toolLabel: string;
|
|
285
289
|
#args: any;
|
|
286
290
|
#expanded = false;
|
|
291
|
+
#toolActivityVisible = true;
|
|
287
292
|
#showImages: boolean;
|
|
288
293
|
#editFuzzyThreshold: number | undefined;
|
|
289
294
|
#editAllowFuzzy: boolean | undefined;
|
|
@@ -411,26 +416,13 @@ export class ToolExecutionComponent extends Container implements NativeScrollbac
|
|
|
411
416
|
// strips PLAIN-blank edges, so framed/minimal blocks (no bg set) drop these
|
|
412
417
|
// lines and keep their tight spacing — only tinted lines survive.
|
|
413
418
|
this.#contentBox = new Box(0, 1);
|
|
414
|
-
this.#contentText = new WidthAwareText(
|
|
415
|
-
contentWidth =>
|
|
416
|
-
formatDefaultToolExecution(
|
|
417
|
-
{
|
|
418
|
-
label: this.#toolLabel,
|
|
419
|
-
args: this.#args,
|
|
420
|
-
result: this.#result ? { output: this.#getTextOutput(), isError: this.#result.isError } : undefined,
|
|
421
|
-
options: this.#renderState,
|
|
422
|
-
},
|
|
423
|
-
contentWidth,
|
|
424
|
-
theme,
|
|
425
|
-
),
|
|
426
|
-
1,
|
|
427
|
-
1,
|
|
428
|
-
);
|
|
419
|
+
this.#contentText = new WidthAwareText(contentWidth => this.#renderDefaultCard(contentWidth), 1, 1);
|
|
429
420
|
|
|
430
421
|
// Use Box for custom tools or built-in tools that have renderers
|
|
431
422
|
const hasRenderer = toolName in toolRenderers;
|
|
432
423
|
const hasCustomRenderer = !!(tool?.renderCall || tool?.renderResult);
|
|
433
|
-
|
|
424
|
+
this.#usesContentBox = hasCustomRenderer || hasRenderer;
|
|
425
|
+
if (this.#usesContentBox) {
|
|
434
426
|
this.addChild(this.#contentBox);
|
|
435
427
|
} else {
|
|
436
428
|
this.addChild(this.#contentText);
|
|
@@ -911,6 +903,11 @@ export class ToolExecutionComponent extends Container implements NativeScrollbac
|
|
|
911
903
|
this.#updateDisplay();
|
|
912
904
|
}
|
|
913
905
|
|
|
906
|
+
setToolActivityVisible(visible: boolean): void {
|
|
907
|
+
this.#toolActivityVisible = visible;
|
|
908
|
+
super.invalidate();
|
|
909
|
+
}
|
|
910
|
+
|
|
914
911
|
setShowImages(show: boolean): void {
|
|
915
912
|
this.#showImages = show;
|
|
916
913
|
this.#updateDisplay();
|
|
@@ -970,6 +967,7 @@ export class ToolExecutionComponent extends Container implements NativeScrollbac
|
|
|
970
967
|
}
|
|
971
968
|
|
|
972
969
|
override render(width: number): readonly string[] {
|
|
970
|
+
if (!this.#toolActivityVisible) return [];
|
|
973
971
|
const lines = super.render(width);
|
|
974
972
|
// Update the paint-tracking flags after `super.render(width)` — the
|
|
975
973
|
// override runs on every compose the parent Container performs, so a
|
|
@@ -998,12 +996,21 @@ export class ToolExecutionComponent extends Container implements NativeScrollbac
|
|
|
998
996
|
|
|
999
997
|
// Non-self-framing tools (custom/extension renderers and the generic
|
|
1000
998
|
// fallback) get a padded, state-tinted block — built-ins that draw their
|
|
1001
|
-
// own frame opt out below via the framed-component mark.
|
|
1002
|
-
|
|
999
|
+
// own frame opt out below via the framed-component mark. A benign skip
|
|
1000
|
+
// (steering/peer interrupt aborted a still-pending call) never ran, so it
|
|
1001
|
+
// gets the neutral pending tint rather than the error tint (#7199).
|
|
1002
|
+
const benignSkip = this.#isBenignSkip();
|
|
1003
|
+
const stateBgKey =
|
|
1004
|
+
this.#isPartial || benignSkip ? "toolPendingBg" : this.#result?.isError ? "toolErrorBg" : "toolSuccessBg";
|
|
1003
1005
|
const stateBgFn = (t: string) => theme.bg(stateBgKey, t);
|
|
1004
1006
|
|
|
1005
|
-
//
|
|
1006
|
-
|
|
1007
|
+
// A benign skip is a synthetic placeholder for a call that never executed,
|
|
1008
|
+
// so bypass any bespoke error frame and draw the neutral generic card —
|
|
1009
|
+
// the per-tool ✘/red-border would misread normal mid-turn steering as a
|
|
1010
|
+
// failure (#7199).
|
|
1011
|
+
if (benignSkip) {
|
|
1012
|
+
this.#renderBenignSkipCard(stateBgFn);
|
|
1013
|
+
} else if (this.#tool && (this.#tool.renderCall || this.#tool.renderResult)) {
|
|
1007
1014
|
const tool = this.#tool;
|
|
1008
1015
|
const mergeCallAndResult = Boolean((tool as { mergeCallAndResult?: boolean }).mergeCallAndResult);
|
|
1009
1016
|
// Custom tools use Box for flexible component rendering
|
|
@@ -1399,4 +1406,62 @@ export class ToolExecutionComponent extends Container implements NativeScrollbac
|
|
|
1399
1406
|
|
|
1400
1407
|
return output;
|
|
1401
1408
|
}
|
|
1409
|
+
|
|
1410
|
+
/**
|
|
1411
|
+
* Format the generic call/result card at `contentWidth`. Shared by the
|
|
1412
|
+
* #contentText fallback and the benign-skip path so both render identically.
|
|
1413
|
+
*/
|
|
1414
|
+
#renderDefaultCard(contentWidth: number): string {
|
|
1415
|
+
return formatDefaultToolExecution(
|
|
1416
|
+
{
|
|
1417
|
+
label: this.#toolLabel,
|
|
1418
|
+
args: this.#args,
|
|
1419
|
+
result: this.#result
|
|
1420
|
+
? { output: this.#getTextOutput(), isError: this.#result.isError, skipped: this.#isBenignSkip() }
|
|
1421
|
+
: undefined,
|
|
1422
|
+
options: this.#renderState,
|
|
1423
|
+
},
|
|
1424
|
+
contentWidth,
|
|
1425
|
+
theme,
|
|
1426
|
+
);
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
/**
|
|
1430
|
+
* True for a steering/peer-interrupt placeholder. A synthetic placeholder
|
|
1431
|
+
* identifies a call that never entered `tool.execute`; an interrupted
|
|
1432
|
+
* placeholder identifies one that started but threw before returning usable
|
|
1433
|
+
* output. Both are normal steering control flow and render neutrally (#7199).
|
|
1434
|
+
*/
|
|
1435
|
+
#isBenignSkip(): boolean {
|
|
1436
|
+
if (this.#isPartial || !this.#result) return false;
|
|
1437
|
+
const details = this.#result.details as
|
|
1438
|
+
| { __synthetic?: boolean; __interrupted?: boolean; source?: string; execution?: string }
|
|
1439
|
+
| undefined;
|
|
1440
|
+
if (details?.source !== "interrupt_skipped") return false;
|
|
1441
|
+
return details.__synthetic === true || (details.__interrupted === true && details.execution === "started");
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
/**
|
|
1445
|
+
* Render a benign skip as the neutral generic card, replacing any bespoke
|
|
1446
|
+
* renderer's error frame. Generic-fallback tools already route through
|
|
1447
|
+
* {@link #renderDefaultCard} (which emits the info card for a skip); they
|
|
1448
|
+
* only need the neutral tint. Bespoke-renderer tools get their content box
|
|
1449
|
+
* swapped for the same neutral card.
|
|
1450
|
+
*/
|
|
1451
|
+
#renderBenignSkipCard(stateBgFn: (text: string) => string): void {
|
|
1452
|
+
if (!this.#usesContentBox) {
|
|
1453
|
+
this.#contentText.setCustomBgFn(stateBgFn);
|
|
1454
|
+
this.#contentText.invalidate();
|
|
1455
|
+
return;
|
|
1456
|
+
}
|
|
1457
|
+
for (const box of this.#multiFileBoxes) {
|
|
1458
|
+
this.removeChild(box);
|
|
1459
|
+
}
|
|
1460
|
+
this.#multiFileBoxes = [];
|
|
1461
|
+
this.#contentBox.setBgFn(undefined);
|
|
1462
|
+
this.#contentBox.clear();
|
|
1463
|
+
this.#contentBox.setPaddingX(1);
|
|
1464
|
+
this.#contentBox.setBgFn(stateBgFn);
|
|
1465
|
+
this.#contentBox.addChild(new WidthAwareText(contentWidth => this.#renderDefaultCard(contentWidth), 0, 0));
|
|
1466
|
+
}
|
|
1402
1467
|
}
|
|
@@ -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,
|