pi-ui-extend 1.0.41 → 1.0.45

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.
Files changed (236) hide show
  1. package/README.md +50 -13
  2. package/dist/app/app.d.ts +13 -0
  3. package/dist/app/app.js +158 -8
  4. package/dist/app/cli/install.js +2 -2
  5. package/dist/app/commands/command-controller.d.ts +4 -0
  6. package/dist/app/commands/command-controller.js +11 -0
  7. package/dist/app/commands/command-git-actions.d.ts +25 -0
  8. package/dist/app/commands/command-git-actions.js +381 -0
  9. package/dist/app/commands/command-host.d.ts +4 -0
  10. package/dist/app/commands/command-host.js +5 -2
  11. package/dist/app/commands/command-model-actions.d.ts +1 -0
  12. package/dist/app/commands/command-model-actions.js +57 -35
  13. package/dist/app/commands/command-navigation-actions.d.ts +1 -0
  14. package/dist/app/commands/command-navigation-actions.js +16 -3
  15. package/dist/app/commands/command-registry.d.ts +2 -0
  16. package/dist/app/commands/command-registry.js +15 -1
  17. package/dist/app/commands/command-session-actions.js +9 -3
  18. package/dist/app/commands/reload-context-inventory.d.ts +11 -0
  19. package/dist/app/commands/reload-context-inventory.js +70 -0
  20. package/dist/app/extensions/extension-actions-controller.d.ts +1 -0
  21. package/dist/app/extensions/extension-actions-controller.js +6 -0
  22. package/dist/app/extensions/subagent-catalog-state.d.ts +9 -0
  23. package/dist/app/extensions/subagent-catalog-state.js +23 -0
  24. package/dist/app/input/autocomplete-controller.js +61 -34
  25. package/dist/app/input/input-action-controller.d.ts +2 -0
  26. package/dist/app/input/input-action-controller.js +8 -1
  27. package/dist/app/input/input-controller.d.ts +2 -1
  28. package/dist/app/input/input-controller.js +7 -2
  29. package/dist/app/input/prompt-enhancer-controller.js +53 -35
  30. package/dist/app/input/voice-controller.d.ts +41 -45
  31. package/dist/app/input/voice-controller.js +351 -419
  32. package/dist/app/model/model-usage-controller.js +17 -7
  33. package/dist/app/model/model-usage-status.d.ts +4 -1
  34. package/dist/app/model/model-usage-status.js +270 -46
  35. package/dist/app/popup/menu-items-controller.d.ts +13 -3
  36. package/dist/app/popup/menu-items-controller.js +37 -21
  37. package/dist/app/popup/popup-action-controller.d.ts +12 -2
  38. package/dist/app/popup/popup-action-controller.js +77 -24
  39. package/dist/app/popup/popup-menu-controller.d.ts +36 -14
  40. package/dist/app/popup/popup-menu-controller.js +239 -69
  41. package/dist/app/rendering/dcp-stats.d.ts +9 -4
  42. package/dist/app/rendering/dcp-stats.js +40 -425
  43. package/dist/app/rendering/editor-panels.js +10 -4
  44. package/dist/app/rendering/popup-menu-renderer.d.ts +3 -5
  45. package/dist/app/rendering/popup-menu-renderer.js +42 -37
  46. package/dist/app/rendering/render-controller.js +23 -2
  47. package/dist/app/rendering/status-line-renderer.d.ts +5 -0
  48. package/dist/app/rendering/status-line-renderer.js +41 -5
  49. package/dist/app/rendering/tab-line-renderer.js +26 -20
  50. package/dist/app/runtime.d.ts +12 -1
  51. package/dist/app/runtime.js +120 -12
  52. package/dist/app/screen/mouse-controller.d.ts +2 -0
  53. package/dist/app/screen/mouse-controller.js +17 -7
  54. package/dist/app/screen/status-controller.d.ts +4 -0
  55. package/dist/app/screen/status-controller.js +5 -0
  56. package/dist/app/session/lazy-session-manager.js +34 -0
  57. package/dist/app/session/session-event-controller.d.ts +1 -0
  58. package/dist/app/session/session-event-controller.js +10 -1
  59. package/dist/app/session/session-history.d.ts +1 -0
  60. package/dist/app/session/session-history.js +12 -1
  61. package/dist/app/session/session-lifecycle-controller.d.ts +7 -1
  62. package/dist/app/session/session-lifecycle-controller.js +16 -1
  63. package/dist/app/session/tabs-controller.d.ts +26 -1
  64. package/dist/app/session/tabs-controller.js +454 -147
  65. package/dist/app/subagents/subagents-files.js +60 -1
  66. package/dist/app/subagents/subagents-model.d.ts +1 -0
  67. package/dist/app/subagents/subagents-model.js +18 -2
  68. package/dist/app/subagents/subagents-widget-controller.d.ts +1 -0
  69. package/dist/app/subagents/subagents-widget-controller.js +6 -0
  70. package/dist/app/types.d.ts +16 -1
  71. package/dist/app/workspace/workspace-actions-controller.js +10 -2
  72. package/dist/app/workspace/workspace-undo.d.ts +1 -0
  73. package/dist/app/workspace/workspace-undo.js +1 -0
  74. package/dist/bundled-extensions/question/index.js +9 -1
  75. package/dist/bundled-extensions/question/remote.d.ts +4 -0
  76. package/dist/bundled-extensions/question/remote.js +33 -0
  77. package/dist/bundled-extensions/telegram-connector/bot.d.ts +43 -0
  78. package/dist/bundled-extensions/telegram-connector/bot.js +166 -0
  79. package/dist/bundled-extensions/telegram-connector/config.d.ts +8 -0
  80. package/dist/bundled-extensions/telegram-connector/config.js +87 -0
  81. package/dist/bundled-extensions/telegram-connector/coordinator.d.ts +66 -0
  82. package/dist/bundled-extensions/telegram-connector/coordinator.js +413 -0
  83. package/dist/bundled-extensions/telegram-connector/index.d.ts +3 -0
  84. package/dist/bundled-extensions/telegram-connector/index.js +195 -0
  85. package/dist/bundled-extensions/terminal-bell/index.d.ts +0 -8
  86. package/dist/bundled-extensions/terminal-bell/index.js +0 -76
  87. package/dist/bundled-extensions/workspace-undo/index.d.ts +26 -0
  88. package/dist/bundled-extensions/workspace-undo/index.js +191 -0
  89. package/dist/config.d.ts +21 -2
  90. package/dist/config.js +159 -32
  91. package/dist/default-pix-config.js +25 -5
  92. package/dist/schemas/index.d.ts +1 -0
  93. package/dist/schemas/index.js +1 -0
  94. package/dist/schemas/pi-tools-suite-schema.d.ts +88 -62
  95. package/dist/schemas/pi-tools-suite-schema.js +54 -83
  96. package/dist/schemas/pix-schema.d.ts +19 -2
  97. package/dist/schemas/pix-schema.js +47 -5
  98. package/dist/schemas/tasks-schema.d.ts +18 -0
  99. package/dist/schemas/tasks-schema.js +41 -0
  100. package/docs/concurrency.md +9 -1
  101. package/docs/desktop-mvp.md +22 -6
  102. package/docs/desktop-task-manager.md +148 -84
  103. package/docs/release.md +30 -6
  104. package/external/pi-tools-suite/README.md +197 -84
  105. package/external/pi-tools-suite/docs/evals.md +1 -1
  106. package/external/pi-tools-suite/docs/session-recovery.md +47 -14
  107. package/external/pi-tools-suite/docs/subagent-model-pools.md +48 -30
  108. package/external/pi-tools-suite/docs/ui-qa-subagent.md +440 -0
  109. package/external/pi-tools-suite/package.json +6 -1
  110. package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +2 -1
  111. package/external/pi-tools-suite/src/antigravity-auth/constants.ts +9 -3
  112. package/external/pi-tools-suite/src/antigravity-auth/headers.ts +41 -3
  113. package/external/pi-tools-suite/src/antigravity-auth/models.ts +94 -21
  114. package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +5 -17
  115. package/external/pi-tools-suite/src/antigravity-auth/payload.ts +72 -7
  116. package/external/pi-tools-suite/src/antigravity-auth/stream.ts +13 -1
  117. package/external/pi-tools-suite/src/async-subagents/agents/frontier-review.md +23 -0
  118. package/external/pi-tools-suite/src/async-subagents/agents/implement.md +1 -1
  119. package/external/pi-tools-suite/src/async-subagents/agents/presets.jsonc +16 -0
  120. package/external/pi-tools-suite/src/async-subagents/agents/research.md +5 -3
  121. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/browser.mjs +346 -0
  122. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/desktop.mjs +1038 -0
  123. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/tui.mjs +759 -0
  124. package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/scripts/browser-qa-runner.mjs +32 -23
  125. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/chrome-devtools/chrome-devtools-provider.mjs +895 -0
  126. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/linux/linux-atspi.py +494 -0
  127. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/macos/macos-accessibility.swift +1085 -0
  128. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/bridge-client.mjs +50 -0
  129. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/native-terminal-host.mjs +501 -0
  130. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/windows/windows-uia.ps1 +454 -0
  131. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-auth.md +114 -0
  132. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-chrome-devtools.md +91 -0
  133. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-playwright.md +145 -0
  134. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser.md +82 -0
  135. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-linux.md +26 -0
  136. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-macos.md +29 -0
  137. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-windows.md +23 -0
  138. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop.md +54 -0
  139. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-native-terminal.md +59 -0
  140. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-pty.md +37 -0
  141. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui.md +60 -0
  142. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/scripts/ui-qa-runner.mjs +535 -0
  143. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa.md +75 -0
  144. package/external/pi-tools-suite/src/async-subagents/commands.ts +15 -71
  145. package/external/pi-tools-suite/src/async-subagents/core/activity.ts +33 -0
  146. package/external/pi-tools-suite/src/async-subagents/core/agent-catalog.ts +5 -4
  147. package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +1 -1
  148. package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +8 -5
  149. package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +16 -2
  150. package/external/pi-tools-suite/src/async-subagents/core/config.ts +160 -327
  151. package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +2 -1
  152. package/external/pi-tools-suite/src/async-subagents/core/registry.ts +158 -33
  153. package/external/pi-tools-suite/src/async-subagents/core/routing.ts +21 -5
  154. package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +40 -26
  155. package/external/pi-tools-suite/src/async-subagents/core/state.ts +40 -0
  156. package/external/pi-tools-suite/src/async-subagents/core/types.ts +7 -0
  157. package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +51 -45
  158. package/external/pi-tools-suite/src/async-subagents/index.ts +69 -5
  159. package/external/pi-tools-suite/src/async-subagents/lib.ts +16 -9
  160. package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +8 -5
  161. package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +5 -4
  162. package/external/pi-tools-suite/src/async-subagents/types.ts +1 -0
  163. package/external/pi-tools-suite/src/coding-discipline/index.ts +90 -59
  164. package/external/pi-tools-suite/src/config.ts +55 -1
  165. package/external/pi-tools-suite/src/context-gateway/accounting-log.ts +282 -0
  166. package/external/pi-tools-suite/src/context-gateway/config.ts +77 -3
  167. package/external/pi-tools-suite/src/context-gateway/efficiency.ts +414 -0
  168. package/external/pi-tools-suite/src/context-gateway/enforcement.ts +222 -0
  169. package/external/pi-tools-suite/src/context-gateway/index.ts +206 -19
  170. package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +7 -7
  171. package/external/pi-tools-suite/src/context-gateway/telemetry.ts +101 -28
  172. package/external/pi-tools-suite/src/context-gateway/types.ts +16 -3
  173. package/external/pi-tools-suite/src/context-inventory.ts +99 -0
  174. package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +39 -4
  175. package/external/pi-tools-suite/src/dcp/auto-compress.ts +128 -49
  176. package/external/pi-tools-suite/src/dcp/commands.ts +32 -156
  177. package/external/pi-tools-suite/src/dcp/compress-tool.ts +177 -46
  178. package/external/pi-tools-suite/src/dcp/compression-blocks.ts +6 -58
  179. package/external/pi-tools-suite/src/dcp/compression-preview.ts +9 -0
  180. package/external/pi-tools-suite/src/dcp/compression-progress.ts +22 -0
  181. package/external/pi-tools-suite/src/dcp/config.ts +114 -17
  182. package/external/pi-tools-suite/src/dcp/conversation-index.ts +36 -9
  183. package/external/pi-tools-suite/src/dcp/diagnostics.ts +41 -0
  184. package/external/pi-tools-suite/src/dcp/fresh-tool-results.ts +38 -0
  185. package/external/pi-tools-suite/src/dcp/index.ts +338 -66
  186. package/external/pi-tools-suite/src/dcp/journal.ts +126 -4
  187. package/external/pi-tools-suite/src/dcp/progress-controller.ts +2 -1
  188. package/external/pi-tools-suite/src/dcp/prompts.ts +83 -192
  189. package/external/pi-tools-suite/src/dcp/protected-continuity.ts +175 -0
  190. package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +93 -3
  191. package/external/pi-tools-suite/src/dcp/pruner-message-ids.ts +6 -10
  192. package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +36 -33
  193. package/external/pi-tools-suite/src/dcp/pruner-tools.ts +6 -3
  194. package/external/pi-tools-suite/src/dcp/pruner.ts +1 -0
  195. package/external/pi-tools-suite/src/dcp/routine-pressure.ts +86 -0
  196. package/external/pi-tools-suite/src/dcp/state.ts +9 -0
  197. package/external/pi-tools-suite/src/dcp/statistics.d.ts +8 -0
  198. package/external/pi-tools-suite/src/dcp/statistics.js +156 -0
  199. package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +78 -22
  200. package/external/pi-tools-suite/src/index.ts +7 -1
  201. package/external/pi-tools-suite/src/lib/project.ts +36 -1
  202. package/external/pi-tools-suite/src/model-tools/index.ts +10 -7
  203. package/external/pi-tools-suite/src/repo-discovery/index.ts +304 -4
  204. package/external/pi-tools-suite/src/resource-registry/index.ts +2551 -0
  205. package/external/pi-tools-suite/src/session-recovery/index.ts +17 -0
  206. package/external/pi-tools-suite/src/shell-command-policy.ts +219 -0
  207. package/external/pi-tools-suite/src/todo/index.ts +21 -0
  208. package/external/pi-tools-suite/src/todo/todo.ts +19 -1
  209. package/external/pi-tools-suite/src/tool-descriptions.ts +47 -19
  210. package/package.json +10 -9
  211. package/schemas/pi-tools-suite.json +466 -287
  212. package/schemas/pix.json +129 -11
  213. package/schemas/tasks.json +131 -0
  214. package/skills/simplify/SKILL.md +33 -5
  215. package/docs/desktop-markdown-media.md +0 -77
  216. package/external/pi-tools-suite/docs/browser-qa-subagent.md +0 -177
  217. package/external/pi-tools-suite/docs/dcp-emergency-current-turn.md +0 -102
  218. package/external/pi-tools-suite/src/async-subagents/agents/browser-qa.md +0 -598
  219. package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +0 -54
  220. package/external/pi-tools-suite/src/skill-installer/index.ts +0 -333
  221. package/skills/playwright-cli/SKILL.md +0 -420
  222. package/skills/playwright-cli/references/element-attributes.md +0 -23
  223. package/skills/playwright-cli/references/playwright-tests.md +0 -50
  224. package/skills/playwright-cli/references/request-mocking.md +0 -87
  225. package/skills/playwright-cli/references/running-code.md +0 -241
  226. package/skills/playwright-cli/references/session-management.md +0 -273
  227. package/skills/playwright-cli/references/spec-driven-testing.md +0 -311
  228. package/skills/playwright-cli/references/storage-state.md +0 -290
  229. package/skills/playwright-cli/references/test-generation.md +0 -142
  230. package/skills/playwright-cli/references/tracing.md +0 -154
  231. package/skills/playwright-cli/references/video-recording.md +0 -147
  232. package/skills/spec-lite/SKILL.md +0 -140
  233. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-auth.example.jsonc +0 -0
  234. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-flow.example.jsonc +0 -0
  235. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.LICENSE +0 -0
  236. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.mjs +0 -0
package/README.md CHANGED
@@ -34,7 +34,7 @@ Pi provides the agent runtime, models, tools, skills, extensions, and persistent
34
34
  - **Keep projects organized.** Tabs are scoped to the working directory and survive restarts. Search, resume, fork, clone, jump through, import, export, share, or delete sessions without leaving the terminal.
35
35
  - **Stay in flow.** Run quick commands with `!`, open a raw interactive terminal with `!!`, paste images, follow file links, dictate in English or Russian, and improve a prompt before sending it.
36
36
  - **Know what the agent is doing.** The status area exposes model, thinking level, context, usage, workspace, todos, sub-agents, voice state, and prompt actions — with mouse targets where useful.
37
- - **Bring a serious toolkit.** Pix ships with `pi-tools-suite`: 18 integrated modules for indexed repository discovery, AST edits, LSP diagnostics, parallel agents, durable todos, context compression, web access, provider accounts, and more.
37
+ - **Bring a serious toolkit.** Pix ships with `pi-tools-suite`: 21 integrated modules for indexed repository discovery, AST edits, LSP diagnostics, parallel agents, durable todos, context compression, web access, provider accounts, and more.
38
38
  - **Use the models you want.** Pix runs on Pi's provider ecosystem and supports model switching, scoped model lists, per-model thinking levels, usage views, autocomplete, and fallback-aware helper workflows.
39
39
 
40
40
  Pix is not a separate agent protocol or an RPC wrapper around Pi. It runs on the Pi SDK, so the runtime, session format, extensions, skills, prompts, and tools remain part of the same ecosystem.
@@ -95,8 +95,10 @@ On startup, Pix tries to link the bundled suite into the active Pi agent directo
95
95
  | Context control | `dcp` | Explicit compression and context pruning for long sessions, including sidecar state. |
96
96
  | Local web access | `web-search` | Web search and page extraction through a local Ollama instance. |
97
97
  | Providers and quotas | `antigravity-auth`, `opencode-import`, `usage` | Antigravity OAuth/account failover, OpenCode credential import, and multi-provider usage views. |
98
- | Reusable workflows | `prompt-commands`, `skill-installer`, `session-name` | Prompt-command CRUD, skill installation/export, and session naming. |
98
+ | Reusable workflows | `prompt-commands`, `resource-registry`, `session-name` | Prompt-command CRUD, private Git-backed skill/agent install/update/push/remote-remove/local-uninstall with reload-on-change, project-scoped `.pi/tasks.jsonc` + `.pi/plans/` + `.pi/TODO.md` sync, a Desktop Registry sidebar for status/actions/configuration, and session naming. |
99
99
  | Model compatibility | `coding-discipline`, `model-tools`, `codex-reasoning-fix` | Model-specific discipline and vision lookup, compatibility aliases, and a Codex reasoning payload workaround. |
100
+ | Agent session context | `session-recovery` | Bounded session overview/search/section tools so agents can recover prior context. |
101
+ | Payload hygiene | `context-gateway`, `truncation-metadata-normalizer`, `credential-firewall` | Observe-only result-chain gateway, opt-in truncation-metadata cleanup, and an opt-in secret firewall. |
100
102
 
101
103
  Every module can be disabled. Optional integrations only activate when their requirements are available — for example, repository tools require an index, web tools require local Ollama web search, and LSP servers must be configured and trusted.
102
104
 
@@ -136,8 +138,8 @@ Recommended:
136
138
 
137
139
  Optional:
138
140
 
139
- - the `vosk` optional dependency for local voice input
140
- - an audio recorder for dictation: SoX (`rec`/`sox`), `ffmpeg`, or `arecord` on Linux
141
+ - a Deepgram API key in `dictation.apiKey` inside `~/.config/pi/pix.jsonc` for voice input; `DEEPGRAM_API_KEY` remains supported as a fallback
142
+ - an audio recorder for terminal dictation: SoX (`rec`/`sox`), `ffmpeg`, or `arecord` on Linux
141
143
  - `tmux` and `rsvg-convert` only if you want to regenerate README screenshots
142
144
  - Ollama with web search enabled for the bundled `web_search` and `web_fetch` tools
143
145
  - language servers for the LSP module (see [LSP setup](external/pi-tools-suite/README.md#lsp-setup) for install commands and ready-to-paste configs for popular servers, including Svelte, Vue, Go, clangd, Lua, and bash)
@@ -210,7 +212,7 @@ Pix uses Pi's model and authentication stores. Environment-based API keys and cr
210
212
  | Model-backed helpers | No | Review `promptEnhancer`, `autocomplete`, and `sessionTitle` in `pix.jsonc` | Each configured helper model needs credentials for its own provider; it need not use the main session provider. |
211
213
  | Ollama/Tavily web access | No | Use local Ollama without a cloud key, set `OLLAMA_API_KEY`/`TAVILY_API_KEY`, or run `/web-credentials` | Stored keys live in `~/.config/pi/pi-tools-suite-credentials.json` with mode `0600`. |
212
214
  | Context7 documentation skill | No | Export `CONTEXT7_API_KEY` | The skill fails before making a network request when the variable is absent. |
213
- | Telegram terminal bell | No | Configure `terminalBell.telegram` or `PI_TERMINAL_BELL_TELEGRAM_BOT_TOKEN` plus `PI_TERMINAL_BELL_TELEGRAM_CHAT_ID` | Used only for the optional terminal notification integration. |
215
+ | Telegram task connector | No | Configure `telegramConnector.botToken` + `telegramConnector.chatId`, or `PIX_TELEGRAM_BOT_TOKEN` + `PIX_TELEGRAM_CHAT_ID` | Completion/question notifications; reply to continue the exact live session, or use `/new <task>` for a fresh session. |
214
216
 
215
217
  `pix install` reports whether these sources appear configured, but never displays, copies, or overwrites token values.
216
218
 
@@ -267,6 +269,12 @@ Pix can provide inline, model-backed autocomplete with configurable debounce, ti
267
269
  - While it runs, submit editor text to its stdin; use `Ctrl-C` to interrupt.
268
270
  - `!!command` opens a raw interactive terminal for REPLs, TUIs, debuggers, and development servers. Exit it to return to Pix.
269
271
 
272
+ ### Git helpers
273
+
274
+ - `/code-review` reviews staged, unstaged, and untracked Git changes with the configured review model and prints the findings locally in the TUI.
275
+ - `/commit-message` generates a message from staged changes, shows the full message, and asks for confirmation before running `git commit`. If the staged diff changes before confirmation completes, Pix refuses the commit and asks you to regenerate the message.
276
+ - These helpers use the existing `desktop.git.reviewModelRef` / `reviewFallbackModels` and `desktop.git.commitMessageModelRef` / `commitMessageFallbackModels` settings for compatibility. `/commit-message` never stages changes or bypasses Git hooks.
277
+
270
278
  ### Images, clipboard, and files
271
279
 
272
280
  - Paste an image from the clipboard with `Ctrl+V`/`Cmd+V` in supported terminals.
@@ -274,14 +282,25 @@ Pix can provide inline, model-backed autocomplete with configurable debounce, ti
274
282
  - `/copy` copies the last assistant message.
275
283
  - Pix integrates with the native clipboard on macOS and Windows and common Wayland/X11 helpers on Linux.
276
284
 
277
- ### Local voice input
285
+ ### Voice input
286
+
287
+ Put the Deepgram key in the user Pix config:
288
+
289
+ ```jsonc
290
+ {
291
+ "dictation": {
292
+ "apiKey": "your-deepgram-api-key"
293
+ }
294
+ }
295
+ ```
296
+
297
+ The file is `~/.config/pi/pix.jsonc`. Keep the key in this user config rather than a project `.pi/pix.jsonc`; project config is intentionally not allowed to override the secret. `DEEPGRAM_API_KEY` remains supported as a compatibility fallback when `dictation.apiKey` is not set.
278
298
 
279
- Press `Ctrl+G` or click the microphone in the status area to start/stop dictation. Pix supports configurable local Vosk models and ships defaults for:
299
+ Then press `Ctrl+G` or click the microphone in the terminal status area to start/stop dictation. Pix streams microphone audio to Deepgram Nova-3 and inserts finalized text into the editor so you can review it before sending. The default dictation languages are English and Russian and can be changed with the existing language control.
280
300
 
281
- - English: `vosk-model-small-en-us-0.15`
282
- - Russian: `vosk-model-small-ru-0.22`
301
+ Pix Desktop exposes the same voice-input action directly in the message composer. The desktop client uses Nova-3 and respects `dictation.language` plus the selected language's `deepgramLanguage` value from the user Pix config. It requests a short-lived Deepgram token from the local Tauri backend; the permanent API key is read from the user Pix config (or the environment fallback) by Rust and is never exposed to the WebView. The Settings UI also exposes `Dictation · Api Key` as a sensitive field because it is generated from the Pix schema.
283
302
 
284
- The selected model is downloaded on first use. Recognition is local; the resulting text is inserted into the editor so you can review it before sending.
303
+ Voice audio is sent to Deepgram while recording. Pix no longer downloads or installs local speech-recognition models.
285
304
 
286
305
  ### Workspace undo
287
306
 
@@ -312,12 +331,13 @@ Type `/` for the live, searchable list. Extensions can add more commands than th
312
331
  | Models | `/model`, `/default-model`, `/scoped-models`, `/thinking`, `/default-thinking`, `/autocomplete` |
313
332
  | Project context | `/no-context-files`, `/compact` |
314
333
  | Prompt workflow | `/enhance`, `/queue`, `/copy` |
334
+ | Git | `/code-review`, `/commit-message` |
315
335
  | Sessions | `/new`, `/new_tab`, `/resume`, `/name`, `/session`, `/search`, `/history`, `/jump`, `/tree` |
316
336
  | Branching and files | `/fork`, `/clone`, `/delete`, `/export`, `/import`, `/share` |
317
337
  | Status | `/usage` |
318
338
  | Process | `/quit`, `/exit` |
319
339
 
320
- Useful suite commands include `/todos`, `/todos-persist`, `/todos-scope`, `/sub-status`, `/sub-stop`, `/ultrawork`, `/hyperplan`, `/subagent-preset`, `/usage`, `/dcp`, `/idx-init`, `/idx-update`, `/opencode-import`, `/antigravity-add-account`, `/install-skill`, and `/export-skill`.
340
+ Useful suite commands include `/todos`, `/todos-persist`, `/todos-scope`, `/sub-status`, `/sub-stop`, `/ultrawork`, `/hyperplan`, `/subagent-preset`, `/usage`, `/dcp`, `/idx-init`, `/idx-update`, `/opencode-import`, `/antigravity-add-account`, and `/registry`.
321
341
 
322
342
  ### Keyboard and mouse
323
343
 
@@ -361,6 +381,7 @@ Both support the published schema:
361
381
  "$schema": "https://unpkg.com/pi-ui-extend/schemas/pix.json",
362
382
  "defaultModel": {
363
383
  "modelRef": "openai-codex/gpt-5.6-sol",
384
+ "fallbackModels": [],
364
385
  "thinking": "medium"
365
386
  },
366
387
  "toolRenderer": {
@@ -371,9 +392,10 @@ Both support the published schema:
371
392
  "apply_patch": { "defaultExpanded": true }
372
393
  }
373
394
  },
374
- "promptEnhancer": { "modelRef": "openai-codex/gpt-5.6-luna" },
395
+ "promptEnhancer": { "modelRef": "openai-codex/gpt-5.6-luna", "fallbackModels": [] },
375
396
  "autocomplete": {
376
397
  "modelRef": "zai/glm-5-turbo",
398
+ "fallbackModels": [],
377
399
  "debounceMs": 350,
378
400
  "timeoutMs": 3000
379
401
  },
@@ -387,6 +409,12 @@ Both support the published schema:
387
409
  }
388
410
  ```
389
411
 
412
+ Singular model selectors resolve with an explicit ordered fallback array, even
413
+ when it is empty. Existing configs that omit the array remain compatible and
414
+ normalize to `[]`. Pix uses `fallbackModels` for object selectors; Desktop Git
415
+ uses `reviewFallbackModels` and `commitMessageFallbackModels` beside the
416
+ corresponding primary model refs.
417
+
390
418
  Configurable areas include:
391
419
 
392
420
  - default model and thinking level;
@@ -449,7 +477,7 @@ Install `wl-clipboard` on Wayland or `xclip`/`xsel` on X11, then run `pix instal
449
477
 
450
478
  ### Voice input is unavailable
451
479
 
452
- Ensure the optional `vosk` dependency installed successfully, the configured model URL is reachable for its first download, and an audio recorder is available: SoX (`rec`/`sox`), `ffmpeg`, or `arecord` on Linux. Voice support can be omitted without affecting the rest of Pix.
480
+ Ensure `dictation.apiKey` is set in `~/.config/pi/pix.jsonc`, or set the compatibility fallback `DEEPGRAM_API_KEY` in the environment that launches Pix. Terminal voice input also needs an audio recorder: SoX (`rec`/`sox`), `ffmpeg`, or `arecord` on Linux. Pix Desktop additionally needs microphone permission from the operating system. Voice support can be omitted without affecting the rest of Pix.
453
481
 
454
482
  ### A provider login dialog is missing
455
483
 
@@ -500,8 +528,17 @@ npm run test:tools-suite
500
528
 
501
529
  # Build the publishable renderer
502
530
  npm run build:pix
531
+
532
+ # Watch Pix, ACP, the bundled suite, and Desktop
533
+ npm run watch:all
503
534
  ```
504
535
 
536
+ `watch:all` rebuilds only the affected project parts. It keeps the last working
537
+ Desktop process alive while changes compile, then replaces it only after the
538
+ entire queued build succeeds. A failed build is reported without replacing the
539
+ running Desktop. Desktop web changes rebuild the Vite bundle first and then
540
+ invalidate the native Tauri asset embedding before the replacement app starts.
541
+
505
542
  Regenerate the README screenshots without accounts or live model traffic:
506
543
 
507
544
  ```bash
package/dist/app/app.d.ts CHANGED
@@ -51,6 +51,7 @@ export declare class PiUiExtendApp {
51
51
  * for one tab never reaches another tab's extensions.
52
52
  */
53
53
  private readonly extensionEventBusByRuntime;
54
+ private readonly subagentCatalogBySessionId;
54
55
  private readonly inputEditor;
55
56
  private lastInputEditorContentVersion;
56
57
  private readonly requestHistory;
@@ -67,9 +68,18 @@ export declare class PiUiExtendApp {
67
68
  private voicePartialText;
68
69
  private resumeSessions;
69
70
  private resumeLoading;
71
+ private draftModels;
72
+ private draftModelRef;
73
+ private draftThinkingLevel;
74
+ private draftModelOverrideRef;
70
75
  constructor(options: AppOptions);
71
76
  private createRuntime;
72
77
  private loadStartupConfig;
78
+ private refreshDraftModelCatalog;
79
+ private resetDraftModelSelection;
80
+ private selectDraftModel;
81
+ private draftModelState;
82
+ private draftModelStatus;
73
83
  private applyPixConfig;
74
84
  private updateOutputFilters;
75
85
  start(): Promise<void>;
@@ -77,7 +87,10 @@ export declare class PiUiExtendApp {
77
87
  private bindCurrentSession;
78
88
  private awaitCurrentSessionExtensions;
79
89
  private activateRuntime;
90
+ private deactivateRuntimeForDraft;
80
91
  private createExtensionEventBus;
92
+ private subagentTypesForRuntime;
93
+ private contextInventoryText;
81
94
  private handleTerminalBellAttention;
82
95
  private afterSessionReplacement;
83
96
  private requireRuntime;
package/dist/app/app.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { THEMES } from "../theme.js";
2
2
  import { InputEditor } from "../input-editor.js";
3
- import { compileOutputFilterPatterns, defaultPixConfig, loadPixConfig, resolveToolRule, } from "../config.js";
3
+ import { compileOutputFilterPatterns, defaultPixConfig, loadPixConfig, resolveDefaultModelRef, resolveToolRule, savePixThinkingLevelForModel, savePixVisibleModels, } from "../config.js";
4
4
  import { AppCommandController } from "./commands/command-controller.js";
5
5
  import { ConversationViewport } from "./rendering/conversation-viewport.js";
6
6
  import { renderRegisteredExtensionEntry } from "./rendering/extension-entry-renderer.js";
@@ -23,7 +23,8 @@ import { AppAutocompleteController } from "./input/autocomplete-controller.js";
23
23
  import { AppQueuedMessageController } from "./session/queued-message-controller.js";
24
24
  import { AppRequestHistory } from "./session/request-history.js";
25
25
  import { AppRenderController } from "./rendering/render-controller.js";
26
- import { createPixRuntime } from "./runtime.js";
26
+ import { createPixDraftModelCatalog, createPixRuntime } from "./runtime.js";
27
+ import { parseModelRef } from "./model/model-ref.js";
27
28
  import { ScreenStyler } from "./screen/screen-styler.js";
28
29
  import { AppScrollController } from "./screen/scroll-controller.js";
29
30
  import { searchResultScrollNeedles, searchResultTargetEntry } from "./session/session-search.js";
@@ -47,6 +48,8 @@ import { checkPiUpdate, checkPixUpdate, formatPixStartupUpdateDialog, formatPiSt
47
48
  import { checkAndUpdateIdxOnStartup, formatIdxStartupUpdateNotice } from "./cli/startup-checks.js";
48
49
  import { AppVoiceController } from "./input/voice-controller.js";
49
50
  import { createIsolatedExtensionEventBus } from "./extensions/extension-event-bus.js";
51
+ import { parseSubagentCatalogState, SUBAGENTS_CATALOG_STATE_EVENT, } from "./extensions/subagent-catalog-state.js";
52
+ import { createReloadContextInventory, formatReloadContextInventory } from "./commands/reload-context-inventory.js";
50
53
  import { setAppIconTheme } from "./icons.js";
51
54
  const TERMINAL_BELL_ATTENTION_EVENT = "pix:terminal-bell:attention";
52
55
  function normalizeJumpTargetText(text) {
@@ -123,6 +126,7 @@ export class PiUiExtendApp {
123
126
  * for one tab never reaches another tab's extensions.
124
127
  */
125
128
  extensionEventBusByRuntime = new WeakMap();
129
+ subagentCatalogBySessionId = new Map();
126
130
  inputEditor = new InputEditor();
127
131
  lastInputEditorContentVersion = this.inputEditor.contentVersion;
128
132
  requestHistory;
@@ -139,6 +143,10 @@ export class PiUiExtendApp {
139
143
  voicePartialText;
140
144
  resumeSessions = [];
141
145
  resumeLoading = false;
146
+ draftModels = [];
147
+ draftModelRef;
148
+ draftThinkingLevel = "off";
149
+ draftModelOverrideRef;
142
150
  constructor(options) {
143
151
  this.options = options;
144
152
  this.theme = THEMES[options.themeName];
@@ -167,6 +175,7 @@ export class PiUiExtendApp {
167
175
  theme: this.theme,
168
176
  blinkController: this.blinkController,
169
177
  runtimeSession: () => this.runtime?.session,
178
+ draftModelStatus: () => this.draftModelStatus(),
170
179
  render: () => this.scheduleRender(),
171
180
  });
172
181
  this.agentPauseController = new AgentPauseController({
@@ -183,7 +192,7 @@ export class PiUiExtendApp {
183
192
  maxProjectSessions: () => this.pixConfig.maxProjectSessions,
184
193
  blinkController: this.blinkController,
185
194
  runtime: () => this.runtime,
186
- createRuntimeForNewSession: () => this.createRuntime(
195
+ createRuntimeForNewSession: (modelRef) => this.createRuntime(
187
196
  // Never reuse services across tabs. The SDK ties the extension
188
197
  // runtime (resourceLoader.getExtensions().runtime) to the
189
198
  // resourceLoader, and that runtime is shared by every session
@@ -194,12 +203,18 @@ export class PiUiExtendApp {
194
203
  // then throw "ctx is stale after session replacement or reload".
195
204
  // Fresh services per session = fresh extension runtime = no
196
205
  // cross-session invalidation.
197
- newTabRuntimeOptions(this.options)),
206
+ {
207
+ ...newTabRuntimeOptions(this.options),
208
+ ...(modelRef ? { modelRef } : {}),
209
+ }),
198
210
  createRuntimeForSession: (sessionPath) => this.createRuntime({
199
211
  ...this.options,
200
212
  noSession: false,
201
213
  sessionPath,
202
214
  }),
215
+ draftModelOverrideRef: () => this.draftModelOverrideRef,
216
+ resetDraftModelSelection: () => this.resetDraftModelSelection(),
217
+ deactivateRuntimeForDraft: () => this.deactivateRuntimeForDraft(),
203
218
  awaitCurrentSessionExtensions: (runtime) => this.awaitCurrentSessionExtensions(runtime),
204
219
  activateRuntime: (runtime, options) => this.activateRuntime(runtime, options),
205
220
  disposeRuntime: (runtime) => this.terminalController.disposeRuntime(runtime),
@@ -221,6 +236,13 @@ export class PiUiExtendApp {
221
236
  restoreAutoUserMessages: (messages) => this.queuedMessages.restoreAutoUserMessages(messages),
222
237
  captureDeferredUserMessages: () => this.queuedMessages.captureDeferredUserMessages(),
223
238
  restoreDeferredUserMessages: (messages) => this.queuedMessages.restoreDeferredUserMessages(messages),
239
+ openDraftSessionSelector: () => {
240
+ void this.commandController.runDraftSessionSelector();
241
+ },
242
+ closeDraftSessionSelector: () => {
243
+ this.popupMenus.closeDraftSessionSelectorForTabLifecycle();
244
+ },
245
+ contextInventoryText: (runtime, heading) => this.contextInventoryText(runtime, heading),
224
246
  addEntry: (entry) => this.addEntry(entry),
225
247
  showToast: (message, kind) => this.showToast(message, kind),
226
248
  render: () => this.render(),
@@ -258,9 +280,12 @@ export class PiUiExtendApp {
258
280
  }, this.pixConfig.dictation);
259
281
  this.menuItems = new AppMenuItemsController({
260
282
  runtime: () => this.runtime,
283
+ draftModelState: () => this.draftModelState(),
284
+ visibleModels: () => this.pixConfig.visibleModels,
261
285
  getBuiltinSlashCommands: () => this.slashCommands,
262
286
  getEntries: () => this.entries,
263
287
  getResumeSessions: () => this.resumeSessions,
288
+ getOpenSessionPaths: () => this.tabsController.openSessionPaths(),
264
289
  });
265
290
  const popupMenuRenderer = new PopupMenuRenderer({
266
291
  theme: this.theme,
@@ -275,6 +300,8 @@ export class PiUiExtendApp {
275
300
  this.popupMenus = new AppPopupMenuController({
276
301
  get entries() { return app.entries; },
277
302
  get session() { return app.runtime?.session; },
303
+ currentThinkingLevel: () => this.runtime?.session.thinkingLevel ?? this.draftModelState()?.thinkingLevel,
304
+ rememberedThinkingLevel: (modelRef) => this.pixConfig.thinkingByModel?.[modelRef],
278
305
  get resumeLoading() { return app.resumeLoading; },
279
306
  get resumeSessionCount() { return app.resumeSessions.length; },
280
307
  isRunning: () => this.running,
@@ -282,9 +309,9 @@ export class PiUiExtendApp {
282
309
  setInput: (value) => this.setInput(value),
283
310
  parseSlashInput: (text) => this.menuItems.parseSlashInput(text),
284
311
  getSlashCommandMenuItems: (query) => this.menuItems.getSlashCommandMenuItems(query),
285
- getModelMenuItems: (query) => this.menuItems.getModelMenuItems(query),
312
+ getModelMenuItems: (query, includeHidden) => this.menuItems.getModelMenuItems(query, includeHidden),
286
313
  getThinkingMenuItems: (query) => this.menuItems.getThinkingMenuItems(query),
287
- getResumeMenuItems: (query, limit) => this.menuItems.getResumeMenuItems(query, limit),
314
+ getResumeMenuItems: (query, limit, options) => this.menuItems.getResumeMenuItems(query, limit, options),
288
315
  getUserMessageMenuItems: () => this.menuItems.getUserMessageMenuItems(),
289
316
  getUserMessageJumpMenuItems: (query) => this.menuItems.getUserMessageJumpMenuItems(query),
290
317
  getQueueMessageMenuItems: () => this.menuItems.getQueueMessageMenuItems(),
@@ -298,6 +325,7 @@ export class PiUiExtendApp {
298
325
  theme: this.theme,
299
326
  screenStyler: this.screenStyler,
300
327
  get session() { return app.runtime?.session; },
328
+ draftModelStatus: () => this.draftModelStatus(),
301
329
  modelColors: this.pixConfig.modelColors,
302
330
  get sessionActivity() { return app.statusController.sessionActivity; },
303
331
  get statusDotBright() { return app.statusController.statusDotBright; },
@@ -358,6 +386,7 @@ export class PiUiExtendApp {
358
386
  this.extensionActions = new AppExtensionActionsController({
359
387
  isRunning: () => this.running,
360
388
  runtime: () => this.runtime,
389
+ subagentTypes: (runtime) => this.subagentTypesForRuntime(runtime),
361
390
  getInput: () => this.input,
362
391
  setInput: (value) => this.setInput(value),
363
392
  awaitCurrentSessionExtensions: (runtime) => this.awaitCurrentSessionExtensions(runtime),
@@ -372,6 +401,7 @@ export class PiUiExtendApp {
372
401
  });
373
402
  this.subagentsWidgetController = new AppSubagentsWidgetController({
374
403
  cwd: this.options.cwd,
404
+ hasActiveRuntime: () => this.runtime !== undefined,
375
405
  sessionFile: () => this.runtime?.session.sessionFile,
376
406
  isRunning: () => this.running,
377
407
  render: () => this.scheduleRender(),
@@ -508,6 +538,8 @@ export class PiUiExtendApp {
508
538
  this.commandController = new AppCommandController({
509
539
  options: this.options,
510
540
  runtime: () => this.runtime,
541
+ inputScopeKey: () => this.tabsController.activeInputTabId(),
542
+ subagentTypes: (runtime) => this.subagentTypesForRuntime(runtime),
511
543
  requestHistory: () => this.requestHistory,
512
544
  getInput: () => this.input,
513
545
  setInput: (value) => this.setInput(value),
@@ -552,6 +584,7 @@ export class PiUiExtendApp {
552
584
  setDirectPopupMenuQuery: (query) => {
553
585
  this.popupMenus.setDirectQuery(query);
554
586
  },
587
+ setResumeMenuMode: (mode) => this.popupMenus.setResumeMenuMode(mode),
555
588
  refreshUserMessageJumpMenuItems: () => this.menuItems.refreshUserMessageJumpMenuItems(),
556
589
  getResumeLoading: () => this.resumeLoading,
557
590
  getResumeSessions: () => this.resumeSessions,
@@ -570,6 +603,10 @@ export class PiUiExtendApp {
570
603
  });
571
604
  this.popupActions = new AppPopupActionController({
572
605
  runtime: () => this.runtime,
606
+ inputScopeKey: () => this.tabsController.activeInputTabId(),
607
+ isDraftTabActive: () => this.tabsController.isDraftTabActive(),
608
+ materializeDraftSession: () => this.tabsController.materializeActiveDraftTab(),
609
+ selectDraftModel: (model, thinkingLevel) => this.selectDraftModel(model, thinkingLevel),
573
610
  getBuiltinSlashCommands: () => this.slashCommands,
574
611
  isRunning: () => this.running,
575
612
  setInput: (value) => this.setInput(value),
@@ -577,9 +614,20 @@ export class PiUiExtendApp {
577
614
  setStatus: (status) => this.setStatus(status),
578
615
  setSessionStatus: (session) => this.setSessionStatus(session),
579
616
  showToast: (message, kind) => this.showToast(message, kind),
617
+ visibleModels: () => this.pixConfig.visibleModels,
618
+ saveVisibleModels: (modelRefs) => {
619
+ const saved = savePixVisibleModels(modelRefs);
620
+ this.pixConfig.visibleModels = [...saved];
621
+ return saved;
622
+ },
623
+ saveThinkingLevelForModel: (modelRef, thinkingLevel) => {
624
+ const saved = savePixThinkingLevelForModel(modelRef, thinkingLevel);
625
+ this.pixConfig.thinkingByModel = { ...saved };
626
+ },
580
627
  render: () => this.render(),
581
628
  awaitCurrentSessionExtensions: (runtime) => this.awaitCurrentSessionExtensions(runtime),
582
629
  afterSessionReplacement: (message) => this.afterSessionReplacement(message),
630
+ openSessionInActiveDraftTab: (sessionPath) => this.tabsController.openSessionInActiveDraftTab(sessionPath),
583
631
  scrollToConversationEntry: (entryId) => this.scrollController.scrollToConversationEntry(entryId),
584
632
  scrollToUserMessageJumpTarget: (target) => this.scrollToUserMessageJumpTarget(target),
585
633
  }, this.popupMenus, this.commandController, this.menuItems, this.queuedMessages, this.workspaceActions);
@@ -691,6 +739,8 @@ export class PiUiExtendApp {
691
739
  this.inputActions = new AppInputActionController({
692
740
  runtime: () => this.runtime,
693
741
  inputScopeKey: () => this.tabsController.activeInputTabId(),
742
+ isDraftTabActive: () => this.tabsController.isDraftTabActive(),
743
+ materializeDraftSession: () => this.tabsController.materializeActiveDraftTab(),
694
744
  isRunning: () => this.running,
695
745
  isSessionSwitching: () => this.tabsController.isSwitching(),
696
746
  inputEditor: () => this.inputEditor,
@@ -730,6 +780,7 @@ export class PiUiExtendApp {
730
780
  resetInputMenuDismissals: () => this.popupMenus.resetInputMenuDismissals(),
731
781
  render: () => this.render(),
732
782
  moveActivePopupMenuSelection: (delta) => this.popupMenus.moveActivePopupMenuSelection(delta),
783
+ moveActiveModelThinkingLevel: (delta) => this.popupMenus.moveActiveModelThinkingLevel(delta),
733
784
  navigateRequestHistory: (delta) => this.requestHistory.navigate(delta),
734
785
  scrollByLines: (delta) => this.scrollController.scrollByLines(delta),
735
786
  scrollByPage: (delta) => this.scrollController.scrollByPage(delta),
@@ -738,8 +789,8 @@ export class PiUiExtendApp {
738
789
  handleInterrupt: () => this.inputActions.handleInterrupt(),
739
790
  handleEscape: () => this.inputActions.handleEscape(),
740
791
  handleDirectPopupInput: (char) => this.popupMenus.handleDirectPopupInput(char),
792
+ toggleModelVisibilityMode: () => this.popupMenus.toggleModelVisibilityMode(),
741
793
  autocompleteModel: () => this.popupMenus.autocompleteModel(),
742
- autocompleteThinking: () => this.popupMenus.autocompleteThinking(),
743
794
  acceptAutocompleteSuggestion: () => this.autocompleteController.acceptSuggestion(),
744
795
  autocompleteSlashCommand: () => this.popupMenus.autocompleteSlashCommand(),
745
796
  toggleVoiceRecording: () => {
@@ -774,7 +825,10 @@ export class PiUiExtendApp {
774
825
  });
775
826
  this.sessionLifecycle = new AppSessionLifecycleController({
776
827
  options: this.options,
777
- createRuntime: () => this.createRuntime(this.options),
828
+ prepareStartupRuntime: () => this.tabsController.prepareStartupRuntime(),
829
+ createRuntime: (startup) => this.createRuntime(startup?.sessionPath
830
+ ? { ...this.options, noSession: false, sessionPath: startup.sessionPath }
831
+ : this.options),
778
832
  entries: this.entries,
779
833
  runtime: () => this.runtime,
780
834
  setRuntime: (runtime) => {
@@ -800,6 +854,7 @@ export class PiUiExtendApp {
800
854
  handleExtensionError: (error) => this.extensionActions.handleExtensionError(error),
801
855
  handleSessionEvent: (event) => this.handleSessionEvent(event),
802
856
  bindAgentPause: (session) => this.agentPauseController.bind(session),
857
+ contextInventoryText: (runtime, heading) => this.contextInventoryText(runtime, heading),
803
858
  addEntry: (entry) => this.addEntry(entry),
804
859
  setStatus: (status) => this.setStatus(status),
805
860
  showToast: (message, kind) => this.showToast(message, kind),
@@ -856,6 +911,59 @@ export class PiUiExtendApp {
856
911
  async loadStartupConfig() {
857
912
  await yieldToEventLoop();
858
913
  this.applyPixConfig(loadPixConfig(this.options.cwd));
914
+ await this.refreshDraftModelCatalog();
915
+ }
916
+ async refreshDraftModelCatalog() {
917
+ try {
918
+ this.draftModels = await createPixDraftModelCatalog({ cwd: this.options.cwd });
919
+ }
920
+ catch {
921
+ this.draftModels = [];
922
+ }
923
+ this.resetDraftModelSelection();
924
+ }
925
+ resetDraftModelSelection() {
926
+ this.draftModelOverrideRef = undefined;
927
+ const configuredRef = this.options.modelRef ?? resolveDefaultModelRef(this.pixConfig);
928
+ if (configuredRef) {
929
+ try {
930
+ const parsed = parseModelRef(configuredRef);
931
+ this.draftModelRef = `${parsed.provider}/${parsed.modelId}`;
932
+ this.draftThinkingLevel = parsed.thinkingLevel ?? "off";
933
+ return;
934
+ }
935
+ catch {
936
+ // Runtime creation will surface an invalid configured model. Keep the
937
+ // draft picker usable so the user can select a valid model first.
938
+ }
939
+ }
940
+ const first = this.draftModels[0];
941
+ this.draftModelRef = first ? `${first.provider}/${first.id}` : undefined;
942
+ this.draftThinkingLevel = "off";
943
+ }
944
+ selectDraftModel(model, thinkingLevel) {
945
+ if (!this.tabsController.isDraftTabActive())
946
+ return;
947
+ const ref = `${model.provider}/${model.id}`;
948
+ this.draftModelRef = ref;
949
+ this.draftThinkingLevel = thinkingLevel;
950
+ this.draftModelOverrideRef = `${ref}:${thinkingLevel}`;
951
+ this.setStatus("new conversation");
952
+ }
953
+ draftModelState() {
954
+ if (!this.tabsController.isDraftTabActive())
955
+ return undefined;
956
+ return {
957
+ models: this.draftModels,
958
+ ...(this.draftModelRef ? { modelRef: this.draftModelRef } : {}),
959
+ thinkingLevel: this.draftThinkingLevel,
960
+ };
961
+ }
962
+ draftModelStatus() {
963
+ const state = this.draftModelState();
964
+ if (!state?.modelRef)
965
+ return undefined;
966
+ return { modelLabel: state.modelRef, thinkingLabel: state.thinkingLevel };
859
967
  }
860
968
  applyPixConfig(config) {
861
969
  replaceRecord(this.pixConfig.toolRenderer, config.toolRenderer);
@@ -869,6 +977,14 @@ export class PiUiExtendApp {
869
977
  delete this.pixConfig.defaultModel;
870
978
  else
871
979
  this.pixConfig.defaultModel = { ...config.defaultModel };
980
+ if (config.visibleModels === undefined)
981
+ delete this.pixConfig.visibleModels;
982
+ else
983
+ this.pixConfig.visibleModels = [...config.visibleModels];
984
+ if (config.thinkingByModel === undefined)
985
+ delete this.pixConfig.thinkingByModel;
986
+ else
987
+ this.pixConfig.thinkingByModel = { ...config.thinkingByModel };
872
988
  this.pixConfig.ignoreContextFiles = config.ignoreContextFiles;
873
989
  this.pixConfig.maxProjectSessions = config.maxProjectSessions;
874
990
  this.updateOutputFilters();
@@ -939,16 +1055,49 @@ export class PiUiExtendApp {
939
1055
  });
940
1056
  await this.bindCurrentSession(options);
941
1057
  }
1058
+ deactivateRuntimeForDraft() {
1059
+ const runtime = this.runtime;
1060
+ if (!runtime)
1061
+ return;
1062
+ const scopeKey = this.activeExtensionUiScope();
1063
+ // Clear the visible runtime before any UI cleanup. cancelCustomUi() can
1064
+ // synchronously render; leaving the old runtime attached during that render
1065
+ // lets tab synchronization incorrectly reactivate the previous real tab.
1066
+ this.runtime = undefined;
1067
+ this.extensionUiController.cancelCustomUi(scopeKey);
1068
+ this.extensionUiController.clearWidgets(scopeKey, { cancelCustomUi: false });
1069
+ void this.voiceController.stopRecording();
1070
+ this.sessionLifecycle.unsubscribeSession();
1071
+ }
942
1072
  createExtensionEventBus() {
943
1073
  return createIsolatedExtensionEventBus((channel, data) => {
944
1074
  if (channel === TERMINAL_BELL_ATTENTION_EVENT)
945
1075
  this.handleTerminalBellAttention(data);
946
1076
  if (channel === SUBAGENTS_LIVE_STATE_EVENT)
947
1077
  this.subagentsWidgetController.observeLiveState(data);
1078
+ if (channel === SUBAGENTS_CATALOG_STATE_EVENT) {
1079
+ const catalog = parseSubagentCatalogState(data);
1080
+ if (catalog?.sessionId)
1081
+ this.subagentCatalogBySessionId.set(catalog.sessionId, catalog);
1082
+ }
948
1083
  if (channel === TODO_STATE_EVENT)
949
1084
  this.todoWidgetController.observeLiveState(data);
950
1085
  });
951
1086
  }
1087
+ subagentTypesForRuntime(runtime) {
1088
+ const sessionId = runtime.session.sessionManager.getSessionId();
1089
+ const catalog = this.subagentCatalogBySessionId.get(sessionId);
1090
+ if (!catalog)
1091
+ return undefined;
1092
+ const model = runtime.session.model;
1093
+ const currentModelRef = model ? `${model.provider}/${model.id}` : undefined;
1094
+ if (catalog.model && currentModelRef && catalog.model !== currentModelRef)
1095
+ return undefined;
1096
+ return catalog.types;
1097
+ }
1098
+ contextInventoryText(runtime, heading) {
1099
+ return formatReloadContextInventory(createReloadContextInventory(runtime, this.subagentTypesForRuntime(runtime)), heading);
1100
+ }
952
1101
  handleTerminalBellAttention(data) {
953
1102
  const sessionFile = isRecord(data) && typeof data.sessionFile === "string" ? data.sessionFile : undefined;
954
1103
  this.tabsController.markTerminalBellAttention(sessionFile);
@@ -1250,6 +1399,7 @@ export class PiUiExtendApp {
1250
1399
  if (contentVersion === this.lastInputEditorContentVersion)
1251
1400
  return;
1252
1401
  this.lastInputEditorContentVersion = contentVersion;
1402
+ this.tabsController.noteActiveDraftInputChanged();
1253
1403
  this.scrollController.scrollToBottom();
1254
1404
  }
1255
1405
  conversationQuickScrollDirections() {
@@ -59,7 +59,7 @@ export function inspectPixOnboarding(homeDir = homedir(), env = process.env) {
59
59
  opencodeAntigravityExists: pixInstallDeps.existsSync(join(opencodeConfigDir, "antigravity-accounts.json")),
60
60
  webCredentialsConfigured: Boolean(env.OLLAMA_API_KEY?.trim() || env.TAVILY_API_KEY?.trim()) || jsonObjectHasEntries(webCredentialPath),
61
61
  context7Configured: Boolean(env.CONTEXT7_API_KEY?.trim()),
62
- telegramConfigured: Boolean(env.PI_TERMINAL_BELL_TELEGRAM_BOT_TOKEN?.trim() && env.PI_TERMINAL_BELL_TELEGRAM_CHAT_ID?.trim()),
62
+ telegramConfigured: Boolean(env.PIX_TELEGRAM_BOT_TOKEN?.trim() && env.PIX_TELEGRAM_CHAT_ID?.trim()),
63
63
  };
64
64
  }
65
65
  export function ensurePixSetupFiles(homeDir = homedir()) {
@@ -106,7 +106,7 @@ export function formatPixInstallNextSteps(homeDir = homedir(), state = inspectPi
106
106
  "Optional integrations:",
107
107
  ` ${state.webCredentialsConfigured ? "✓ Web credentials detected." : "○ Web search: use local Ollama without a key, or run /web-credentials for Ollama Cloud/Tavily."}`,
108
108
  ` ${state.context7Configured ? "✓ Context7 API key detected." : "○ Context7 docs skill: export CONTEXT7_API_KEY."}`,
109
- ` ${state.telegramConfigured ? "✓ Telegram terminal-bell credentials detected in the environment." : "○ Telegram bell: set terminalBell.telegram in Pix config or PI_TERMINAL_BELL_TELEGRAM_* env vars."}`,
109
+ ` ${state.telegramConfigured ? "✓ Telegram connector credentials detected in the environment." : "○ Telegram connector: set telegramConnector in tools config or PIX_TELEGRAM_BOT_TOKEN plus PIX_TELEGRAM_CHAT_ID."}`,
110
110
  " ○ Model-backed helpers: review promptEnhancer, autocomplete, and sessionTitle model refs; each provider needs its own credentials.",
111
111
  " ○ Voice: set dictation.language in Pix config. LSP: configure and trust servers under lsp.servers in tools config.",
112
112
  "",
@@ -4,14 +4,18 @@ export declare class AppCommandController {
4
4
  private readonly host;
5
5
  readonly slashCommands: readonly SlashCommand[];
6
6
  private readonly modelActions;
7
+ private readonly gitActions;
7
8
  private readonly sessionActions;
8
9
  private readonly navigationActions;
9
10
  constructor(host: CommandControllerHost);
10
11
  runResumeCommand(queryOrOptions?: string | {
11
12
  preserveStatus?: boolean;
12
13
  placement?: PopupMenuPlacement;
14
+ draft?: boolean;
13
15
  }): Promise<void>;
16
+ runDraftSessionSelector(): Promise<void>;
14
17
  runModelCommand(model: SessionModel): Promise<void>;
18
+ runModelThinkingCommand(model: SessionModel, level: ThinkingLevel): Promise<void>;
15
19
  runThinkingCommand(level: ThinkingLevel): Promise<void>;
16
20
  private registryActions;
17
21
  }