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
@@ -37,8 +37,11 @@ export class AppMenuItemsController {
37
37
  modelRef(model) {
38
38
  return `${model.provider}/${model.id}`;
39
39
  }
40
- getModelMenuItems(query) {
41
- const models = [...this.getModelMenuModels()].sort((left, right) => {
40
+ getModelMenuItems(query, includeHidden = false) {
41
+ const visibleModels = this.host.visibleModels();
42
+ const models = [...this.getModelMenuModels()]
43
+ .filter((model) => includeHidden || this.isVisibleModel(model, visibleModels))
44
+ .sort((left, right) => {
42
45
  const leftCurrent = this.isCurrentModel(left);
43
46
  const rightCurrent = this.isCurrentModel(right);
44
47
  if (leftCurrent && !rightCurrent)
@@ -51,8 +54,9 @@ export class AppMenuItemsController {
51
54
  const items = models.map((model) => {
52
55
  const ref = this.modelRef(model);
53
56
  const current = this.isCurrentModel(model);
57
+ const visible = current || visibleModels === undefined || visibleModels.includes(ref);
54
58
  return {
55
- value: { model, ref, current },
59
+ value: { model, ref, current, visible },
56
60
  label: ref,
57
61
  aliases: [model.id, model.name, model.provider],
58
62
  keywords: [model.name, `${model.provider} ${model.id}`],
@@ -67,7 +71,7 @@ export class AppMenuItemsController {
67
71
  }
68
72
  getThinkingMenuItems(query) {
69
73
  const session = this.host.runtime()?.session;
70
- const currentLevel = session?.thinkingLevel ?? "off";
74
+ const currentLevel = session?.thinkingLevel ?? this.host.draftModelState?.()?.thinkingLevel ?? "off";
71
75
  const levels = session ? normalizeAvailableThinkingLevels(session.getAvailableThinkingLevels()) : [...THINKING_LEVELS];
72
76
  const items = levels.map((level) => ({
73
77
  value: { level, current: level === currentLevel },
@@ -134,29 +138,38 @@ export class AppMenuItemsController {
134
138
  { value: "send-now", label: "Send immediately", description: "Send now and keep the rest queued" },
135
139
  ];
136
140
  }
137
- getResumeMenuItems(query, limit) {
141
+ getResumeMenuItems(query, limit, options = {}) {
138
142
  const sessionFile = this.host.runtime()?.session.sessionFile;
139
- const currentSessionFile = sessionFile ? resolve(sessionFile) : undefined;
140
- const loader = this.getResumeMenuItemsLoader(currentSessionFile, query);
143
+ const currentSessionFile = options.draft ? undefined : sessionFile ? resolve(sessionFile) : undefined;
144
+ const excludedSessionPaths = options.draft
145
+ ? this.host.getOpenSessionPaths?.().map((path) => resolve(path)) ?? []
146
+ : [];
147
+ const excluded = new Set(excludedSessionPaths);
148
+ const sessions = excluded.size === 0
149
+ ? this.host.getResumeSessions()
150
+ : this.host.getResumeSessions().filter((session) => !excluded.has(resolve(session.path)));
151
+ const loader = this.getResumeMenuItemsLoader(sessions, currentSessionFile, query, [...excluded].sort().join("\0"));
141
152
  return [
142
- { value: { kind: "new" }, label: "new", description: "Create a new session" },
153
+ ...(options.draft
154
+ ? [{ value: { kind: "new" }, label: "New session", description: "Start typing in the composer" }]
155
+ : [{ value: { kind: "new" }, label: "new", description: "Create a new session" }]),
143
156
  ...loader.items(limit).map((item) => ({
144
157
  ...item,
145
158
  value: { kind: "session", session: item.value },
146
159
  })),
147
160
  ];
148
161
  }
149
- getResumeMenuItemsLoader(currentSessionFile, query) {
150
- const sessions = this.host.getResumeSessions();
162
+ getResumeMenuItemsLoader(sessions, currentSessionFile, query, excludedSessionPathsKey) {
151
163
  const cache = this.resumeMenuLoaderCache;
152
164
  if (cache &&
153
165
  cache.sessions === sessions &&
154
166
  cache.currentSessionFile === currentSessionFile &&
155
- cache.query === query) {
167
+ cache.query === query &&
168
+ cache.excludedSessionPathsKey === excludedSessionPathsKey) {
156
169
  return cache.loader;
157
170
  }
158
171
  const loader = createSessionInfoMenuItemsLoader(sessions, currentSessionFile, query);
159
- this.resumeMenuLoaderCache = { sessions, currentSessionFile, query, loader };
172
+ this.resumeMenuLoaderCache = { sessions, currentSessionFile, query, excludedSessionPathsKey, loader };
160
173
  return loader;
161
174
  }
162
175
  getAllSlashCommands() {
@@ -164,21 +177,24 @@ export class AppMenuItemsController {
164
177
  }
165
178
  isCurrentModel(model) {
166
179
  const current = this.host.runtime()?.session.model;
167
- return current?.provider === model.provider && current.id === model.id;
180
+ if (current)
181
+ return current.provider === model.provider && current.id === model.id;
182
+ return this.host.draftModelState?.()?.modelRef === this.modelRef(model);
183
+ }
184
+ isVisibleModel(model, visibleModels) {
185
+ return this.isCurrentModel(model) || visibleModels === undefined || visibleModels.includes(this.modelRef(model));
168
186
  }
169
187
  getModelMenuModels() {
170
188
  const runtime = this.host.runtime();
171
189
  if (!runtime)
172
- return [];
173
- const { session } = runtime;
190
+ return [...(this.host.draftModelState?.()?.models ?? [])];
174
191
  const modelRuntime = runtime.services.modelRuntime;
175
- if (!session.scopedModels.length) {
176
- return [...modelRuntime.getAvailableSnapshot()];
192
+ const models = [...modelRuntime.getAvailableSnapshot()];
193
+ const current = runtime.session.model;
194
+ if (current && !models.some((model) => model.provider === current.provider && model.id === current.id)) {
195
+ models.push(current);
177
196
  }
178
- return session.scopedModels.map((scoped) => {
179
- const refreshed = modelRuntime.getModel(scoped.model.provider, scoped.model.id);
180
- return (refreshed ?? scoped.model);
181
- });
197
+ return models;
182
198
  }
183
199
  thinkingLevelDescription(level, _availableLevels) {
184
200
  switch (level) {
@@ -3,10 +3,14 @@ import type { AppCommandController } from "../commands/command-controller.js";
3
3
  import type { AppMenuItemsController } from "./menu-items-controller.js";
4
4
  import type { AppPopupMenuController } from "./popup-menu-controller.js";
5
5
  import type { AppQueuedMessageController } from "../session/queued-message-controller.js";
6
- import type { Entry, SlashCommand, UserMessageJumpMenuValue } from "../types.js";
6
+ import type { Entry, SessionModel, SlashCommand, ThinkingLevel, UserMessageJumpMenuValue } from "../types.js";
7
7
  import type { AppWorkspaceActionsController } from "../workspace/workspace-actions-controller.js";
8
8
  export type AppPopupActionControllerHost = {
9
9
  runtime(): AgentSessionRuntime | undefined;
10
+ inputScopeKey?(): string | undefined;
11
+ isDraftTabActive?(): boolean;
12
+ materializeDraftSession?(): Promise<AgentSessionRuntime | undefined>;
13
+ selectDraftModel?(model: SessionModel, thinkingLevel: ThinkingLevel): void;
10
14
  awaitCurrentSessionExtensions(runtime?: AgentSessionRuntime): Promise<void>;
11
15
  getBuiltinSlashCommands(): readonly SlashCommand[];
12
16
  isRunning(): boolean;
@@ -15,8 +19,12 @@ export type AppPopupActionControllerHost = {
15
19
  setStatus(status: string): void;
16
20
  setSessionStatus(session: AgentSession | undefined): void;
17
21
  showToast(message: string, kind: "success" | "error" | "warning" | "info"): void;
22
+ visibleModels(): readonly string[] | undefined;
23
+ saveVisibleModels(modelRefs: readonly string[]): readonly string[];
24
+ saveThinkingLevelForModel(modelRef: string, thinkingLevel: ThinkingLevel): void;
18
25
  render(): void;
19
26
  afterSessionReplacement(message?: string): void;
27
+ openSessionInActiveDraftTab?(sessionPath: string): Promise<boolean>;
20
28
  scrollToConversationEntry(entryId: string): boolean;
21
29
  scrollToUserMessageJumpTarget(target: UserMessageJumpMenuValue): Promise<boolean>;
22
30
  };
@@ -32,7 +40,9 @@ export declare class AppPopupActionController {
32
40
  submitSlashCommand(text: string): Promise<void>;
33
41
  private submitSelectedSlashCommand;
34
42
  private submitSelectedModel;
35
- private submitSelectedThinking;
43
+ private persistThinkingPreference;
44
+ private toggleSelectedModelVisibility;
45
+ clearVisibleModels(): boolean;
36
46
  private submitSelectedUserMessageAction;
37
47
  private submitSelectedUserMessageJump;
38
48
  private submitSelectedQueueMessageAction;
@@ -29,8 +29,6 @@ export class AppPopupActionController {
29
29
  return await this.submitSelectedResume();
30
30
  if (active === "model")
31
31
  return await this.submitSelectedModel();
32
- if (active === "thinking")
33
- return await this.submitSelectedThinking();
34
32
  if (active === "sdk-menu")
35
33
  return this.popupMenus.submitSelectedSdkMenu();
36
34
  if (active === "slash")
@@ -38,7 +36,7 @@ export class AppPopupActionController {
38
36
  return false;
39
37
  }
40
38
  async submitSlashCommand(text) {
41
- const scope = this.captureScope();
39
+ let scope = this.captureScope();
42
40
  const parsed = this.menuItems.parseSlashInput(text);
43
41
  if (!parsed)
44
42
  return;
@@ -61,6 +59,12 @@ export class AppPopupActionController {
61
59
  this.host.render();
62
60
  return;
63
61
  }
62
+ if (command.kind === "resource" && !scope.runtime && this.host.isDraftTabActive?.()) {
63
+ const runtime = await this.host.materializeDraftSession?.();
64
+ if (!runtime || (this.host.inputScopeKey && this.host.inputScopeKey() !== scope.inputScopeKey))
65
+ return;
66
+ scope = this.captureScope();
67
+ }
64
68
  this.host.setInput("");
65
69
  if (!command.suppressCommandEcho) {
66
70
  this.host.addEntry({ id: createId("system"), kind: "system", text: `command: ${this.formatSlashCommandLine(command.name, parsed.arguments)}` });
@@ -100,53 +104,91 @@ export class AppPopupActionController {
100
104
  return true;
101
105
  }
102
106
  async submitSelectedModel() {
107
+ if (this.popupMenus.modelVisibilityModeActive())
108
+ return this.toggleSelectedModelVisibility();
103
109
  const scope = this.captureScope();
104
- const selected = this.popupMenus.selectedModel();
110
+ const selected = this.popupMenus.selectedModelThinking();
105
111
  if (!selected)
106
112
  return false;
107
113
  this.popupMenus.closeModelSelection();
114
+ if (!scope.runtime && this.host.isDraftTabActive?.()) {
115
+ this.host.selectDraftModel?.(selected.value.model, selected.thinkingLevel);
116
+ this.persistThinkingPreference(selected.value.ref, selected.thinkingLevel);
117
+ this.host.render();
118
+ return true;
119
+ }
108
120
  if (!selected.direct) {
109
121
  this.host.setInput("");
110
- this.host.addEntry({ id: createId("system"), kind: "system", text: `command: /model ${selected.value.ref}` });
122
+ this.host.addEntry({
123
+ id: createId("system"),
124
+ kind: "system",
125
+ text: `command: /model ${selected.value.ref}:${selected.thinkingLevel}`,
126
+ });
111
127
  }
112
128
  this.host.render();
113
129
  try {
114
- await this.commandController.runModelCommand(selected.value.model);
130
+ await this.commandController.runModelThinkingCommand(selected.value.model, selected.thinkingLevel);
131
+ this.persistThinkingPreference(selected.value.ref, selected.thinkingLevel);
115
132
  }
116
133
  catch (error) {
117
134
  if (!this.isScopeActive(scope))
118
135
  return true;
119
136
  this.host.addEntry({ id: createId("error"), kind: "error", text: stringifyUnknown(error) });
120
- this.host.showToast("/model failed", "error");
137
+ this.host.showToast("Model selection failed", "error");
121
138
  this.host.setSessionStatus(this.host.runtime()?.session);
122
139
  }
123
140
  if (this.isScopeActive(scope))
124
141
  this.host.render();
125
142
  return true;
126
143
  }
127
- async submitSelectedThinking() {
128
- const scope = this.captureScope();
129
- const selected = this.popupMenus.selectedThinking();
144
+ persistThinkingPreference(modelRef, thinkingLevel) {
145
+ try {
146
+ this.host.saveThinkingLevelForModel(modelRef, thinkingLevel);
147
+ }
148
+ catch (error) {
149
+ this.host.showToast(`Model changed, but thinking preference could not be saved: ${stringifyUnknown(error)}`, "warning");
150
+ }
151
+ }
152
+ toggleSelectedModelVisibility() {
153
+ const selected = this.popupMenus.selectedModel();
130
154
  if (!selected)
131
155
  return false;
132
- this.popupMenus.closeThinkingSelection();
133
- if (!selected.direct) {
134
- this.host.setInput("");
135
- this.host.addEntry({ id: createId("system"), kind: "system", text: `command: /thinking ${selected.value.level}` });
156
+ if (selected.value.current) {
157
+ this.host.showToast("The current model must remain visible", "warning");
158
+ return true;
159
+ }
160
+ const allAvailableRefs = this.menuItems.getModelMenuItems("", true).map((item) => item.value.ref);
161
+ const configured = this.host.visibleModels();
162
+ const visible = new Set(configured === undefined ? allAvailableRefs : configured);
163
+ const wasVisible = visible.has(selected.value.ref);
164
+ if (wasVisible)
165
+ visible.delete(selected.value.ref);
166
+ else
167
+ visible.add(selected.value.ref);
168
+ const currentModel = this.host.runtime()?.session.model;
169
+ if (currentModel)
170
+ visible.add(this.menuItems.modelRef(currentModel));
171
+ try {
172
+ this.host.saveVisibleModels([...visible]);
173
+ this.host.showToast(`${selected.value.ref} ${wasVisible ? "hidden from" : "shown in"} model pickers`, "info");
174
+ }
175
+ catch (error) {
176
+ this.host.showToast(`Failed to save model visibility: ${stringifyUnknown(error)}`, "error");
136
177
  }
137
178
  this.host.render();
179
+ return true;
180
+ }
181
+ clearVisibleModels() {
182
+ if (!this.popupMenus.modelVisibilityModeActive())
183
+ return false;
138
184
  try {
139
- await this.commandController.runThinkingCommand(selected.value.level);
185
+ this.host.saveVisibleModels([]);
186
+ this.host.showToast("Cleared model picker visibility", "info");
140
187
  }
141
188
  catch (error) {
142
- if (!this.isScopeActive(scope))
143
- return true;
144
- this.host.addEntry({ id: createId("error"), kind: "error", text: stringifyUnknown(error) });
145
- this.host.showToast("/thinking failed", "error");
146
- this.host.setSessionStatus(this.host.runtime()?.session);
189
+ this.host.showToast(`Failed to clear model visibility: ${stringifyUnknown(error)}`, "error");
147
190
  }
148
- if (this.isScopeActive(scope))
149
- this.host.render();
191
+ this.host.render();
150
192
  return true;
151
193
  }
152
194
  async submitSelectedUserMessageAction() {
@@ -231,10 +273,18 @@ export class AppPopupActionController {
231
273
  const selected = this.popupMenus.selectedResume();
232
274
  if (!selected)
233
275
  return false;
276
+ const draftSelector = this.popupMenus.draftSessionSelectorActive();
234
277
  this.popupMenus.setDirectMenu(undefined);
235
278
  this.popupMenus.setDirectPreserveStatus(false);
236
279
  this.popupMenus.setDirectQuery("");
237
280
  this.popupMenus.closeResumeMenu();
281
+ this.popupMenus.setResumeMenuMode("resume");
282
+ if (draftSelector) {
283
+ if (selected.kind !== "session")
284
+ return true;
285
+ await this.host.openSessionInActiveDraftTab?.(selected.session.path);
286
+ return true;
287
+ }
238
288
  if (selected.kind === "new") {
239
289
  await this.submitSlashCommand("/new");
240
290
  return true;
@@ -283,10 +333,13 @@ export class AppPopupActionController {
283
333
  }
284
334
  captureScope() {
285
335
  const runtime = this.host.runtime();
286
- return { runtime, session: runtime?.session };
336
+ return { runtime, session: runtime?.session, inputScopeKey: this.host.inputScopeKey?.() };
287
337
  }
288
338
  isScopeActive(scope) {
289
- return this.host.isRunning() && this.host.runtime() === scope.runtime && scope.runtime?.session === scope.session;
339
+ return this.host.isRunning()
340
+ && this.host.runtime() === scope.runtime
341
+ && scope.runtime?.session === scope.session
342
+ && (this.host.inputScopeKey === undefined || this.host.inputScopeKey() === scope.inputScopeKey);
290
343
  }
291
344
  isRuntimeActive(runtime) {
292
345
  return this.host.isRunning() && this.host.runtime() === runtime;
@@ -1,9 +1,8 @@
1
1
  import { PopupMenu, type PopupMenuItem } from "../../ui.js";
2
- import type { ActivePopupMenu, Entry, ModelMenuValue, ParsedSlashInput, PixMenuController, PixMenuItem, PixMenuOptions, PixMenuSelectOptions, PopupMenuPlacement, QueueMessageMenuValue, RenderedLine, ResumeMenuValue, SlashCommand, ThinkingMenuValue, UserMessageJumpMenuValue, UserMessageMenuValue } from "../types.js";
2
+ import type { ActivePopupMenu, Entry, ModelMenuValue, ModelThinkingMenuState, ParsedSlashInput, PixMenuController, PixMenuItem, PixMenuOptions, PixMenuSelectOptions, PopupMenuPlacement, QueueMessageMenuValue, RenderedLine, ResumeMenuValue, SlashCommand, ThinkingLevel, ThinkingMenuValue, UserMessageJumpMenuValue, UserMessageMenuValue } from "../types.js";
3
3
  import type { AgentSession, SessionInfo } from "@earendil-works/pi-coding-agent";
4
4
  type SlashCommandMenuValue = SlashCommand;
5
5
  type ModelPopupMenuValue = ModelMenuValue;
6
- type ThinkingPopupMenuValue = ThinkingMenuValue;
7
6
  type ResumePopupMenuValue = ResumeMenuValue;
8
7
  type UserMessagePopupMenuValue = UserMessageMenuValue;
9
8
  type UserMessageJumpPopupMenuValue = UserMessageJumpMenuValue;
@@ -17,12 +16,12 @@ type PopupMenuRendererPort = {
17
16
  overlayPlainText(line: RenderedLine, width: number): string;
18
17
  renderUserMessageMenu(width: number, menu: PopupMenu<UserMessagePopupMenuValue>): RenderedLine[];
19
18
  renderSlashCommandMenu(width: number, menu: PopupMenu<SlashCommandMenuValue>): RenderedLine[];
20
- renderModelMenu(width: number, menu: PopupMenu<ModelPopupMenuValue>): RenderedLine[];
21
- renderThinkingMenu(width: number, menu: PopupMenu<ThinkingPopupMenuValue>): RenderedLine[];
19
+ renderModelMenu(width: number, menu: PopupMenu<ModelPopupMenuValue>, state: ModelThinkingMenuState): RenderedLine[];
22
20
  renderResumeMenu(width: number, menu: PopupMenu<ResumePopupMenuValue>, state: {
23
21
  directQuery: string;
24
22
  allSessionsLoaded: boolean;
25
23
  loadedSessionCount: number;
24
+ draft: boolean;
26
25
  }): RenderedLine[];
27
26
  renderUserMessageJumpMenu(width: number, menu: PopupMenu<UserMessageJumpPopupMenuValue>, directQuery: string): RenderedLine[];
28
27
  renderQueueMessageMenu(width: number, menu: PopupMenu<QueueMessagePopupMenuValue>): RenderedLine[];
@@ -34,6 +33,8 @@ export type DirectPopupMenu = Exclude<ActivePopupMenu, "slash">;
34
33
  export type AppPopupMenuControllerHost = {
35
34
  readonly entries: readonly Entry[];
36
35
  readonly session: AgentSession | undefined;
36
+ currentThinkingLevel?(): ThinkingLevel | undefined;
37
+ rememberedThinkingLevel?(modelRef: string): ThinkingLevel | undefined;
37
38
  readonly resumeLoading: boolean;
38
39
  readonly resumeSessionCount: number;
39
40
  isRunning(): boolean;
@@ -41,9 +42,11 @@ export type AppPopupMenuControllerHost = {
41
42
  setInput(value: string): void;
42
43
  parseSlashInput(text: string): ParsedSlashInput | undefined;
43
44
  getSlashCommandMenuItems(query: string): PopupMenuItem<SlashCommand>[];
44
- getModelMenuItems(query: string): PopupMenuItem<ModelMenuValue>[];
45
+ getModelMenuItems(query: string, includeHidden?: boolean): PopupMenuItem<ModelMenuValue>[];
45
46
  getThinkingMenuItems(query: string): PopupMenuItem<ThinkingMenuValue>[];
46
- getResumeMenuItems(query: string, limit?: number): PopupMenuItem<ResumeMenuValue>[];
47
+ getResumeMenuItems(query: string, limit?: number, options?: {
48
+ draft?: boolean;
49
+ }): PopupMenuItem<ResumeMenuValue>[];
47
50
  getUserMessageMenuItems(): PopupMenuItem<UserMessageMenuValue>[];
48
51
  getUserMessageJumpMenuItems(query: string): PopupMenuItem<UserMessageJumpMenuValue>[];
49
52
  getQueueMessageMenuItems(): PopupMenuItem<QueueMessageMenuValue>[];
@@ -59,7 +62,6 @@ export declare class AppPopupMenuController {
59
62
  readonly menuController: PixMenuController;
60
63
  private readonly slashCommandMenu;
61
64
  private readonly modelMenu;
62
- private readonly thinkingMenu;
63
65
  private readonly resumeMenu;
64
66
  private readonly userMessageMenu;
65
67
  private readonly userMessageJumpMenu;
@@ -70,8 +72,13 @@ export declare class AppPopupMenuController {
70
72
  private dismissedSlashCommandMenuInput;
71
73
  private modelMenuQuery;
72
74
  private dismissedModelMenuInput;
73
- private thinkingMenuQuery;
75
+ private modelThinkingInputQuery;
74
76
  private dismissedThinkingMenuInput;
77
+ private modelThinkingLevel;
78
+ private modelThinkingSelectedRef;
79
+ private readonly stagedThinkingByModel;
80
+ private modelThinkingSource;
81
+ private modelVisibilityMode;
75
82
  private directPopupMenu;
76
83
  private directPopupMenuPreserveStatus;
77
84
  private directPopupMenuPlacement;
@@ -79,11 +86,15 @@ export declare class AppPopupMenuController {
79
86
  private resumeMenuQuery;
80
87
  private resumeMenuSessionLimit;
81
88
  private resumeMenuAllSessionsLoaded;
89
+ private resumeMenuMode;
82
90
  private activeUserMessageEntryId;
83
91
  private activeQueuedMessageEntryId;
84
92
  constructor(host: AppPopupMenuControllerHost, renderer: PopupMenuRendererPort);
85
93
  get directMenu(): DirectPopupMenu | undefined;
86
94
  get directQuery(): string;
95
+ draftSessionSelectorActive(): boolean;
96
+ closeDraftSessionSelectorForTabLifecycle(): void;
97
+ setResumeMenuMode(mode: "resume" | "draft"): void;
87
98
  setDirectMenu(menu: DirectPopupMenu | undefined): void;
88
99
  setDirectPreserveStatus(preserveStatus: boolean): void;
89
100
  setDirectQuery(query: string): void;
@@ -96,7 +107,11 @@ export declare class AppPopupMenuController {
96
107
  }): void;
97
108
  getActivePopupMenu(active: ActivePopupMenu): PopupMenu<unknown>;
98
109
  moveActivePopupMenuSelection(delta: number): boolean;
110
+ moveActiveModelThinkingLevel(delta: number): boolean;
111
+ toggleModelVisibilityMode(): boolean;
112
+ modelVisibilityModeActive(): boolean;
99
113
  scrollActivePopupMenu(delta: number): boolean;
114
+ selectActivePopupMenuIndex(index: number): ActivePopupMenu | undefined;
100
115
  handleDirectPopupInput(char: string): boolean;
101
116
  openDirectPopupMenu(menu: DirectPopupMenu, options?: {
102
117
  preserveStatus?: boolean;
@@ -112,21 +127,21 @@ export declare class AppPopupMenuController {
112
127
  closeQueueMessageMenu(): void;
113
128
  resetConversationMenuState(): void;
114
129
  closeModelSelection(): void;
115
- closeThinkingSelection(): void;
116
130
  closeSlashCommandSelection(): void;
117
131
  closeMenusForTabSwitch(): void;
118
132
  cancelActivePopupMenu(): void;
119
133
  autocompleteSlashCommand(): void;
120
134
  autocompleteModel(): boolean;
121
- autocompleteThinking(): boolean;
122
135
  selectedSlashCommand(): SlashCommand | undefined;
123
136
  selectedModel(): {
124
137
  value: ModelMenuValue;
125
138
  direct: boolean;
126
139
  } | undefined;
127
- selectedThinking(): {
128
- value: ThinkingMenuValue;
140
+ selectedModelThinking(): {
141
+ value: ModelMenuValue;
142
+ thinkingLevel: ThinkingLevel;
129
143
  direct: boolean;
144
+ source: "model" | "thinking";
130
145
  } | undefined;
131
146
  selectedResume(): ResumeMenuValue | undefined;
132
147
  selectedUserMessageAction(): {
@@ -164,7 +179,14 @@ export declare class AppPopupMenuController {
164
179
  private updateResumeMenuLoadedState;
165
180
  private resumeMenuLoadedSessionCount;
166
181
  private syncModelMenu;
167
- private syncThinkingMenu;
182
+ private modelThinkingQuery;
183
+ private stageThinkingFromQuery;
184
+ private modelThinkingMenuState;
185
+ private syncModelThinkingToSelectedModel;
186
+ private rememberStagedThinking;
187
+ private selectedModelThinkingLevels;
188
+ private clampThinkingLevel;
189
+ private resetModelThinkingState;
168
190
  private syncResumeMenu;
169
191
  private syncUserMessageMenu;
170
192
  private syncUserMessageJumpMenu;
@@ -189,4 +211,4 @@ export type UserMessageJumpSourceItem = {
189
211
  };
190
212
  export declare function buildUserMessageJumpItems(entries: readonly Entry[] | readonly UserMessageJumpSourceItem[]): PopupMenuItem<UserMessageJumpMenuValue>[];
191
213
  export declare function filterUserMessageJumpItems(items: readonly PopupMenuItem<UserMessageJumpMenuValue>[], query: string): PopupMenuItem<UserMessageJumpMenuValue>[];
192
- export type { ModelPopupMenuValue, QueueMessagePopupMenuValue, ResumePopupMenuValue, SlashCommandMenuValue, ThinkingPopupMenuValue, UserMessageJumpPopupMenuValue, UserMessagePopupMenuValue, };
214
+ export type { ModelPopupMenuValue, QueueMessagePopupMenuValue, ResumePopupMenuValue, SlashCommandMenuValue, UserMessageJumpPopupMenuValue, UserMessagePopupMenuValue, };