pi-ui-extend 0.1.8 → 0.1.11
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/README.md +57 -2
- package/bin/pix.mjs +4 -4
- package/dist/app/app.d.ts +4 -0
- package/dist/app/app.js +112 -45
- package/dist/app/{cli.d.ts → cli/cli.d.ts} +1 -1
- package/dist/app/{cli.js → cli/cli.js} +1 -1
- package/dist/app/{install.d.ts → cli/install.d.ts} +2 -0
- package/dist/app/{install.js → cli/install.js} +18 -3
- package/dist/app/{command-controller.d.ts → commands/command-controller.d.ts} +1 -1
- package/dist/app/{command-controller.js → commands/command-controller.js} +4 -0
- package/dist/app/{command-host.d.ts → commands/command-host.d.ts} +7 -3
- package/dist/app/{command-model-actions.d.ts → commands/command-model-actions.d.ts} +6 -1
- package/dist/app/{command-model-actions.js → commands/command-model-actions.js} +106 -2
- package/dist/app/{command-navigation-actions.d.ts → commands/command-navigation-actions.d.ts} +7 -2
- package/dist/app/{command-navigation-actions.js → commands/command-navigation-actions.js} +42 -19
- package/dist/app/{command-registry.d.ts → commands/command-registry.d.ts} +5 -1
- package/dist/app/{command-registry.js → commands/command-registry.js} +32 -0
- package/dist/app/{command-runtime.js → commands/command-runtime.js} +1 -1
- package/dist/app/{command-session-actions.d.ts → commands/command-session-actions.d.ts} +1 -0
- package/dist/app/{command-session-actions.js → commands/command-session-actions.js} +18 -8
- package/dist/app/{shell-controller.d.ts → commands/shell-controller.d.ts} +2 -1
- package/dist/app/{shell-controller.js → commands/shell-controller.js} +2 -2
- package/dist/app/{slash-commands.d.ts → commands/slash-commands.d.ts} +2 -2
- package/dist/app/{slash-commands.js → commands/slash-commands.js} +1 -1
- package/dist/app/constants.d.ts +1 -1
- package/dist/app/constants.js +1 -1
- package/dist/app/{extension-actions-controller.d.ts → extensions/extension-actions-controller.d.ts} +1 -1
- package/dist/app/{extension-actions-controller.js → extensions/extension-actions-controller.js} +1 -1
- package/dist/app/{extension-ui-controller.d.ts → extensions/extension-ui-controller.d.ts} +3 -3
- package/dist/app/{extension-ui-controller.js → extensions/extension-ui-controller.js} +3 -3
- package/dist/app/icons.js +1 -1
- package/dist/app/input/autocomplete-controller.d.ts +52 -0
- package/dist/app/input/autocomplete-controller.js +352 -0
- package/dist/app/{input-action-controller.d.ts → input/input-action-controller.d.ts} +8 -7
- package/dist/app/{input-action-controller.js → input/input-action-controller.js} +24 -3
- package/dist/app/{input-controller.d.ts → input/input-controller.d.ts} +4 -3
- package/dist/app/{input-controller.js → input/input-controller.js} +3 -1
- package/dist/app/{input-paste-handler.d.ts → input/input-paste-handler.d.ts} +2 -1
- package/dist/app/{input-paste-handler.js → input/input-paste-handler.js} +25 -21
- package/dist/app/{native-modifiers.js → input/native-modifiers.js} +2 -2
- package/dist/app/{prompt-enhancer-controller.d.ts → input/prompt-enhancer-controller.d.ts} +5 -5
- package/dist/app/{prompt-enhancer-controller.js → input/prompt-enhancer-controller.js} +3 -3
- package/dist/app/{voice-controller.d.ts → input/voice-controller.d.ts} +3 -1
- package/dist/app/{voice-controller.js → input/voice-controller.js} +29 -17
- package/dist/app/{model-ref.d.ts → model/model-ref.d.ts} +1 -1
- package/dist/app/{model-ref.js → model/model-ref.js} +1 -1
- package/dist/app/{model-usage-controller.js → model/model-usage-controller.js} +1 -1
- package/dist/app/{model-usage-status.d.ts → model/model-usage-status.d.ts} +10 -1
- package/dist/app/{model-usage-status.js → model/model-usage-status.js} +125 -35
- package/dist/app/{menu-items-controller.d.ts → popup/menu-items-controller.d.ts} +4 -4
- package/dist/app/{menu-items-controller.js → popup/menu-items-controller.js} +5 -5
- package/dist/app/{popup-action-controller.d.ts → popup/popup-action-controller.d.ts} +4 -4
- package/dist/app/{popup-action-controller.js → popup/popup-action-controller.js} +3 -3
- package/dist/app/{popup-menu-controller.d.ts → popup/popup-menu-controller.d.ts} +4 -4
- package/dist/app/{popup-menu-controller.js → popup/popup-menu-controller.js} +7 -7
- package/dist/app/process.d.ts +17 -0
- package/dist/app/process.js +68 -0
- package/dist/app/{conversation-entry-renderer.d.ts → rendering/conversation-entry-renderer.d.ts} +3 -3
- package/dist/app/{conversation-entry-renderer.js → rendering/conversation-entry-renderer.js} +20 -9
- package/dist/app/{conversation-shell-renderer.d.ts → rendering/conversation-shell-renderer.d.ts} +1 -1
- package/dist/app/{conversation-shell-renderer.js → rendering/conversation-shell-renderer.js} +1 -1
- package/dist/app/{conversation-tool-renderer.d.ts → rendering/conversation-tool-renderer.d.ts} +3 -3
- package/dist/app/{conversation-tool-renderer.js → rendering/conversation-tool-renderer.js} +10 -9
- package/dist/app/{conversation-viewport.d.ts → rendering/conversation-viewport.d.ts} +3 -3
- package/dist/app/{dcp-stats.js → rendering/dcp-stats.js} +1 -1
- package/dist/app/{editor-layout-renderer.d.ts → rendering/editor-layout-renderer.d.ts} +4 -3
- package/dist/app/{editor-layout-renderer.js → rendering/editor-layout-renderer.js} +13 -3
- package/dist/app/{editor-panels.d.ts → rendering/editor-panels.d.ts} +2 -2
- package/dist/app/{editor-panels.js → rendering/editor-panels.js} +4 -4
- package/dist/app/{message-content.d.ts → rendering/message-content.d.ts} +1 -1
- package/dist/app/{message-content.js → rendering/message-content.js} +66 -8
- package/dist/app/{render-controller.d.ts → rendering/render-controller.d.ts} +6 -6
- package/dist/app/{render-controller.js → rendering/render-controller.js} +11 -6
- package/dist/app/{render-text.d.ts → rendering/render-text.d.ts} +5 -2
- package/dist/app/{render-text.js → rendering/render-text.js} +53 -5
- package/dist/app/{status-line-renderer.d.ts → rendering/status-line-renderer.d.ts} +8 -4
- package/dist/app/{status-line-renderer.js → rendering/status-line-renderer.js} +73 -29
- package/dist/app/{tab-line-renderer.d.ts → rendering/tab-line-renderer.d.ts} +3 -3
- package/dist/app/{tab-line-renderer.js → rendering/tab-line-renderer.js} +2 -2
- package/dist/app/{toast-controller.d.ts → rendering/toast-controller.d.ts} +1 -1
- package/dist/app/{toast-controller.js → rendering/toast-controller.js} +2 -2
- package/dist/app/{toast-renderer.d.ts → rendering/toast-renderer.d.ts} +3 -3
- package/dist/app/{toast-renderer.js → rendering/toast-renderer.js} +3 -3
- package/dist/app/{tool-block-renderer.d.ts → rendering/tool-block-renderer.d.ts} +5 -5
- package/dist/app/{tool-block-renderer.js → rendering/tool-block-renderer.js} +15 -33
- package/dist/app/runtime.d.ts +6 -1
- package/dist/app/runtime.js +35 -2
- package/dist/app/{blink-controller.js → screen/blink-controller.js} +1 -1
- package/dist/app/{clipboard.d.ts → screen/clipboard.d.ts} +2 -2
- package/dist/app/{clipboard.js → screen/clipboard.js} +13 -18
- package/dist/app/{image-click-targets.d.ts → screen/image-click-targets.d.ts} +2 -2
- package/dist/app/{image-opener.d.ts → screen/image-opener.d.ts} +1 -1
- package/dist/app/{mouse-controller.d.ts → screen/mouse-controller.d.ts} +17 -10
- package/dist/app/{mouse-controller.js → screen/mouse-controller.js} +72 -29
- package/dist/app/{screen-selection.d.ts → screen/screen-selection.d.ts} +1 -1
- package/dist/app/{screen-styler.d.ts → screen/screen-styler.d.ts} +6 -3
- package/dist/app/{screen-styler.js → screen/screen-styler.js} +7 -6
- package/dist/app/{scroll-controller.d.ts → screen/scroll-controller.d.ts} +3 -3
- package/dist/app/{scroll-controller.js → screen/scroll-controller.js} +1 -1
- package/dist/app/{status-controller.d.ts → screen/status-controller.d.ts} +5 -2
- package/dist/app/{status-controller.js → screen/status-controller.js} +24 -9
- package/dist/app/{queued-message-controller.d.ts → session/queued-message-controller.d.ts} +9 -3
- package/dist/app/{queued-message-controller.js → session/queued-message-controller.js} +34 -23
- package/dist/app/{request-history.js → session/request-history.js} +2 -2
- package/dist/app/session/resume-session-loader.d.ts +15 -0
- package/dist/app/session/resume-session-loader.js +204 -0
- package/dist/app/{session-event-controller.d.ts → session/session-event-controller.d.ts} +8 -4
- package/dist/app/{session-event-controller.js → session/session-event-controller.js} +75 -8
- package/dist/app/{session-history.d.ts → session/session-history.d.ts} +1 -1
- package/dist/app/{session-history.js → session/session-history.js} +7 -6
- package/dist/app/{session-lifecycle-controller.d.ts → session/session-lifecycle-controller.d.ts} +7 -2
- package/dist/app/{session-lifecycle-controller.js → session/session-lifecycle-controller.js} +13 -5
- package/dist/app/{session-search.d.ts → session/session-search.d.ts} +1 -1
- package/dist/app/{session-search.js → session/session-search.js} +3 -3
- package/dist/app/{tabs-controller.d.ts → session/tabs-controller.d.ts} +11 -2
- package/dist/app/{tabs-controller.js → session/tabs-controller.js} +105 -9
- package/dist/app/{subagents-files.d.ts → subagents/subagents-files.d.ts} +1 -1
- package/dist/app/{subagents-files.js → subagents/subagents-files.js} +1 -1
- package/dist/app/{subagents-model.d.ts → subagents/subagents-model.d.ts} +1 -1
- package/dist/app/{subagents-model.js → subagents/subagents-model.js} +4 -4
- package/dist/app/{subagents-widget-controller.d.ts → subagents/subagents-widget-controller.d.ts} +1 -1
- package/dist/app/{subagents-widget-controller.js → subagents/subagents-widget-controller.js} +2 -2
- package/dist/app/{nerd-font-controller.js → terminal/nerd-font-controller.js} +16 -17
- package/dist/app/{terminal-bell-sound-controller.js → terminal/terminal-bell-sound-controller.js} +1 -1
- package/dist/app/{terminal-controller.d.ts → terminal/terminal-controller.d.ts} +1 -0
- package/dist/app/{terminal-controller.js → terminal/terminal-controller.js} +3 -2
- package/dist/app/{todo-model.d.ts → todo/todo-model.d.ts} +1 -1
- package/dist/app/{todo-model.js → todo/todo-model.js} +3 -3
- package/dist/app/{todo-widget-controller.d.ts → todo/todo-widget-controller.d.ts} +1 -1
- package/dist/app/{todo-widget-controller.js → todo/todo-widget-controller.js} +2 -2
- package/dist/app/types.d.ts +16 -2
- package/dist/app/{workspace-actions-controller.d.ts → workspace/workspace-actions-controller.d.ts} +2 -2
- package/dist/app/{workspace-actions-controller.js → workspace/workspace-actions-controller.js} +6 -6
- package/dist/app/{workspace-undo.d.ts → workspace/workspace-undo.d.ts} +1 -1
- package/dist/app/{workspace-undo.js → workspace/workspace-undo.js} +22 -20
- package/dist/config.d.ts +27 -0
- package/dist/config.js +174 -1
- package/dist/default-pix-config.js +38 -353
- package/dist/input-editor.d.ts +7 -1
- package/dist/input-editor.js +47 -6
- package/dist/main.js +2 -2
- package/dist/markdown-format.d.ts +1 -0
- package/dist/markdown-format.js +26 -1
- package/external/pi-tools-suite/README.md +78 -0
- package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +4 -0
- package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +6 -1
- package/external/pi-tools-suite/src/dcp/compression-blocks.ts +1 -0
- package/external/pi-tools-suite/src/dcp/prompts.ts +5 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +314 -193
- package/external/pi-tools-suite/src/index.ts +1 -0
- package/external/pi-tools-suite/src/lib/lsp.ts +2 -1
- package/external/pi-tools-suite/src/lsp/_shared/output.ts +8 -7
- package/external/pi-tools-suite/src/lsp/manager.ts +4 -4
- package/external/pi-tools-suite/src/opencode-import/commands.ts +86 -0
- package/external/pi-tools-suite/src/opencode-import/importer.ts +208 -0
- package/external/pi-tools-suite/src/opencode-import/index.ts +25 -0
- package/external/pi-tools-suite/src/repo-discovery/index.ts +49 -2
- package/external/pi-tools-suite/src/todo/tool/response-envelope.ts +9 -1
- package/external/pi-tools-suite/src/tool-descriptions.ts +1 -1
- package/package.json +1 -1
- /package/dist/app/{startup-checks.d.ts → cli/startup-checks.d.ts} +0 -0
- /package/dist/app/{startup-checks.js → cli/startup-checks.js} +0 -0
- /package/dist/app/{startup-info.d.ts → cli/startup-info.d.ts} +0 -0
- /package/dist/app/{startup-info.js → cli/startup-info.js} +0 -0
- /package/dist/app/{update.d.ts → cli/update.d.ts} +0 -0
- /package/dist/app/{update.js → cli/update.js} +0 -0
- /package/dist/app/{command-host.js → commands/command-host.js} +0 -0
- /package/dist/app/{command-runtime.d.ts → commands/command-runtime.d.ts} +0 -0
- /package/dist/app/{shell-command.d.ts → commands/shell-command.d.ts} +0 -0
- /package/dist/app/{shell-command.js → commands/shell-command.js} +0 -0
- /package/dist/app/{extension-event-bus.d.ts → extensions/extension-event-bus.d.ts} +0 -0
- /package/dist/app/{extension-event-bus.js → extensions/extension-event-bus.js} +0 -0
- /package/dist/app/{native-modifiers.d.ts → input/native-modifiers.d.ts} +0 -0
- /package/dist/app/{terminal-edit-shortcuts.d.ts → input/terminal-edit-shortcuts.d.ts} +0 -0
- /package/dist/app/{terminal-edit-shortcuts.js → input/terminal-edit-shortcuts.js} +0 -0
- /package/dist/app/{model-usage-controller.d.ts → model/model-usage-controller.d.ts} +0 -0
- /package/dist/app/{conversation-viewport.js → rendering/conversation-viewport.js} +0 -0
- /package/dist/app/{dcp-stats.d.ts → rendering/dcp-stats.d.ts} +0 -0
- /package/dist/app/{blink-controller.d.ts → screen/blink-controller.d.ts} +0 -0
- /package/dist/app/{file-link-opener.d.ts → screen/file-link-opener.d.ts} +0 -0
- /package/dist/app/{file-link-opener.js → screen/file-link-opener.js} +0 -0
- /package/dist/app/{file-links.d.ts → screen/file-links.d.ts} +0 -0
- /package/dist/app/{file-links.js → screen/file-links.js} +0 -0
- /package/dist/app/{image-click-targets.js → screen/image-click-targets.js} +0 -0
- /package/dist/app/{image-opener.js → screen/image-opener.js} +0 -0
- /package/dist/app/{screen-selection.js → screen/screen-selection.js} +0 -0
- /package/dist/app/{request-history.d.ts → session/request-history.d.ts} +0 -0
- /package/dist/app/{nerd-font-controller.d.ts → terminal/nerd-font-controller.d.ts} +0 -0
- /package/dist/app/{terminal-bell-sound-controller.d.ts → terminal/terminal-bell-sound-controller.d.ts} +0 -0
- /package/dist/app/{terminal-output-buffer.d.ts → terminal/terminal-output-buffer.d.ts} +0 -0
- /package/dist/app/{terminal-output-buffer.js → terminal/terminal-output-buffer.js} +0 -0
package/README.md
CHANGED
|
@@ -14,6 +14,23 @@ The npm package is currently named `pi-ui-extend` and installs the `pix` CLI.
|
|
|
14
14
|
- Pix extension UI helpers for toasts, menus, and rows above the input editor.
|
|
15
15
|
- Bundled `pi-tools-suite` payload. On startup, Pix links it into Pi's standard user extension directory.
|
|
16
16
|
|
|
17
|
+
## Why use Pix instead of bare Pi?
|
|
18
|
+
|
|
19
|
+
Pix keeps the same Pi agent engine and SDK, but replaces the default terminal experience with a faster, more interactive coding cockpit:
|
|
20
|
+
|
|
21
|
+
- **Tabs for real work.** Keep several workspace-scoped Pi sessions open in one terminal, switch between tasks instantly, and restore tab state after restart.
|
|
22
|
+
- **A readable tool-call UI.** Tool output is grouped into clickable rows, so long reads, patches, shell logs, and errors can be collapsed or expanded instead of flooding the conversation.
|
|
23
|
+
- **Local shell without leaving the chat.** Prefix a command with `!` to run it in an ephemeral in-chat shell block, or use `!!` for raw TTY programs.
|
|
24
|
+
- **Voice prompts.** Dictate prompts locally in Russian or English with Vosk; no cloud speech service is required.
|
|
25
|
+
- **Prompt drafting assistance.** Inline AI autocomplete suggests the next words while you type, and `/enhance` rewrites a rough draft into a clearer agent prompt.
|
|
26
|
+
- **Workspace safety net.** Pix tracks supported file mutations and lets you roll back the latest workspace change with `/undo`.
|
|
27
|
+
- **Clickable files and images.** File paths in the conversation become clickable links that open in Zed, including line and column when available; image labels can be opened in the system viewer.
|
|
28
|
+
- **Session power tools.** Search across saved sessions, fork from an earlier message, clone the current branch, rename sessions, export/import JSONL, or share a private gist.
|
|
29
|
+
- **Queued follow-ups.** Add the next prompt while the agent is still running; Pix sends it automatically when the current turn finishes.
|
|
30
|
+
- **Live status panels.** Built-in panels surface todo state, async sub-agent activity, model/context usage, and compression stats above the editor.
|
|
31
|
+
- **Renderer-aware extensions.** Pix extensions can draw rows above/below the input, show stackable toasts, open searchable popup menus, and react through an isolated event bus.
|
|
32
|
+
- **Nicer terminal ergonomics.** Mouse scrolling, PageUp/PageDown scrollback, tab attention, status lines, terminal-output buffering, Nerd Font icons, and fallback icon mode are handled by the Pix renderer.
|
|
33
|
+
|
|
17
34
|
## Requirements
|
|
18
35
|
|
|
19
36
|
- Node.js `>=22.19.0 <25` (`24.16.0` is pinned for development).
|
|
@@ -43,6 +60,12 @@ pix install --check
|
|
|
43
60
|
|
|
44
61
|
`pix install` checks the icon font, `pi` CLI availability, and clipboard helpers. The `pix` launcher also prepends Pix's bundled dependency bin directory to `PATH`, so a package-manager install can use the bundled Pi CLI even when a separate global `pi` command is not present.
|
|
45
62
|
|
|
63
|
+
After the setup check, review the user config files:
|
|
64
|
+
|
|
65
|
+
- `~/.config/pi/pix.jsonc`: choose the voice-input language with `dictation.language` and keep only the `dictation.languages` models you want enabled.
|
|
66
|
+
- `~/.config/pi/pi-tools-suite.jsonc`: enable/configure your LSP servers under `lsp.servers` and adjust pi-tools-suite modules or sub-agent presets if needed.
|
|
67
|
+
- In Pix, run `/opencode-import` to import opencode accounts. For Antigravity OAuth accounts, run `/antigravity-import` or add another account with `/antigravity-add-account`.
|
|
68
|
+
|
|
46
69
|
On startup, Pix ensures the bundled suite is available at:
|
|
47
70
|
|
|
48
71
|
```text
|
|
@@ -153,8 +176,6 @@ Useful environment variables:
|
|
|
153
176
|
- `PIX_DISABLE_TERMINAL_OUTPUT_BUFFER=1` or `PIX_TERMINAL_OUTPUT_BUFFER=0`: disable Pix terminal output region buffering.
|
|
154
177
|
- `PIX_USE_FALLBACK_ICONS=1` or `PIX_ICON_THEME=fallback`: use plain fallback icons when Nerd Font glyphs are unavailable.
|
|
155
178
|
- `PIX_ICON_THEME=nerdFont`: force the Nerd Font icon theme.
|
|
156
|
-
- `PIX_ANTIGRAVITY_GOOGLE_CLIENT_ID` / `ANTIGRAVITY_GOOGLE_CLIENT_ID`: Google OAuth client ID used for Antigravity quota/login integrations.
|
|
157
|
-
- `PIX_ANTIGRAVITY_GOOGLE_CLIENT_SECRET` / `ANTIGRAVITY_GOOGLE_CLIENT_SECRET`: Google OAuth client secret used for Antigravity quota/login integrations.
|
|
158
179
|
|
|
159
180
|
Pix user configuration is read from:
|
|
160
181
|
|
|
@@ -185,6 +206,40 @@ Example fallback icon configuration:
|
|
|
185
206
|
- Click a tool row: expand or collapse that tool result.
|
|
186
207
|
- Click the right-aligned microphone/language status widget: toggle voice input and switch Russian/English dictation.
|
|
187
208
|
|
|
209
|
+
## Slash commands
|
|
210
|
+
|
|
211
|
+
Type `/` in the prompt to open the command picker. Commands that accept arguments can also be called directly with inline arguments.
|
|
212
|
+
|
|
213
|
+
| Command | Arguments | Description |
|
|
214
|
+
|---|---|---|
|
|
215
|
+
| `/settings` | — | Show current session, model, theme, and key settings. |
|
|
216
|
+
| `/model` | `[provider/model[:thinking]]` | Select the active model. Without arguments, opens the model picker. With a reference like `anthropic/claude-sonnet-4-20250514:medium`, sets the model and optional thinking level directly. |
|
|
217
|
+
| `/scoped-models` | `[refs…\|reset]` | Show or set the models used by the model selector and cycling. Pass one or more `provider/model[:thinking]` references separated by spaces or commas. Use `reset` to restore the default favorites. |
|
|
218
|
+
| `/thinking` | `[level]` | Select the thinking level. Without arguments, opens the thinking picker. Accepts an explicit level (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`). |
|
|
219
|
+
| `/enhance` | — | Improve the current prompt draft using the prompt enhancer model. |
|
|
220
|
+
| `/export` | `[path]` | Export the session. Defaults to HTML. Pass a `.jsonl` path to export as JSONL. |
|
|
221
|
+
| `/import` | `<path.jsonl>` | Import and resume a session from a JSONL file. |
|
|
222
|
+
| `/share` | — | Share the session as a private GitHub gist (requires `gh` CLI). |
|
|
223
|
+
| `/copy` | — | Copy the last agent message to the clipboard. |
|
|
224
|
+
| `/name` | `[name]` | Show or set the session display name. |
|
|
225
|
+
| `/session` | — | Show session info: message counts, token usage, and cost. |
|
|
226
|
+
| `/usage` | — | Show local account quota usage and context window utilization. |
|
|
227
|
+
| `/changelog` | — | Show the Pi package changelog. |
|
|
228
|
+
| `/update` | `[--force\|--help]` | Check for Pix package updates. `/update` is check-only; run `pix update` in a shell to install. |
|
|
229
|
+
| `/hotkeys` | — | Show keyboard shortcuts. |
|
|
230
|
+
| `/fork` | `[entry-id]` | Fork the session from the latest or specified user-message entry. |
|
|
231
|
+
| `/clone` | — | Duplicate the current session at the current position. |
|
|
232
|
+
| `/jump` | `[query]` | Jump to a previous user message. Opens the message picker, optionally filtered by query. |
|
|
233
|
+
| `/search` | `<text>` | Search sessions for matching text and open a result in a new tab. |
|
|
234
|
+
| `/reload` | — | Reload keybindings, extensions, skills, prompts, and themes from disk. |
|
|
235
|
+
| `/resume` | `[path\|query]` | Resume a different session. Without arguments, opens the session picker. |
|
|
236
|
+
| `/new` | — | Start a fresh session in the current tab. |
|
|
237
|
+
| `/new_tab` | — | Open a fresh session in a new tab. |
|
|
238
|
+
| `/compact` | `[instructions]` | Manually compact the session context, optionally with custom instructions for the compaction. |
|
|
239
|
+
| `/quit`, `/exit` | — | Quit the renderer. |
|
|
240
|
+
|
|
241
|
+
Extensions, prompt templates, and skills may register additional slash commands that appear in the command picker alongside the built-in ones.
|
|
242
|
+
|
|
188
243
|
## Voice input
|
|
189
244
|
|
|
190
245
|
Pix can dictate into the prompt through local Vosk. The first start for each language downloads the small model into the gitignored `models/vosk/` directory inside this project:
|
package/bin/pix.mjs
CHANGED
|
@@ -9,8 +9,8 @@ const minimumNodeVersionLabel = "22.19.0";
|
|
|
9
9
|
const launcherPath = fileURLToPath(import.meta.url);
|
|
10
10
|
const packageRoot = dirname(dirname(launcherPath));
|
|
11
11
|
const mainPath = fileURLToPath(new URL("../dist/main.js", import.meta.url));
|
|
12
|
-
const updatePath = fileURLToPath(new URL("../dist/app/update.js", import.meta.url));
|
|
13
|
-
const installPath = fileURLToPath(new URL("../dist/app/install.js", import.meta.url));
|
|
12
|
+
const updatePath = fileURLToPath(new URL("../dist/app/cli/update.js", import.meta.url));
|
|
13
|
+
const installPath = fileURLToPath(new URL("../dist/app/cli/install.js", import.meta.url));
|
|
14
14
|
const distPath = dirname(mainPath);
|
|
15
15
|
const rawArgs = process.argv.slice(2);
|
|
16
16
|
const childArgs = [];
|
|
@@ -39,7 +39,7 @@ if (childArgs[0] === "update") {
|
|
|
39
39
|
console.error("pix update is not built yet. Run `npm run build:pix` or update from a published package.");
|
|
40
40
|
process.exit(1);
|
|
41
41
|
}
|
|
42
|
-
const { runPixUpdateCli } = await import(new URL("../dist/app/update.js", import.meta.url));
|
|
42
|
+
const { runPixUpdateCli } = await import(new URL("../dist/app/cli/update.js", import.meta.url));
|
|
43
43
|
process.exit(await runPixUpdateCli(childArgs.slice(1)));
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -48,7 +48,7 @@ if (childArgs[0] === "install" || childArgs[0] === "setup") {
|
|
|
48
48
|
console.error("pix install is not built yet. Run `npm run build:pix` or update from a published package.");
|
|
49
49
|
process.exit(1);
|
|
50
50
|
}
|
|
51
|
-
const { runPixInstallCli } = await import(new URL("../dist/app/install.js", import.meta.url));
|
|
51
|
+
const { runPixInstallCli } = await import(new URL("../dist/app/cli/install.js", import.meta.url));
|
|
52
52
|
process.exit(await runPixInstallCli(childArgs.slice(1), { env: pixChildEnv() }));
|
|
53
53
|
}
|
|
54
54
|
|
package/dist/app/app.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export declare class PiUiExtendApp {
|
|
|
31
31
|
private readonly nerdFontController;
|
|
32
32
|
private readonly popupActions;
|
|
33
33
|
private readonly promptEnhancer;
|
|
34
|
+
private readonly autocompleteController;
|
|
34
35
|
private readonly mouseController;
|
|
35
36
|
private readonly popupMenus;
|
|
36
37
|
private readonly voiceController;
|
|
@@ -48,6 +49,7 @@ export declare class PiUiExtendApp {
|
|
|
48
49
|
private get input();
|
|
49
50
|
private set input(value);
|
|
50
51
|
private running;
|
|
52
|
+
private scheduledRenderTimer;
|
|
51
53
|
private todoPanelExpanded;
|
|
52
54
|
private subagentsPanelExpanded;
|
|
53
55
|
private allThinkingExpanded;
|
|
@@ -85,6 +87,7 @@ export declare class PiUiExtendApp {
|
|
|
85
87
|
private setSessionStatus;
|
|
86
88
|
private setSessionActivity;
|
|
87
89
|
private toolDefaultExpanded;
|
|
90
|
+
private toggleSuperCompactTools;
|
|
88
91
|
private stopBlinking;
|
|
89
92
|
private stop;
|
|
90
93
|
private toggleTerminalBellSound;
|
|
@@ -92,6 +95,7 @@ export declare class PiUiExtendApp {
|
|
|
92
95
|
private showToast;
|
|
93
96
|
private clearToastTimers;
|
|
94
97
|
private render;
|
|
98
|
+
private scheduleRender;
|
|
95
99
|
private renderStatusLine;
|
|
96
100
|
private terminalColumns;
|
|
97
101
|
private terminalRows;
|
package/dist/app/app.js
CHANGED
|
@@ -1,51 +1,53 @@
|
|
|
1
1
|
import { THEMES } from "../theme.js";
|
|
2
2
|
import { InputEditor } from "../input-editor.js";
|
|
3
3
|
import { compileOutputFilterPatterns, loadPixConfig, resolveToolRule, } from "../config.js";
|
|
4
|
-
import { AppCommandController } from "./command-controller.js";
|
|
5
|
-
import { ConversationViewport } from "./conversation-viewport.js";
|
|
6
|
-
import { EditorLayoutRenderer } from "./editor-layout-renderer.js";
|
|
7
|
-
import { AppExtensionActionsController } from "./extension-actions-controller.js";
|
|
8
|
-
import { ExtensionUiController } from "./extension-ui-controller.js";
|
|
9
|
-
import { AppInputActionController } from "./input-action-controller.js";
|
|
10
|
-
import { AppInputController } from "./input-controller.js";
|
|
11
|
-
import { AppBlinkController } from "./blink-controller.js";
|
|
4
|
+
import { AppCommandController } from "./commands/command-controller.js";
|
|
5
|
+
import { ConversationViewport } from "./rendering/conversation-viewport.js";
|
|
6
|
+
import { EditorLayoutRenderer } from "./rendering/editor-layout-renderer.js";
|
|
7
|
+
import { AppExtensionActionsController } from "./extensions/extension-actions-controller.js";
|
|
8
|
+
import { ExtensionUiController } from "./extensions/extension-ui-controller.js";
|
|
9
|
+
import { AppInputActionController } from "./input/input-action-controller.js";
|
|
10
|
+
import { AppInputController } from "./input/input-controller.js";
|
|
11
|
+
import { AppBlinkController } from "./screen/blink-controller.js";
|
|
12
12
|
import { isRecord } from "./guards.js";
|
|
13
|
-
import { AppMenuItemsController } from "./menu-items-controller.js";
|
|
14
|
-
import { AppMouseController } from "./mouse-controller.js";
|
|
13
|
+
import { AppMenuItemsController } from "./popup/menu-items-controller.js";
|
|
14
|
+
import { AppMouseController } from "./screen/mouse-controller.js";
|
|
15
15
|
import { createId } from "./id.js";
|
|
16
|
-
import { NerdFontController } from "./nerd-font-controller.js";
|
|
17
|
-
import { AppPopupActionController } from "./popup-action-controller.js";
|
|
18
|
-
import { AppPopupMenuController } from "./popup-menu-controller.js";
|
|
19
|
-
import { AppPromptEnhancerController } from "./prompt-enhancer-controller.js";
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
16
|
+
import { NerdFontController } from "./terminal/nerd-font-controller.js";
|
|
17
|
+
import { AppPopupActionController } from "./popup/popup-action-controller.js";
|
|
18
|
+
import { AppPopupMenuController } from "./popup/popup-menu-controller.js";
|
|
19
|
+
import { AppPromptEnhancerController } from "./input/prompt-enhancer-controller.js";
|
|
20
|
+
import { AppAutocompleteController } from "./input/autocomplete-controller.js";
|
|
21
|
+
import { AppQueuedMessageController } from "./session/queued-message-controller.js";
|
|
22
|
+
import { AppRequestHistory } from "./session/request-history.js";
|
|
23
|
+
import { AppRenderController } from "./rendering/render-controller.js";
|
|
23
24
|
import { createPixRuntime } from "./runtime.js";
|
|
24
|
-
import { ScreenStyler } from "./screen-styler.js";
|
|
25
|
-
import { AppScrollController } from "./scroll-controller.js";
|
|
26
|
-
import { searchResultScrollNeedles, searchResultTargetEntry } from "./session-search.js";
|
|
27
|
-
import { AppSessionLifecycleController } from "./session-lifecycle-controller.js";
|
|
28
|
-
import { AppShellController } from "./shell-controller.js";
|
|
29
|
-
import { runInteractiveShellCommand } from "./shell-command.js";
|
|
30
|
-
import { AppSessionEventController } from "./session-event-controller.js";
|
|
31
|
-
import { AppStatusController } from "./status-controller.js";
|
|
32
|
-
import { StatusLineRenderer } from "./status-line-renderer.js";
|
|
33
|
-
import { AppModelUsageController } from "./model-usage-controller.js";
|
|
34
|
-
import { AppWorkspaceActionsController } from "./workspace-actions-controller.js";
|
|
35
|
-
import { AppSubagentsWidgetController } from "./subagents-widget-controller.js";
|
|
36
|
-
import { AppTodoWidgetController } from "./todo-widget-controller.js";
|
|
37
|
-
import { AppTabsController } from "./tabs-controller.js";
|
|
38
|
-
import { TabLineRenderer } from "./tab-line-renderer.js";
|
|
39
|
-
import { AppTerminalController } from "./terminal-controller.js";
|
|
40
|
-
import { TerminalBellSoundController } from "./terminal-bell-sound-controller.js";
|
|
41
|
-
import { AppToastController } from "./toast-controller.js";
|
|
42
|
-
import { checkPixUpdate, formatPixStartupUpdateDialog } from "./update.js";
|
|
43
|
-
import { AppVoiceController } from "./voice-controller.js";
|
|
44
|
-
import { createIsolatedExtensionEventBus } from "./extension-event-bus.js";
|
|
25
|
+
import { ScreenStyler } from "./screen/screen-styler.js";
|
|
26
|
+
import { AppScrollController } from "./screen/scroll-controller.js";
|
|
27
|
+
import { searchResultScrollNeedles, searchResultTargetEntry } from "./session/session-search.js";
|
|
28
|
+
import { AppSessionLifecycleController } from "./session/session-lifecycle-controller.js";
|
|
29
|
+
import { AppShellController } from "./commands/shell-controller.js";
|
|
30
|
+
import { runInteractiveShellCommand } from "./commands/shell-command.js";
|
|
31
|
+
import { AppSessionEventController } from "./session/session-event-controller.js";
|
|
32
|
+
import { AppStatusController } from "./screen/status-controller.js";
|
|
33
|
+
import { StatusLineRenderer } from "./rendering/status-line-renderer.js";
|
|
34
|
+
import { AppModelUsageController } from "./model/model-usage-controller.js";
|
|
35
|
+
import { AppWorkspaceActionsController } from "./workspace/workspace-actions-controller.js";
|
|
36
|
+
import { AppSubagentsWidgetController } from "./subagents/subagents-widget-controller.js";
|
|
37
|
+
import { AppTodoWidgetController } from "./todo/todo-widget-controller.js";
|
|
38
|
+
import { AppTabsController } from "./session/tabs-controller.js";
|
|
39
|
+
import { TabLineRenderer } from "./rendering/tab-line-renderer.js";
|
|
40
|
+
import { AppTerminalController } from "./terminal/terminal-controller.js";
|
|
41
|
+
import { TerminalBellSoundController } from "./terminal/terminal-bell-sound-controller.js";
|
|
42
|
+
import { AppToastController } from "./rendering/toast-controller.js";
|
|
43
|
+
import { checkPixUpdate, formatPixStartupUpdateDialog } from "./cli/update.js";
|
|
44
|
+
import { AppVoiceController } from "./input/voice-controller.js";
|
|
45
|
+
import { createIsolatedExtensionEventBus } from "./extensions/extension-event-bus.js";
|
|
45
46
|
import { setAppIconTheme } from "./icons.js";
|
|
46
47
|
const TERMINAL_BELL_ATTENTION_EVENT = "pix:terminal-bell:attention";
|
|
47
48
|
const SUBAGENTS_LIVE_STATE_EVENT = "pi-tools-suite:async-subagents:live-state";
|
|
48
49
|
const TODO_STATE_EVENT = "pi-tools-suite:todo:state";
|
|
50
|
+
const COALESCED_RENDER_DELAY_MS = 16;
|
|
49
51
|
export class PiUiExtendApp {
|
|
50
52
|
entries = [];
|
|
51
53
|
options;
|
|
@@ -78,6 +80,7 @@ export class PiUiExtendApp {
|
|
|
78
80
|
nerdFontController;
|
|
79
81
|
popupActions;
|
|
80
82
|
promptEnhancer;
|
|
83
|
+
autocompleteController;
|
|
81
84
|
mouseController;
|
|
82
85
|
popupMenus;
|
|
83
86
|
voiceController;
|
|
@@ -111,6 +114,7 @@ export class PiUiExtendApp {
|
|
|
111
114
|
get input() { return this.inputEditor.text; }
|
|
112
115
|
set input(value) { this.inputEditor.setText(value); }
|
|
113
116
|
running = false;
|
|
117
|
+
scheduledRenderTimer;
|
|
114
118
|
todoPanelExpanded = true;
|
|
115
119
|
subagentsPanelExpanded = true;
|
|
116
120
|
allThinkingExpanded = false;
|
|
@@ -143,6 +147,7 @@ export class PiUiExtendApp {
|
|
|
143
147
|
theme: this.theme,
|
|
144
148
|
blinkController: this.blinkController,
|
|
145
149
|
runtimeSession: () => this.runtime?.session,
|
|
150
|
+
render: () => this.scheduleRender(),
|
|
146
151
|
});
|
|
147
152
|
this.modelUsageController = new AppModelUsageController({
|
|
148
153
|
runtimeSession: () => this.runtime?.session,
|
|
@@ -170,6 +175,8 @@ export class PiUiExtendApp {
|
|
|
170
175
|
syncUserSessionEntryMetadata: () => this.workspaceActions.syncUserSessionEntryMetadata(),
|
|
171
176
|
captureInputState: () => ({ text: this.inputEditor.text, cursor: this.inputEditor.cursor }),
|
|
172
177
|
restoreInputState: (state) => this.restoreTabInputState(state.text, state.cursor),
|
|
178
|
+
captureDeferredUserMessages: () => this.queuedMessages.captureDeferredUserMessages(),
|
|
179
|
+
restoreDeferredUserMessages: (messages) => this.queuedMessages.restoreDeferredUserMessages(messages),
|
|
173
180
|
addEntry: (entry) => this.addEntry(entry),
|
|
174
181
|
showToast: (message, kind) => this.showToast(message, kind),
|
|
175
182
|
render: () => this.render(),
|
|
@@ -191,6 +198,13 @@ export class PiUiExtendApp {
|
|
|
191
198
|
toast: this.toastNotifier,
|
|
192
199
|
render: () => this.render(),
|
|
193
200
|
});
|
|
201
|
+
this.autocompleteController = new AppAutocompleteController({
|
|
202
|
+
runtime: () => this.runtime,
|
|
203
|
+
inputEditor: () => this.inputEditor,
|
|
204
|
+
autocompleteConfig: () => this.pixConfig.autocomplete,
|
|
205
|
+
isRunning: () => this.running,
|
|
206
|
+
render: () => this.render(),
|
|
207
|
+
});
|
|
194
208
|
this.voiceController = new AppVoiceController({
|
|
195
209
|
insertTranscript: (text) => this.insertVoiceTranscript(text),
|
|
196
210
|
setPartialTranscript: (text) => this.setVoicePartialTranscript(text),
|
|
@@ -251,6 +265,7 @@ export class PiUiExtendApp {
|
|
|
251
265
|
terminalBellSoundStatusWidgetEnabled: () => this.terminalBellSoundController.isEnabled(),
|
|
252
266
|
voiceStatusWidgetText: () => this.voiceController.statusWidgetText(),
|
|
253
267
|
voiceStatusWidgetActive: () => this.voiceController.statusWidgetActive(),
|
|
268
|
+
queueableInputActive: () => this.inputEditor.promptText.trimEnd().length > 0 || this.inputEditor.images.length > 0,
|
|
254
269
|
userMessageJumpMenuActive: () => this.popupMenus.directMenu === "user-message-jump",
|
|
255
270
|
allThinkingExpandedActive: () => this.allThinkingExpanded,
|
|
256
271
|
superCompactToolsActive: () => this.superCompactTools,
|
|
@@ -291,12 +306,12 @@ export class PiUiExtendApp {
|
|
|
291
306
|
cwd: this.options.cwd,
|
|
292
307
|
sessionFile: () => this.runtime?.session.sessionFile,
|
|
293
308
|
isRunning: () => this.running,
|
|
294
|
-
render: () => this.
|
|
309
|
+
render: () => this.scheduleRender(),
|
|
295
310
|
});
|
|
296
311
|
this.todoWidgetController = new AppTodoWidgetController({
|
|
297
312
|
sessionFile: () => this.runtime?.session.sessionFile,
|
|
298
313
|
isRunning: () => this.running,
|
|
299
|
-
render: () => this.
|
|
314
|
+
render: () => this.scheduleRender(),
|
|
300
315
|
});
|
|
301
316
|
this.workspaceActions = new AppWorkspaceActionsController({
|
|
302
317
|
entries: this.entries,
|
|
@@ -320,13 +335,11 @@ export class PiUiExtendApp {
|
|
|
320
335
|
conversationViewport: () => this.conversationViewport,
|
|
321
336
|
isRunning: () => this.running,
|
|
322
337
|
render: () => this.render(),
|
|
338
|
+
scheduleRender: () => this.scheduleRender(),
|
|
323
339
|
setStatus: (status) => this.setStatus(status),
|
|
324
340
|
restoreSessionStatus: () => this.restoreSessionStatus(),
|
|
325
341
|
setSessionStatus: (session) => this.setSessionStatus(session),
|
|
326
342
|
setSessionActivity: (activity) => this.setSessionActivity(activity),
|
|
327
|
-
flushDeferredUserMessages: () => {
|
|
328
|
-
void this.queuedMessages.flushDeferredUserMessages();
|
|
329
|
-
},
|
|
330
343
|
updateQueuedMessageStatus: () => this.queuedMessages.updateQueuedMessageStatus(),
|
|
331
344
|
prepareWorkspaceMutation: (toolName, args) => this.workspaceActions.prepareWorkspaceMutation(toolName, args),
|
|
332
345
|
workspaceMutationFromToolExecution: (input) => this.workspaceActions.workspaceMutationFromToolExecution(input),
|
|
@@ -355,6 +368,7 @@ export class PiUiExtendApp {
|
|
|
355
368
|
setInput: (value) => this.inputEditor.setText(value),
|
|
356
369
|
insertInput: (value) => this.inputEditor.insert(value),
|
|
357
370
|
attachImage: (data, mimeType) => this.inputEditor.attachImage(data, mimeType),
|
|
371
|
+
onDeferredUserMessagesChanged: () => this.tabsController.persistActiveDeferredUserMessages(),
|
|
358
372
|
});
|
|
359
373
|
this.editorLayoutRenderer = new EditorLayoutRenderer({
|
|
360
374
|
theme: this.theme,
|
|
@@ -365,6 +379,7 @@ export class PiUiExtendApp {
|
|
|
365
379
|
get subagentsPanelExpanded() { return app.subagentsPanelExpanded; },
|
|
366
380
|
get subagentsWidgetState() { return app.subagentsWidgetController.widgetState; },
|
|
367
381
|
get voicePartialText() { return app.voicePartialText; },
|
|
382
|
+
get autocompleteSuggestion() { return app.autocompleteController.suggestionText(); },
|
|
368
383
|
renderExtensionInputComponent: (width) => this.extensionUiController.renderActiveCustomUi(width),
|
|
369
384
|
extensionInputUsesEditor: () => this.extensionUiController.activeCustomUiUsesEditor(),
|
|
370
385
|
widgetTuiHandle: () => this.extensionUiController.widgetTuiHandle(),
|
|
@@ -401,6 +416,11 @@ export class PiUiExtendApp {
|
|
|
401
416
|
getInput: () => this.input,
|
|
402
417
|
setInput: (value) => this.setInput(value),
|
|
403
418
|
promptEnhancerModelRef: () => this.pixConfig.promptEnhancer.modelRef,
|
|
419
|
+
autocompleteModelRef: () => this.pixConfig.autocomplete.modelRef,
|
|
420
|
+
setAutocompleteModelRef: (modelRef) => {
|
|
421
|
+
this.pixConfig.autocomplete.modelRef = modelRef;
|
|
422
|
+
this.autocompleteController.dispose();
|
|
423
|
+
},
|
|
404
424
|
enhancePrompt: () => this.promptEnhancer.enhancePrompt(),
|
|
405
425
|
isRunning: () => this.running,
|
|
406
426
|
stop: () => this.stop(),
|
|
@@ -414,6 +434,9 @@ export class PiUiExtendApp {
|
|
|
414
434
|
modelRef: (model) => this.menuItems.modelRef(model),
|
|
415
435
|
getFavoriteScopedModels: () => this.menuItems.getFavoriteScopedModels(),
|
|
416
436
|
setSessionStatus: (session) => this.setSessionStatus(session),
|
|
437
|
+
queueUserMessage: (text) => {
|
|
438
|
+
this.queuedMessages.deferUserMessage(this.queuedMessages.createSubmittedUserMessage(text, text, []));
|
|
439
|
+
},
|
|
417
440
|
resetSessionView: () => this.resetSessionView(),
|
|
418
441
|
loadSessionHistory: () => this.loadSessionHistory(),
|
|
419
442
|
afterSessionReplacement: (message) => this.afterSessionReplacement(message),
|
|
@@ -430,6 +453,7 @@ export class PiUiExtendApp {
|
|
|
430
453
|
this.popupMenus.setDirectQuery(query);
|
|
431
454
|
},
|
|
432
455
|
getResumeLoading: () => this.resumeLoading,
|
|
456
|
+
getResumeSessions: () => this.resumeSessions,
|
|
433
457
|
setResumeLoading: (loading) => {
|
|
434
458
|
this.resumeLoading = loading;
|
|
435
459
|
},
|
|
@@ -499,12 +523,20 @@ export class PiUiExtendApp {
|
|
|
499
523
|
showToast: (message, kind, options) => this.showToast(message, kind, options),
|
|
500
524
|
dismissToast: (toastId) => this.toastController.dismissToast(toastId),
|
|
501
525
|
refreshModelUsageStatus: () => this.refreshModelUsageStatusFromClick(),
|
|
526
|
+
queueInputFromStatus: () => {
|
|
527
|
+
void this.inputActions.queueInputFromEditor().catch((error) => {
|
|
528
|
+
this.addEntry({ id: createId("error"), kind: "error", text: `Queue input failed: ${error instanceof Error ? error.message : String(error)}` });
|
|
529
|
+
this.showToast("Queue input failed", "error");
|
|
530
|
+
this.setSessionStatus(this.runtime?.session);
|
|
531
|
+
this.render();
|
|
532
|
+
});
|
|
533
|
+
},
|
|
502
534
|
toggleAllThinkingExpanded: () => {
|
|
503
535
|
this.allThinkingExpanded = !this.allThinkingExpanded;
|
|
504
536
|
this.render();
|
|
505
537
|
},
|
|
506
538
|
toggleSuperCompactTools: () => {
|
|
507
|
-
this.
|
|
539
|
+
this.toggleSuperCompactTools();
|
|
508
540
|
this.render();
|
|
509
541
|
},
|
|
510
542
|
toggleTerminalBellSound: () => this.toggleTerminalBellSound(),
|
|
@@ -543,6 +575,7 @@ export class PiUiExtendApp {
|
|
|
543
575
|
setSessionActivity: (activity) => this.setSessionActivity(activity),
|
|
544
576
|
restoreSessionStatus: () => this.restoreSessionStatus(),
|
|
545
577
|
render: () => this.render(),
|
|
578
|
+
scheduleRender: () => this.scheduleRender(),
|
|
546
579
|
});
|
|
547
580
|
this.inputActions = new AppInputActionController({
|
|
548
581
|
runtime: () => this.runtime,
|
|
@@ -587,6 +620,7 @@ export class PiUiExtendApp {
|
|
|
587
620
|
handleDirectPopupInput: (char) => this.popupMenus.handleDirectPopupInput(char),
|
|
588
621
|
autocompleteModel: () => this.popupMenus.autocompleteModel(),
|
|
589
622
|
autocompleteThinking: () => this.popupMenus.autocompleteThinking(),
|
|
623
|
+
acceptAutocompleteSuggestion: () => this.autocompleteController.acceptSuggestion(),
|
|
590
624
|
autocompleteSlashCommand: () => this.popupMenus.autocompleteSlashCommand(),
|
|
591
625
|
toggleVoiceRecording: () => {
|
|
592
626
|
void this.voiceController.toggleRecording();
|
|
@@ -609,6 +643,7 @@ export class PiUiExtendApp {
|
|
|
609
643
|
stopSubagentsPolling: () => this.subagentsWidgetController.stopPolling(),
|
|
610
644
|
stopModelUsagePolling: () => this.modelUsageController.stopPolling(),
|
|
611
645
|
stopVoiceInput: () => this.voiceController.dispose(),
|
|
646
|
+
stopAutocomplete: () => this.autocompleteController.dispose(),
|
|
612
647
|
stopShellCommand: () => this.shellController.dispose(),
|
|
613
648
|
unsubscribeSession: () => {
|
|
614
649
|
this.sessionLifecycle.unsubscribeSession();
|
|
@@ -660,6 +695,7 @@ export class PiUiExtendApp {
|
|
|
660
695
|
this.mouseController.statusThinkingTarget = undefined;
|
|
661
696
|
this.mouseController.statusContextTarget = undefined;
|
|
662
697
|
this.mouseController.statusModelUsageTarget = undefined;
|
|
698
|
+
this.mouseController.statusDraftQueueTarget = undefined;
|
|
663
699
|
this.mouseController.statusUserJumpTarget = undefined;
|
|
664
700
|
this.mouseController.statusThinkingExpandTarget = undefined;
|
|
665
701
|
this.mouseController.statusCompactToolsTarget = undefined;
|
|
@@ -672,6 +708,7 @@ export class PiUiExtendApp {
|
|
|
672
708
|
},
|
|
673
709
|
scrollReset: () => this.scrollController.reset(),
|
|
674
710
|
loadSessionHistoryEntries: () => this.sessionEvents.loadSessionHistory(),
|
|
711
|
+
loadSessionHistoryEntriesAsync: (options) => this.sessionEvents.loadSessionHistoryAsync(options),
|
|
675
712
|
syncUserSessionEntryMetadata: () => this.workspaceActions.syncUserSessionEntryMetadata(),
|
|
676
713
|
restoreTabsAfterStartup: () => this.tabsController.restoreAfterStartup(),
|
|
677
714
|
render: () => this.render(),
|
|
@@ -735,15 +772,18 @@ export class PiUiExtendApp {
|
|
|
735
772
|
this.popupMenus.resetInputMenuDismissals();
|
|
736
773
|
}
|
|
737
774
|
this.input = value;
|
|
775
|
+
this.autocompleteController.dispose();
|
|
738
776
|
}
|
|
739
777
|
resetInputAfterProgrammaticEdit() {
|
|
740
778
|
this.requestHistory.resetNavigation();
|
|
741
779
|
this.popupMenus.resetInputMenuDismissals();
|
|
780
|
+
this.autocompleteController.dispose();
|
|
742
781
|
}
|
|
743
782
|
restoreTabInputState(text, cursor) {
|
|
744
783
|
this.requestHistory.resetNavigation();
|
|
745
784
|
this.popupMenus.resetInputMenuDismissals();
|
|
746
785
|
this.inputEditor.setText(text, cursor);
|
|
786
|
+
this.autocompleteController.dispose();
|
|
747
787
|
}
|
|
748
788
|
async clearPersistedInputDraft() {
|
|
749
789
|
await this.tabsController.setInputStateForTab(this.tabsController.activeInputTabId(), { text: "", cursor: 0 });
|
|
@@ -768,7 +808,7 @@ export class PiUiExtendApp {
|
|
|
768
808
|
if (this.voicePartialText === text)
|
|
769
809
|
return;
|
|
770
810
|
this.voicePartialText = text;
|
|
771
|
-
this.
|
|
811
|
+
this.scheduleRender();
|
|
772
812
|
}
|
|
773
813
|
addVoiceSystemMessage(message) {
|
|
774
814
|
this.addEntry({ id: createId("system"), kind: "system", text: message });
|
|
@@ -828,8 +868,21 @@ export class PiUiExtendApp {
|
|
|
828
868
|
this.statusController.setSessionActivity(activity);
|
|
829
869
|
}
|
|
830
870
|
toolDefaultExpanded(toolName) {
|
|
871
|
+
if (this.superCompactTools)
|
|
872
|
+
return false;
|
|
831
873
|
return resolveToolRule(toolName, this.pixConfig.toolRenderer).defaultExpanded === true;
|
|
832
874
|
}
|
|
875
|
+
toggleSuperCompactTools() {
|
|
876
|
+
this.superCompactTools = !this.superCompactTools;
|
|
877
|
+
if (!this.superCompactTools)
|
|
878
|
+
return;
|
|
879
|
+
for (const entry of this.entries) {
|
|
880
|
+
if (entry.kind !== "tool" || !entry.expanded)
|
|
881
|
+
continue;
|
|
882
|
+
entry.expanded = false;
|
|
883
|
+
this.touchEntry(entry);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
833
886
|
stopBlinking() {
|
|
834
887
|
this.blinkController.dispose();
|
|
835
888
|
}
|
|
@@ -877,8 +930,22 @@ export class PiUiExtendApp {
|
|
|
877
930
|
this.toastController.clearToastTimers();
|
|
878
931
|
}
|
|
879
932
|
render() {
|
|
933
|
+
if (this.scheduledRenderTimer) {
|
|
934
|
+
clearTimeout(this.scheduledRenderTimer);
|
|
935
|
+
this.scheduledRenderTimer = undefined;
|
|
936
|
+
}
|
|
937
|
+
this.autocompleteController.observeInput();
|
|
880
938
|
this.renderController.render();
|
|
881
939
|
}
|
|
940
|
+
scheduleRender() {
|
|
941
|
+
if (!this.running || this.scheduledRenderTimer)
|
|
942
|
+
return;
|
|
943
|
+
this.scheduledRenderTimer = setTimeout(() => {
|
|
944
|
+
this.scheduledRenderTimer = undefined;
|
|
945
|
+
this.renderController.render();
|
|
946
|
+
}, COALESCED_RENDER_DELAY_MS);
|
|
947
|
+
this.scheduledRenderTimer.unref?.();
|
|
948
|
+
}
|
|
882
949
|
renderStatusLine() {
|
|
883
950
|
this.renderController.renderStatusLine();
|
|
884
951
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
|
-
import { parseThemeName } from "
|
|
2
|
+
import { parseThemeName } from "../../theme.js";
|
|
3
3
|
export function usage() {
|
|
4
4
|
return `Usage: pix [--cwd <path>] [--no-session] [--session <path>] [--theme dark|light] [--model <provider/model[:thinking]>]
|
|
5
5
|
pix update [--check] [--force]
|
|
@@ -4,7 +4,9 @@ export type PixInstallCliOptions = {
|
|
|
4
4
|
};
|
|
5
5
|
export type PixInstallCliContext = {
|
|
6
6
|
env?: NodeJS.ProcessEnv;
|
|
7
|
+
homeDir?: string;
|
|
7
8
|
};
|
|
9
|
+
export declare function formatPixInstallNextSteps(homeDir?: string): string;
|
|
8
10
|
export declare function pixInstallUsage(): string;
|
|
9
11
|
export declare function parsePixInstallArgs(argv: readonly string[]): PixInstallCliOptions;
|
|
10
12
|
export declare function runPixInstallCli(argv?: readonly string[], context?: PixInstallCliContext): Promise<number>;
|
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
3
4
|
import { join } from "node:path";
|
|
4
|
-
import { FONT_FAMILY_NAME, installJetBrainsNerdFont, isJetBrainsNerdFontInstalled, } from "
|
|
5
|
-
import { clipboardInstallHint, clipboardSupportAvailable } from "
|
|
5
|
+
import { FONT_FAMILY_NAME, installJetBrainsNerdFont, isJetBrainsNerdFontInstalled, } from "../terminal/nerd-font-controller.js";
|
|
6
|
+
import { clipboardInstallHint, clipboardSupportAvailable } from "../screen/clipboard.js";
|
|
7
|
+
import { getPixConfigPath } from "../../config.js";
|
|
8
|
+
export function formatPixInstallNextSteps(homeDir = homedir()) {
|
|
9
|
+
const pixConfigPath = getPixConfigPath(homeDir);
|
|
10
|
+
const toolsConfigPath = join(homeDir, ".config", "pi", "pi-tools-suite.jsonc");
|
|
11
|
+
return [
|
|
12
|
+
"",
|
|
13
|
+
"Next steps:",
|
|
14
|
+
` 1. Edit ${pixConfigPath} and set dictation.language / dictation.languages for voice input.`,
|
|
15
|
+
` 2. Edit ${toolsConfigPath} and enable the LSP servers you use under lsp.servers.`,
|
|
16
|
+
" 3. Start pix, then run /opencode-import to import opencode accounts.",
|
|
17
|
+
" For Antigravity accounts, run /antigravity-import or /antigravity-add-account.",
|
|
18
|
+
].join("\n");
|
|
19
|
+
}
|
|
6
20
|
export function pixInstallUsage() {
|
|
7
21
|
return `Usage: pix install [--check]
|
|
8
22
|
pix setup [--check]
|
|
@@ -86,7 +100,7 @@ export async function runPixInstallCli(argv = process.argv.slice(2), context = {
|
|
|
86
100
|
failures += 1;
|
|
87
101
|
}
|
|
88
102
|
}
|
|
89
|
-
if (clipboardSupportAvailable(env)) {
|
|
103
|
+
if (await clipboardSupportAvailable(env)) {
|
|
90
104
|
console.log("✓ Clipboard support is available");
|
|
91
105
|
}
|
|
92
106
|
else {
|
|
@@ -94,6 +108,7 @@ export async function runPixInstallCli(argv = process.argv.slice(2), context = {
|
|
|
94
108
|
if (process.platform === "linux")
|
|
95
109
|
failures += 1;
|
|
96
110
|
}
|
|
111
|
+
console.log(formatPixInstallNextSteps(context.homeDir));
|
|
97
112
|
return failures === 0 ? 0 : 1;
|
|
98
113
|
}
|
|
99
114
|
async function resolvePiCliStatus(env) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CommandControllerHost } from "./command-host.js";
|
|
2
|
-
import type { PopupMenuPlacement, SessionModel, SlashCommand, ThinkingLevel } from "
|
|
2
|
+
import type { PopupMenuPlacement, SessionModel, SlashCommand, ThinkingLevel } from "../types.js";
|
|
3
3
|
export declare class AppCommandController {
|
|
4
4
|
private readonly host;
|
|
5
5
|
readonly slashCommands: readonly SlashCommand[];
|
|
@@ -28,13 +28,17 @@ export class AppCommandController {
|
|
|
28
28
|
return {
|
|
29
29
|
runSettingsCommand: () => this.modelActions.runSettingsCommand(),
|
|
30
30
|
runModelSlashCommand: (argumentsText) => this.modelActions.runModelSlashCommand(argumentsText),
|
|
31
|
+
runDefaultModelSlashCommand: (argumentsText) => this.modelActions.runDefaultModelSlashCommand(argumentsText),
|
|
32
|
+
runAutocompleteSlashCommand: (argumentsText) => this.modelActions.runAutocompleteSlashCommand(argumentsText),
|
|
31
33
|
runScopedModelsCommand: (argumentsText) => this.modelActions.runScopedModelsCommand(argumentsText),
|
|
32
34
|
runThinkingSlashCommand: (argumentsText) => this.modelActions.runThinkingSlashCommand(argumentsText),
|
|
35
|
+
runDefaultThinkingSlashCommand: (argumentsText) => this.modelActions.runDefaultThinkingSlashCommand(argumentsText),
|
|
33
36
|
runEnhanceCommand: () => this.host.enhancePrompt(),
|
|
34
37
|
runExportCommand: (argumentsText) => this.sessionActions.runExportCommand(argumentsText),
|
|
35
38
|
runImportCommand: (argumentsText) => this.sessionActions.runImportCommand(argumentsText),
|
|
36
39
|
runShareCommand: () => this.sessionActions.runShareCommand(),
|
|
37
40
|
runCopyCommand: () => this.sessionActions.runCopyCommand(),
|
|
41
|
+
runQueueCommand: (argumentsText) => this.sessionActions.runQueueCommand(argumentsText),
|
|
38
42
|
runNameCommand: (argumentsText) => this.sessionActions.runNameCommand(argumentsText),
|
|
39
43
|
runSessionInfoCommand: () => this.sessionActions.runSessionInfoCommand(),
|
|
40
44
|
runUsageCommand: () => this.sessionActions.runUsageCommand(),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AgentSession, AgentSessionRuntime, SessionInfo } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import type { SessionSearchResult } from "
|
|
3
|
-
import type { ActivePopupMenu, AppOptions, Entry, ModelMenuValue, PixMenuItem, PixMenuOptions, PopupMenuPlacement, ScopedSessionModel, SessionModel, ThinkingMenuValue } from "
|
|
4
|
-
import type { ToastNotifier } from "
|
|
2
|
+
import type { SessionSearchResult } from "../session/session-search.js";
|
|
3
|
+
import type { ActivePopupMenu, AppOptions, Entry, ModelMenuValue, PixMenuItem, PixMenuOptions, PopupMenuPlacement, ScopedSessionModel, SessionModel, ThinkingMenuValue } from "../types.js";
|
|
4
|
+
import type { ToastNotifier } from "../../ui.js";
|
|
5
5
|
export type DirectPopupMenu = Exclude<ActivePopupMenu, "slash">;
|
|
6
6
|
export type CommandControllerHost = {
|
|
7
7
|
readonly options: AppOptions;
|
|
@@ -9,6 +9,8 @@ export type CommandControllerHost = {
|
|
|
9
9
|
getInput(): string;
|
|
10
10
|
setInput(value: string): void;
|
|
11
11
|
promptEnhancerModelRef(): string;
|
|
12
|
+
autocompleteModelRef(): string;
|
|
13
|
+
setAutocompleteModelRef(modelRef: string): void;
|
|
12
14
|
enhancePrompt(): Promise<void>;
|
|
13
15
|
isRunning(): boolean;
|
|
14
16
|
stop(): void | Promise<void>;
|
|
@@ -22,6 +24,7 @@ export type CommandControllerHost = {
|
|
|
22
24
|
modelRef(model: SessionModel): string;
|
|
23
25
|
getFavoriteScopedModels(): ScopedSessionModel[];
|
|
24
26
|
setSessionStatus(session: AgentSession | undefined): void;
|
|
27
|
+
queueUserMessage(text: string): void;
|
|
25
28
|
resetSessionView(): void;
|
|
26
29
|
loadSessionHistory(): void;
|
|
27
30
|
afterSessionReplacement(message?: string): void;
|
|
@@ -35,6 +38,7 @@ export type CommandControllerHost = {
|
|
|
35
38
|
getDirectPopupMenuQuery(): string;
|
|
36
39
|
setDirectPopupMenuQuery(query: string): void;
|
|
37
40
|
getResumeLoading(): boolean;
|
|
41
|
+
getResumeSessions(): readonly SessionInfo[];
|
|
38
42
|
setResumeLoading(loading: boolean): void;
|
|
39
43
|
setResumeSessions(sessions: SessionInfo[]): void;
|
|
40
44
|
openResumeMenuWithQuery(query: string): void;
|