pi-ui-extend 1.0.42 → 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 (233) hide show
  1. package/README.md +41 -12
  2. package/dist/app/app.d.ts +10 -0
  3. package/dist/app/app.js +132 -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 +3 -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 +51 -34
  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 +14 -0
  17. package/dist/app/commands/reload-context-inventory.js +12 -1
  18. package/dist/app/input/autocomplete-controller.js +61 -34
  19. package/dist/app/input/input-action-controller.d.ts +2 -0
  20. package/dist/app/input/input-action-controller.js +8 -1
  21. package/dist/app/input/input-controller.d.ts +2 -1
  22. package/dist/app/input/input-controller.js +7 -2
  23. package/dist/app/input/prompt-enhancer-controller.js +53 -35
  24. package/dist/app/input/voice-controller.d.ts +41 -45
  25. package/dist/app/input/voice-controller.js +351 -419
  26. package/dist/app/model/model-usage-controller.js +17 -7
  27. package/dist/app/model/model-usage-status.d.ts +4 -1
  28. package/dist/app/model/model-usage-status.js +270 -46
  29. package/dist/app/popup/menu-items-controller.d.ts +13 -3
  30. package/dist/app/popup/menu-items-controller.js +37 -21
  31. package/dist/app/popup/popup-action-controller.d.ts +12 -2
  32. package/dist/app/popup/popup-action-controller.js +77 -24
  33. package/dist/app/popup/popup-menu-controller.d.ts +36 -14
  34. package/dist/app/popup/popup-menu-controller.js +239 -69
  35. package/dist/app/rendering/dcp-stats.d.ts +9 -4
  36. package/dist/app/rendering/dcp-stats.js +40 -425
  37. package/dist/app/rendering/popup-menu-renderer.d.ts +3 -5
  38. package/dist/app/rendering/popup-menu-renderer.js +42 -37
  39. package/dist/app/rendering/render-controller.js +23 -2
  40. package/dist/app/rendering/status-line-renderer.d.ts +5 -0
  41. package/dist/app/rendering/status-line-renderer.js +41 -5
  42. package/dist/app/rendering/tab-line-renderer.js +26 -20
  43. package/dist/app/runtime.d.ts +12 -1
  44. package/dist/app/runtime.js +120 -12
  45. package/dist/app/screen/mouse-controller.d.ts +2 -0
  46. package/dist/app/screen/mouse-controller.js +17 -7
  47. package/dist/app/screen/status-controller.d.ts +4 -0
  48. package/dist/app/screen/status-controller.js +5 -0
  49. package/dist/app/session/lazy-session-manager.js +34 -0
  50. package/dist/app/session/session-event-controller.d.ts +1 -0
  51. package/dist/app/session/session-event-controller.js +10 -1
  52. package/dist/app/session/session-history.d.ts +1 -0
  53. package/dist/app/session/session-history.js +12 -1
  54. package/dist/app/session/session-lifecycle-controller.d.ts +6 -1
  55. package/dist/app/session/session-lifecycle-controller.js +10 -1
  56. package/dist/app/session/tabs-controller.d.ts +25 -1
  57. package/dist/app/session/tabs-controller.js +442 -153
  58. package/dist/app/subagents/subagents-widget-controller.d.ts +1 -0
  59. package/dist/app/subagents/subagents-widget-controller.js +6 -0
  60. package/dist/app/types.d.ts +11 -1
  61. package/dist/app/workspace/workspace-actions-controller.js +10 -2
  62. package/dist/app/workspace/workspace-undo.d.ts +1 -0
  63. package/dist/app/workspace/workspace-undo.js +1 -0
  64. package/dist/bundled-extensions/question/index.js +9 -1
  65. package/dist/bundled-extensions/question/remote.d.ts +4 -0
  66. package/dist/bundled-extensions/question/remote.js +33 -0
  67. package/dist/bundled-extensions/telegram-connector/bot.d.ts +43 -0
  68. package/dist/bundled-extensions/telegram-connector/bot.js +166 -0
  69. package/dist/bundled-extensions/telegram-connector/config.d.ts +8 -0
  70. package/dist/bundled-extensions/telegram-connector/config.js +87 -0
  71. package/dist/bundled-extensions/telegram-connector/coordinator.d.ts +66 -0
  72. package/dist/bundled-extensions/telegram-connector/coordinator.js +413 -0
  73. package/dist/bundled-extensions/telegram-connector/index.d.ts +3 -0
  74. package/dist/bundled-extensions/telegram-connector/index.js +195 -0
  75. package/dist/bundled-extensions/terminal-bell/index.d.ts +0 -8
  76. package/dist/bundled-extensions/terminal-bell/index.js +0 -76
  77. package/dist/bundled-extensions/workspace-undo/index.d.ts +26 -0
  78. package/dist/bundled-extensions/workspace-undo/index.js +191 -0
  79. package/dist/config.d.ts +21 -2
  80. package/dist/config.js +159 -32
  81. package/dist/default-pix-config.js +20 -10
  82. package/dist/schemas/pi-tools-suite-schema.d.ts +8 -4
  83. package/dist/schemas/pi-tools-suite-schema.js +11 -5
  84. package/dist/schemas/pix-schema.d.ts +12 -2
  85. package/dist/schemas/pix-schema.js +37 -9
  86. package/dist/schemas/tasks-schema.js +1 -1
  87. package/docs/concurrency.md +3 -1
  88. package/docs/desktop-mvp.md +10 -5
  89. package/docs/desktop-task-manager.md +81 -28
  90. package/docs/release.md +30 -6
  91. package/external/pi-tools-suite/README.md +165 -39
  92. package/external/pi-tools-suite/docs/session-recovery.md +7 -0
  93. package/external/pi-tools-suite/docs/subagent-model-pools.md +12 -5
  94. package/external/pi-tools-suite/docs/ui-qa-subagent.md +440 -0
  95. package/external/pi-tools-suite/package.json +6 -1
  96. package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +2 -1
  97. package/external/pi-tools-suite/src/antigravity-auth/constants.ts +9 -3
  98. package/external/pi-tools-suite/src/antigravity-auth/headers.ts +41 -3
  99. package/external/pi-tools-suite/src/antigravity-auth/models.ts +94 -21
  100. package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +5 -17
  101. package/external/pi-tools-suite/src/antigravity-auth/payload.ts +72 -7
  102. package/external/pi-tools-suite/src/antigravity-auth/stream.ts +13 -1
  103. package/external/pi-tools-suite/src/async-subagents/agents/implement.md +1 -1
  104. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/browser.mjs +346 -0
  105. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/desktop.mjs +1038 -0
  106. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/tui.mjs +759 -0
  107. package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/scripts/browser-qa-runner.mjs +32 -23
  108. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/chrome-devtools/chrome-devtools-provider.mjs +895 -0
  109. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/linux/linux-atspi.py +494 -0
  110. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/macos/macos-accessibility.swift +1085 -0
  111. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/bridge-client.mjs +50 -0
  112. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/native-terminal-host.mjs +501 -0
  113. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/windows/windows-uia.ps1 +454 -0
  114. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-auth.md +114 -0
  115. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-chrome-devtools.md +91 -0
  116. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-playwright.md +145 -0
  117. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser.md +82 -0
  118. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-linux.md +26 -0
  119. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-macos.md +29 -0
  120. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-windows.md +23 -0
  121. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop.md +54 -0
  122. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-native-terminal.md +59 -0
  123. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-pty.md +37 -0
  124. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui.md +60 -0
  125. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/scripts/ui-qa-runner.mjs +535 -0
  126. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa.md +75 -0
  127. package/external/pi-tools-suite/src/async-subagents/commands.ts +1 -1
  128. package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +1 -1
  129. package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +0 -2
  130. package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +16 -2
  131. package/external/pi-tools-suite/src/async-subagents/core/config.ts +40 -17
  132. package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +2 -1
  133. package/external/pi-tools-suite/src/async-subagents/core/registry.ts +158 -33
  134. package/external/pi-tools-suite/src/async-subagents/core/routing.ts +7 -4
  135. package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +34 -24
  136. package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +51 -45
  137. package/external/pi-tools-suite/src/async-subagents/lib.ts +9 -1
  138. package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +0 -1
  139. package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +2 -2
  140. package/external/pi-tools-suite/src/coding-discipline/index.ts +90 -59
  141. package/external/pi-tools-suite/src/config.ts +14 -0
  142. package/external/pi-tools-suite/src/context-gateway/accounting-log.ts +282 -0
  143. package/external/pi-tools-suite/src/context-gateway/config.ts +66 -1
  144. package/external/pi-tools-suite/src/context-gateway/efficiency.ts +414 -0
  145. package/external/pi-tools-suite/src/context-gateway/enforcement.ts +123 -3
  146. package/external/pi-tools-suite/src/context-gateway/index.ts +137 -4
  147. package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +5 -5
  148. package/external/pi-tools-suite/src/context-gateway/telemetry.ts +2 -2
  149. package/external/pi-tools-suite/src/context-gateway/types.ts +8 -1
  150. package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +39 -4
  151. package/external/pi-tools-suite/src/dcp/auto-compress.ts +41 -14
  152. package/external/pi-tools-suite/src/dcp/commands.ts +14 -156
  153. package/external/pi-tools-suite/src/dcp/compress-tool.ts +8 -2
  154. package/external/pi-tools-suite/src/dcp/compression-progress.ts +22 -0
  155. package/external/pi-tools-suite/src/dcp/config.ts +58 -4
  156. package/external/pi-tools-suite/src/dcp/conversation-index.ts +36 -9
  157. package/external/pi-tools-suite/src/dcp/diagnostics.ts +41 -0
  158. package/external/pi-tools-suite/src/dcp/fresh-tool-results.ts +38 -0
  159. package/external/pi-tools-suite/src/dcp/index.ts +338 -66
  160. package/external/pi-tools-suite/src/dcp/journal.ts +126 -4
  161. package/external/pi-tools-suite/src/dcp/progress-controller.ts +2 -1
  162. package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +92 -2
  163. package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +36 -33
  164. package/external/pi-tools-suite/src/dcp/pruner.ts +1 -0
  165. package/external/pi-tools-suite/src/dcp/routine-pressure.ts +86 -0
  166. package/external/pi-tools-suite/src/dcp/state.ts +9 -0
  167. package/external/pi-tools-suite/src/dcp/statistics.d.ts +8 -0
  168. package/external/pi-tools-suite/src/dcp/statistics.js +156 -0
  169. package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +68 -16
  170. package/external/pi-tools-suite/src/lib/project.ts +36 -1
  171. package/external/pi-tools-suite/src/model-tools/index.ts +10 -7
  172. package/external/pi-tools-suite/src/repo-discovery/index.ts +304 -4
  173. package/external/pi-tools-suite/src/resource-registry/index.ts +282 -21
  174. package/external/pi-tools-suite/src/session-recovery/index.ts +17 -0
  175. package/external/pi-tools-suite/src/todo/index.ts +21 -0
  176. package/external/pi-tools-suite/src/todo/todo.ts +19 -1
  177. package/external/pi-tools-suite/src/tool-descriptions.ts +44 -15
  178. package/package.json +7 -8
  179. package/schemas/pi-tools-suite.json +44 -12
  180. package/schemas/pix.json +109 -15
  181. package/schemas/tasks.json +1 -2
  182. package/skills/simplify/SKILL.md +33 -5
  183. package/external/pi-tools-suite/docs/browser-qa-subagent.md +0 -196
  184. package/external/pi-tools-suite/src/async-subagents/agents/browser-qa.md +0 -598
  185. package/skills/playwright-cli/SKILL.md +0 -420
  186. package/skills/playwright-cli/references/element-attributes.md +0 -23
  187. package/skills/playwright-cli/references/playwright-tests.md +0 -50
  188. package/skills/playwright-cli/references/request-mocking.md +0 -87
  189. package/skills/playwright-cli/references/running-code.md +0 -241
  190. package/skills/playwright-cli/references/session-management.md +0 -273
  191. package/skills/playwright-cli/references/spec-driven-testing.md +0 -311
  192. package/skills/playwright-cli/references/storage-state.md +0 -290
  193. package/skills/playwright-cli/references/test-generation.md +0 -142
  194. package/skills/playwright-cli/references/tracing.md +0 -154
  195. package/skills/playwright-cli/references/video-recording.md +0 -147
  196. package/skills/spec-wiki/SKILL.md +0 -55
  197. package/skills/spec-wiki/evals/evals.json +0 -132
  198. package/skills/spec-wiki/evals/files/bootstrap/architecture/rfc-007.md +0 -14
  199. package/skills/spec-wiki/evals/files/bootstrap/docs/how-to-pay.md +0 -4
  200. package/skills/spec-wiki/evals/files/bootstrap/docs/overview.md +0 -9
  201. package/skills/spec-wiki/evals/files/bootstrap/requirements/payment-behavior.md +0 -17
  202. package/skills/spec-wiki/evals/files/bootstrap/src/payments.ts +0 -12
  203. package/skills/spec-wiki/evals/files/bootstrap/tests/payments.test.ts +0 -11
  204. package/skills/spec-wiki/evals/files/focused/src/session.ts +0 -5
  205. package/skills/spec-wiki/evals/files/focused/tests/session.test.ts +0 -17
  206. package/skills/spec-wiki/evals/files/maintenance/low-signal/incoming/capture.txt +0 -2
  207. package/skills/spec-wiki/evals/files/maintenance/low-signal/src/capture.ts +0 -3
  208. package/skills/spec-wiki/evals/files/maintenance/move/docs/old-job-contract.md +0 -18
  209. package/skills/spec-wiki/evals/files/maintenance/move/src/job.ts +0 -5
  210. package/skills/spec-wiki/evals/files/maintenance/new-relation/docs/session-refresh.md +0 -24
  211. package/skills/spec-wiki/evals/files/maintenance/new-relation/incoming/refresh-worker.ts +0 -7
  212. package/skills/spec-wiki/evals/files/maintenance/new-relation/src/session.ts +0 -7
  213. package/skills/spec-wiki/evals/files/maintenance/no-impact/docs/auth-contract.md +0 -17
  214. package/skills/spec-wiki/evals/files/maintenance/no-impact/incoming/telemetry-format.ts +0 -3
  215. package/skills/spec-wiki/evals/files/maintenance/no-impact/src/auth.ts +0 -3
  216. package/skills/spec-wiki/evals/files/query/docs/how-to-run-jobs.md +0 -4
  217. package/skills/spec-wiki/evals/files/query/docs/spec-overview.md +0 -9
  218. package/skills/spec-wiki/evals/files/query/features/jobs/cancellation-contract.md +0 -15
  219. package/skills/spec-wiki/evals/files/query/features/jobs/retry-spec.md +0 -6
  220. package/skills/spec-wiki/evals/maintenance_regression.py +0 -311
  221. package/skills/spec-wiki/evals/retrieval-eval.md +0 -37
  222. package/skills/spec-wiki/evals/retrieval-evals.json +0 -37
  223. package/skills/spec-wiki/evals/trigger-evals.json +0 -94
  224. package/skills/spec-wiki/references/bootstrap.md +0 -100
  225. package/skills/spec-wiki/references/focused-spec.md +0 -117
  226. package/skills/spec-wiki/references/index-schema.md +0 -330
  227. package/skills/spec-wiki/references/maintenance.md +0 -134
  228. package/skills/spec-wiki/references/query.md +0 -74
  229. package/skills/spec-wiki/scripts/spec_wiki.py +0 -2076
  230. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-auth.example.jsonc +0 -0
  231. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-flow.example.jsonc +0 -0
  232. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.LICENSE +0 -0
  233. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.mjs +0 -0
@@ -2,7 +2,8 @@ import { resolve } from "node:path";
2
2
  import { fuzzySearch } from "../../fuzzy.js";
3
3
  import { PopupMenu } from "../../ui.js";
4
4
  import { sanitizeText } from "../rendering/render-text.js";
5
- import { RESUME_MENU_INITIAL_SESSION_ROWS, RESUME_MENU_LOAD_BATCH_ROWS, RESUME_MENU_LOAD_THRESHOLD_ROWS, RESUME_MENU_MAX_ROWS, SLASH_COMMAND_MENU_MAX_ROWS, THINKING_MENU_MAX_ROWS, } from "../constants.js";
5
+ import { RESUME_MENU_INITIAL_SESSION_ROWS, RESUME_MENU_LOAD_BATCH_ROWS, RESUME_MENU_LOAD_THRESHOLD_ROWS, RESUME_MENU_MAX_ROWS, SLASH_COMMAND_MENU_MAX_ROWS, THINKING_LEVELS, } from "../constants.js";
6
+ import { getSupportedThinkingLevels } from "@earendil-works/pi-ai";
6
7
  export class AppPopupMenuController {
7
8
  host;
8
9
  renderer;
@@ -15,7 +16,6 @@ export class AppPopupMenuController {
15
16
  };
16
17
  slashCommandMenu = new PopupMenu({ maxVisibleRows: SLASH_COMMAND_MENU_MAX_ROWS });
17
18
  modelMenu = new PopupMenu({ maxVisibleRows: SLASH_COMMAND_MENU_MAX_ROWS });
18
- thinkingMenu = new PopupMenu({ maxVisibleRows: THINKING_MENU_MAX_ROWS });
19
19
  resumeMenu = new PopupMenu({ maxVisibleRows: RESUME_MENU_MAX_ROWS });
20
20
  userMessageMenu = new PopupMenu({ maxVisibleRows: 4 });
21
21
  userMessageJumpMenu = new PopupMenu({ maxVisibleRows: RESUME_MENU_MAX_ROWS });
@@ -26,8 +26,13 @@ export class AppPopupMenuController {
26
26
  dismissedSlashCommandMenuInput;
27
27
  modelMenuQuery = "";
28
28
  dismissedModelMenuInput;
29
- thinkingMenuQuery = "";
29
+ modelThinkingInputQuery = "";
30
30
  dismissedThinkingMenuInput;
31
+ modelThinkingLevel;
32
+ modelThinkingSelectedRef;
33
+ stagedThinkingByModel = new Map();
34
+ modelThinkingSource = "model";
35
+ modelVisibilityMode = false;
31
36
  directPopupMenu;
32
37
  directPopupMenuPreserveStatus = false;
33
38
  directPopupMenuPlacement = "default";
@@ -35,6 +40,7 @@ export class AppPopupMenuController {
35
40
  resumeMenuQuery = "";
36
41
  resumeMenuSessionLimit = RESUME_MENU_INITIAL_SESSION_ROWS;
37
42
  resumeMenuAllSessionsLoaded = false;
43
+ resumeMenuMode = "resume";
38
44
  activeUserMessageEntryId;
39
45
  activeQueuedMessageEntryId;
40
46
  constructor(host, renderer) {
@@ -47,7 +53,29 @@ export class AppPopupMenuController {
47
53
  get directQuery() {
48
54
  return this.directPopupMenuQuery;
49
55
  }
56
+ draftSessionSelectorActive() {
57
+ return this.directPopupMenu === "resume"
58
+ && this.resumeMenuMode === "draft"
59
+ && this.directPopupMenuPlacement === "draft-surface";
60
+ }
61
+ closeDraftSessionSelectorForTabLifecycle() {
62
+ if (!this.draftSessionSelectorActive())
63
+ return;
64
+ this.directPopupMenu = undefined;
65
+ this.directPopupMenuQuery = "";
66
+ this.directPopupMenuPreserveStatus = false;
67
+ this.directPopupMenuPlacement = "default";
68
+ this.resumeMenuMode = "resume";
69
+ this.resumeMenu.close();
70
+ }
71
+ setResumeMenuMode(mode) {
72
+ this.resumeMenuMode = mode;
73
+ }
50
74
  setDirectMenu(menu) {
75
+ if (this.directPopupMenu === "resume" && menu !== "resume")
76
+ this.resumeMenuMode = "resume";
77
+ if (menu !== this.directPopupMenu && (menu === "model" || menu === "thinking" || this.directPopupMenu === "model" || this.directPopupMenu === "thinking"))
78
+ this.resetModelThinkingState();
51
79
  this.directPopupMenu = menu;
52
80
  if (!menu)
53
81
  this.directPopupMenuPlacement = "default";
@@ -113,7 +141,7 @@ export class AppPopupMenuController {
113
141
  case "model":
114
142
  return this.modelMenu;
115
143
  case "thinking":
116
- return this.thinkingMenu;
144
+ return this.modelMenu;
117
145
  case "resume":
118
146
  return this.resumeMenu;
119
147
  case "slash":
@@ -125,17 +153,61 @@ export class AppPopupMenuController {
125
153
  if (!active)
126
154
  return false;
127
155
  this.getActivePopupMenu(active).moveSelection(delta);
156
+ if (active === "model")
157
+ this.syncModelThinkingToSelectedModel();
158
+ this.host.render();
159
+ return true;
160
+ }
161
+ moveActiveModelThinkingLevel(delta) {
162
+ if (this.syncActivePopupMenu() !== "model")
163
+ return false;
164
+ if (this.modelVisibilityMode)
165
+ return true;
166
+ const state = this.modelThinkingMenuState();
167
+ const levels = state.availableThinkingLevels;
168
+ if (levels.length === 0)
169
+ return true;
170
+ const currentIndex = Math.max(0, levels.indexOf(state.thinkingLevel));
171
+ const nextIndex = (currentIndex + delta + levels.length) % levels.length;
172
+ this.modelThinkingLevel = levels[nextIndex] ?? state.thinkingLevel;
173
+ this.rememberStagedThinking();
128
174
  this.host.render();
129
175
  return true;
130
176
  }
177
+ toggleModelVisibilityMode() {
178
+ if (this.syncActivePopupMenu() !== "model")
179
+ return false;
180
+ this.modelVisibilityMode = !this.modelVisibilityMode;
181
+ this.resetPopupMenuSelection(this.modelMenu);
182
+ this.syncModelThinkingToSelectedModel();
183
+ this.host.render();
184
+ return true;
185
+ }
186
+ modelVisibilityModeActive() {
187
+ return this.modelVisibilityMode && this.syncActivePopupMenu() === "model";
188
+ }
131
189
  scrollActivePopupMenu(delta) {
132
190
  const active = this.syncActivePopupMenu();
133
191
  if (!active)
134
192
  return false;
135
193
  this.getActivePopupMenu(active).scroll(delta);
194
+ if (active === "model")
195
+ this.syncModelThinkingToSelectedModel();
136
196
  this.host.render();
137
197
  return true;
138
198
  }
199
+ selectActivePopupMenuIndex(index) {
200
+ const active = this.syncActivePopupMenu();
201
+ if (!active)
202
+ return undefined;
203
+ const menu = this.getActivePopupMenu(active);
204
+ menu.selectedIndex = index;
205
+ menu.moveSelection(0);
206
+ if (active === "model")
207
+ this.syncModelThinkingToSelectedModel();
208
+ this.host.render();
209
+ return active;
210
+ }
139
211
  handleDirectPopupInput(char) {
140
212
  const active = this.directPopupMenu;
141
213
  if (!active)
@@ -161,6 +233,10 @@ export class AppPopupMenuController {
161
233
  this.closeSdkMenu(undefined, { render: false, restoreStatus: false });
162
234
  }
163
235
  this.directPopupMenu = menu;
236
+ if (menu === "model" || menu === "thinking") {
237
+ this.resetModelThinkingState();
238
+ this.modelThinkingSource = menu;
239
+ }
164
240
  this.directPopupMenuPreserveStatus = options.preserveStatus === true;
165
241
  this.directPopupMenuPlacement = options.placement ?? "default";
166
242
  this.directPopupMenuQuery = "";
@@ -174,7 +250,6 @@ export class AppPopupMenuController {
174
250
  this.dismissedThinkingMenuInput = undefined;
175
251
  this.slashCommandMenu.close();
176
252
  this.modelMenu.close();
177
- this.thinkingMenu.close();
178
253
  this.resumeMenu.close();
179
254
  this.userMessageMenu.close();
180
255
  this.queueMessageMenu.close();
@@ -202,7 +277,9 @@ export class AppPopupMenuController {
202
277
  openResumeMenuWithQuery(query) {
203
278
  this.resetPopupMenuSelection(this.resumeMenu);
204
279
  this.resetResumeMenuLazyState(query);
205
- this.resumeMenu.openWithItems(this.withoutCloseMenuItems(this.host.getResumeMenuItems(query, this.resumeMenuSessionLimit)));
280
+ this.resumeMenu.openWithItems(this.withoutCloseMenuItems(this.host.getResumeMenuItems(query, this.resumeMenuSessionLimit, {
281
+ draft: this.resumeMenuMode === "draft",
282
+ })));
206
283
  this.updateResumeMenuLoadedState();
207
284
  }
208
285
  closeResumeMenu() {
@@ -247,17 +324,13 @@ export class AppPopupMenuController {
247
324
  }
248
325
  closeModelSelection() {
249
326
  this.modelMenu.close();
250
- this.directPopupMenu = undefined;
327
+ if (this.directPopupMenu === "model" || this.directPopupMenu === "thinking")
328
+ this.directPopupMenu = undefined;
251
329
  this.directPopupMenuPreserveStatus = false;
252
330
  this.directPopupMenuQuery = "";
253
331
  this.dismissedModelMenuInput = undefined;
254
- }
255
- closeThinkingSelection() {
256
- this.thinkingMenu.close();
257
- this.directPopupMenu = undefined;
258
- this.directPopupMenuPreserveStatus = false;
259
- this.directPopupMenuQuery = "";
260
332
  this.dismissedThinkingMenuInput = undefined;
333
+ this.resetModelThinkingState();
261
334
  }
262
335
  closeSlashCommandSelection() {
263
336
  this.slashCommandMenu.close();
@@ -271,11 +344,11 @@ export class AppPopupMenuController {
271
344
  this.directPopupMenuQuery = "";
272
345
  this.directPopupMenuPreserveStatus = false;
273
346
  this.directPopupMenuPlacement = "default";
347
+ this.resumeMenuMode = "resume";
274
348
  this.activeUserMessageEntryId = undefined;
275
349
  this.activeQueuedMessageEntryId = undefined;
276
350
  this.slashCommandMenu.close();
277
351
  this.modelMenu.close();
278
- this.thinkingMenu.close();
279
352
  this.resumeMenu.close();
280
353
  this.userMessageMenu.close();
281
354
  this.userMessageJumpMenu.close();
@@ -285,6 +358,7 @@ export class AppPopupMenuController {
285
358
  this.dismissedSlashCommandMenuInput = input;
286
359
  this.dismissedModelMenuInput = input;
287
360
  this.dismissedThinkingMenuInput = input;
361
+ this.resetModelThinkingState();
288
362
  }
289
363
  cancelActivePopupMenu() {
290
364
  const active = this.syncActivePopupMenu();
@@ -293,17 +367,22 @@ export class AppPopupMenuController {
293
367
  return;
294
368
  }
295
369
  if (this.directPopupMenu) {
370
+ const closingResume = this.directPopupMenu === "resume";
371
+ const closingCombinedModelMenu = this.directPopupMenu === "model" || this.directPopupMenu === "thinking";
296
372
  this.directPopupMenu = undefined;
297
373
  this.directPopupMenuQuery = "";
298
374
  this.activeUserMessageEntryId = undefined;
299
375
  this.activeQueuedMessageEntryId = undefined;
300
376
  this.modelMenu.close();
301
- this.thinkingMenu.close();
302
377
  this.resumeMenu.close();
303
378
  this.userMessageMenu.close();
304
379
  this.userMessageJumpMenu.close();
305
380
  this.queueMessageMenu.close();
306
381
  this.sdkMenu.close();
382
+ if (closingCombinedModelMenu)
383
+ this.resetModelThinkingState();
384
+ if (closingResume)
385
+ this.resumeMenuMode = "resume";
307
386
  const preserveStatus = this.directPopupMenuPreserveStatus;
308
387
  this.directPopupMenuPreserveStatus = false;
309
388
  if (!preserveStatus)
@@ -313,11 +392,9 @@ export class AppPopupMenuController {
313
392
  }
314
393
  if (active === "model") {
315
394
  this.dismissedModelMenuInput = this.host.getInput();
316
- this.modelMenu.close();
317
- }
318
- else if (active === "thinking") {
319
395
  this.dismissedThinkingMenuInput = this.host.getInput();
320
- this.thinkingMenu.close();
396
+ this.modelMenu.close();
397
+ this.resetModelThinkingState();
321
398
  }
322
399
  else if (active === "slash") {
323
400
  this.dismissedSlashCommandMenuInput = this.host.getInput();
@@ -337,24 +414,12 @@ export class AppPopupMenuController {
337
414
  autocompleteModel() {
338
415
  if (!this.syncModelMenu())
339
416
  return false;
340
- const selected = this.selectedModel();
417
+ const selected = this.selectedModelThinking();
341
418
  if (!selected)
342
419
  return true;
343
420
  if (selected.direct)
344
421
  return true;
345
- this.host.setInput(`/model ${selected.value.ref}`);
346
- this.host.render();
347
- return true;
348
- }
349
- autocompleteThinking() {
350
- if (!this.syncThinkingMenu())
351
- return false;
352
- const selected = this.selectedThinking();
353
- if (!selected)
354
- return true;
355
- if (selected.direct)
356
- return true;
357
- this.host.setInput(`/thinking ${selected.value.level}`);
422
+ this.host.setInput(`/model ${selected.value.ref}:${selected.thinkingLevel}`);
358
423
  this.host.render();
359
424
  return true;
360
425
  }
@@ -369,15 +434,21 @@ export class AppPopupMenuController {
369
434
  const value = this.modelMenu.selectedItem()?.value;
370
435
  if (!value)
371
436
  return undefined;
372
- return { value, direct: this.directPopupMenu === "model" };
437
+ return { value, direct: this.directPopupMenu === "model" || this.directPopupMenu === "thinking" };
373
438
  }
374
- selectedThinking() {
375
- if (!this.syncThinkingMenu())
439
+ selectedModelThinking() {
440
+ if (!this.syncModelMenu())
376
441
  return undefined;
377
- const value = this.thinkingMenu.selectedItem()?.value;
442
+ const value = this.modelMenu.selectedItem()?.value;
378
443
  if (!value)
379
444
  return undefined;
380
- return { value, direct: this.directPopupMenu === "thinking" };
445
+ const state = this.modelThinkingMenuState();
446
+ return {
447
+ value,
448
+ thinkingLevel: state.thinkingLevel,
449
+ direct: this.directPopupMenu === "model" || this.directPopupMenu === "thinking",
450
+ source: state.source,
451
+ };
381
452
  }
382
453
  selectedResume() {
383
454
  if (!this.syncResumeMenu())
@@ -426,8 +497,6 @@ export class AppPopupMenuController {
426
497
  return "sdk-menu";
427
498
  if (this.syncModelMenu())
428
499
  return "model";
429
- if (this.syncThinkingMenu())
430
- return "thinking";
431
500
  if (this.syncSlashCommandMenu())
432
501
  return "slash";
433
502
  return undefined;
@@ -444,14 +513,13 @@ export class AppPopupMenuController {
444
513
  directQuery: this.directPopupMenuQuery,
445
514
  allSessionsLoaded: this.resumeMenuAllSessionsLoaded,
446
515
  loadedSessionCount: this.resumeMenuLoadedSessionCount(),
516
+ draft: this.resumeMenuMode === "draft",
447
517
  });
448
518
  }
449
519
  if (this.syncSdkMenu())
450
520
  return this.renderer.renderSdkMenu(width, this.sdkMenu, this.sdkMenuRequest, this.directPopupMenuQuery);
451
521
  if (this.syncModelMenu())
452
- return this.renderer.renderModelMenu(width, this.modelMenu);
453
- if (this.syncThinkingMenu())
454
- return this.renderer.renderThinkingMenu(width, this.thinkingMenu);
522
+ return this.renderer.renderModelMenu(width, this.modelMenu, this.modelThinkingMenuState());
455
523
  return this.syncSlashCommandMenu() ? this.renderer.renderSlashCommandMenu(width, this.slashCommandMenu) : [];
456
524
  }
457
525
  popupMenuWidth(columns) {
@@ -516,44 +584,146 @@ export class AppPopupMenuController {
516
584
  return this.resumeMenu.items.filter((item) => item.value.kind === "session").length;
517
585
  }
518
586
  syncModelMenu() {
519
- if (this.directPopupMenu === "model") {
587
+ if (this.directPopupMenu === "model" || this.directPopupMenu === "thinking") {
588
+ const source = this.directPopupMenu;
589
+ const opening = !this.modelMenu.open || this.modelThinkingSource !== source;
590
+ if (opening) {
591
+ this.resetPopupMenuSelection(this.modelMenu);
592
+ this.resetModelThinkingState();
593
+ this.modelThinkingSource = source;
594
+ }
520
595
  this.closeMenusExcept("model");
521
- this.modelMenu.openWithItems(this.withoutCloseMenuItems(this.host.getModelMenuItems(this.directPopupMenuQuery)));
596
+ this.modelMenu.openWithItems(this.withoutCloseMenuItems(this.host.getModelMenuItems(this.directPopupMenuQuery, this.modelVisibilityMode)));
597
+ this.syncModelThinkingToSelectedModel();
522
598
  return true;
523
599
  }
524
600
  const parsed = this.host.parseSlashInput(this.host.getInput());
525
- if (parsed?.commandName.toLowerCase() !== "model" || this.dismissedModelMenuInput === this.host.getInput()) {
601
+ const source = parsed?.commandName.toLowerCase();
602
+ const combinedSource = source === "model" || source === "thinking" ? source : undefined;
603
+ const dismissed = combinedSource === "thinking"
604
+ ? this.dismissedThinkingMenuInput === this.host.getInput()
605
+ : this.dismissedModelMenuInput === this.host.getInput();
606
+ if (!combinedSource || dismissed) {
607
+ if (this.modelMenu.open)
608
+ this.resetModelThinkingState();
526
609
  this.modelMenu.close();
527
610
  return false;
528
611
  }
529
- const query = parsed.hasArguments ? parsed.arguments : "";
530
- if (this.modelMenuQuery !== query) {
612
+ const rawQuery = parsed?.hasArguments ? parsed.arguments : "";
613
+ const normalizedThinkingQuery = rawQuery.trim().toLowerCase();
614
+ const parsedQuery = combinedSource === "model"
615
+ ? this.modelThinkingQuery(rawQuery)
616
+ : THINKING_LEVELS.includes(normalizedThinkingQuery)
617
+ ? { modelQuery: "", thinkingQuery: normalizedThinkingQuery }
618
+ : { modelQuery: rawQuery };
619
+ const opening = !this.modelMenu.open || this.modelThinkingSource !== combinedSource;
620
+ if (opening || this.modelMenuQuery !== parsedQuery.modelQuery) {
531
621
  this.resetPopupMenuSelection(this.modelMenu);
532
- this.modelMenuQuery = query;
622
+ this.modelMenuQuery = parsedQuery.modelQuery;
623
+ }
624
+ if (opening) {
625
+ this.resetModelThinkingState();
626
+ this.modelThinkingSource = combinedSource;
533
627
  }
534
628
  this.closeMenusExcept("model");
535
- this.modelMenu.openWithItems(this.withoutCloseMenuItems(this.host.getModelMenuItems(query)));
629
+ this.modelMenu.openWithItems(this.withoutCloseMenuItems(this.host.getModelMenuItems(parsedQuery.modelQuery, this.modelVisibilityMode)));
630
+ this.syncModelThinkingToSelectedModel();
631
+ if (parsedQuery.thinkingQuery !== undefined && this.modelThinkingInputQuery !== parsedQuery.thinkingQuery) {
632
+ this.modelThinkingInputQuery = parsedQuery.thinkingQuery;
633
+ this.stageThinkingFromQuery(parsedQuery.thinkingQuery);
634
+ }
536
635
  return true;
537
636
  }
538
- syncThinkingMenu() {
539
- if (this.directPopupMenu === "thinking") {
540
- this.closeMenusExcept("thinking");
541
- this.thinkingMenu.openWithItems(this.withoutCloseMenuItems(this.host.getThinkingMenuItems(this.directPopupMenuQuery)));
542
- return true;
637
+ modelThinkingQuery(query) {
638
+ const trimmed = query.trim();
639
+ const separator = trimmed.lastIndexOf(":");
640
+ if (separator <= trimmed.indexOf("/"))
641
+ return { modelQuery: query };
642
+ const thinkingQuery = trimmed.slice(separator + 1).toLowerCase();
643
+ if (!THINKING_LEVELS.includes(thinkingQuery))
644
+ return { modelQuery: query };
645
+ return { modelQuery: trimmed.slice(0, separator), thinkingQuery };
646
+ }
647
+ stageThinkingFromQuery(query) {
648
+ if (!query.trim())
649
+ return;
650
+ const normalized = query.trim().toLowerCase();
651
+ const level = THINKING_LEVELS.includes(normalized)
652
+ ? normalized
653
+ : this.host.getThinkingMenuItems(query)[0]?.value.level;
654
+ if (!level)
655
+ return;
656
+ this.modelThinkingLevel = this.clampThinkingLevel(level, this.selectedModelThinkingLevels());
657
+ this.rememberStagedThinking();
658
+ }
659
+ modelThinkingMenuState() {
660
+ this.syncModelThinkingToSelectedModel();
661
+ const availableThinkingLevels = this.selectedModelThinkingLevels();
662
+ return {
663
+ thinkingLevel: this.modelThinkingLevel ?? availableThinkingLevels[0] ?? "off",
664
+ availableThinkingLevels,
665
+ source: this.modelThinkingSource,
666
+ visibilityMode: this.modelVisibilityMode,
667
+ };
668
+ }
669
+ syncModelThinkingToSelectedModel() {
670
+ const selected = this.modelMenu.selectedItem()?.value;
671
+ if (!selected) {
672
+ this.modelThinkingSelectedRef = undefined;
673
+ return;
543
674
  }
544
- const parsed = this.host.parseSlashInput(this.host.getInput());
545
- if (parsed?.commandName.toLowerCase() !== "thinking" || this.dismissedThinkingMenuInput === this.host.getInput()) {
546
- this.thinkingMenu.close();
547
- return false;
675
+ if (this.modelThinkingSelectedRef
676
+ && this.modelThinkingSelectedRef !== selected.ref
677
+ && this.modelThinkingLevel !== undefined) {
678
+ this.stagedThinkingByModel.set(this.modelThinkingSelectedRef, this.modelThinkingLevel);
548
679
  }
549
- const query = parsed.hasArguments ? parsed.arguments : "";
550
- if (this.thinkingMenuQuery !== query) {
551
- this.resetPopupMenuSelection(this.thinkingMenu);
552
- this.thinkingMenuQuery = query;
680
+ const levels = this.selectedModelThinkingLevels();
681
+ if (this.modelThinkingSelectedRef !== selected.ref || this.modelThinkingLevel === undefined) {
682
+ const currentThinking = this.host.session?.thinkingLevel ?? this.host.currentThinkingLevel?.() ?? "off";
683
+ const initial = this.stagedThinkingByModel.get(selected.ref)
684
+ ?? (selected.current ? currentThinking : this.host.rememberedThinkingLevel?.(selected.ref))
685
+ ?? currentThinking;
686
+ this.modelThinkingLevel = this.clampThinkingLevel(initial, levels);
687
+ this.modelThinkingSelectedRef = selected.ref;
688
+ this.stagedThinkingByModel.set(selected.ref, this.modelThinkingLevel);
553
689
  }
554
- this.closeMenusExcept("thinking");
555
- this.thinkingMenu.openWithItems(this.withoutCloseMenuItems(this.host.getThinkingMenuItems(query)));
556
- return true;
690
+ }
691
+ rememberStagedThinking() {
692
+ if (!this.modelThinkingSelectedRef || this.modelThinkingLevel === undefined)
693
+ return;
694
+ this.stagedThinkingByModel.set(this.modelThinkingSelectedRef, this.modelThinkingLevel);
695
+ }
696
+ selectedModelThinkingLevels() {
697
+ const model = this.modelMenu.selectedItem()?.value.model;
698
+ if (!model)
699
+ return ["off"];
700
+ const supported = getSupportedThinkingLevels(model);
701
+ const levels = THINKING_LEVELS.filter((level) => supported.includes(level));
702
+ return levels.length > 0 ? levels : ["off"];
703
+ }
704
+ clampThinkingLevel(level, availableLevels) {
705
+ if (availableLevels.includes(level))
706
+ return level;
707
+ const requestedIndex = THINKING_LEVELS.indexOf(level);
708
+ for (let index = Math.max(0, requestedIndex); index < THINKING_LEVELS.length; index += 1) {
709
+ const candidate = THINKING_LEVELS[index];
710
+ if (candidate && availableLevels.includes(candidate))
711
+ return candidate;
712
+ }
713
+ for (let index = requestedIndex - 1; index >= 0; index -= 1) {
714
+ const candidate = THINKING_LEVELS[index];
715
+ if (candidate && availableLevels.includes(candidate))
716
+ return candidate;
717
+ }
718
+ return availableLevels[0] ?? "off";
719
+ }
720
+ resetModelThinkingState() {
721
+ this.modelThinkingLevel = undefined;
722
+ this.modelThinkingSelectedRef = undefined;
723
+ this.stagedThinkingByModel.clear();
724
+ this.modelMenuQuery = "";
725
+ this.modelThinkingInputQuery = "";
726
+ this.modelVisibilityMode = false;
557
727
  }
558
728
  syncResumeMenu() {
559
729
  if (this.directPopupMenu !== "resume") {
@@ -562,7 +732,9 @@ export class AppPopupMenuController {
562
732
  }
563
733
  this.closeMenusExcept("resume");
564
734
  this.maybeGrowResumeMenuWindow(this.directPopupMenuQuery);
565
- this.resumeMenu.openWithItems(this.withoutCloseMenuItems(this.host.getResumeMenuItems(this.directPopupMenuQuery, this.resumeMenuSessionLimit)));
735
+ this.resumeMenu.openWithItems(this.withoutCloseMenuItems(this.host.getResumeMenuItems(this.directPopupMenuQuery, this.resumeMenuSessionLimit, {
736
+ draft: this.resumeMenuMode === "draft",
737
+ })));
566
738
  this.updateResumeMenuLoadedState();
567
739
  return true;
568
740
  }
@@ -642,8 +814,6 @@ export class AppPopupMenuController {
642
814
  this.slashCommandMenu.close();
643
815
  if (active !== "model")
644
816
  this.modelMenu.close();
645
- if (active !== "thinking")
646
- this.thinkingMenu.close();
647
817
  if (active !== "resume")
648
818
  this.resumeMenu.close();
649
819
  if (active !== "user-message")
@@ -1,7 +1,12 @@
1
1
  import type { AgentSession } from "@earendil-works/pi-coding-agent";
2
- type FormatDcpStatsOptions = {
3
- manualModeBaseline?: boolean;
4
- configPath?: string;
2
+ export type FormatDcpStatsOptions = {
3
+ /** Must contain the complete ACTIVE branch, never a presentation cursor. */
4
+ branch?: readonly unknown[];
5
5
  };
6
+ /** On-demand TUI path: read the full branch asynchronously without hydrating
7
+ * the lazy presentation manager or blocking terminal input. ACP supplies a
8
+ * complete branch directly to the synchronous formatter instead. */
9
+ export declare function loadDcpStatsToast(session: AgentSession): Promise<string>;
10
+ /** TUI and ACP use the same passive report as /dcp stats. Opening this view
11
+ * never re-runs pruning, mutates history, or launches a model. */
6
12
  export declare function formatDcpStatsToast(session: AgentSession, options?: FormatDcpStatsOptions): string;
7
- export {};