@astralyn/pi 0.87.0 → 0.87.2
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 +31 -0
- package/dist/bundle/chunks/{anthropic-messages-R2LYJUDD.js → anthropic-messages-XWFTZP2N.js} +1 -1
- package/dist/bundle/chunks/{chunk-INDBRWNK.js → chunk-NBIUJDV6.js} +1 -1
- package/dist/bundle/chunks/{chunk-RKLIHRPH.js → chunk-RFLBIA5Z.js} +82 -82
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{openai-completions-JZCEEJ43.js → openai-completions-SHS3CAEL.js} +1 -1
- package/dist/bundle/chunks/{virtual-modules-CG7NJ5WO.js → virtual-modules-GOHLE5JL.js} +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +14 -4
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +9 -0
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +158 -157
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +30 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +514 -443
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/background/service.d.ts +9 -0
- package/dist/core/background/service.d.ts.map +1 -1
- package/dist/core/background/service.js +13 -1
- package/dist/core/background/service.js.map +1 -1
- package/dist/core/background/session.d.ts +5 -0
- package/dist/core/background/session.d.ts.map +1 -1
- package/dist/core/background/session.js +2 -1
- package/dist/core/background/session.js.map +1 -1
- package/dist/core/background/types.d.ts +2 -0
- package/dist/core/background/types.d.ts.map +1 -1
- package/dist/core/background/types.js.map +1 -1
- package/dist/core/compaction/compaction.js +9 -9
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/extensions/distribution-api.d.ts +41 -0
- package/dist/core/extensions/distribution-api.d.ts.map +1 -0
- package/dist/core/extensions/distribution-api.js +12 -0
- package/dist/core/extensions/distribution-api.js.map +1 -0
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +1 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +0 -2
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +15 -45
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +1 -11
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/virtual-modules.js +2 -1
- package/dist/core/extensions/virtual-modules.js.map +1 -1
- package/dist/core/keybinding-registry.d.ts +11 -0
- package/dist/core/keybinding-registry.d.ts.map +1 -0
- package/dist/core/keybinding-registry.js +24 -0
- package/dist/core/keybinding-registry.js.map +1 -0
- package/dist/core/keybindings.d.ts +4 -64
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +2 -41
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-config.d.ts +70 -2
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +2 -26
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-resolver.js +1 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +5 -11
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +2 -2
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/shell-execution.d.ts +1 -0
- package/dist/core/tools/shell-execution.d.ts.map +1 -1
- package/dist/core/tools/shell-execution.js +21 -0
- package/dist/core/tools/shell-execution.js.map +1 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +11 -48
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/extensions/background/index.d.ts +2 -0
- package/dist/extensions/background/index.d.ts.map +1 -1
- package/dist/extensions/background/index.js +17 -0
- package/dist/extensions/background/index.js.map +1 -1
- package/dist/extensions/background/keybindings.d.ts +10 -0
- package/dist/extensions/background/keybindings.d.ts.map +1 -0
- package/dist/extensions/background/keybindings.js +14 -0
- package/dist/extensions/background/keybindings.js.map +1 -0
- package/dist/extensions/background/manager.d.ts +2 -0
- package/dist/extensions/background/manager.d.ts.map +1 -1
- package/dist/extensions/background/manager.js +1 -0
- package/dist/extensions/background/manager.js.map +1 -1
- package/dist/extensions/btw/controller.d.ts +1 -0
- package/dist/extensions/btw/controller.d.ts.map +1 -1
- package/dist/extensions/btw/controller.js +5 -5
- package/dist/extensions/btw/controller.js.map +1 -1
- package/dist/extensions/btw/index.js +1 -2
- package/dist/extensions/btw/index.js.map +1 -1
- package/dist/extensions/btw/keybindings.d.ts +10 -0
- package/dist/extensions/btw/keybindings.d.ts.map +1 -0
- package/dist/extensions/btw/keybindings.js +8 -0
- package/dist/extensions/btw/keybindings.js.map +1 -0
- package/dist/extensions/btw/panel.d.ts +1 -0
- package/dist/extensions/btw/panel.d.ts.map +1 -1
- package/dist/extensions/btw/panel.js +1 -0
- package/dist/extensions/btw/panel.js.map +1 -1
- package/dist/extensions/list-keybindings.d.ts +8 -0
- package/dist/extensions/list-keybindings.d.ts.map +1 -0
- package/dist/extensions/list-keybindings.js +8 -0
- package/dist/extensions/list-keybindings.js.map +1 -0
- package/dist/extensions/provider/compat-fields.d.ts.map +1 -1
- package/dist/extensions/provider/compat-fields.js +23 -3
- package/dist/extensions/provider/compat-fields.js.map +1 -1
- package/dist/extensions/provider/connection.d.ts.map +1 -1
- package/dist/extensions/provider/connection.js +1 -1
- package/dist/extensions/provider/connection.js.map +1 -1
- package/dist/extensions/provider/constants.d.ts +2 -0
- package/dist/extensions/provider/constants.d.ts.map +1 -1
- package/dist/extensions/provider/constants.js +2 -0
- package/dist/extensions/provider/constants.js.map +1 -1
- package/dist/extensions/provider/keybindings.d.ts +9 -0
- package/dist/extensions/provider/keybindings.d.ts.map +1 -0
- package/dist/extensions/provider/keybindings.js +12 -0
- package/dist/extensions/provider/keybindings.js.map +1 -0
- package/dist/extensions/provider/probe.d.ts +8 -4
- package/dist/extensions/provider/probe.d.ts.map +1 -1
- package/dist/extensions/provider/probe.js +169 -11
- package/dist/extensions/provider/probe.js.map +1 -1
- package/dist/extensions/provider/ui/builtin-data.d.ts +1 -0
- package/dist/extensions/provider/ui/builtin-data.d.ts.map +1 -1
- package/dist/extensions/provider/ui/builtin-data.js +1 -0
- package/dist/extensions/provider/ui/builtin-data.js.map +1 -1
- package/dist/extensions/provider/ui/compat.d.ts +1 -0
- package/dist/extensions/provider/ui/compat.d.ts.map +1 -1
- package/dist/extensions/provider/ui/compat.js +1 -0
- package/dist/extensions/provider/ui/compat.js.map +1 -1
- package/dist/extensions/provider/ui/dictionary.d.ts +1 -0
- package/dist/extensions/provider/ui/dictionary.d.ts.map +1 -1
- package/dist/extensions/provider/ui/dictionary.js +1 -0
- package/dist/extensions/provider/ui/dictionary.js.map +1 -1
- package/dist/extensions/provider/ui/editor.d.ts +1 -0
- package/dist/extensions/provider/ui/editor.d.ts.map +1 -1
- package/dist/extensions/provider/ui/editor.js +1 -0
- package/dist/extensions/provider/ui/editor.js.map +1 -1
- package/dist/extensions/provider/ui/fetch-models.d.ts +5 -3
- package/dist/extensions/provider/ui/fetch-models.d.ts.map +1 -1
- package/dist/extensions/provider/ui/fetch-models.js +28 -3
- package/dist/extensions/provider/ui/fetch-models.js.map +1 -1
- package/dist/extensions/provider/ui/model-fields.d.ts +1 -0
- package/dist/extensions/provider/ui/model-fields.d.ts.map +1 -1
- package/dist/extensions/provider/ui/model-fields.js +1 -0
- package/dist/extensions/provider/ui/model-fields.js.map +1 -1
- package/dist/extensions/provider/ui/model-options.d.ts +1 -0
- package/dist/extensions/provider/ui/model-options.d.ts.map +1 -1
- package/dist/extensions/provider/ui/model-options.js +1 -0
- package/dist/extensions/provider/ui/model-options.js.map +1 -1
- package/dist/extensions/provider/ui/provider-fields.d.ts +1 -0
- package/dist/extensions/provider/ui/provider-fields.d.ts.map +1 -1
- package/dist/extensions/provider/ui/provider-fields.js +1 -0
- package/dist/extensions/provider/ui/provider-fields.js.map +1 -1
- package/dist/extensions/question/dialog.d.ts +1 -0
- package/dist/extensions/question/dialog.d.ts.map +1 -1
- package/dist/extensions/question/dialog.js +1 -0
- package/dist/extensions/question/dialog.js.map +1 -1
- package/dist/extensions/question/keybindings.d.ts +2 -0
- package/dist/extensions/question/keybindings.d.ts.map +1 -0
- package/dist/extensions/question/keybindings.js +3 -0
- package/dist/extensions/question/keybindings.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/editor-host.d.ts +43 -0
- package/dist/modes/interactive/editor-host.d.ts.map +1 -0
- package/dist/modes/interactive/editor-host.js +83 -0
- package/dist/modes/interactive/editor-host.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +1 -11
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +300 -360
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/tool-chat.d.ts +21 -0
- package/dist/modes/interactive/tool-chat.d.ts.map +1 -0
- package/dist/modes/interactive/tool-chat.js +58 -0
- package/dist/modes/interactive/tool-chat.js.map +1 -0
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +0 -2
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/path-identity.d.ts +12 -0
- package/dist/utils/path-identity.d.ts.map +1 -0
- package/dist/utils/path-identity.js +63 -0
- package/dist/utils/path-identity.js.map +1 -0
- package/dist/utils/shell.d.ts +0 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +0 -21
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts +2 -0
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js +2 -0
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/docs/bundled/extensions/background.md +3 -3
- package/docs/bundled/extensions/provider.md +7 -3
- package/docs/bundled/extensions/subagent.md +1 -1
- package/docs/compaction.md +1 -1
- package/docs/extensions.md +15 -5
- package/docs/sdk.md +1 -1
- package/docs/usage.md +3 -0
- package/examples/README.md +11 -1
- package/examples/extensions/README.md +34 -14
- package/examples/extensions/auto-commit-on-exit.ts +1 -1
- package/examples/extensions/bash-spawn-hook.ts +2 -2
- package/examples/extensions/bookmark.ts +1 -1
- package/examples/extensions/border-status-editor.ts +6 -1
- package/examples/extensions/built-in-tool-renderer.ts +2 -2
- package/examples/extensions/claude-rules.ts +1 -1
- package/examples/extensions/commands.ts +1 -1
- package/examples/extensions/confirm-destructive.ts +1 -1
- package/examples/extensions/custom-compaction.ts +2 -2
- package/examples/extensions/custom-footer.ts +1 -1
- package/examples/extensions/custom-header.ts +2 -2
- package/examples/extensions/custom-provider-anthropic/index.ts +6 -6
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +3 -3
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/dirty-repo-guard.ts +1 -1
- package/examples/extensions/doom-overlay/index.ts +1 -1
- package/examples/extensions/dynamic-resources/dynamic.json +3 -1
- package/examples/extensions/dynamic-resources/index.ts +1 -1
- package/examples/extensions/dynamic-tools.ts +1 -1
- package/examples/extensions/entry-renderer.ts +1 -1
- package/examples/extensions/event-bus.ts +1 -1
- package/examples/extensions/file-trigger.ts +1 -1
- package/examples/extensions/git-checkpoint.ts +1 -1
- package/examples/extensions/git-merge-and-resolve.ts +1 -1
- package/examples/extensions/github-issue-autocomplete.ts +1 -1
- package/examples/extensions/gondolin/index.ts +9 -7
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/handoff.ts +2 -2
- package/examples/extensions/hello.ts +1 -1
- package/examples/extensions/hidden-thinking-label.ts +1 -1
- package/examples/extensions/inline-bash.ts +1 -1
- package/examples/extensions/input-transform-streaming.ts +1 -1
- package/examples/extensions/input-transform.ts +1 -1
- package/examples/extensions/interactive-shell.ts +1 -1
- package/examples/extensions/mac-system-theme.ts +1 -1
- package/examples/extensions/message-renderer.ts +1 -1
- package/examples/extensions/minimal-mode.ts +2 -2
- package/examples/extensions/modal-editor.ts +1 -1
- package/examples/extensions/model-status.ts +1 -1
- package/examples/extensions/notify.ts +1 -1
- package/examples/extensions/overlay-qa-tests.ts +3 -3
- package/examples/extensions/overlay-test.ts +1 -1
- package/examples/extensions/permission-gate.ts +1 -1
- package/examples/extensions/pirate.ts +1 -1
- package/examples/extensions/plan-mode/index.ts +1 -1
- package/examples/extensions/preset.ts +2 -2
- package/examples/extensions/project-trust.ts +3 -3
- package/examples/extensions/prompt-customizer.ts +1 -1
- package/examples/extensions/protected-paths.ts +1 -1
- package/examples/extensions/provider-payload.ts +1 -1
- package/examples/extensions/qna.ts +2 -2
- package/examples/extensions/question.ts +1 -1
- package/examples/extensions/questionnaire.ts +1 -1
- package/examples/extensions/rainbow-editor.ts +1 -1
- package/examples/extensions/reload-runtime.ts +1 -1
- package/examples/extensions/rpc-demo.ts +1 -1
- package/examples/extensions/sandbox/index.ts +2 -2
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/send-user-message.ts +1 -1
- package/examples/extensions/session-name.ts +1 -1
- package/examples/extensions/shutdown-command.ts +1 -1
- package/examples/extensions/snake.ts +1 -1
- package/examples/extensions/space-invaders.ts +1 -1
- package/examples/extensions/ssh.ts +2 -2
- package/examples/extensions/status-line.ts +1 -1
- package/examples/extensions/structured-output.ts +1 -1
- package/examples/extensions/summarize.ts +2 -3
- package/examples/extensions/system-prompt-header.ts +1 -1
- package/examples/extensions/tic-tac-toe.ts +1 -1
- package/examples/extensions/timed-confirm.ts +1 -1
- package/examples/extensions/titlebar-spinner.ts +1 -1
- package/examples/extensions/todo.ts +1 -1
- package/examples/extensions/tool-override.ts +1 -1
- package/examples/extensions/tools.ts +2 -2
- package/examples/extensions/trigger-compact.ts +1 -1
- package/examples/extensions/truncated-tool.ts +4 -4
- package/examples/extensions/widget-placement.ts +1 -1
- package/examples/extensions/with-deps/index.ts +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/extensions/working-indicator.ts +1 -1
- package/examples/extensions/working-message-test.ts +1 -1
- package/examples/rpc-client.ts +35 -0
- package/examples/rpc-extension-ui.ts +25 -5
- package/npm-shrinkwrap.json +43 -43
- package/package.json +8 -8
|
@@ -8,7 +8,7 @@ import * as os from "node:os";
|
|
|
8
8
|
import * as path from "node:path";
|
|
9
9
|
import { isRetryableAssistantError, } from "@earendil-works/pi-ai/compat";
|
|
10
10
|
import * as TuiLayouts from "@earendil-works/pi-tui";
|
|
11
|
-
import { CombinedAutocompleteProvider, Container, fuzzyFilter, Markdown, matchesKey, Spacer, setCapabilityOverrides, setKeybindings, Text, TruncatedText, TuiAltScreen, TuiMainScreen, visibleWidth, } from "@earendil-works/pi-tui";
|
|
11
|
+
import { CombinedAutocompleteProvider, Container, fuzzyFilter, getCapabilities, hyperlink, Markdown, matchesKey, Spacer, setCapabilityOverrides, setKeybindings, Text, TruncatedText, TuiAltScreen, TuiMainScreen, visibleWidth, } from "@earendil-works/pi-tui";
|
|
12
12
|
import chalk from "chalk";
|
|
13
13
|
import { spawn } from "child_process";
|
|
14
14
|
import { APP_NAME, APP_TITLE, CONFIG_DIR_NAME, getAgentDir, getAuthPath, getDebugLogPath, getDocsPath, INSTALL_TELEMETRY_URL, UPDATE_CHANGELOG_HINT, VERSION, } from "../../config.js";
|
|
@@ -39,6 +39,7 @@ import { parseGitUrl } from "../../utils/git.js";
|
|
|
39
39
|
import { getCwdRelativePath } from "../../utils/paths.js";
|
|
40
40
|
import { getPiUserAgent } from "../../utils/pi-user-agent.js";
|
|
41
41
|
import { killTrackedDetachedChildren } from "../../utils/shell.js";
|
|
42
|
+
import { loadAllHighlightLanguages } from "../../utils/syntax-highlight.js";
|
|
42
43
|
import { ensureTool } from "../../utils/tools-manager.js";
|
|
43
44
|
import { checkForNewPiVersion } from "../../utils/version-check.js";
|
|
44
45
|
import { reportBug } from "./bug-report.js";
|
|
@@ -58,7 +59,7 @@ import { ExtensionEditorComponent } from "./components/extension-editor.js";
|
|
|
58
59
|
import { ExtensionInputComponent } from "./components/extension-input.js";
|
|
59
60
|
import { ExtensionSelectorComponent } from "./components/extension-selector.js";
|
|
60
61
|
import { FooterComponent, formatTokens } from "./components/footer.js";
|
|
61
|
-
import { formatKeyText, keyDisplayText, keyHint,
|
|
62
|
+
import { formatKeyText, keyDisplayText, keyHint, keyText, rawKeyHint } from "./components/keybinding-hints.js";
|
|
62
63
|
import { LoginDialogComponent } from "./components/login-dialog.js";
|
|
63
64
|
import { createMermaidMarkdownTransformer } from "./components/mermaid.js";
|
|
64
65
|
import { ModelSelectorComponent } from "./components/model-selector.js";
|
|
@@ -70,17 +71,18 @@ import { SkillInvocationMessageComponent } from "./components/skill-invocation-m
|
|
|
70
71
|
import { BranchSummaryStatusIndicator, CompactionStatusIndicator, IdleStatus, RetryStatusIndicator, WorkingStatusIndicator, } from "./components/status-indicator.js";
|
|
71
72
|
import { ThinkingSelectorComponent } from "./components/thinking-selector.js";
|
|
72
73
|
import { ToolExecutionComponent } from "./components/tool-execution.js";
|
|
73
|
-
import { ToolGroupComponent } from "./components/tool-group.js";
|
|
74
74
|
import { TreeSelectorComponent } from "./components/tree-selector.js";
|
|
75
75
|
import { TrustSelectorComponent } from "./components/trust-selector.js";
|
|
76
76
|
import { UserMessageComponent } from "./components/user-message.js";
|
|
77
77
|
import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
|
|
78
|
+
import { InteractiveEditorHost } from "./editor-host.js";
|
|
78
79
|
import { editInExternalEditor } from "./external-editor.js";
|
|
79
80
|
import { refreshModelCatalogs } from "./model-catalog-refresh.js";
|
|
80
81
|
import { getModelSearchText } from "./model-search.js";
|
|
81
82
|
import { shareSession } from "./session-share.js";
|
|
82
83
|
import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, onThemeChange, setRegisteredThemes, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
|
|
83
84
|
import { InteractiveThemeController } from "./theme/theme-controller.js";
|
|
85
|
+
import { appendToolRow, disposeChatRows, isToolChatComponent, PendingToolMap, ToolChatContainer, toolDetachHint, } from "./tool-chat.js";
|
|
84
86
|
import { createInteractiveTui, createInteractiveTuiReference } from "./tui-renderer.js";
|
|
85
87
|
export { createInteractiveTui, createInteractiveTuiReference } from "./tui-renderer.js";
|
|
86
88
|
function isWorkingStatusEditor(editor) {
|
|
@@ -207,10 +209,6 @@ function formatLoginProviderCompletionDescription(provider) {
|
|
|
207
209
|
const authTypes = provider.authTypes.map(formatAuthSelectorProviderType).join("/");
|
|
208
210
|
return provider.name === provider.id ? authTypes : `${provider.name} · ${authTypes}`;
|
|
209
211
|
}
|
|
210
|
-
/** Chat children that host tool presentation and share image display settings. */
|
|
211
|
-
function isToolChatComponent(child) {
|
|
212
|
-
return child instanceof ToolExecutionComponent || child instanceof ToolGroupComponent;
|
|
213
|
-
}
|
|
214
212
|
export class InteractiveMode {
|
|
215
213
|
// Convenience accessors
|
|
216
214
|
get session() {
|
|
@@ -252,7 +250,19 @@ export class InteractiveMode {
|
|
|
252
250
|
this.entriesRenderedByBoundaryCompaction = new Set();
|
|
253
251
|
this.streamingMessage = undefined;
|
|
254
252
|
// Tool execution tracking: toolCallId -> component
|
|
255
|
-
this.pendingTools = new
|
|
253
|
+
this.pendingTools = new PendingToolMap();
|
|
254
|
+
this.editorHost = new InteractiveEditorHost({
|
|
255
|
+
isSessionCommand: (name) => this.session.extensionRunner.getCommand(name) !== undefined ||
|
|
256
|
+
this.session.promptTemplates.some((template) => template.name === name) ||
|
|
257
|
+
this.skillCommands.has(name),
|
|
258
|
+
getEditor: () => this.editor,
|
|
259
|
+
getFocusedComponent: () => this.renderer.getFocusedComponent(),
|
|
260
|
+
hasOverlay: () => this.ui.hasOverlay(),
|
|
261
|
+
addTerminalInputListener: (handler) => this.addExtensionTerminalInputListener(handler),
|
|
262
|
+
setEditorText: (text) => this.editor.setText(text),
|
|
263
|
+
requestRender: () => this.ui.requestRender(),
|
|
264
|
+
showError: (message) => this.showError(message),
|
|
265
|
+
});
|
|
256
266
|
// Tool output expansion state
|
|
257
267
|
this.toolOutputExpanded = false;
|
|
258
268
|
// Thinking block visibility state
|
|
@@ -281,7 +291,6 @@ export class InteractiveMode {
|
|
|
281
291
|
this.extensionSelector = undefined;
|
|
282
292
|
this.extensionInput = undefined;
|
|
283
293
|
this.extensionEditor = undefined;
|
|
284
|
-
this.extensionEditorSubmitHandlers = new Set();
|
|
285
294
|
this.extensionTerminalInputSubscriptions = new Set();
|
|
286
295
|
// Extension widgets (components rendered above/below the editor)
|
|
287
296
|
this.extensionWidgetsAbove = new Map();
|
|
@@ -326,7 +335,7 @@ export class InteractiveMode {
|
|
|
326
335
|
this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
|
|
327
336
|
this.headerContainer = new Container();
|
|
328
337
|
this.loadedResourcesContainer = new Container();
|
|
329
|
-
this.chatContainer = new
|
|
338
|
+
this.chatContainer = new ToolChatContainer();
|
|
330
339
|
this.documentContainer = new Container();
|
|
331
340
|
this.documentContainer.addChild(this.headerContainer);
|
|
332
341
|
this.documentContainer.addChild(this.loadedResourcesContainer);
|
|
@@ -585,7 +594,6 @@ export class InteractiveMode {
|
|
|
585
594
|
return true;
|
|
586
595
|
nextUi.start();
|
|
587
596
|
this.themeController.rebindTui();
|
|
588
|
-
this.setupBackgroundInputListener();
|
|
589
597
|
this.rebindExtensionTerminalInputListeners();
|
|
590
598
|
if (restoreProgress &&
|
|
591
599
|
this.settingsManager.getShowTerminalProgress() &&
|
|
@@ -722,6 +730,14 @@ export class InteractiveMode {
|
|
|
722
730
|
});
|
|
723
731
|
// Initialize available provider count for footer display
|
|
724
732
|
await this.updateAvailableProviderCount();
|
|
733
|
+
// Flush the completed startup state before loading the remaining syntax grammars.
|
|
734
|
+
this.ui.renderNow();
|
|
735
|
+
void loadAllHighlightLanguages().then(() => {
|
|
736
|
+
if (!this.isInitialized)
|
|
737
|
+
return;
|
|
738
|
+
this.ui.invalidate();
|
|
739
|
+
this.ui.requestRender();
|
|
740
|
+
});
|
|
725
741
|
}
|
|
726
742
|
/**
|
|
727
743
|
* Update terminal title with session name and cwd.
|
|
@@ -923,15 +939,14 @@ export class InteractiveMode {
|
|
|
923
939
|
return undefined;
|
|
924
940
|
}
|
|
925
941
|
reportInstallTelemetry(version) {
|
|
926
|
-
if (!INSTALL_TELEMETRY_URL) {
|
|
927
|
-
return;
|
|
928
|
-
}
|
|
929
942
|
if (process.env.PI_OFFLINE) {
|
|
930
943
|
return;
|
|
931
944
|
}
|
|
932
945
|
if (!isInstallTelemetryEnabled(this.settingsManager)) {
|
|
933
946
|
return;
|
|
934
947
|
}
|
|
948
|
+
if (!INSTALL_TELEMETRY_URL)
|
|
949
|
+
return;
|
|
935
950
|
void fetch(`${INSTALL_TELEMETRY_URL}?version=${encodeURIComponent(version)}`, {
|
|
936
951
|
headers: {
|
|
937
952
|
"User-Agent": getPiUserAgent(version),
|
|
@@ -1438,7 +1453,7 @@ export class InteractiveMode {
|
|
|
1438
1453
|
if (result.cancelled) {
|
|
1439
1454
|
return { cancelled: true };
|
|
1440
1455
|
}
|
|
1441
|
-
this.
|
|
1456
|
+
this.chatContainer.clear();
|
|
1442
1457
|
this.renderInitialMessages();
|
|
1443
1458
|
if (result.editorText && !this.editor.getText().trim()) {
|
|
1444
1459
|
this.editor.setText(result.editorText);
|
|
@@ -1575,32 +1590,14 @@ export class InteractiveMode {
|
|
|
1575
1590
|
return;
|
|
1576
1591
|
this.suggestBugReport();
|
|
1577
1592
|
}
|
|
1578
|
-
disposeChatToolComponents() {
|
|
1579
|
-
for (const child of this.chatContainer.children) {
|
|
1580
|
-
const disposable = child;
|
|
1581
|
-
if (typeof disposable.dispose === "function") {
|
|
1582
|
-
disposable.dispose();
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
}
|
|
1586
|
-
clearChat() {
|
|
1587
|
-
this.disposeChatToolComponents();
|
|
1588
|
-
this.chatContainer.clear();
|
|
1589
|
-
}
|
|
1590
|
-
clearPendingTools() {
|
|
1591
|
-
for (const component of this.pendingTools.values()) {
|
|
1592
|
-
component.dispose();
|
|
1593
|
-
}
|
|
1594
|
-
this.pendingTools.clear();
|
|
1595
|
-
}
|
|
1596
1593
|
renderCurrentSessionState() {
|
|
1597
1594
|
this.loadedResourcesContainer.clear();
|
|
1598
|
-
this.
|
|
1595
|
+
this.chatContainer.clear();
|
|
1599
1596
|
this.pendingMessagesContainer.clear();
|
|
1600
1597
|
this.compactionQueuedMessages = [];
|
|
1601
1598
|
this.streamingComponent = undefined;
|
|
1602
1599
|
this.streamingMessage = undefined;
|
|
1603
|
-
this.
|
|
1600
|
+
this.pendingTools.clear();
|
|
1604
1601
|
this.renderInitialMessages();
|
|
1605
1602
|
}
|
|
1606
1603
|
/**
|
|
@@ -1613,39 +1610,6 @@ export class InteractiveMode {
|
|
|
1613
1610
|
getRegisteredToolDefinition(toolName) {
|
|
1614
1611
|
return withBuiltInRenderers(toolName, this.session.getToolDefinition(toolName));
|
|
1615
1612
|
}
|
|
1616
|
-
createToolExecutionComponent(toolName, toolCallId, args) {
|
|
1617
|
-
const component = new ToolExecutionComponent(toolName, toolCallId, args, {
|
|
1618
|
-
showImages: this.settingsManager.getShowImages(),
|
|
1619
|
-
imageWidthCells: this.settingsManager.getImageWidthCells(),
|
|
1620
|
-
detachHint: {
|
|
1621
|
-
// Everything BackgroundService.detachForeground() can move: shell tools and subagents.
|
|
1622
|
-
isDetachable: (name) => name === "bash" || name === "powershell" || name === "subagent",
|
|
1623
|
-
keyLabel: () => keyLabel("app.backgroundTasks.detach", { keybindings: this.keybindings }),
|
|
1624
|
-
},
|
|
1625
|
-
}, this.getRegisteredToolDefinition(toolName), this.ui, this.sessionManager.getCwd());
|
|
1626
|
-
component.setExpanded(this.toolOutputExpanded);
|
|
1627
|
-
return component;
|
|
1628
|
-
}
|
|
1629
|
-
appendToolExecutionComponent(component) {
|
|
1630
|
-
const toolGroup = component.toolGroup?.trim();
|
|
1631
|
-
if (!toolGroup) {
|
|
1632
|
-
this.chatContainer.addChild(component);
|
|
1633
|
-
return;
|
|
1634
|
-
}
|
|
1635
|
-
const children = this.chatContainer.children;
|
|
1636
|
-
const lastChild = children[children.length - 1];
|
|
1637
|
-
if (lastChild instanceof ToolGroupComponent && lastChild.toolGroup === toolGroup) {
|
|
1638
|
-
lastChild.addTool(component);
|
|
1639
|
-
return;
|
|
1640
|
-
}
|
|
1641
|
-
if (lastChild instanceof ToolExecutionComponent && lastChild.toolGroup?.trim() === toolGroup) {
|
|
1642
|
-
const group = new ToolGroupComponent(toolGroup, [lastChild, component]);
|
|
1643
|
-
group.setExpanded(this.toolOutputExpanded);
|
|
1644
|
-
children[children.length - 1] = group;
|
|
1645
|
-
return;
|
|
1646
|
-
}
|
|
1647
|
-
this.chatContainer.addChild(component);
|
|
1648
|
-
}
|
|
1649
1613
|
getMarkdownTransformers() {
|
|
1650
1614
|
return [this.mermaidMarkdownTransformer, ...this.session.extensionRunner.getMarkdownTransformers()];
|
|
1651
1615
|
}
|
|
@@ -1801,7 +1765,7 @@ export class InteractiveMode {
|
|
|
1801
1765
|
this.renderWidgets();
|
|
1802
1766
|
}
|
|
1803
1767
|
resetExtensionUI() {
|
|
1804
|
-
this.
|
|
1768
|
+
this.editorHost.clear();
|
|
1805
1769
|
if (this.extensionSelector) {
|
|
1806
1770
|
this.hideExtensionSelector();
|
|
1807
1771
|
}
|
|
@@ -1920,19 +1884,8 @@ export class InteractiveMode {
|
|
|
1920
1884
|
}
|
|
1921
1885
|
this.ui.requestRender();
|
|
1922
1886
|
}
|
|
1923
|
-
addExtensionTerminalInputListener(handler
|
|
1924
|
-
const
|
|
1925
|
-
if (options?.scope === "editor") {
|
|
1926
|
-
const editor = this.editor;
|
|
1927
|
-
if (this.renderer.getFocusedComponent() !== editor ||
|
|
1928
|
-
this.ui.hasOverlay() ||
|
|
1929
|
-
editor.isShowingAutocomplete?.()) {
|
|
1930
|
-
return undefined;
|
|
1931
|
-
}
|
|
1932
|
-
}
|
|
1933
|
-
return handler(data);
|
|
1934
|
-
};
|
|
1935
|
-
const subscription = { handler: scopedHandler, unsubscribe: this.ui.addInputListener(scopedHandler) };
|
|
1887
|
+
addExtensionTerminalInputListener(handler) {
|
|
1888
|
+
const subscription = { handler, unsubscribe: this.ui.addInputListener(handler) };
|
|
1936
1889
|
this.extensionTerminalInputSubscriptions.add(subscription);
|
|
1937
1890
|
return () => {
|
|
1938
1891
|
subscription.unsubscribe();
|
|
@@ -1973,11 +1926,8 @@ export class InteractiveMode {
|
|
|
1973
1926
|
confirm: (title, message, opts) => this.showExtensionConfirm(title, message, opts),
|
|
1974
1927
|
input: (title, placeholder, opts) => this.showExtensionInput(title, placeholder, opts),
|
|
1975
1928
|
notify: (message, type) => this.showExtensionNotify(message, type),
|
|
1976
|
-
onTerminalInput: (handler
|
|
1977
|
-
|
|
1978
|
-
this.extensionEditorSubmitHandlers.add(handler);
|
|
1979
|
-
return () => this.extensionEditorSubmitHandlers.delete(handler);
|
|
1980
|
-
},
|
|
1929
|
+
onTerminalInput: (handler) => this.addExtensionTerminalInputListener(handler),
|
|
1930
|
+
editorHost: this.editorHost,
|
|
1981
1931
|
setStatus: (key, text) => this.setExtensionStatus(key, text),
|
|
1982
1932
|
setWorkingMessage: (message) => {
|
|
1983
1933
|
this.workingMessage = message;
|
|
@@ -1996,10 +1946,6 @@ export class InteractiveMode {
|
|
|
1996
1946
|
pasteToEditor: (text) => this.editor.handleInput(`\x1b[200~${text}\x1b[201~`),
|
|
1997
1947
|
setEditorText: (text) => this.editor.setText(text),
|
|
1998
1948
|
getEditorText: () => this.editor.getExpandedText?.() ?? this.editor.getText(),
|
|
1999
|
-
getEditorCursor: () => {
|
|
2000
|
-
const editor = this.editor;
|
|
2001
|
-
return editor.getCursor?.();
|
|
2002
|
-
},
|
|
2003
1949
|
editor: (title, prefill) => this.showExtensionEditor(title, prefill),
|
|
2004
1950
|
addAutocompleteProvider: (factory) => {
|
|
2005
1951
|
this.autocompleteProviderWrappers.push(factory);
|
|
@@ -2332,24 +2278,10 @@ export class InteractiveMode {
|
|
|
2332
2278
|
}
|
|
2333
2279
|
this.ui.requestRender();
|
|
2334
2280
|
}
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
if (!this.keybindings.matches(data, "app.backgroundTasks.detach"))
|
|
2339
|
-
return undefined;
|
|
2340
|
-
if (this.isShuttingDown)
|
|
2341
|
-
return { consume: true };
|
|
2342
|
-
const count = this.session.background.detachForeground();
|
|
2343
|
-
// Nothing can move: let the key fall through to editor bindings instead of
|
|
2344
|
-
// spending it on a "nothing happened" status line.
|
|
2345
|
-
if (count === 0)
|
|
2346
|
-
return undefined;
|
|
2347
|
-
this.showStatus(`Moved ${count} execution${count === 1 ? "" : "s"} to the background. Use /bg to manage tasks.`);
|
|
2348
|
-
return { consume: true };
|
|
2349
|
-
});
|
|
2350
|
-
}
|
|
2281
|
+
// =========================================================================
|
|
2282
|
+
// Key Handlers
|
|
2283
|
+
// =========================================================================
|
|
2351
2284
|
setupKeyHandlers() {
|
|
2352
|
-
this.setupBackgroundInputListener();
|
|
2353
2285
|
// Set up handlers on defaultEditor - they use this.editor for text access
|
|
2354
2286
|
// so they work correctly regardless of which editor is active
|
|
2355
2287
|
this.defaultEditor.onEscape = () => {
|
|
@@ -2461,240 +2393,203 @@ export class InteractiveMode {
|
|
|
2461
2393
|
this.showStatus("Startup is still in progress");
|
|
2462
2394
|
}
|
|
2463
2395
|
setupEditorSubmitHandler() {
|
|
2464
|
-
this.defaultEditor.onSubmit = (text) =>
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
this.session.promptTemplates.some((template) => template.name === name) ||
|
|
2476
|
-
this.skillCommands.has(name)
|
|
2477
|
-
? "command"
|
|
2478
|
-
: "prompt";
|
|
2479
|
-
}
|
|
2480
|
-
interceptEditorSubmit(text, mode) {
|
|
2481
|
-
if (this.extensionEditorSubmitHandlers.size === 0)
|
|
2482
|
-
return false;
|
|
2483
|
-
const event = { text, mode, kind: this.classifyEditorSubmit(text) };
|
|
2484
|
-
for (const handler of this.extensionEditorSubmitHandlers) {
|
|
2485
|
-
try {
|
|
2486
|
-
const result = handler(event);
|
|
2487
|
-
if (!result?.handled)
|
|
2488
|
-
continue;
|
|
2489
|
-
this.editor.setText(result.editorText ?? "");
|
|
2490
|
-
this.ui.requestRender();
|
|
2491
|
-
return true;
|
|
2396
|
+
this.defaultEditor.onSubmit = async (text) => {
|
|
2397
|
+
text = text.trim();
|
|
2398
|
+
if (!text)
|
|
2399
|
+
return;
|
|
2400
|
+
if (this.editorHost.intercept(text, "steer"))
|
|
2401
|
+
return;
|
|
2402
|
+
// Handle commands
|
|
2403
|
+
if (text === "/settings") {
|
|
2404
|
+
this.showSettingsSelector();
|
|
2405
|
+
this.editor.setText("");
|
|
2406
|
+
return;
|
|
2492
2407
|
}
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
this.
|
|
2496
|
-
|
|
2497
|
-
return true;
|
|
2408
|
+
if (text === "/scoped-models") {
|
|
2409
|
+
this.editor.setText("");
|
|
2410
|
+
await this.showModelsSelector();
|
|
2411
|
+
return;
|
|
2498
2412
|
}
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
}
|
|
2644
|
-
if (text === "/quit") {
|
|
2645
|
-
this.editor.setText("");
|
|
2646
|
-
await this.shutdown();
|
|
2647
|
-
return;
|
|
2648
|
-
}
|
|
2649
|
-
// Handle bash command (! for normal, !! for excluded from context)
|
|
2650
|
-
if (text.startsWith("!")) {
|
|
2651
|
-
const isExcluded = text.startsWith("!!");
|
|
2652
|
-
const command = isExcluded ? text.slice(2).trim() : text.slice(1).trim();
|
|
2653
|
-
if (command) {
|
|
2654
|
-
if (this.session.isBashRunning) {
|
|
2655
|
-
this.showWarning("A bash command is already running. Press Esc to cancel it first.");
|
|
2656
|
-
this.editor.setText(text);
|
|
2413
|
+
if (text === "/model" || text.startsWith("/model ")) {
|
|
2414
|
+
const searchTerm = text.startsWith("/model ") ? text.slice(7).trim() : undefined;
|
|
2415
|
+
this.editor.setText("");
|
|
2416
|
+
await this.handleModelCommand(searchTerm);
|
|
2417
|
+
return;
|
|
2418
|
+
}
|
|
2419
|
+
if (text === "/thinking" || text.startsWith("/thinking ")) {
|
|
2420
|
+
const searchTerm = text.startsWith("/thinking ") ? text.slice(10).trim() : undefined;
|
|
2421
|
+
this.editor.setText("");
|
|
2422
|
+
this.handleThinkingCommand(searchTerm);
|
|
2423
|
+
return;
|
|
2424
|
+
}
|
|
2425
|
+
if (text === "/export" || text.startsWith("/export ")) {
|
|
2426
|
+
await this.handleExportCommand(text);
|
|
2427
|
+
this.editor.setText("");
|
|
2428
|
+
return;
|
|
2429
|
+
}
|
|
2430
|
+
if (text === "/import" || text.startsWith("/import ")) {
|
|
2431
|
+
await this.handleImportCommand(text);
|
|
2432
|
+
this.editor.setText("");
|
|
2433
|
+
return;
|
|
2434
|
+
}
|
|
2435
|
+
if (text === "/share") {
|
|
2436
|
+
await this.handleShareCommand();
|
|
2437
|
+
this.editor.setText("");
|
|
2438
|
+
return;
|
|
2439
|
+
}
|
|
2440
|
+
if (text === "/bug" || text.startsWith("/bug ")) {
|
|
2441
|
+
const hint = text.slice("/bug".length).trim();
|
|
2442
|
+
this.editor.setText("");
|
|
2443
|
+
await this.handleBugCommand(hint ? hint : undefined);
|
|
2444
|
+
return;
|
|
2445
|
+
}
|
|
2446
|
+
if (text === "/copy") {
|
|
2447
|
+
await this.handleCopyCommand();
|
|
2448
|
+
this.editor.setText("");
|
|
2449
|
+
return;
|
|
2450
|
+
}
|
|
2451
|
+
if (text === "/name" || text.startsWith("/name ")) {
|
|
2452
|
+
this.handleNameCommand(text);
|
|
2453
|
+
this.editor.setText("");
|
|
2454
|
+
return;
|
|
2455
|
+
}
|
|
2456
|
+
if (text === "/session") {
|
|
2457
|
+
this.handleSessionCommand();
|
|
2458
|
+
this.editor.setText("");
|
|
2459
|
+
return;
|
|
2460
|
+
}
|
|
2461
|
+
if (text === "/changelog") {
|
|
2462
|
+
this.handleChangelogCommand();
|
|
2463
|
+
this.editor.setText("");
|
|
2464
|
+
return;
|
|
2465
|
+
}
|
|
2466
|
+
if (text === "/hotkeys") {
|
|
2467
|
+
this.handleHotkeysCommand();
|
|
2468
|
+
this.editor.setText("");
|
|
2469
|
+
return;
|
|
2470
|
+
}
|
|
2471
|
+
if (text === "/fork") {
|
|
2472
|
+
this.showUserMessageSelector();
|
|
2473
|
+
this.editor.setText("");
|
|
2474
|
+
return;
|
|
2475
|
+
}
|
|
2476
|
+
if (text === "/clone") {
|
|
2477
|
+
this.editor.setText("");
|
|
2478
|
+
await this.handleCloneCommand();
|
|
2479
|
+
return;
|
|
2480
|
+
}
|
|
2481
|
+
if (text === "/tree") {
|
|
2482
|
+
this.showTreeSelector();
|
|
2483
|
+
this.editor.setText("");
|
|
2484
|
+
return;
|
|
2485
|
+
}
|
|
2486
|
+
if (text === "/trust") {
|
|
2487
|
+
this.showTrustSelector();
|
|
2488
|
+
this.editor.setText("");
|
|
2489
|
+
return;
|
|
2490
|
+
}
|
|
2491
|
+
if (text === "/login" || text.startsWith("/login ")) {
|
|
2492
|
+
const providerRef = text.startsWith("/login ") ? text.slice(7).trim() : undefined;
|
|
2493
|
+
this.editor.setText("");
|
|
2494
|
+
await this.handleLoginCommand(providerRef);
|
|
2495
|
+
return;
|
|
2496
|
+
}
|
|
2497
|
+
if (text === "/logout") {
|
|
2498
|
+
this.showOAuthSelector("logout");
|
|
2499
|
+
this.editor.setText("");
|
|
2500
|
+
return;
|
|
2501
|
+
}
|
|
2502
|
+
if (text === "/new") {
|
|
2503
|
+
this.editor.setText("");
|
|
2504
|
+
await this.handleClearCommand();
|
|
2505
|
+
return;
|
|
2506
|
+
}
|
|
2507
|
+
if (text === "/compact" || text.startsWith("/compact ")) {
|
|
2508
|
+
const customInstructions = text.startsWith("/compact ") ? text.slice(9).trim() : undefined;
|
|
2509
|
+
this.editor.setText("");
|
|
2510
|
+
await this.handleCompactCommand(customInstructions);
|
|
2511
|
+
return;
|
|
2512
|
+
}
|
|
2513
|
+
if (text === "/reload") {
|
|
2514
|
+
this.editor.setText("");
|
|
2515
|
+
await this.handleReloadCommand();
|
|
2516
|
+
return;
|
|
2517
|
+
}
|
|
2518
|
+
if (text === "/debug") {
|
|
2519
|
+
this.handleDebugCommand();
|
|
2520
|
+
this.editor.setText("");
|
|
2521
|
+
return;
|
|
2522
|
+
}
|
|
2523
|
+
if (text === "/arminsayshi") {
|
|
2524
|
+
this.handleArminSaysHi();
|
|
2525
|
+
this.editor.setText("");
|
|
2526
|
+
return;
|
|
2527
|
+
}
|
|
2528
|
+
if (text === "/dementedelves") {
|
|
2529
|
+
this.handleDementedDelves();
|
|
2530
|
+
this.editor.setText("");
|
|
2531
|
+
return;
|
|
2532
|
+
}
|
|
2533
|
+
if (text === "/resume") {
|
|
2534
|
+
this.showSessionSelector();
|
|
2535
|
+
this.editor.setText("");
|
|
2536
|
+
return;
|
|
2537
|
+
}
|
|
2538
|
+
if (text === "/quit") {
|
|
2539
|
+
this.editor.setText("");
|
|
2540
|
+
await this.shutdown();
|
|
2541
|
+
return;
|
|
2542
|
+
}
|
|
2543
|
+
// Handle bash command (! for normal, !! for excluded from context)
|
|
2544
|
+
if (text.startsWith("!")) {
|
|
2545
|
+
const isExcluded = text.startsWith("!!");
|
|
2546
|
+
const command = isExcluded ? text.slice(2).trim() : text.slice(1).trim();
|
|
2547
|
+
if (command) {
|
|
2548
|
+
if (this.session.isBashRunning) {
|
|
2549
|
+
this.showWarning("A bash command is already running. Press Esc to cancel it first.");
|
|
2550
|
+
this.editor.setText(text);
|
|
2551
|
+
return;
|
|
2552
|
+
}
|
|
2553
|
+
this.editor.addToHistory?.(text);
|
|
2554
|
+
await this.handleBashCommand(command, isExcluded);
|
|
2555
|
+
this.isBashMode = false;
|
|
2556
|
+
this.updateEditorBorderColor();
|
|
2657
2557
|
return;
|
|
2658
2558
|
}
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
this.
|
|
2559
|
+
}
|
|
2560
|
+
// Queue input during compaction (extension commands execute immediately)
|
|
2561
|
+
if (this.session.isCompacting) {
|
|
2562
|
+
if (this.isExtensionCommand(text)) {
|
|
2563
|
+
this.editor.addToHistory?.(text);
|
|
2564
|
+
this.editor.setText("");
|
|
2565
|
+
await this.session.prompt(text);
|
|
2566
|
+
}
|
|
2567
|
+
else {
|
|
2568
|
+
this.queueCompactionMessage(text, "steer");
|
|
2569
|
+
}
|
|
2663
2570
|
return;
|
|
2664
2571
|
}
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
if (this.isExtensionCommand(text)) {
|
|
2572
|
+
// If streaming, use prompt() with steer behavior
|
|
2573
|
+
// This handles extension commands (execute immediately), prompt template expansion, and queueing
|
|
2574
|
+
if (this.session.isStreaming) {
|
|
2669
2575
|
this.editor.addToHistory?.(text);
|
|
2670
2576
|
this.editor.setText("");
|
|
2671
|
-
await this.session.prompt(text);
|
|
2577
|
+
await this.session.prompt(text, { streamingBehavior: "steer" });
|
|
2578
|
+
this.updatePendingMessagesDisplay();
|
|
2579
|
+
this.ui.requestRender();
|
|
2580
|
+
return;
|
|
2581
|
+
}
|
|
2582
|
+
// Normal message submission
|
|
2583
|
+
// First, move any pending bash components to chat
|
|
2584
|
+
this.flushPendingBashComponents();
|
|
2585
|
+
if (this.onInputCallback) {
|
|
2586
|
+
this.onInputCallback(text);
|
|
2672
2587
|
}
|
|
2673
2588
|
else {
|
|
2674
|
-
this.
|
|
2589
|
+
this.pendingUserInputs.push(text);
|
|
2675
2590
|
}
|
|
2676
|
-
return;
|
|
2677
|
-
}
|
|
2678
|
-
// If streaming, use prompt() with steer behavior
|
|
2679
|
-
// This handles extension commands (execute immediately), prompt template expansion, and queueing
|
|
2680
|
-
if (this.session.isStreaming) {
|
|
2681
2591
|
this.editor.addToHistory?.(text);
|
|
2682
|
-
|
|
2683
|
-
await this.session.prompt(text, { streamingBehavior: mode });
|
|
2684
|
-
this.updatePendingMessagesDisplay();
|
|
2685
|
-
this.ui.requestRender();
|
|
2686
|
-
return;
|
|
2687
|
-
}
|
|
2688
|
-
// Normal message submission
|
|
2689
|
-
// First, move any pending bash components to chat
|
|
2690
|
-
this.flushPendingBashComponents();
|
|
2691
|
-
if (this.onInputCallback) {
|
|
2692
|
-
this.onInputCallback(text);
|
|
2693
|
-
}
|
|
2694
|
-
else {
|
|
2695
|
-
this.pendingUserInputs.push(text);
|
|
2696
|
-
}
|
|
2697
|
-
this.editor.addToHistory?.(text);
|
|
2592
|
+
};
|
|
2698
2593
|
}
|
|
2699
2594
|
subscribeToAgent() {
|
|
2700
2595
|
this.unsubscribe = this.session.subscribe(async (event) => {
|
|
@@ -2708,7 +2603,7 @@ export class InteractiveMode {
|
|
|
2708
2603
|
this.footer.invalidate();
|
|
2709
2604
|
switch (event.type) {
|
|
2710
2605
|
case "agent_start":
|
|
2711
|
-
this.
|
|
2606
|
+
this.pendingTools.clear();
|
|
2712
2607
|
// Restore main escape handler if retry handler is still active
|
|
2713
2608
|
// (retry success event fires later, but we need main handler now)
|
|
2714
2609
|
if (this.retryEscapeHandler) {
|
|
@@ -2808,8 +2703,13 @@ export class InteractiveMode {
|
|
|
2808
2703
|
for (const content of this.streamingMessage.content) {
|
|
2809
2704
|
if (content.type === "toolCall") {
|
|
2810
2705
|
if (!this.pendingTools.has(content.id)) {
|
|
2811
|
-
const component =
|
|
2812
|
-
|
|
2706
|
+
const component = new ToolExecutionComponent(content.name, content.id, content.arguments, {
|
|
2707
|
+
showImages: this.settingsManager.getShowImages(),
|
|
2708
|
+
imageWidthCells: this.settingsManager.getImageWidthCells(),
|
|
2709
|
+
detachHint: toolDetachHint(this.keybindings),
|
|
2710
|
+
}, this.getRegisteredToolDefinition(content.name), this.ui, this.sessionManager.getCwd());
|
|
2711
|
+
component.setExpanded(this.toolOutputExpanded);
|
|
2712
|
+
appendToolRow(this.chatContainer, component, this.toolOutputExpanded);
|
|
2813
2713
|
this.pendingTools.set(content.id, component);
|
|
2814
2714
|
}
|
|
2815
2715
|
else {
|
|
@@ -2871,8 +2771,13 @@ export class InteractiveMode {
|
|
|
2871
2771
|
case "tool_execution_start": {
|
|
2872
2772
|
let component = this.pendingTools.get(event.toolCallId);
|
|
2873
2773
|
if (!component) {
|
|
2874
|
-
component =
|
|
2875
|
-
|
|
2774
|
+
component = new ToolExecutionComponent(event.toolName, event.toolCallId, event.args, {
|
|
2775
|
+
showImages: this.settingsManager.getShowImages(),
|
|
2776
|
+
imageWidthCells: this.settingsManager.getImageWidthCells(),
|
|
2777
|
+
detachHint: toolDetachHint(this.keybindings),
|
|
2778
|
+
}, this.getRegisteredToolDefinition(event.toolName), this.ui, this.sessionManager.getCwd());
|
|
2779
|
+
component.setExpanded(this.toolOutputExpanded);
|
|
2780
|
+
appendToolRow(this.chatContainer, component, this.toolOutputExpanded);
|
|
2876
2781
|
this.pendingTools.set(event.toolCallId, component);
|
|
2877
2782
|
}
|
|
2878
2783
|
component.markExecutionStarted();
|
|
@@ -2906,7 +2811,7 @@ export class InteractiveMode {
|
|
|
2906
2811
|
this.streamingComponent = undefined;
|
|
2907
2812
|
this.streamingMessage = undefined;
|
|
2908
2813
|
}
|
|
2909
|
-
this.
|
|
2814
|
+
this.pendingTools.clear();
|
|
2910
2815
|
this.ui.requestRender();
|
|
2911
2816
|
break;
|
|
2912
2817
|
case "agent_settled":
|
|
@@ -2947,7 +2852,7 @@ export class InteractiveMode {
|
|
|
2947
2852
|
if (entries[0]?.type !== "compaction") {
|
|
2948
2853
|
throw new Error("Completed compaction is missing from the session context");
|
|
2949
2854
|
}
|
|
2950
|
-
this.
|
|
2855
|
+
this.chatContainer.clear();
|
|
2951
2856
|
// The latest compaction is prepended for model context; append it below at its chronological position.
|
|
2952
2857
|
this.renderSessionEntries(entries.slice(1));
|
|
2953
2858
|
this.addMessageToChat(createCompactionSummaryMessage(event.result.summary, event.result.tokensBefore, new Date().toISOString()));
|
|
@@ -3165,7 +3070,7 @@ export class InteractiveMode {
|
|
|
3165
3070
|
}
|
|
3166
3071
|
}
|
|
3167
3072
|
renderSessionItems(items, options = {}) {
|
|
3168
|
-
this.
|
|
3073
|
+
this.pendingTools.clear();
|
|
3169
3074
|
const renderedPendingTools = new Map();
|
|
3170
3075
|
// Cache misses are not persisted, unlike successful cache-warming usage.
|
|
3171
3076
|
// Re-derive them and inject them after the assistant messages that paid for them.
|
|
@@ -3196,8 +3101,13 @@ export class InteractiveMode {
|
|
|
3196
3101
|
// Render tool call components
|
|
3197
3102
|
for (const content of message.content) {
|
|
3198
3103
|
if (content.type === "toolCall") {
|
|
3199
|
-
const component =
|
|
3200
|
-
|
|
3104
|
+
const component = new ToolExecutionComponent(content.name, content.id, content.arguments, {
|
|
3105
|
+
showImages: this.settingsManager.getShowImages(),
|
|
3106
|
+
imageWidthCells: this.settingsManager.getImageWidthCells(),
|
|
3107
|
+
detachHint: toolDetachHint(this.keybindings),
|
|
3108
|
+
}, this.getRegisteredToolDefinition(content.name), this.ui, this.sessionManager.getCwd());
|
|
3109
|
+
component.setExpanded(this.toolOutputExpanded);
|
|
3110
|
+
appendToolRow(this.chatContainer, component, this.toolOutputExpanded);
|
|
3201
3111
|
if (message.stopReason === "aborted" || message.stopReason === "error") {
|
|
3202
3112
|
let errorMessage;
|
|
3203
3113
|
if (message.stopReason === "aborted") {
|
|
@@ -3383,7 +3293,7 @@ export class InteractiveMode {
|
|
|
3383
3293
|
});
|
|
3384
3294
|
}
|
|
3385
3295
|
rebuildChatFromMessages() {
|
|
3386
|
-
this.
|
|
3296
|
+
this.chatContainer.clear();
|
|
3387
3297
|
this.renderSessionEntries(this.sessionManager.buildContextEntries());
|
|
3388
3298
|
}
|
|
3389
3299
|
// =========================================================================
|
|
@@ -3571,8 +3481,34 @@ export class InteractiveMode {
|
|
|
3571
3481
|
const text = (this.editor.getExpandedText?.() ?? this.editor.getText()).trim();
|
|
3572
3482
|
if (!text)
|
|
3573
3483
|
return;
|
|
3574
|
-
this.
|
|
3575
|
-
|
|
3484
|
+
if (this.editorHost.intercept(text, "followUp"))
|
|
3485
|
+
return;
|
|
3486
|
+
// Queue input during compaction (extension commands execute immediately)
|
|
3487
|
+
if (this.session.isCompacting) {
|
|
3488
|
+
if (this.isExtensionCommand(text)) {
|
|
3489
|
+
this.editor.addToHistory?.(text);
|
|
3490
|
+
this.editor.setText("");
|
|
3491
|
+
await this.session.prompt(text);
|
|
3492
|
+
}
|
|
3493
|
+
else {
|
|
3494
|
+
this.queueCompactionMessage(text, "followUp");
|
|
3495
|
+
}
|
|
3496
|
+
return;
|
|
3497
|
+
}
|
|
3498
|
+
// Alt+Enter queues a follow-up message (waits until agent finishes)
|
|
3499
|
+
// This handles extension commands (execute immediately), prompt template expansion, and queueing
|
|
3500
|
+
if (this.session.isStreaming) {
|
|
3501
|
+
this.editor.addToHistory?.(text);
|
|
3502
|
+
this.editor.setText("");
|
|
3503
|
+
await this.session.prompt(text, { streamingBehavior: "followUp" });
|
|
3504
|
+
this.updatePendingMessagesDisplay();
|
|
3505
|
+
this.ui.requestRender();
|
|
3506
|
+
}
|
|
3507
|
+
// If not streaming, Alt+Enter acts like regular Enter (trigger onSubmit)
|
|
3508
|
+
else if (this.editor.onSubmit) {
|
|
3509
|
+
this.editor.setText("");
|
|
3510
|
+
this.editor.onSubmit(text);
|
|
3511
|
+
}
|
|
3576
3512
|
}
|
|
3577
3513
|
handleDequeue() {
|
|
3578
3514
|
const restored = this.restoreQueuedMessagesToEditor();
|
|
@@ -3697,7 +3633,13 @@ export class InteractiveMode {
|
|
|
3697
3633
|
showNewVersionNotification(release) {
|
|
3698
3634
|
const action = theme.fg("accent", `${APP_NAME} update`);
|
|
3699
3635
|
const updateInstruction = theme.fg("muted", `New version ${release.version} is available. Run `) + action;
|
|
3700
|
-
const
|
|
3636
|
+
const changelogUrl = "https://pi.dev/changelog";
|
|
3637
|
+
const changelogLink = getCapabilities().hyperlinks
|
|
3638
|
+
? hyperlink(theme.fg("accent", changelogUrl), changelogUrl)
|
|
3639
|
+
: theme.fg("accent", changelogUrl);
|
|
3640
|
+
const changelogLine = UPDATE_CHANGELOG_HINT
|
|
3641
|
+
? theme.fg("muted", UPDATE_CHANGELOG_HINT)
|
|
3642
|
+
: theme.fg("muted", "Changelog: ") + changelogLink;
|
|
3701
3643
|
const note = release.note?.trim();
|
|
3702
3644
|
this.chatContainer.addChild(new Spacer(1));
|
|
3703
3645
|
this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text)));
|
|
@@ -3905,15 +3847,8 @@ export class InteractiveMode {
|
|
|
3905
3847
|
showSelector(create) {
|
|
3906
3848
|
const token = {};
|
|
3907
3849
|
let dispose;
|
|
3908
|
-
let disposed = false;
|
|
3909
|
-
const disposeOnce = () => {
|
|
3910
|
-
if (disposed)
|
|
3911
|
-
return;
|
|
3912
|
-
disposed = true;
|
|
3913
|
-
dispose?.();
|
|
3914
|
-
};
|
|
3915
3850
|
const done = () => {
|
|
3916
|
-
|
|
3851
|
+
dispose?.();
|
|
3917
3852
|
if (this.activeSelectorToken !== token)
|
|
3918
3853
|
return;
|
|
3919
3854
|
this.activeSelectorToken = undefined;
|
|
@@ -3923,10 +3858,17 @@ export class InteractiveMode {
|
|
|
3923
3858
|
this.ui.setFocus(this.editor);
|
|
3924
3859
|
};
|
|
3925
3860
|
const created = create(done);
|
|
3926
|
-
|
|
3861
|
+
const release = created.dispose;
|
|
3862
|
+
let released = false;
|
|
3863
|
+
dispose = () => {
|
|
3864
|
+
if (released)
|
|
3865
|
+
return;
|
|
3866
|
+
released = true;
|
|
3867
|
+
release?.();
|
|
3868
|
+
};
|
|
3927
3869
|
this.disposeActiveSelector();
|
|
3928
3870
|
this.activeSelectorToken = token;
|
|
3929
|
-
this.activeSelectorDispose =
|
|
3871
|
+
this.activeSelectorDispose = dispose;
|
|
3930
3872
|
this.editorContainer.clear();
|
|
3931
3873
|
this.editorContainer.addChild(created.component);
|
|
3932
3874
|
this.ui.setFocus(created.focus);
|
|
@@ -4613,7 +4555,7 @@ export class InteractiveMode {
|
|
|
4613
4555
|
return;
|
|
4614
4556
|
}
|
|
4615
4557
|
// Update UI
|
|
4616
|
-
this.
|
|
4558
|
+
this.chatContainer.clear();
|
|
4617
4559
|
this.renderInitialMessages();
|
|
4618
4560
|
if (result.editorText && !this.editor.getText().trim()) {
|
|
4619
4561
|
this.editor.setText(result.editorText);
|
|
@@ -5754,9 +5696,6 @@ export class InteractiveMode {
|
|
|
5754
5696
|
}
|
|
5755
5697
|
}
|
|
5756
5698
|
stop(fullscreenExitOutput = this.settingsManager.getFullscreenExitOutput()) {
|
|
5757
|
-
this.extensionEditorSubmitHandlers.clear();
|
|
5758
|
-
this.backgroundInputUnsubscribe?.();
|
|
5759
|
-
this.backgroundInputUnsubscribe = undefined;
|
|
5760
5699
|
this.disposeActiveSelector();
|
|
5761
5700
|
if (this.settingsManager.getShowTerminalProgress()) {
|
|
5762
5701
|
this.ui.terminal.setProgress(false);
|
|
@@ -5764,8 +5703,9 @@ export class InteractiveMode {
|
|
|
5764
5703
|
this.clearStatusIndicator();
|
|
5765
5704
|
this.themeController.disableAutoSync();
|
|
5766
5705
|
this.clearExtensionTerminalInputListeners();
|
|
5767
|
-
this.
|
|
5768
|
-
this.
|
|
5706
|
+
this.editorHost.clear();
|
|
5707
|
+
this.pendingTools.clear();
|
|
5708
|
+
disposeChatRows(this.chatContainer);
|
|
5769
5709
|
this.footer.dispose();
|
|
5770
5710
|
this.footerDataProvider.dispose();
|
|
5771
5711
|
if (this.unsubscribe) {
|