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
@@ -277,14 +277,15 @@ export class NavigationCommandActions {
277
277
  async runResumeCommand(queryOrOptions = "") {
278
278
  const preserveStatus = typeof queryOrOptions === "object" && queryOrOptions.preserveStatus === true;
279
279
  const placement = typeof queryOrOptions === "object" ? queryOrOptions.placement : undefined;
280
+ const draft = typeof queryOrOptions === "object" && queryOrOptions.draft === true;
280
281
  const initialQuery = typeof queryOrOptions === "string" ? queryOrOptions : "";
281
- const runtime = preserveStatus ? this.host.runtime() : getIdleRuntime(this.host, "resume");
282
- if (!runtime) {
282
+ const runtime = draft ? this.host.runtime() : preserveStatus ? this.host.runtime() : getIdleRuntime(this.host, "resume");
283
+ if (!runtime && !draft) {
283
284
  if (!preserveStatus)
284
285
  this.host.render();
285
286
  return;
286
287
  }
287
- if (runtime.session.isStreaming) {
288
+ if (runtime?.session.isStreaming) {
288
289
  if (!preserveStatus) {
289
290
  this.host.toast.warning("/resume is unavailable while the agent is running");
290
291
  this.host.render();
@@ -292,6 +293,12 @@ export class NavigationCommandActions {
292
293
  return;
293
294
  }
294
295
  if (this.host.getResumeLoading()) {
296
+ if (draft) {
297
+ this.host.setResumeMenuMode?.("draft");
298
+ this.host.openDirectPopupMenu("resume", { preserveStatus: true, ...(placement === undefined ? {} : { placement }) });
299
+ this.host.setDirectPopupMenuQuery(initialQuery);
300
+ this.host.openResumeMenuWithQuery(initialQuery);
301
+ }
295
302
  if (!preserveStatus)
296
303
  this.host.setStatus("loading sessions…");
297
304
  this.host.render();
@@ -300,6 +307,7 @@ export class NavigationCommandActions {
300
307
  this.host.setResumeLoading(true);
301
308
  if (!preserveStatus)
302
309
  this.host.setStatus("loading sessions…");
310
+ this.host.setResumeMenuMode?.(draft ? "draft" : "resume");
303
311
  this.host.openDirectPopupMenu("resume", { preserveStatus, ...(placement === undefined ? {} : { placement }) });
304
312
  this.host.setDirectPopupMenuQuery(initialQuery);
305
313
  if (this.host.getResumeSessions().length > 0) {
@@ -344,6 +352,11 @@ export class NavigationCommandActions {
344
352
  this.host.setSessionStatus(options.scope.session);
345
353
  this.host.render();
346
354
  }
355
+ finally {
356
+ if (options.loadId === this.resumeLoadId && !isCommandScopeActive(this.host, options.scope)) {
357
+ this.host.setResumeLoading(false);
358
+ }
359
+ }
347
360
  }
348
361
  formatSessionTree(runtime) {
349
362
  const tree = runtime.session.sessionManager.getTree();
@@ -10,6 +10,8 @@ export type CommandRegistryActions = {
10
10
  runThinkingSlashCommand(argumentsText: string): Promise<void>;
11
11
  runDefaultThinkingSlashCommand(argumentsText: string): Promise<void>;
12
12
  runEnhanceCommand(): Promise<void>;
13
+ runCodeReviewCommand(): Promise<void>;
14
+ runCommitMessageCommand(): Promise<void>;
13
15
  runExportCommand(argumentsText: string): Promise<void>;
14
16
  runImportCommand(argumentsText: string): Promise<void>;
15
17
  runShareCommand(): Promise<void>;
@@ -71,6 +71,20 @@ export function createSlashCommands(actions, host) {
71
71
  keywords: ["prompt", "rewrite", "improve", "kilocode"],
72
72
  run: () => actions.runEnhanceCommand(),
73
73
  },
74
+ {
75
+ name: "code-review",
76
+ description: "Review staged, unstaged, and untracked Git changes",
77
+ kind: "builtin",
78
+ keywords: ["git", "review", "diff", "changes"],
79
+ run: () => actions.runCodeReviewCommand(),
80
+ },
81
+ {
82
+ name: "commit-message",
83
+ description: "Generate a message for staged changes and commit after confirmation",
84
+ kind: "builtin",
85
+ keywords: ["git", "commit", "message", "staged"],
86
+ run: () => actions.runCommitMessageCommand(),
87
+ },
74
88
  {
75
89
  name: "export",
76
90
  description: "Export session (HTML default, or .jsonl path)",
@@ -217,7 +231,7 @@ export function createSlashCommands(actions, host) {
217
231
  },
218
232
  {
219
233
  name: "reload",
220
- description: "Reload keybindings, extensions, skills, prompts, and themes",
234
+ description: "Reload resources and show model-available skills, tools, and agents",
221
235
  kind: "builtin",
222
236
  keywords: ["restart", "refresh", "resources", "extensions", "skills", "prompts"],
223
237
  run: () => actions.runReloadCommand(),
@@ -11,6 +11,7 @@ import { copyTextToClipboard } from "../screen/clipboard.js";
11
11
  import { formatAccountUsageReport, queryAccountUsageReport } from "../model/model-usage-status.js";
12
12
  import { checkGlobalPiInstall, checkPixUpdate, formatGlobalPiCheck, formatPixUpdateCheck, parsePixUpdateArgs, pixUpdateUsage, } from "../cli/update.js";
13
13
  import { createStartupInfoMessage } from "../cli/startup-info.js";
14
+ import { createReloadContextInventory, formatReloadContextInventory } from "./reload-context-inventory.js";
14
15
  import { getCompleteSessionStats } from "../session/session-stats.js";
15
16
  import { loadSessionTitleConfig } from "../../bundled-extensions/session-title/config.js";
16
17
  import { fallbackSessionTitleFromInput, firstUserMessageText, generateSessionTitleWithRuntime, sessionTitleModelRefs, } from "../../bundled-extensions/session-title/title-generation.js";
@@ -309,7 +310,8 @@ export class SessionCommandActions {
309
310
  if (!isCommandScopeActive(this.host, scope))
310
311
  return;
311
312
  this.host.setSessionStatus(runtime.session);
312
- this.host.addEntry({ id: createId("system"), kind: "system", text: "Reloaded keybindings, extensions, skills, prompts, themes" });
313
+ const inventory = createReloadContextInventory(runtime, this.host.subagentTypes?.(runtime));
314
+ this.host.addEntry({ id: createId("system"), kind: "system", text: formatReloadContextInventory(inventory) });
313
315
  this.host.toast.success("Reloaded resources");
314
316
  }
315
317
  catch (error) {
@@ -391,7 +393,7 @@ export class SessionCommandActions {
391
393
  this.host.addEntry({
392
394
  id: createId("system"),
393
395
  kind: "system",
394
- text: `Deleted session ${targetSessionId}. Started a new session. cwd=${runtime.cwd}`,
396
+ text: formatReloadContextInventory(createReloadContextInventory(runtime, this.host.subagentTypes?.(runtime)), `Deleted session ${targetSessionId}. Started a new session. cwd=${runtime.cwd}`),
395
397
  });
396
398
  if (runtime.modelFallbackMessage)
397
399
  this.host.addEntry({ id: createId("system"), kind: "system", text: runtime.modelFallbackMessage });
@@ -427,7 +429,11 @@ export class SessionCommandActions {
427
429
  return;
428
430
  }
429
431
  this.host.resetSessionView();
430
- this.host.addEntry({ id: createId("system"), kind: "system", text: `Started a new session. cwd=${runtime.cwd}` });
432
+ this.host.addEntry({
433
+ id: createId("system"),
434
+ kind: "system",
435
+ text: formatReloadContextInventory(createReloadContextInventory(runtime, this.host.subagentTypes?.(runtime)), `Started a new session. cwd=${runtime.cwd}`),
436
+ });
431
437
  if (runtime.modelFallbackMessage)
432
438
  this.host.addEntry({ id: createId("system"), kind: "system", text: runtime.modelFallbackMessage });
433
439
  for (const diag of runtime.diagnostics ?? []) {
@@ -0,0 +1,11 @@
1
+ import type { AgentSessionRuntime } from "@earendil-works/pi-coding-agent";
2
+ export interface ReloadContextInventory {
3
+ readonly model: string;
4
+ readonly skills: readonly string[];
5
+ readonly tools: readonly string[];
6
+ readonly agents: readonly string[] | undefined;
7
+ readonly skillsReadable: boolean;
8
+ readonly subagentsActive: boolean;
9
+ }
10
+ export declare function createReloadContextInventory(runtime: AgentSessionRuntime, agentTypes: readonly string[] | undefined): ReloadContextInventory;
11
+ export declare function formatReloadContextInventory(inventory: ReloadContextInventory, heading?: string): string;
@@ -0,0 +1,70 @@
1
+ export function createReloadContextInventory(runtime, agentTypes) {
2
+ const session = runtime.session;
3
+ const tools = unique(session.getActiveToolNames());
4
+ const skillsReadable = tools.some(isSkillFileAccessTool);
5
+ const subagentsActive = tools.includes("subagents");
6
+ const skills = skillsReadable
7
+ ? unique(session.resourceLoader.getSkills().skills.map((skill) => skill.name)).sort(compareText)
8
+ : [];
9
+ const agents = subagentsActive && agentTypes !== undefined
10
+ ? unique(agentTypes).sort(compareText)
11
+ : subagentsActive
12
+ ? undefined
13
+ : [];
14
+ return {
15
+ model: currentModelLabel(runtime),
16
+ skills,
17
+ tools,
18
+ agents,
19
+ skillsReadable,
20
+ subagentsActive,
21
+ };
22
+ }
23
+ function isSkillFileAccessTool(toolName) {
24
+ switch (toolName.trim().toLowerCase()) {
25
+ case "read":
26
+ case "bash":
27
+ case "shell":
28
+ case "shell_command":
29
+ return true;
30
+ default:
31
+ return false;
32
+ }
33
+ }
34
+ export function formatReloadContextInventory(inventory, heading = "Reloaded keybindings, extensions, skills, prompts, themes") {
35
+ return [
36
+ heading,
37
+ "",
38
+ `Model: ${inventory.model}`,
39
+ "",
40
+ `Skills (in context): ${inventory.skillsReadable ? listOrNone(inventory.skills) : "(none; read/bash inactive)"}`,
41
+ "",
42
+ `Tools (active): ${listOrNone(inventory.tools)}`,
43
+ "",
44
+ `Agents (available): ${formatAgents(inventory)}`,
45
+ ].join("\n");
46
+ }
47
+ function currentModelLabel(runtime) {
48
+ const model = runtime.session.model;
49
+ if (!model)
50
+ return "unavailable";
51
+ const thinking = runtime.session.thinkingLevel;
52
+ const modelRef = `${model.provider}/${model.id}`;
53
+ return !thinking || thinking === "off" ? modelRef : `${modelRef}:${thinking}`;
54
+ }
55
+ function formatAgents(inventory) {
56
+ if (!inventory.subagentsActive)
57
+ return "(none; subagents tool inactive)";
58
+ if (inventory.agents === undefined)
59
+ return "(catalog unavailable)";
60
+ return listOrNone(inventory.agents);
61
+ }
62
+ function listOrNone(values) {
63
+ return values.length > 0 ? values.join(", ") : "(none)";
64
+ }
65
+ function unique(values) {
66
+ return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
67
+ }
68
+ function compareText(left, right) {
69
+ return left.localeCompare(right);
70
+ }
@@ -4,6 +4,7 @@ import type { Entry } from "../types.js";
4
4
  export type AppExtensionActionsHost = {
5
5
  isRunning(): boolean;
6
6
  runtime(): AgentSessionRuntime | undefined;
7
+ subagentTypes?(runtime: AgentSessionRuntime): readonly string[] | undefined;
7
8
  getInput(): string;
8
9
  setInput(value: string): void;
9
10
  awaitCurrentSessionExtensions(runtime?: AgentSessionRuntime): Promise<void>;
@@ -1,6 +1,7 @@
1
1
  import { basename } from "node:path";
2
2
  import { createId } from "../id.js";
3
3
  import { logPixEvent } from "../logger.js";
4
+ import { createReloadContextInventory, formatReloadContextInventory } from "../commands/reload-context-inventory.js";
4
5
  export class AppExtensionActionsController {
5
6
  host;
6
7
  logExtensionError;
@@ -60,6 +61,11 @@ export class AppExtensionActionsController {
60
61
  if (!this.isSessionActive(runtime, session))
61
62
  return;
62
63
  this.host.setSessionStatus(session);
64
+ this.host.addEntry({
65
+ id: createId("system"),
66
+ kind: "system",
67
+ text: formatReloadContextInventory(createReloadContextInventory(runtime, this.host.subagentTypes?.(runtime)), "Reloaded resources"),
68
+ });
63
69
  this.host.showToast("Reloaded resources", "success");
64
70
  this.host.render();
65
71
  },
@@ -0,0 +1,9 @@
1
+ export declare const SUBAGENTS_CATALOG_STATE_EVENT = "pi-tools-suite:async-subagents:catalog";
2
+ export interface SubagentCatalogState {
3
+ readonly version: 1;
4
+ readonly sessionId?: string;
5
+ readonly sessionFile?: string;
6
+ readonly model?: string;
7
+ readonly types: readonly string[];
8
+ }
9
+ export declare function parseSubagentCatalogState(value: unknown): SubagentCatalogState | undefined;
@@ -0,0 +1,23 @@
1
+ export const SUBAGENTS_CATALOG_STATE_EVENT = "pi-tools-suite:async-subagents:catalog";
2
+ export function parseSubagentCatalogState(value) {
3
+ if (!isRecord(value) || value.version !== 1 || !Array.isArray(value.types))
4
+ return undefined;
5
+ if (!value.types.every((type) => typeof type === "string" && type.trim().length > 0))
6
+ return undefined;
7
+ if (value.sessionId !== undefined && typeof value.sessionId !== "string")
8
+ return undefined;
9
+ if (value.sessionFile !== undefined && typeof value.sessionFile !== "string")
10
+ return undefined;
11
+ if (value.model !== undefined && typeof value.model !== "string")
12
+ return undefined;
13
+ return {
14
+ version: 1,
15
+ ...(value.sessionId ? { sessionId: value.sessionId } : {}),
16
+ ...(value.sessionFile ? { sessionFile: value.sessionFile } : {}),
17
+ ...(value.model ? { model: value.model } : {}),
18
+ types: [...new Set(value.types.map((type) => type.trim()))],
19
+ };
20
+ }
21
+ function isRecord(value) {
22
+ return typeof value === "object" && value !== null && !Array.isArray(value);
23
+ }
@@ -138,57 +138,84 @@ export class AppAutocompleteController {
138
138
  }
139
139
  }
140
140
  export async function completeInputWithPi(runtime, draft, config, signal) {
141
- const parsedModel = parseModelRef(config.modelRef);
142
141
  const modelRuntime = runtime.services.modelRuntime;
143
- let model = modelRuntime.getModel(parsedModel.provider, parsedModel.modelId);
144
- if (!model) {
145
- await modelRuntime.refresh();
146
- model = modelRuntime.getModel(parsedModel.provider, parsedModel.modelId);
147
- }
148
- if (!model)
149
- throw new Error(`Model not found: ${parsedModel.provider}/${parsedModel.modelId}`);
150
142
  const timeoutMs = numberInRange(config.timeoutMs, AUTOCOMPLETE_TIMEOUT_MS, 250, 10_000);
151
143
  const maxTokens = numberInRange(config.maxTokens, AUTOCOMPLETE_MAX_TOKENS, 8, 256);
152
144
  const maxPromptTokens = numberInRange(config.maxPromptTokens, AUTOCOMPLETE_MAX_PROMPT_TOKENS, 256, 16_000);
153
145
  const requestSignal = createTimeoutSignal(signal, timeoutMs);
154
- const requestMaxTokens = model.maxTokens > 0 ? Math.min(model.maxTokens, maxTokens) : maxTokens;
155
- const requestModel = { ...model, maxTokens: requestMaxTokens };
156
146
  const includeRecentMessages = numberInRange(config.includeRecentMessages, AUTOCOMPLETE_INCLUDE_RECENT_MESSAGES, 0, 20);
157
147
  const history = includeRecentMessages > 0 ? autocompleteHistoryFromMessages(runtime.session.messages, includeRecentMessages) : [];
158
148
  const prompt = buildAutocompletePrompt({ cwd: runtime.cwd, draft, history, maxPromptTokens });
159
149
  if (!prompt)
160
150
  return "";
161
- let output = "";
162
- let streamError;
163
151
  try {
164
- const stream = modelRuntime.streamSimple(requestModel, {
165
- systemPrompt: AUTOCOMPLETE_SYSTEM_PROMPT,
166
- messages: [{ role: "user", content: prompt, timestamp: Date.now() }],
167
- }, {
168
- cacheRetention: "none",
169
- maxRetryDelayMs: 0,
170
- maxRetries: 0,
171
- maxTokens: requestModel.maxTokens,
172
- ...(parsedModel.thinkingLevel && parsedModel.thinkingLevel !== "off" ? { reasoning: parsedModel.thinkingLevel } : {}),
173
- signal: requestSignal.signal,
174
- timeoutMs,
175
- });
176
- for await (const event of stream) {
177
- if (event.type === "text_delta")
178
- output += event.delta;
179
- else if (event.type === "done" && !output)
180
- output = assistantMessageText(event.message);
181
- else if (event.type === "error")
182
- streamError = event.error.errorMessage ?? event.reason;
152
+ let refreshed = false;
153
+ let lastError;
154
+ for (const modelRef of modelRefChain(config.modelRef, config.fallbackModels)) {
155
+ if (requestSignal.signal.aborted)
156
+ throw requestSignal.signal.reason ?? new Error("Autocomplete request aborted");
157
+ let parsedModel;
158
+ try {
159
+ parsedModel = parseModelRef(modelRef);
160
+ }
161
+ catch (error) {
162
+ lastError = error;
163
+ continue;
164
+ }
165
+ let model = modelRuntime.getModel(parsedModel.provider, parsedModel.modelId);
166
+ if (!model && !refreshed) {
167
+ await modelRuntime.refresh();
168
+ refreshed = true;
169
+ model = modelRuntime.getModel(parsedModel.provider, parsedModel.modelId);
170
+ }
171
+ if (!model) {
172
+ lastError = new Error(`Model not found: ${parsedModel.provider}/${parsedModel.modelId}`);
173
+ continue;
174
+ }
175
+ try {
176
+ const requestMaxTokens = model.maxTokens > 0 ? Math.min(model.maxTokens, maxTokens) : maxTokens;
177
+ const requestModel = { ...model, maxTokens: requestMaxTokens };
178
+ let output = "";
179
+ let streamError;
180
+ const stream = modelRuntime.streamSimple(requestModel, {
181
+ systemPrompt: AUTOCOMPLETE_SYSTEM_PROMPT,
182
+ messages: [{ role: "user", content: prompt, timestamp: Date.now() }],
183
+ }, {
184
+ cacheRetention: "none",
185
+ maxRetryDelayMs: 0,
186
+ maxRetries: 0,
187
+ maxTokens: requestModel.maxTokens,
188
+ ...(parsedModel.thinkingLevel && parsedModel.thinkingLevel !== "off" ? { reasoning: parsedModel.thinkingLevel } : {}),
189
+ signal: requestSignal.signal,
190
+ timeoutMs,
191
+ });
192
+ for await (const event of stream) {
193
+ if (event.type === "text_delta")
194
+ output += event.delta;
195
+ else if (event.type === "done" && !output)
196
+ output = assistantMessageText(event.message);
197
+ else if (event.type === "error")
198
+ streamError = event.error.errorMessage ?? event.reason;
199
+ }
200
+ if (streamError)
201
+ throw new Error(streamError);
202
+ return output;
203
+ }
204
+ catch (error) {
205
+ if (requestSignal.signal.aborted)
206
+ throw requestSignal.signal.reason ?? error;
207
+ lastError = error;
208
+ }
183
209
  }
184
- if (streamError)
185
- throw new Error(streamError);
186
- return output;
210
+ throw lastError ?? new Error("No autocomplete models are configured");
187
211
  }
188
212
  finally {
189
213
  requestSignal.dispose();
190
214
  }
191
215
  }
216
+ function modelRefChain(primary, fallbacks) {
217
+ return [...new Set([primary, ...(fallbacks ?? [])].map((ref) => ref.trim()).filter(Boolean))];
218
+ }
192
219
  export function autocompleteHistoryFromMessages(messages, includeRecentMessages) {
193
220
  const limit = numberInRange(includeRecentMessages, AUTOCOMPLETE_INCLUDE_RECENT_MESSAGES, 0, 20);
194
221
  if (limit <= 0)
@@ -9,6 +9,8 @@ import type { Entry, SessionActivity } from "../types.js";
9
9
  export type AppInputActionControllerHost = {
10
10
  runtime(): AgentSessionRuntime | undefined;
11
11
  inputScopeKey?(): string | undefined;
12
+ isDraftTabActive?(): boolean;
13
+ materializeDraftSession?(): Promise<AgentSessionRuntime | undefined>;
12
14
  isRunning(): boolean;
13
15
  isSessionSwitching(): boolean;
14
16
  inputEditor(): InputEditor;
@@ -149,7 +149,6 @@ export class AppInputActionController {
149
149
  await this.host.stopVoiceInput();
150
150
  if (this.host.inputScopeKey && this.host.inputScopeKey() !== inputScopeKey)
151
151
  return;
152
- const runtime = this.host.runtime();
153
152
  const inputEditor = this.host.inputEditor();
154
153
  const rawPromptText = inputEditor.promptText;
155
154
  const rawDisplayText = inputEditor.expandedText;
@@ -176,6 +175,14 @@ export class AppInputActionController {
176
175
  await this.popupActions.submitSlashCommand(promptText);
177
176
  return;
178
177
  }
178
+ let runtime = this.host.runtime();
179
+ if (!runtime && this.host.isDraftTabActive?.()) {
180
+ runtime = await this.host.materializeDraftSession?.();
181
+ if (this.host.inputScopeKey && this.host.inputScopeKey() !== inputScopeKey)
182
+ return;
183
+ if (!runtime)
184
+ return;
185
+ }
179
186
  const message = this.queuedMessages.createSubmittedUserMessage(promptText, displayText, images);
180
187
  this.host.requestHistory().add(message.displayText);
181
188
  inputEditor.clear();
@@ -16,6 +16,7 @@ export type InputControllerHost = {
16
16
  resetInputMenuDismissals(): void;
17
17
  render(): void;
18
18
  moveActivePopupMenuSelection(delta: number): boolean;
19
+ moveActiveModelThinkingLevel(delta: number): boolean;
19
20
  navigateRequestHistory(delta: number): boolean;
20
21
  scrollByLines(delta: number): void;
21
22
  scrollByPage(delta: number): void;
@@ -24,8 +25,8 @@ export type InputControllerHost = {
24
25
  handleInterrupt(): Promise<void>;
25
26
  handleEscape(): Promise<void>;
26
27
  handleDirectPopupInput(char: string): boolean;
28
+ toggleModelVisibilityMode(): boolean;
27
29
  autocompleteModel(): boolean;
28
- autocompleteThinking(): boolean;
29
30
  acceptAutocompleteSuggestion(): boolean;
30
31
  autocompleteSlashCommand(): void;
31
32
  toggleVoiceRecording(): void;
@@ -229,6 +229,9 @@ export class AppInputController {
229
229
  getEscapeSequences() {
230
230
  return [
231
231
  ...SHIFT_ENTER_ESCAPE_SEQUENCES.map((sequence) => [sequence, () => this.insertInputNewline()]),
232
+ ["\x1b[Z", () => { this.host.toggleModelVisibilityMode(); }],
233
+ ["\x1b[9;2u", () => { this.host.toggleModelVisibilityMode(); }],
234
+ ["\x1b[27;2;9~", () => { this.host.toggleModelVisibilityMode(); }],
232
235
  ["\x1b[13u", () => this.host.handleEnter()],
233
236
  ["\x1b[13;1u", () => this.host.handleEnter()],
234
237
  ["\x1b[5~", () => this.host.scrollByPage(-1)],
@@ -460,6 +463,8 @@ export class AppInputController {
460
463
  this.host.scrollByLines(1);
461
464
  }
462
465
  handleArrowLeft() {
466
+ if (this.host.moveActiveModelThinkingLevel(-1))
467
+ return;
463
468
  if (this.host.inputEditor.hasSelection) {
464
469
  const [start] = this.orderedEditorSelection();
465
470
  this.host.inputEditor.clearSelection();
@@ -473,6 +478,8 @@ export class AppInputController {
473
478
  }
474
479
  }
475
480
  handleArrowRight() {
481
+ if (this.host.moveActiveModelThinkingLevel(1))
482
+ return;
476
483
  if (this.host.inputEditor.hasSelection) {
477
484
  const [, end] = this.orderedEditorSelection();
478
485
  this.host.inputEditor.clearSelection();
@@ -554,8 +561,6 @@ export class AppInputController {
554
561
  return;
555
562
  if (this.host.autocompleteModel())
556
563
  return;
557
- if (this.host.autocompleteThinking())
558
- return;
559
564
  this.host.autocompleteSlashCommand();
560
565
  return;
561
566
  }
@@ -129,7 +129,6 @@ export function promptEnhancerTextIsSufficient(text) {
129
129
  return text.trim().length >= PROMPT_ENHANCER_MIN_TEXT_LENGTH;
130
130
  }
131
131
  async function enhancePromptWithPi(runtime, draft, config) {
132
- const parsedModel = parseModelRef(config.modelRef);
133
132
  const services = await promptEnhancerPiDeps.createAgentSessionServices({
134
133
  cwd: runtime.cwd,
135
134
  agentDir: runtime.services.agentDir,
@@ -145,41 +144,60 @@ async function enhancePromptWithPi(runtime, draft, config) {
145
144
  },
146
145
  });
147
146
  await services.modelRuntime.refresh();
148
- const model = services.modelRuntime.getModel(parsedModel.provider, parsedModel.modelId);
149
- if (!model) {
150
- throw new Error(modelNotFoundMessage(parsedModel.provider, parsedModel.modelId, services.modelRuntime.getModels()));
151
- }
152
- const { session } = await promptEnhancerPiDeps.createAgentSessionFromServices({
153
- services,
154
- sessionManager: promptEnhancerPiDeps.sessionManagerInMemory(runtime.cwd),
155
- model,
156
- thinkingLevel: parsedModel.thinkingLevel ?? "minimal",
157
- noTools: "all",
158
- });
159
- let output = "";
160
- let streamError;
161
- const unsubscribe = session.subscribe((event) => {
162
- if (event.type !== "message_update")
163
- return;
164
- const assistantEvent = event.assistantMessageEvent;
165
- if (assistantEvent.type === "text_delta")
166
- output += assistantEvent.delta;
167
- else if (assistantEvent.type === "error")
168
- streamError = assistantEvent.error.errorMessage ?? assistantEvent.reason;
169
- });
170
- try {
171
- await session.prompt(buildEnhancerPrompt(draft), { expandPromptTemplates: false });
172
- if (streamError)
173
- throw new Error(streamError);
174
- const cleaned = cleanupEnhancedPrompt(output);
175
- if (cleaned.length === 0)
176
- throw new Error("model returned an empty prompt");
177
- return cleaned;
178
- }
179
- finally {
180
- unsubscribe();
181
- session.dispose();
147
+ let lastError;
148
+ for (const modelRef of modelRefChain(config.modelRef, config.fallbackModels)) {
149
+ let parsedModel;
150
+ try {
151
+ parsedModel = parseModelRef(modelRef);
152
+ }
153
+ catch (error) {
154
+ lastError = error;
155
+ continue;
156
+ }
157
+ const model = services.modelRuntime.getModel(parsedModel.provider, parsedModel.modelId);
158
+ if (!model) {
159
+ lastError = new Error(modelNotFoundMessage(parsedModel.provider, parsedModel.modelId, services.modelRuntime.getModels()));
160
+ continue;
161
+ }
162
+ const { session } = await promptEnhancerPiDeps.createAgentSessionFromServices({
163
+ services,
164
+ sessionManager: promptEnhancerPiDeps.sessionManagerInMemory(runtime.cwd),
165
+ model,
166
+ thinkingLevel: parsedModel.thinkingLevel ?? "minimal",
167
+ noTools: "all",
168
+ });
169
+ let output = "";
170
+ let streamError;
171
+ const unsubscribe = session.subscribe((event) => {
172
+ if (event.type !== "message_update")
173
+ return;
174
+ const assistantEvent = event.assistantMessageEvent;
175
+ if (assistantEvent.type === "text_delta")
176
+ output += assistantEvent.delta;
177
+ else if (assistantEvent.type === "error")
178
+ streamError = assistantEvent.error.errorMessage ?? assistantEvent.reason;
179
+ });
180
+ try {
181
+ await session.prompt(buildEnhancerPrompt(draft), { expandPromptTemplates: false });
182
+ if (streamError)
183
+ throw new Error(streamError);
184
+ const cleaned = cleanupEnhancedPrompt(output);
185
+ if (cleaned.length === 0)
186
+ throw new Error("model returned an empty prompt");
187
+ return cleaned;
188
+ }
189
+ catch (error) {
190
+ lastError = error;
191
+ }
192
+ finally {
193
+ unsubscribe();
194
+ session.dispose();
195
+ }
182
196
  }
197
+ throw lastError ?? new Error("No prompt enhancer models are configured");
198
+ }
199
+ function modelRefChain(primary, fallbacks) {
200
+ return [...new Set([primary, ...(fallbacks ?? [])].map((ref) => ref.trim()).filter(Boolean))];
183
201
  }
184
202
  function buildEnhancerPrompt(draft) {
185
203
  return [