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
@@ -1,3 +1,4 @@
1
+ import { GitCommandActions } from "./command-git-actions.js";
1
2
  import { ModelCommandActions } from "./command-model-actions.js";
2
3
  import { NavigationCommandActions } from "./command-navigation-actions.js";
3
4
  import { createSlashCommands } from "./command-registry.js";
@@ -6,11 +7,13 @@ export class AppCommandController {
6
7
  host;
7
8
  slashCommands;
8
9
  modelActions;
10
+ gitActions;
9
11
  sessionActions;
10
12
  navigationActions;
11
13
  constructor(host) {
12
14
  this.host = host;
13
15
  this.modelActions = new ModelCommandActions(host);
16
+ this.gitActions = new GitCommandActions(host);
14
17
  this.sessionActions = new SessionCommandActions(host);
15
18
  this.navigationActions = new NavigationCommandActions(host);
16
19
  this.slashCommands = createSlashCommands(this.registryActions(), host);
@@ -18,9 +21,15 @@ export class AppCommandController {
18
21
  async runResumeCommand(queryOrOptions = "") {
19
22
  await this.navigationActions.runResumeCommand(queryOrOptions);
20
23
  }
24
+ async runDraftSessionSelector() {
25
+ await this.navigationActions.runResumeCommand({ preserveStatus: true, placement: "draft-surface", draft: true });
26
+ }
21
27
  async runModelCommand(model) {
22
28
  await this.modelActions.runModelCommand(model);
23
29
  }
30
+ async runModelThinkingCommand(model, level) {
31
+ await this.modelActions.runModelThinkingCommand(model, level);
32
+ }
24
33
  async runThinkingCommand(level) {
25
34
  await this.modelActions.runThinkingCommand(level);
26
35
  }
@@ -35,6 +44,8 @@ export class AppCommandController {
35
44
  runThinkingSlashCommand: (argumentsText) => this.modelActions.runThinkingSlashCommand(argumentsText),
36
45
  runDefaultThinkingSlashCommand: (argumentsText) => this.modelActions.runDefaultThinkingSlashCommand(argumentsText),
37
46
  runEnhanceCommand: () => this.host.enhancePrompt(),
47
+ runCodeReviewCommand: () => this.gitActions.runCodeReviewCommand(),
48
+ runCommitMessageCommand: () => this.gitActions.runCommitMessageCommand(),
38
49
  runExportCommand: (argumentsText) => this.sessionActions.runExportCommand(argumentsText),
39
50
  runImportCommand: (argumentsText) => this.sessionActions.runImportCommand(argumentsText),
40
51
  runShareCommand: () => this.sessionActions.runShareCommand(),
@@ -0,0 +1,25 @@
1
+ import type { AgentSessionRuntime } from "@earendil-works/pi-coding-agent";
2
+ import { type AsyncProcessResult, type RunProcessOptions } from "../process.js";
3
+ import { type CommandControllerHost } from "./command-host.js";
4
+ export type GitAssistantKind = "review" | "commit-message";
5
+ type GitProcessRunner = (command: string, args?: readonly string[], options?: RunProcessOptions) => Promise<AsyncProcessResult>;
6
+ type GitAssistantRunner = (runtime: AgentSessionRuntime, kind: GitAssistantKind, diff: string) => Promise<string>;
7
+ export type GitCommandActionsDeps = {
8
+ runProcess?: GitProcessRunner;
9
+ generateGitAssistantText?: GitAssistantRunner;
10
+ };
11
+ export declare class GitCommandActions {
12
+ private readonly host;
13
+ private readonly runProcess;
14
+ private readonly generateGitAssistantText;
15
+ constructor(host: CommandControllerHost, deps?: GitCommandActionsDeps);
16
+ runCodeReviewCommand(): Promise<void>;
17
+ runCommitMessageCommand(): Promise<void>;
18
+ private gitRoot;
19
+ private trackedDiff;
20
+ private reviewInput;
21
+ private untrackedFiles;
22
+ }
23
+ export declare function generateGitAssistantText(runtime: AgentSessionRuntime, kind: GitAssistantKind, diff: string): Promise<string>;
24
+ export declare function loadGitAssistantModelRefs(cwd: string, kind: GitAssistantKind, homeDir?: string): string[];
25
+ export {};
@@ -0,0 +1,381 @@
1
+ import { existsSync, lstatSync, readFileSync, readlinkSync, statSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { isAbsolute, relative, resolve, sep } from "node:path";
4
+ import { parse as parseJsonc } from "jsonc-parser";
5
+ import { getPixConfigPath, getProjectPixConfigPath } from "../../config.js";
6
+ import { createId } from "../id.js";
7
+ import { parseModelRef } from "../model/model-ref.js";
8
+ import { runProcess } from "../process.js";
9
+ import { captureCommandScope, isCommandScopeActive, } from "./command-host.js";
10
+ import { getIdleRuntime } from "./command-runtime.js";
11
+ const GIT_REVIEW_TIMEOUT_MS = 120_000;
12
+ const GIT_COMMIT_MESSAGE_TIMEOUT_MS = 45_000;
13
+ const GIT_REVIEW_MAX_TOKENS = 4_096;
14
+ const GIT_COMMIT_MESSAGE_MAX_TOKENS = 768;
15
+ const GIT_DIFF_MAX_CHARS = 200_000;
16
+ const UNTRACKED_FILE_MAX_BYTES = 128 * 1024;
17
+ const DEFAULT_GIT_REVIEW_MODEL = "openai-codex/gpt-5.6-luna:medium";
18
+ const DEFAULT_GIT_COMMIT_MESSAGE_MODEL = "openai-codex/gpt-5.6-luna:minimal";
19
+ const REVIEW_SYSTEM_PROMPT = `You review Git diffs as a senior software engineer.
20
+
21
+ Focus on correctness, regressions, edge cases, security, data loss, concurrency, and missing tests.
22
+ Report concrete findings in descending severity and include file/line context when the diff provides it.
23
+ Do not invent problems or request unrelated refactors.
24
+ Do not flag a deletion merely because code or functionality was removed. Report a deletion only when the diff gives concrete evidence of a surviving broken reference, violated contract, unintended data loss/security impact, or another specific regression.
25
+ If there are no significant findings, say that clearly and briefly.
26
+ Return concise Markdown suitable for a code-review panel.`;
27
+ const COMMIT_MESSAGE_SYSTEM_PROMPT = `You write Git commit messages from staged diffs.
28
+
29
+ Write an imperative subject line no longer than 72 characters.
30
+ Add a short body only when it materially improves understanding.
31
+ Describe what changed and why, not implementation trivia.
32
+ Output only the final commit message. Do not use Markdown fences or commentary.`;
33
+ export class GitCommandActions {
34
+ host;
35
+ runProcess;
36
+ generateGitAssistantText;
37
+ constructor(host, deps = {}) {
38
+ this.host = host;
39
+ this.runProcess = deps.runProcess ?? runProcess;
40
+ this.generateGitAssistantText = deps.generateGitAssistantText ?? generateGitAssistantText;
41
+ }
42
+ async runCodeReviewCommand() {
43
+ const runtime = getIdleRuntime(this.host, "code-review");
44
+ if (!runtime)
45
+ return;
46
+ const scope = captureCommandScope(this.host);
47
+ this.host.setStatus("collecting Git changes");
48
+ this.host.render();
49
+ const root = await this.gitRoot(runtime.cwd);
50
+ if (!isCommandScopeActive(this.host, scope))
51
+ return;
52
+ const diff = await this.reviewInput(root);
53
+ if (!isCommandScopeActive(this.host, scope))
54
+ return;
55
+ if (!diff.trim()) {
56
+ this.host.addEntry({ id: createId("system"), kind: "system", text: "No Git changes to review." });
57
+ this.host.setSessionStatus(runtime.session);
58
+ return;
59
+ }
60
+ this.host.setStatus("reviewing Git changes");
61
+ this.host.render();
62
+ const review = await this.generateGitAssistantText(runtime, "review", diff);
63
+ if (!isCommandScopeActive(this.host, scope))
64
+ return;
65
+ this.host.addEntry({ id: createId("system"), kind: "system", text: `Code review\n\n${review}` });
66
+ this.host.setSessionStatus(runtime.session);
67
+ this.host.toast.success("Code review complete");
68
+ }
69
+ async runCommitMessageCommand() {
70
+ const runtime = getIdleRuntime(this.host, "commit-message");
71
+ if (!runtime)
72
+ return;
73
+ const scope = captureCommandScope(this.host);
74
+ this.host.setStatus("reading staged changes");
75
+ this.host.render();
76
+ const root = await this.gitRoot(runtime.cwd);
77
+ if (!isCommandScopeActive(this.host, scope))
78
+ return;
79
+ const stagedDiff = await this.trackedDiff(root, true);
80
+ if (!isCommandScopeActive(this.host, scope))
81
+ return;
82
+ if (!stagedDiff.trim()) {
83
+ this.host.addEntry({ id: createId("system"), kind: "system", text: "There are no staged changes to commit." });
84
+ this.host.setSessionStatus(runtime.session);
85
+ this.host.toast.info("No staged changes");
86
+ return;
87
+ }
88
+ this.host.setStatus("generating commit message");
89
+ this.host.render();
90
+ const message = await this.generateGitAssistantText(runtime, "commit-message", capGitInput(stagedDiff));
91
+ if (!isCommandScopeActive(this.host, scope))
92
+ return;
93
+ this.host.addEntry({
94
+ id: createId("system"),
95
+ kind: "system",
96
+ text: `Generated commit message\n\n${message}`,
97
+ });
98
+ this.host.setSessionStatus(runtime.session);
99
+ const action = await this.host.showMenu([
100
+ {
101
+ value: "commit",
102
+ label: "Commit staged changes",
103
+ description: firstLine(message),
104
+ variant: "accent",
105
+ },
106
+ { value: "cancel", label: "Cancel" },
107
+ ], { title: "Create Git commit?", searchable: false, preserveStatus: true });
108
+ if (!isCommandScopeActive(this.host, scope))
109
+ return;
110
+ if (action !== "commit") {
111
+ this.host.addEntry({ id: createId("system"), kind: "system", text: "Commit cancelled." });
112
+ this.host.setSessionStatus(runtime.session);
113
+ return;
114
+ }
115
+ const currentStagedDiff = await this.trackedDiff(root, true);
116
+ if (!isCommandScopeActive(this.host, scope))
117
+ return;
118
+ if (currentStagedDiff !== stagedDiff) {
119
+ this.host.addEntry({
120
+ id: createId("error"),
121
+ kind: "error",
122
+ text: "Staged changes changed after the commit message was generated. Run /commit-message again before committing.",
123
+ });
124
+ this.host.setSessionStatus(runtime.session);
125
+ this.host.toast.warning("Staged changes changed");
126
+ return;
127
+ }
128
+ this.host.setStatus("creating Git commit");
129
+ this.host.render();
130
+ const result = await this.runProcess("git", ["commit", "-F", "-"], {
131
+ cwd: root,
132
+ input: `${message.trim()}\n`,
133
+ timeoutMs: 120_000,
134
+ maxBufferBytes: 256 * 1024,
135
+ });
136
+ if (!isCommandScopeActive(this.host, scope))
137
+ return;
138
+ if (result.status !== 0) {
139
+ throw new Error(gitFailureMessage("git commit", result));
140
+ }
141
+ const detail = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join("\n");
142
+ this.host.addEntry({
143
+ id: createId("system"),
144
+ kind: "system",
145
+ text: detail ? `Git commit created\n\n${detail}` : "Git commit created.",
146
+ });
147
+ this.host.setSessionStatus(runtime.session);
148
+ this.host.toast.success("Git commit created");
149
+ }
150
+ async gitRoot(cwd) {
151
+ const result = await this.runProcess("git", ["rev-parse", "--show-toplevel"], {
152
+ cwd,
153
+ timeoutMs: 10_000,
154
+ maxBufferBytes: 16 * 1024,
155
+ });
156
+ if (result.status !== 0)
157
+ throw new Error(gitFailureMessage("git rev-parse", result));
158
+ const root = result.stdout.trim();
159
+ if (!root)
160
+ throw new Error("Git repository root is unavailable");
161
+ return root;
162
+ }
163
+ async trackedDiff(root, staged) {
164
+ const args = ["diff", ...(staged ? ["--cached"] : []), "--no-ext-diff", "--no-color", "--minimal"];
165
+ const result = await this.runProcess("git", args, {
166
+ cwd: root,
167
+ timeoutMs: 20_000,
168
+ maxBufferBytes: GIT_DIFF_MAX_CHARS + 16 * 1024,
169
+ });
170
+ if (result.status !== 0)
171
+ throw new Error(gitFailureMessage(staged ? "git diff --cached" : "git diff", result));
172
+ return result.stdout;
173
+ }
174
+ async reviewInput(root) {
175
+ const staged = await this.trackedDiff(root, true);
176
+ const unstaged = await this.trackedDiff(root, false);
177
+ const untracked = await this.untrackedFiles(root);
178
+ const sections = [];
179
+ if (staged.trim())
180
+ sections.push(`# Staged changes\n\n${staged.trimEnd()}`);
181
+ if (unstaged.trim())
182
+ sections.push(`# Working tree changes\n\n${unstaged.trimEnd()}`);
183
+ if (untracked.trim())
184
+ sections.push(`# Untracked files\n\n${untracked.trimEnd()}`);
185
+ return capGitInput(sections.join("\n\n"));
186
+ }
187
+ async untrackedFiles(root) {
188
+ const result = await this.runProcess("git", ["ls-files", "--others", "--exclude-standard", "-z"], {
189
+ cwd: root,
190
+ timeoutMs: 10_000,
191
+ maxBufferBytes: GIT_DIFF_MAX_CHARS,
192
+ });
193
+ if (result.status !== 0)
194
+ throw new Error(gitFailureMessage("git ls-files", result));
195
+ const files = result.stdout.split("\0").filter(Boolean);
196
+ const sections = [];
197
+ let used = 0;
198
+ for (const file of files) {
199
+ const absolutePath = resolve(root, file);
200
+ const relativePath = relative(root, absolutePath);
201
+ if (isAbsolute(relativePath) || relativePath === ".." || relativePath.startsWith(`..${sep}`))
202
+ continue;
203
+ const label = displayGitPath(file);
204
+ let body;
205
+ try {
206
+ const info = lstatSync(absolutePath);
207
+ if (info.isSymbolicLink()) {
208
+ body = `new symbolic link -> ${readlinkSync(absolutePath)}`;
209
+ }
210
+ else if (!info.isFile()) {
211
+ body = "non-regular file omitted";
212
+ }
213
+ else if (statSync(absolutePath).size > UNTRACKED_FILE_MAX_BYTES) {
214
+ body = `file omitted: larger than ${UNTRACKED_FILE_MAX_BYTES} bytes`;
215
+ }
216
+ else {
217
+ const bytes = readFileSync(absolutePath);
218
+ body = bytes.includes(0)
219
+ ? "binary file omitted"
220
+ : bytes.toString("utf8").split(/\r?\n/u).map((line) => `+${line}`).join("\n");
221
+ }
222
+ }
223
+ catch {
224
+ body = "file became unavailable while collecting review input";
225
+ }
226
+ const section = `## ${label}\n\n--- /dev/null\n+++ b/${label}\n${body}`;
227
+ if (used + section.length > GIT_DIFF_MAX_CHARS) {
228
+ sections.push("[additional untracked files omitted: review input limit reached]");
229
+ break;
230
+ }
231
+ sections.push(section);
232
+ used += section.length;
233
+ }
234
+ return sections.join("\n\n");
235
+ }
236
+ }
237
+ export async function generateGitAssistantText(runtime, kind, diff) {
238
+ const normalizedDiff = diff.trim();
239
+ if (!normalizedDiff)
240
+ throw new Error("Git diff is empty");
241
+ const timeoutMs = kind === "review" ? GIT_REVIEW_TIMEOUT_MS : GIT_COMMIT_MESSAGE_TIMEOUT_MS;
242
+ const signal = AbortSignal.timeout(timeoutMs);
243
+ const modelRuntime = runtime.services.modelRuntime;
244
+ await modelRuntime.refresh({ signal });
245
+ let lastError;
246
+ for (const modelRef of loadGitAssistantModelRefs(runtime.cwd, kind)) {
247
+ if (signal.aborted)
248
+ throw signal.reason ?? new Error("Git assistant request aborted");
249
+ let parsed;
250
+ try {
251
+ parsed = parseModelRef(modelRef);
252
+ }
253
+ catch (error) {
254
+ lastError = error;
255
+ continue;
256
+ }
257
+ const model = modelRuntime.getModel(parsed.provider, parsed.modelId);
258
+ if (!model) {
259
+ lastError = new Error(`Git assistant model not found: ${parsed.provider}/${parsed.modelId}`);
260
+ continue;
261
+ }
262
+ try {
263
+ const tokenLimit = kind === "review" ? GIT_REVIEW_MAX_TOKENS : GIT_COMMIT_MESSAGE_MAX_TOKENS;
264
+ const maxTokens = model.maxTokens > 0 ? Math.min(model.maxTokens, tokenLimit) : tokenLimit;
265
+ let output = "";
266
+ let streamError;
267
+ const stream = modelRuntime.streamSimple({ ...model, maxTokens }, {
268
+ systemPrompt: kind === "review" ? REVIEW_SYSTEM_PROMPT : COMMIT_MESSAGE_SYSTEM_PROMPT,
269
+ messages: [{
270
+ role: "user",
271
+ content: [
272
+ kind === "review" ? "Review this diff." : "Write a commit message for this staged diff.",
273
+ "<git-diff>",
274
+ normalizedDiff,
275
+ "</git-diff>",
276
+ ].join("\n"),
277
+ timestamp: Date.now(),
278
+ }],
279
+ }, {
280
+ signal,
281
+ reasoning: parsed.thinkingLevel && parsed.thinkingLevel !== "off" ? parsed.thinkingLevel : "minimal",
282
+ cacheRetention: "none",
283
+ maxRetryDelayMs: 0,
284
+ maxRetries: 0,
285
+ maxTokens,
286
+ timeoutMs,
287
+ });
288
+ for await (const event of stream) {
289
+ if (event.type === "text_delta")
290
+ output += event.delta;
291
+ else if (event.type === "done" && !output)
292
+ output = assistantText(event.message);
293
+ else if (event.type === "error")
294
+ streamError = event.error.errorMessage ?? event.reason;
295
+ }
296
+ if (streamError)
297
+ throw new Error(streamError);
298
+ const cleaned = cleanupOutput(output);
299
+ if (!cleaned)
300
+ throw new Error("Git assistant returned an empty response");
301
+ return cleaned;
302
+ }
303
+ catch (error) {
304
+ if (signal.aborted)
305
+ throw signal.reason ?? error;
306
+ lastError = error;
307
+ }
308
+ }
309
+ throw lastError ?? new Error("No Git assistant models are configured");
310
+ }
311
+ export function loadGitAssistantModelRefs(cwd, kind, homeDir = homedir()) {
312
+ const defaults = kind === "review"
313
+ ? { modelRef: DEFAULT_GIT_REVIEW_MODEL, fallbackModels: [] }
314
+ : { modelRef: DEFAULT_GIT_COMMIT_MESSAGE_MODEL, fallbackModels: [] };
315
+ const globalConfig = { ...defaults, ...readGitAssistantModelConfig(getPixConfigPath(homeDir), kind) };
316
+ const projectConfig = readGitAssistantModelConfig(getProjectPixConfigPath(cwd), kind);
317
+ const resolved = { ...globalConfig, ...projectConfig };
318
+ return [...new Set([resolved.modelRef, ...resolved.fallbackModels].map((ref) => ref.trim()).filter(Boolean))];
319
+ }
320
+ function readGitAssistantModelConfig(path, kind) {
321
+ if (!existsSync(path))
322
+ return {};
323
+ try {
324
+ const parsed = parseJsonc(readFileSync(path, "utf8"));
325
+ if (!isRecord(parsed) || !isRecord(parsed.desktop) || !isRecord(parsed.desktop.git))
326
+ return {};
327
+ const git = parsed.desktop.git;
328
+ const modelValue = kind === "review" ? git.reviewModelRef : git.commitMessageModelRef;
329
+ const fallbackKey = kind === "review" ? "reviewFallbackModels" : "commitMessageFallbackModels";
330
+ const modelRef = typeof modelValue === "string" && modelValue.trim() ? modelValue.trim() : undefined;
331
+ const hasFallbackModels = Object.prototype.hasOwnProperty.call(git, fallbackKey);
332
+ return {
333
+ ...(modelRef ? { modelRef } : {}),
334
+ ...(hasFallbackModels ? { fallbackModels: modelFallbackList(git[fallbackKey]) } : {}),
335
+ };
336
+ }
337
+ catch {
338
+ return {};
339
+ }
340
+ }
341
+ function modelFallbackList(value) {
342
+ if (!Array.isArray(value))
343
+ return [];
344
+ return [...new Set(value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean))];
345
+ }
346
+ function capGitInput(value) {
347
+ if (value.length <= GIT_DIFF_MAX_CHARS)
348
+ return value;
349
+ const marker = "\n\n[Git diff truncated to fit the review input limit]";
350
+ return `${value.slice(0, GIT_DIFF_MAX_CHARS - marker.length)}${marker}`;
351
+ }
352
+ function cleanupOutput(value) {
353
+ let text = value.replace(/\r\n/gu, "\n").trim();
354
+ const fenced = /^```[^\n`]*\n([\s\S]*?)\n```$/u.exec(text);
355
+ if (fenced)
356
+ text = fenced[1].trim();
357
+ return text;
358
+ }
359
+ function assistantText(message) {
360
+ if (!isRecord(message))
361
+ return "";
362
+ const content = message.content;
363
+ if (typeof content === "string")
364
+ return content;
365
+ if (!Array.isArray(content))
366
+ return "";
367
+ return content.flatMap((part) => isRecord(part) && part.type === "text" && typeof part.text === "string" ? [part.text] : []).join("");
368
+ }
369
+ function firstLine(value) {
370
+ return value.trim().split(/\r?\n/u, 1)[0] ?? "Use the generated commit message";
371
+ }
372
+ function displayGitPath(value) {
373
+ return value.replaceAll("\n", "\\n").replaceAll("\r", "\\r");
374
+ }
375
+ function gitFailureMessage(command, result) {
376
+ const detail = result.stderr.trim() || result.stdout.trim() || result.error?.message;
377
+ return detail ? `${command} failed: ${detail}` : `${command} failed`;
378
+ }
379
+ function isRecord(value) {
380
+ return typeof value === "object" && value !== null && !Array.isArray(value);
381
+ }
@@ -7,6 +7,8 @@ export type DirectPopupMenu = Exclude<ActivePopupMenu, "slash">;
7
7
  export type CommandControllerHost = {
8
8
  readonly options: AppOptions;
9
9
  runtime(): AgentSessionRuntime | undefined;
10
+ inputScopeKey?(): string | undefined;
11
+ subagentTypes?(runtime: AgentSessionRuntime): readonly string[] | undefined;
10
12
  awaitCurrentSessionExtensions(runtime?: AgentSessionRuntime): Promise<void>;
11
13
  requestHistory(): AppRequestHistory;
12
14
  getInput(): string;
@@ -41,6 +43,7 @@ export type CommandControllerHost = {
41
43
  setDirectPopupMenuPreserveStatus(preserveStatus: boolean): void;
42
44
  getDirectPopupMenuQuery(): string;
43
45
  setDirectPopupMenuQuery(query: string): void;
46
+ setResumeMenuMode?(mode: "resume" | "draft"): void;
44
47
  refreshUserMessageJumpMenuItems(): Promise<void>;
45
48
  getResumeLoading(): boolean;
46
49
  getResumeSessions(): readonly SessionInfo[];
@@ -54,6 +57,7 @@ export type CommandControllerHost = {
54
57
  export type CommandScope = {
55
58
  readonly runtime: AgentSessionRuntime | undefined;
56
59
  readonly session: AgentSession | undefined;
60
+ readonly inputScopeKey: string | undefined;
57
61
  };
58
62
  export declare function captureCommandScope(host: CommandControllerHost): CommandScope;
59
63
  export declare function isCommandRuntimeActive(host: CommandControllerHost, runtime: AgentSessionRuntime): boolean;
@@ -1,10 +1,13 @@
1
1
  export function captureCommandScope(host) {
2
2
  const runtime = host.runtime();
3
- return { runtime, session: runtime?.session };
3
+ return { runtime, session: runtime?.session, inputScopeKey: host.inputScopeKey?.() };
4
4
  }
5
5
  export function isCommandRuntimeActive(host, runtime) {
6
6
  return host.isRunning() && host.runtime() === runtime;
7
7
  }
8
8
  export function isCommandScopeActive(host, scope) {
9
- return host.isRunning() && host.runtime() === scope.runtime && scope.runtime?.session === scope.session;
9
+ return host.isRunning()
10
+ && host.runtime() === scope.runtime
11
+ && scope.runtime?.session === scope.session
12
+ && (host.inputScopeKey === undefined || host.inputScopeKey() === scope.inputScopeKey);
10
13
  }
@@ -12,6 +12,7 @@ export declare class ModelCommandActions {
12
12
  runThinkingSlashCommand(argumentsText: string): Promise<void>;
13
13
  runDefaultThinkingSlashCommand(argumentsText: string): Promise<void>;
14
14
  runModelCommand(model: SessionModel): Promise<void>;
15
+ runModelThinkingCommand(model: SessionModel, level: ThinkingLevel): Promise<void>;
15
16
  runThinkingCommand(level: ThinkingLevel): Promise<void>;
16
17
  private addPersistentSystemEntry;
17
18
  private reloadAfterModelChange;
@@ -4,6 +4,7 @@ import { getProjectPixConfigPath, savePixAutocompleteModel, savePixDefaultModel,
4
4
  import { createId } from "../id.js";
5
5
  import { isThinkingLevel, parseScopedModelRef } from "../model/model-ref.js";
6
6
  import { appendPixSystemDisplayEntry } from "../session/pix-system-message.js";
7
+ import { createReloadContextInventory, formatReloadContextInventory } from "./reload-context-inventory.js";
7
8
  export class ModelCommandActions {
8
9
  host;
9
10
  constructor(host) {
@@ -45,19 +46,7 @@ export class ModelCommandActions {
45
46
  const scope = captureCommandScope(this.host);
46
47
  const modelRef = argumentsText.trim();
47
48
  if (!modelRef) {
48
- const selected = await this.host.showMenu(this.host.getModelMenuItems(""), {
49
- title: "Select model",
50
- placeholder: "Search models",
51
- emptyText: "No matching models",
52
- });
53
- if (!isCommandScopeActive(this.host, scope))
54
- return;
55
- if (!selected) {
56
- this.host.setSessionStatus(this.host.runtime()?.session);
57
- this.host.render();
58
- return;
59
- }
60
- await this.runModelCommand(selected.model);
49
+ this.host.openDirectPopupMenu("model");
61
50
  this.host.render();
62
51
  return;
63
52
  }
@@ -73,14 +62,10 @@ export class ModelCommandActions {
73
62
  const model = runtime.services.modelRuntime.getModel(parsed.provider, parsed.modelId);
74
63
  if (!model)
75
64
  throw new Error(`Model not found: ${parsed.provider}/${parsed.modelId}`);
76
- await this.runModelCommand(model);
77
- if (!isCommandScopeActive(this.host, scope))
78
- return;
79
- if (parsed.thinkingLevel !== undefined) {
80
- runtime.session.setThinkingLevel(parsed.thinkingLevel);
81
- this.addPersistentSystemEntry(runtime.session, `Selected thinking level ${runtime.session.thinkingLevel}`);
82
- this.host.setSessionStatus(runtime.session);
83
- }
65
+ if (parsed.thinkingLevel !== undefined)
66
+ await this.runModelThinkingCommand(model, parsed.thinkingLevel);
67
+ else
68
+ await this.runModelCommand(model);
84
69
  }
85
70
  async runDefaultModelSlashCommand(argumentsText) {
86
71
  const scope = captureCommandScope(this.host);
@@ -241,19 +226,7 @@ export class ModelCommandActions {
241
226
  const scope = captureCommandScope(this.host);
242
227
  const level = argumentsText.trim();
243
228
  if (!level) {
244
- const selected = await this.host.showMenu(this.host.getThinkingMenuItems(""), {
245
- title: "Select thinking level",
246
- placeholder: "Search thinking levels",
247
- emptyText: "No matching thinking levels",
248
- });
249
- if (!isCommandScopeActive(this.host, scope))
250
- return;
251
- if (!selected) {
252
- this.host.setSessionStatus(this.host.runtime()?.session);
253
- this.host.render();
254
- return;
255
- }
256
- await this.runThinkingCommand(selected.level);
229
+ this.host.openDirectPopupMenu("thinking");
257
230
  this.host.render();
258
231
  return;
259
232
  }
@@ -312,6 +285,51 @@ export class ModelCommandActions {
312
285
  return;
313
286
  this.host.setSessionStatus(runtime.session);
314
287
  }
288
+ async runModelThinkingCommand(model, level) {
289
+ const runtime = getRuntime(this.host, "model");
290
+ if (!runtime)
291
+ return;
292
+ const scope = captureCommandScope(this.host);
293
+ const session = runtime.session;
294
+ const ref = this.host.modelRef(model);
295
+ const currentModel = session.model;
296
+ const modelChanged = currentModel?.provider !== model.provider || currentModel.id !== model.id;
297
+ const initialThinking = session.thinkingLevel;
298
+ if (!modelChanged && initialThinking === level) {
299
+ this.host.setSessionStatus(session);
300
+ return;
301
+ }
302
+ this.host.setStatus(`selecting ${ref} · thinking ${level}`);
303
+ this.host.render();
304
+ if (modelChanged) {
305
+ await session.setModel(model);
306
+ if (!isCommandScopeActive(this.host, scope))
307
+ return;
308
+ this.host.addEntry({ id: createId("system"), kind: "system", text: `Selected model ${ref}` });
309
+ }
310
+ session.setThinkingLevel(level);
311
+ if (modelChanged || session.thinkingLevel !== initialThinking) {
312
+ this.addPersistentSystemEntry(session, `Selected thinking level ${session.thinkingLevel}`);
313
+ }
314
+ if (!modelChanged) {
315
+ this.host.setSessionStatus(session);
316
+ return;
317
+ }
318
+ if (session.isStreaming) {
319
+ this.host.addEntry({
320
+ id: createId("system"),
321
+ kind: "system",
322
+ text: "Skipped reload because the agent is still running. Run /reload when idle to refresh model-specific tools.",
323
+ });
324
+ this.host.toast.warning("Model changed; reload skipped while the agent is running");
325
+ this.host.setSessionStatus(session);
326
+ return;
327
+ }
328
+ await this.reloadAfterModelChange(session, ref, scope);
329
+ if (!isCommandScopeActive(this.host, scope))
330
+ return;
331
+ this.host.setSessionStatus(session);
332
+ }
315
333
  async runThinkingCommand(level) {
316
334
  const runtime = getRuntime(this.host, "thinking");
317
335
  if (!runtime)
@@ -333,10 +351,14 @@ export class ModelCommandActions {
333
351
  await session.reload();
334
352
  if (!isCommandScopeActive(this.host, scope))
335
353
  return;
354
+ const runtime = scope.runtime;
355
+ const text = runtime
356
+ ? formatReloadContextInventory(createReloadContextInventory(runtime, this.host.subagentTypes?.(runtime)), `Reloaded resources after model change to ${ref}`)
357
+ : `Reloaded resources after model change to ${ref}`;
336
358
  this.host.addEntry({
337
359
  id: createId("system"),
338
360
  kind: "system",
339
- text: `Reloaded resources after model change to ${ref}`,
361
+ text,
340
362
  });
341
363
  this.host.toast.success("Model changed and resources reloaded");
342
364
  }
@@ -26,6 +26,7 @@ export declare class NavigationCommandActions {
26
26
  runResumeCommand(queryOrOptions?: string | {
27
27
  preserveStatus?: boolean;
28
28
  placement?: PopupMenuPlacement;
29
+ draft?: boolean;
29
30
  }): Promise<void>;
30
31
  private loadResumeSessionsInBackground;
31
32
  private formatSessionTree;