@vantran-se/openchamber-web 1.22.1 → 1.23.0

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 (238) hide show
  1. package/README.md +2 -3
  2. package/bin/cli.js +11 -1
  3. package/bin/cli.test.js +92 -0
  4. package/bin/lib/cli-startup.js +49 -0
  5. package/bin/lib/commands-startup.js +41 -6
  6. package/dist/assets/{CodeMirrorCommentWidgets-C53Q7pbX.js → CodeMirrorCommentWidgets-DFg2wnpo.js} +1 -1
  7. package/dist/assets/DiffView-3Dn4QHbu.js +4 -0
  8. package/dist/assets/DirtyBranchSwitchDialog-CwOerqVi.js +1 -0
  9. package/dist/assets/FilesView-BdTOpew9.js +17 -0
  10. package/dist/assets/GitView-Dqf9vHJh.js +6 -0
  11. package/dist/assets/{JsonTreeView-Bl0lp9Rs.js → JsonTreeView-BKdsjg5B.js} +1 -1
  12. package/dist/assets/LinearIssuesView-CmbeL7I6.js +1 -0
  13. package/dist/assets/MarkdownImageGallery-_5gEVr0X.js +1 -0
  14. package/dist/assets/MarkdownRendererImpl-wVZlx4dd.js +12 -0
  15. package/dist/assets/OnboardingScreen-DdP4_nuc.js +1 -0
  16. package/dist/assets/{PatchDiff-D6NXAfJk.js → PatchDiff-am3SAss2.js} +1 -1
  17. package/dist/assets/PierreDiffViewer-DCsydlKs.js +161 -0
  18. package/dist/assets/PlanView-BoJxdRZe.js +5 -0
  19. package/dist/assets/SettingsView-CcM8pF5O.js +28 -0
  20. package/dist/assets/{SettingsWindow-BiWDBRvb.js → SettingsWindow-DVTdDSol.js} +1 -1
  21. package/dist/assets/SymbolsNerdFontMono-Regular-aK5vsLov.woff2 +0 -0
  22. package/dist/assets/{ToolOutputDialog-BQexMQIm.js → ToolOutputDialog-BgfTbDZ4.js} +6 -6
  23. package/dist/assets/ToolPartDiffPreview-C7WLk5i9.js +8 -0
  24. package/dist/assets/{VirtualizedFileDiff-Dpz2ra8h.js → VirtualizedFileDiff-DcdgkH-x.js} +1 -1
  25. package/dist/assets/WalkthroughView-BEVUDxuw.js +4 -0
  26. package/dist/assets/{computeVirtualFileMetrics-DtyozJdt.js → computeVirtualFileMetrics-C8byMnRh.js} +2 -2
  27. package/dist/assets/contextPanelEmbeddedChat-CirXEPJq.js +1 -0
  28. package/dist/assets/de-C8jV7J9y.js +10 -0
  29. package/dist/assets/es-BI6J1M5R.js +16 -0
  30. package/dist/assets/fr-D6oDFt7E.js +14 -0
  31. package/dist/assets/ghostty-vt-DdA0Zryv.wasm +0 -0
  32. package/dist/assets/{index-DmhujXbT.js → index-BB7ryz8y.js} +1 -1
  33. package/dist/assets/index-BqhiCmYS.js +39 -0
  34. package/dist/assets/index-FqSOBz0J.css +1 -0
  35. package/dist/assets/{isDiffPlainText-XyulMHxx.js → isDiffPlainText-45ujMPGb.js} +1 -1
  36. package/dist/assets/{isFilePlainText-B19Ddps1.js → isFilePlainText-Cc4KFSYi.js} +1 -1
  37. package/dist/assets/ja-C_4i5EQu.js +16 -0
  38. package/dist/assets/ko-BFbOTpbq.js +16 -0
  39. package/dist/assets/{main-B2a_JfKZ.js → main-C9ETLKFc.js} +2 -2
  40. package/dist/assets/main-CJmb2dF8.js +930 -0
  41. package/dist/assets/markdownCore-DVuZpnli.js +5 -0
  42. package/dist/assets/{miniChat-B3CSU_Ps.js → miniChat-B4Ytoq2n.js} +2 -2
  43. package/dist/assets/{mobile-QNcFIVCW.js → mobile-BUT6-lo1.js} +2 -2
  44. package/dist/assets/patchFileDiff-8j1apICU.js +13 -0
  45. package/dist/assets/pl-COFvT56l.js +16 -0
  46. package/dist/assets/pt-BR-DtVOO2Lj.js +16 -0
  47. package/dist/assets/renderElectronMiniChatApp-B6vUG-vF.js +2 -0
  48. package/dist/assets/renderMobileApp-BNgHraq6.js +25 -0
  49. package/dist/assets/runtimeEndpointReset-B8LYpWvr.js +17 -0
  50. package/dist/assets/scheduledTasksApi-GC4epIYA.js +1 -0
  51. package/dist/assets/{shikiHighlight-DE-OwqGw.js → shikiHighlight-BJISeZsQ.js} +1 -1
  52. package/dist/assets/surface-BvRzS58U.js +1 -0
  53. package/dist/assets/tr-B8Q0Go2l.js +7 -0
  54. package/dist/assets/uk-Dk4a-Fn-.js +16 -0
  55. package/dist/assets/{useAppFontEffects-COAeIX-D.js → useAppFontEffects-DpFNefUA.js} +153 -179
  56. package/dist/assets/useGitComparison-Dfxaqd0s.js +1 -0
  57. package/dist/assets/useInlineCommentController-CscsE4t-.js +2 -0
  58. package/dist/assets/useRootScrollLock-BaCvuRlT.js +1 -0
  59. package/dist/assets/{vendor-base-ui-BeMD8X_w.js → vendor-base-ui-DdV8vhHn.js} +1 -1
  60. package/dist/assets/{vendor-codemirror-language-data-BG3v1Ghq.js → vendor-codemirror-language-data-DzlSIu_W.js} +2 -2
  61. package/dist/assets/vendor-legendapp-list-BuBPBC3R.js +1 -0
  62. package/dist/assets/vendor-zod-BPAANqvH.js +39 -0
  63. package/dist/assets/{web-components-BNMwa0qm.js → web-components-CdGfR2XJ.js} +1 -1
  64. package/dist/assets/zh-CN-B_BXxG1Q.js +16 -0
  65. package/dist/assets/zh-TW-DLrl1SPZ.js +16 -0
  66. package/dist/index.html +5 -43
  67. package/dist/mini-chat.html +4 -4
  68. package/dist/mobile.html +4 -4
  69. package/package.json +8 -5
  70. package/server/index.d.ts +15 -0
  71. package/server/index.js +82 -13
  72. package/server/lib/agent-tool/runtime.js +2 -19
  73. package/server/lib/changelog/update-notes.js +82 -0
  74. package/server/lib/changelog/update-notes.test.js +59 -0
  75. package/server/lib/data-dir-migration.js +40 -0
  76. package/server/lib/data-dir-migration.test.js +59 -0
  77. package/server/lib/dev-tunnel/DOCUMENTATION.md +13 -4
  78. package/server/lib/dev-tunnel/runtime.js +4 -4
  79. package/server/lib/dev-tunnel/tunnel.test.js +20 -0
  80. package/server/lib/event-stream/runtime.test.js +12 -12
  81. package/server/lib/fs/DOCUMENTATION.md +5 -0
  82. package/server/lib/fs/routes.js +63 -21
  83. package/server/lib/fs/routes.test.js +187 -1
  84. package/server/lib/git/DOCUMENTATION.md +32 -6
  85. package/server/lib/git/routes.js +40 -4
  86. package/server/lib/git/service.js +291 -215
  87. package/server/lib/git/service.test.js +593 -25
  88. package/server/lib/inherited-env.js +16 -9
  89. package/server/lib/inherited-env.test.js +8 -9
  90. package/server/lib/mcp-reconnect/DOCUMENTATION.md +55 -0
  91. package/server/lib/mcp-reconnect/runtime.js +122 -0
  92. package/server/lib/mcp-reconnect/runtime.test.js +140 -0
  93. package/server/lib/message-queue/DOCUMENTATION.md +161 -0
  94. package/server/lib/message-queue/runtime.js +870 -0
  95. package/server/lib/message-queue/runtime.test.js +482 -0
  96. package/server/lib/network-defaults.js +23 -0
  97. package/server/lib/network-defaults.test.js +52 -0
  98. package/server/lib/openchamber-sessions/routes.js +102 -0
  99. package/server/lib/openchamber-sessions/routes.test.js +88 -0
  100. package/server/lib/opencode/DOCUMENTATION.md +30 -6
  101. package/server/lib/opencode/bootstrap-runtime.js +2 -0
  102. package/server/lib/opencode/config-paths.test.js +116 -0
  103. package/server/lib/opencode/core-routes.js +1 -0
  104. package/server/lib/opencode/feature-routes-runtime.js +7 -0
  105. package/server/lib/opencode/input-history-scope.js +14 -0
  106. package/server/lib/opencode/managed-plugin-config.js +35 -0
  107. package/server/lib/opencode/openchamber-routes.js +64 -4
  108. package/server/lib/opencode/openchamber-routes.test.js +130 -3
  109. package/server/lib/opencode/plugins.js +2 -2
  110. package/server/lib/opencode/providers.js +44 -2
  111. package/server/lib/opencode/providers.test.js +131 -4
  112. package/server/lib/opencode/routes.js +9 -7
  113. package/server/lib/opencode/server-startup-runtime.js +1 -1
  114. package/server/lib/opencode/settings-files.js +214 -0
  115. package/server/lib/opencode/settings-helpers.js +113 -41
  116. package/server/lib/opencode/settings-helpers.test.js +342 -0
  117. package/server/lib/opencode/settings-registry.json +747 -0
  118. package/server/lib/opencode/settings-runtime.js +141 -20
  119. package/server/lib/opencode/settings-runtime.test.js +191 -4
  120. package/server/lib/opencode/shared.js +4 -1
  121. package/server/lib/opencode/shutdown-runtime.js +2 -0
  122. package/server/lib/opencode/skill-routes.js +2 -1
  123. package/server/lib/opencode/snippets.js +1 -2
  124. package/server/lib/package-manager.js +4 -29
  125. package/server/lib/package-manager.test.js +2 -2
  126. package/server/lib/project-context/DOCUMENTATION.md +25 -1
  127. package/server/lib/project-context/routes.http.test.js +18 -0
  128. package/server/lib/project-context/routes.js +15 -0
  129. package/server/lib/project-context/runtime.js +248 -23
  130. package/server/lib/project-context/runtime.test.js +106 -3
  131. package/server/lib/projects/DOCUMENTATION.md +76 -0
  132. package/server/lib/projects/project-config.js +142 -9
  133. package/server/lib/projects/project-id.js +17 -0
  134. package/server/lib/projects/project-setup.js +409 -0
  135. package/server/lib/projects/project-setup.test.js +557 -0
  136. package/server/lib/projects/routes.js +59 -0
  137. package/server/lib/quota/DOCUMENTATION.md +40 -2
  138. package/server/lib/quota/credentials/providers.js +4 -0
  139. package/server/lib/quota/credentials/store.js +1 -1
  140. package/server/lib/quota/credentials/store.test.js +4 -4
  141. package/server/lib/quota/index.js +1 -0
  142. package/server/lib/quota/providers/cline-pass.js +125 -0
  143. package/server/lib/quota/providers/cline-pass.test.js +103 -0
  144. package/server/lib/quota/providers/exe-dev.js +75 -0
  145. package/server/lib/quota/providers/exe-dev.test.js +47 -0
  146. package/server/lib/quota/providers/hyper.js +118 -0
  147. package/server/lib/quota/providers/hyper.test.js +126 -0
  148. package/server/lib/quota/providers/index.js +22 -0
  149. package/server/lib/quota/providers/neuralwatt.js +3 -6
  150. package/server/lib/quota/providers/neuralwatt.test.js +7 -7
  151. package/server/lib/quota/providers/ollama-cloud.js +31 -0
  152. package/server/lib/quota/providers/ollama-cloud.test.js +33 -1
  153. package/server/lib/quota/providers/opencode-go.js +2 -1
  154. package/server/lib/quota/providers/opencode-go.test.js +31 -2
  155. package/server/lib/quota/providers/openrouter.js +119 -24
  156. package/server/lib/quota/providers/openrouter.test.js +330 -0
  157. package/server/lib/quota/routes.js +2 -0
  158. package/server/lib/quota/utils/auth.js +1 -1
  159. package/server/lib/relay/DOCUMENTATION.md +56 -1
  160. package/server/lib/relay/cross-compat.test.js +26 -0
  161. package/server/lib/relay/downstream-scheduler.js +154 -0
  162. package/server/lib/relay/downstream-scheduler.test.js +162 -0
  163. package/server/lib/relay/e2ee.js +10 -8
  164. package/server/lib/relay/flow-control.test.js +177 -0
  165. package/server/lib/relay/host-client.js +37 -8
  166. package/server/lib/relay/host-client.test.js +9 -1
  167. package/server/lib/relay/tunnel-codec.js +9 -0
  168. package/server/lib/relay/tunnel-host.js +69 -18
  169. package/server/lib/relay/tunnel-host.test.js +9 -1
  170. package/server/lib/security/request-security.js +21 -6
  171. package/server/lib/security/request-security.test.js +42 -8
  172. package/server/lib/session-assist/runtime.js +7 -10
  173. package/server/lib/session-goal/DOCUMENTATION.md +20 -7
  174. package/server/lib/session-goal/create.js +3 -1
  175. package/server/lib/session-goal/runtime.js +81 -20
  176. package/server/lib/session-goal/runtime.test.js +426 -0
  177. package/server/lib/skills-catalog/DOCUMENTATION.md +1 -1
  178. package/server/lib/skills-catalog/install.js +3 -2
  179. package/server/lib/small-model/DOCUMENTATION.md +7 -2
  180. package/server/lib/small-model/call.js +17 -6
  181. package/server/lib/small-model/call.test.js +52 -0
  182. package/server/lib/small-model/index.js +7 -11
  183. package/server/lib/small-model/routes.js +2 -1
  184. package/server/lib/small-model/runtime-providers.js +15 -7
  185. package/server/lib/small-model/runtime-providers.test.js +7 -1
  186. package/server/lib/system-prompt/runtime.js +2 -21
  187. package/server/lib/terminal/DOCUMENTATION.md +14 -10
  188. package/server/lib/terminal/runtime.js +190 -31
  189. package/server/lib/terminal/runtime.test.js +571 -37
  190. package/server/lib/terminal/shells.js +17 -0
  191. package/server/lib/terminal/shells.test.js +32 -1
  192. package/server/lib/ui-auth/ui-auth.js +4 -1
  193. package/server/lib/ui-auth/ui-auth.test.js +16 -0
  194. package/server/lib/walkthrough/DOCUMENTATION.md +33 -14
  195. package/server/lib/walkthrough/index.js +1 -0
  196. package/server/lib/walkthrough/model-settings.js +8 -12
  197. package/server/lib/walkthrough/prompt.js +3 -1
  198. package/server/lib/walkthrough/routes.test.js +26 -5
  199. package/server/lib/walkthrough/sources.js +23 -2
  200. package/dist/assets/CommitSection-X-f2RgYr.js +0 -1
  201. package/dist/assets/DiffView-Dh1ey2x9.js +0 -4
  202. package/dist/assets/FilesView-3ZYP72ki.js +0 -17
  203. package/dist/assets/GitView-CMuN7z2Z.js +0 -6
  204. package/dist/assets/LinearIssuesView-CQiUDU8b.js +0 -1
  205. package/dist/assets/MarkdownImageGallery-bA0PS-tn.js +0 -1
  206. package/dist/assets/MarkdownRendererImpl-BGQi2PLq.js +0 -12
  207. package/dist/assets/OnboardingScreen-D3kYJIb6.js +0 -1
  208. package/dist/assets/PierreDiffViewer-Ct2A13NO.js +0 -157
  209. package/dist/assets/PlanView-6AUjzNQn.js +0 -5
  210. package/dist/assets/SettingsView-CHI8fFaK.js +0 -28
  211. package/dist/assets/ToolPartDiffPreview-DPAATNn6.js +0 -8
  212. package/dist/assets/WalkthroughView-AX-u2pFg.js +0 -4
  213. package/dist/assets/contextPanelEmbeddedChat-C9EcRSDF.js +0 -1
  214. package/dist/assets/de-DqVn5vme.js +0 -9
  215. package/dist/assets/es-hj43Z53i.js +0 -15
  216. package/dist/assets/fr-BmkZt2mF.js +0 -13
  217. package/dist/assets/index-L_ncV-6H.css +0 -1
  218. package/dist/assets/index-qES19dlJ.js +0 -7
  219. package/dist/assets/ja-DioMIEGF.js +0 -15
  220. package/dist/assets/ko-BqPgaQJb.js +0 -15
  221. package/dist/assets/main-CYgSu6dx.js +0 -928
  222. package/dist/assets/markdownCore-CWRCqSH2.js +0 -3
  223. package/dist/assets/patchFileDiff-BpMQZnYu.js +0 -10
  224. package/dist/assets/pl-slULBF4R.js +0 -15
  225. package/dist/assets/pt-BR-BqH8fuCH.js +0 -15
  226. package/dist/assets/renderElectronMiniChatApp-D77bmLqo.js +0 -2
  227. package/dist/assets/renderMobileApp-BQ3Kdm-d.js +0 -25
  228. package/dist/assets/runtimeEndpointReset-CRGn1gVj.js +0 -16
  229. package/dist/assets/scheduledTasksApi-BSRCtP6T.js +0 -1
  230. package/dist/assets/tr-CjEbw1Aw.js +0 -6
  231. package/dist/assets/uk-BkkfxbOs.js +0 -15
  232. package/dist/assets/useInlineCommentController-JsBboQwt.js +0 -2
  233. package/dist/assets/useRootScrollLock-C0N9mCwz.js +0 -1
  234. package/dist/assets/vendor-ghostty-web-CrxinGGH.js +0 -13
  235. package/dist/assets/vendor-legendapp-list-gg7YLRW7.js +0 -1
  236. package/dist/assets/vendor-zod-BLfBSgBh.js +0 -39
  237. package/dist/assets/zh-CN-C6FMdVgv.js +0 -15
  238. package/dist/assets/zh-TW-CdcMjDxv.js +0 -15
@@ -1,5 +1,6 @@
1
1
  const TERMINAL_SHELL_IDS = ['bash', 'zsh', 'sh', 'fish', 'pwsh', 'powershell', 'cmd', 'dash', 'ksh', 'nu'];
2
2
  const TERMINAL_SHELL_ID_SET = new Set(TERMINAL_SHELL_IDS);
3
+ const isString = (value) => String(value) === value;
3
4
 
4
5
  export const normalizeTerminalShell = (value) => {
5
6
  if (typeof value !== 'string') return null;
@@ -24,6 +25,22 @@ export const getTerminalShellLoginArgs = (executable, platform = process.platfor
24
25
  return null;
25
26
  };
26
27
 
28
+ export const buildTerminalShellLaunch = (executable, { mode = 'interactive', command = null, loginShell = false, platform = process.platform } = {}) => {
29
+ const loginArgs = loginShell ? getTerminalShellLoginArgs(executable, platform) : [];
30
+ if (!loginArgs) throw new Error(`Terminal shell "${shellIdFromPath(executable) ?? executable}" does not support login mode`);
31
+
32
+ if (mode === 'interactive') return { executable, args: loginArgs };
33
+
34
+ const trimmedCommand = isString(command) ? command.trim() : '';
35
+ if (!trimmedCommand) throw new Error('Terminal command is required');
36
+
37
+ const id = shellIdFromPath(executable);
38
+ if (id === 'nu') return { executable, args: [...loginArgs, '-c', trimmedCommand] };
39
+ if (id === 'pwsh' || id === 'powershell') return { executable, args: [...loginArgs, '-Command', trimmedCommand] };
40
+ if (id === 'cmd') return { executable, args: ['/d', '/s', '/c', trimmedCommand] };
41
+ return { executable, args: [...loginArgs, '-i', '-c', trimmedCommand] };
42
+ };
43
+
27
44
  export const createTerminalShellResolver = ({ fs, path, searchPathFor, isExecutable, buildAugmentedPath = () => env.PATH || '', platform = process.platform, env = process.env }) => {
28
45
  const resolveExecutable = (candidate) => {
29
46
  if (!candidate) return null;
@@ -1,6 +1,8 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
 
3
- import { createTerminalShellResolver, getTerminalShellLoginArgs } from './shells.js';
3
+ import * as shells from './shells.js';
4
+
5
+ const { createTerminalShellResolver, getTerminalShellLoginArgs } = shells;
4
6
 
5
7
  const createResolver = ({ platform = 'linux', env = {}, augmentedPath = '/augmented/bin', executables = [] } = {}) => {
6
8
  const available = new Set(executables);
@@ -70,4 +72,33 @@ describe('terminal shell resolver', () => {
70
72
  expect(getTerminalShellLoginArgs('C:\\Program Files\\PowerShell\\7\\pwsh.exe', 'win32')).toBeNull();
71
73
  expect(getTerminalShellLoginArgs('/bin/dash', 'linux')).toBeNull();
72
74
  });
75
+
76
+ it('builds interactive shell launches by shell family', () => {
77
+ const buildLaunch = shells.buildTerminalShellLaunch;
78
+
79
+ expect(buildLaunch('/bin/bash', { mode: 'interactive', loginShell: true, platform: 'linux' })).toEqual({ executable: '/bin/bash', args: ['-l'] });
80
+ expect(buildLaunch('/opt/homebrew/bin/fish', { mode: 'interactive', loginShell: true, platform: 'darwin' })).toEqual({ executable: '/opt/homebrew/bin/fish', args: ['--login'] });
81
+ expect(buildLaunch('/usr/bin/nu', { mode: 'interactive', loginShell: true, platform: 'linux' })).toEqual({ executable: '/usr/bin/nu', args: ['--login'] });
82
+ expect(buildLaunch('/usr/bin/pwsh', { mode: 'interactive', loginShell: true, platform: 'linux' })).toEqual({ executable: '/usr/bin/pwsh', args: ['-Login'] });
83
+ expect(buildLaunch('C:\\Windows\\System32\\cmd.exe', { mode: 'interactive', loginShell: false, platform: 'win32' })).toEqual({ executable: 'C:\\Windows\\System32\\cmd.exe', args: [] });
84
+ });
85
+
86
+ it('builds command launches by shell family', () => {
87
+ const buildLaunch = shells.buildTerminalShellLaunch;
88
+
89
+ expect(buildLaunch('/bin/zsh', { mode: 'command', command: 'printf ready', loginShell: true, platform: 'linux' })).toEqual({ executable: '/bin/zsh', args: ['-l', '-i', '-c', 'printf ready'] });
90
+ expect(buildLaunch('/opt/homebrew/bin/fish', { mode: 'command', command: 'echo ready', loginShell: true, platform: 'darwin' })).toEqual({ executable: '/opt/homebrew/bin/fish', args: ['--login', '-i', '-c', 'echo ready'] });
91
+ expect(buildLaunch('/usr/bin/nu', { mode: 'command', command: 'ls', loginShell: true, platform: 'linux' })).toEqual({ executable: '/usr/bin/nu', args: ['--login', '-c', 'ls'] });
92
+ expect(buildLaunch('/usr/bin/pwsh', { mode: 'command', command: 'Get-ChildItem', loginShell: true, platform: 'linux' })).toEqual({ executable: '/usr/bin/pwsh', args: ['-Login', '-Command', 'Get-ChildItem'] });
93
+ expect(buildLaunch('C:\\Program Files\\PowerShell\\7\\pwsh.exe', { mode: 'command', command: 'Get-Date', loginShell: false, platform: 'win32' })).toEqual({ executable: 'C:\\Program Files\\PowerShell\\7\\pwsh.exe', args: ['-Command', 'Get-Date'] });
94
+ expect(buildLaunch('C:\\Windows\\System32\\cmd.exe', { mode: 'command', command: 'dir', loginShell: false, platform: 'win32' })).toEqual({ executable: 'C:\\Windows\\System32\\cmd.exe', args: ['/d', '/s', '/c', 'dir'] });
95
+ });
96
+
97
+ it('rejects unsupported login and command combinations', () => {
98
+ const buildLaunch = shells.buildTerminalShellLaunch;
99
+
100
+ expect(() => buildLaunch('/bin/sh', { mode: 'interactive', loginShell: true, platform: 'linux' })).toThrow('does not support login mode');
101
+ expect(() => buildLaunch('/bin/dash', { mode: 'command', command: 'pwd', loginShell: true, platform: 'linux' })).toThrow('does not support login mode');
102
+ expect(() => buildLaunch('/bin/bash', { mode: 'command', command: '', loginShell: false, platform: 'linux' })).toThrow('Terminal command is required');
103
+ });
73
104
  });
@@ -310,6 +310,7 @@ const isUrlAuthWebSocketPath = (pathname) => {
310
310
  || pathname === '/api/openchamber/realtime-proxy/ws'
311
311
  || pathname === '/api/terminal/ws'
312
312
  || pathname === '/api/dictation/ws'
313
+ || pathname === '/api/dev-tunnel'
313
314
  || pathname.startsWith('/api/preview/proxy/');
314
315
  };
315
316
 
@@ -984,7 +985,9 @@ export const createUiAuth = ({
984
985
  handlePasskeyList,
985
986
  handlePasskeyRevoke,
986
987
  handleResetAuth,
987
- ensureSessionToken: async (req, _res) => {
988
+ ensureSessionToken: (req, _res) => {
989
+ const urlAuth = authenticateUrlAuthToken(req);
990
+ if (urlAuth) return clientSessionToken(urlAuth);
988
991
  return resolveAuthenticatedSessionToken(req);
989
992
  },
990
993
  dispose,
@@ -221,6 +221,22 @@ describe('ui auth client credential seam', () => {
221
221
  };
222
222
  expect(await auth.ensureSessionToken(dictationWsReq, null)).toBe('client:device-1');
223
223
 
224
+ const devTunnelWsReq = {
225
+ method: 'GET',
226
+ path: '/api/dev-tunnel',
227
+ url: `/api/dev-tunnel?port=4322&oc_url_token=${encodeURIComponent(urlToken)}`,
228
+ headers: { upgrade: 'websocket' },
229
+ };
230
+ expect(await auth.ensureSessionToken(devTunnelWsReq, null)).toBe('client:device-1');
231
+
232
+ const devTunnelSubpathWsReq = {
233
+ method: 'GET',
234
+ path: '/api/dev-tunnel/private',
235
+ url: `/api/dev-tunnel/private?port=4322&oc_url_token=${encodeURIComponent(urlToken)}`,
236
+ headers: { upgrade: 'websocket' },
237
+ };
238
+ expect(await auth.ensureSessionToken(devTunnelSubpathWsReq, null)).toBe(null);
239
+
224
240
  const dictationHttpReq = {
225
241
  method: 'GET',
226
242
  path: '/api/dictation/ws',
@@ -52,20 +52,39 @@ written against staged code never silently re-anchors onto an unstaged edit.
52
52
  | Kind | Sections | Notes |
53
53
  |---|---|---|
54
54
  | `working-tree` (`all` \| `staged` \| `working`) | `staged`, `working` | Untracked files are fetched individually because `git diff` omits them |
55
- | `branch` | `branch` | `getRangeDiff` uses three-dot `base...head`, so work merged in from the base branch is excluded |
56
- | `pr` | `pr:<number>` | GitHub returns the merge-base diff, matching the branch semantics |
57
-
58
- For the current-branch source, the UI takes the base from the default branch of
59
- the current branch's tracking remote (`defaultBranches` in the branches
60
- response), and only then falls back to the conventional names. It does not offer
61
- the source at all when the chosen base exists neither locally nor on a remote —
62
- a repository whose default is neither `main`, `master` nor `develop` used to be
63
- handed `main...<head>`, which git rejects outright.
64
-
65
- A base that exists only on a remote still works: `getRangeDiff` prefers
66
- `origin/<base>` when it exists, and otherwise resolves the base through whichever
67
- remote carries it, because a bare branch name git cannot find in `refs/heads`
68
- fails the same way.
55
+ | `branch` | `branch` | `getRangeDiff` with `includeWorkingTree: true` compares the selected merge base with current files, including committed and local work in one net diff |
56
+ | `commit` | `commit` | `getCommitDiff` compares the full selected commit hash with its first parent; root commits compare with an empty tree |
57
+ | `pr` | `pr:<number>` | GitHub's committed pull-request diff, without local working-tree changes |
58
+
59
+ Changes and walkthrough resolve the current branch's base through
60
+ `packages/ui/src/hooks/useBranchComparisonBase.ts`. An explicit choice in Changes
61
+ outranks reflog detection. Both toolbars use
62
+ `packages/ui/src/components/views/git/BranchComparisonSelector.tsx` to select or
63
+ change the base directly. Walkthrough allows selecting Branch before a base is
64
+ known and waits for a valid choice before loading or generating. Opening
65
+ walkthrough from Changes carries the selected base and head; later selections
66
+ in either toolbar update both comparisons.
67
+
68
+ Commit mode uses the shared `CommitComparisonSelector` in both toolbars. It
69
+ lists the latest 50 commits reachable from the checked-out branch, with subject,
70
+ author, date, and short hash. Opening the picker refreshes that list; selecting a
71
+ commit changes the comparison, not the checkout. Changes hands the selected full
72
+ hash to walkthrough. The server accepts full object IDs for commit sources and
73
+ keys their cache entries and generation jobs as `commit:<hash>`, so reviews of
74
+ different commits cannot overwrite each other. Existing source keys keep their
75
+ format. Commit reads have no working-tree freshness dependency, and selecting a
76
+ commit never starts model generation.
77
+
78
+ The Git module owns exact-ref and working-tree comparison semantics. Local and
79
+ remote bases remain distinct, and a checkout during a branch review requires
80
+ the source to be resolved for the new branch rather than including another
81
+ branch's local files.
82
+
83
+ Successful status refreshes invalidate the visible branch comparison even when
84
+ file names and insertion/deletion counts stay the same. Walkthrough refreshes
85
+ its current hunk index while visible; regeneration remains user-initiated. The
86
+ content-addressed cache continues to reuse an old review only when its hunks
87
+ match, and otherwise reports stale anchors and uncovered current hunks.
69
88
 
70
89
  The panel offers the current branch's pull request on its own: it registers with
71
90
  the shared GitHub PR status store (`useGitHubPrStatusStore`) rather than waiting
@@ -474,6 +474,7 @@ async function runGeneration({ directory, source, repoRoot, key, force, explicit
474
474
  prompt: options.prompt,
475
475
  system: options.system,
476
476
  directory,
477
+ sessionID: `openchamber-walkthrough-${cacheKey}`,
477
478
  model: `${model.providerID}/${model.modelID}`,
478
479
  responseSchema: options.responseSchema,
479
480
  onOverflow: 'error',
@@ -1,6 +1,7 @@
1
1
  import fs from 'fs';
2
2
  import os from 'os';
3
3
  import path from 'path';
4
+ import { readMergedSettingsSync } from '../opencode/settings-files.js';
4
5
 
5
6
  // The walkthrough may run on a different model than the rest of the small-model
6
7
  // callers. Those callers want cheap and fast; this one needs structured output
@@ -23,16 +24,11 @@ const SETTINGS_FILE = path.join(
23
24
  * not use the small model" with nothing to use instead.
24
25
  */
25
26
  export function readWalkthroughModelOverride() {
26
- try {
27
- const settings = JSON.parse(fs.readFileSync(SETTINGS_FILE, 'utf8'));
28
- if (!settings || typeof settings !== 'object') return null;
29
- const override = typeof settings.walkthroughModelOverride === 'string'
30
- ? settings.walkthroughModelOverride.trim()
31
- : '';
32
- return override || null;
33
- } catch {
34
- // No settings file, unreadable, or malformed all mean the same thing: no
35
- // override, use the small model.
36
- return null;
37
- }
27
+ // No settings file, unreadable, or malformed all mean the same thing: no
28
+ // override, use the small model.
29
+ const settings = readMergedSettingsSync({ fs, path, settingsFilePath: SETTINGS_FILE });
30
+ const override = typeof settings.walkthroughModelOverride === 'string'
31
+ ? settings.walkthroughModelOverride.trim()
32
+ : '';
33
+ return override || null;
38
34
  }
@@ -86,7 +86,9 @@ export function buildPrompt({ digest, fileCount, hunkCount, source, previousWalk
86
86
  ? `Uncommitted local changes (${source.scope === 'all' ? 'staged and unstaged' : source.scope}).`
87
87
  : source.kind === 'branch'
88
88
  ? `All work on branch "${source.headRef}" that is not in "${source.baseRef}". Changes merged in from ${source.baseRef} are already excluded.`
89
- : `Pull request #${source.number}.`;
89
+ : source.kind === 'commit'
90
+ ? `Only the changes introduced by commit ${source.hash}, relative to its first parent (or the empty tree for a root commit).`
91
+ : `Pull request #${source.number}.`;
90
92
 
91
93
  const prompt = `Reviewing: ${sourceLine}
92
94
 
@@ -15,6 +15,7 @@ describe('walkthrough routes', () => {
15
15
  let job;
16
16
 
17
17
  let lastArgs;
18
+ let generateCalls = 0;
18
19
 
19
20
  const service = {
20
21
  async getWalkthrough(args) {
@@ -23,6 +24,7 @@ describe('walkthrough routes', () => {
23
24
  },
24
25
  async generateWalkthrough(args) {
25
26
  lastArgs = args;
27
+ generateCalls += 1;
26
28
  if (job) return job;
27
29
  job = new Promise((resolve) => {
28
30
  releaseJob = () => resolve({ walkthrough: { title: 'DONE' }, hunks: [], hunkCount: 1 });
@@ -54,12 +56,27 @@ describe('walkthrough routes', () => {
54
56
  });
55
57
 
56
58
  afterEach(async () => {
59
+ // A response a failed test never received keeps its keep-alive socket
60
+ // open, and server.close() would wait on it until the hook timeout.
61
+ server.closeAllConnections();
57
62
  await new Promise((resolve) => server.close(resolve));
58
63
  });
59
64
 
65
+ // Resolves once the route has asked the service to generate one more time
66
+ // than `seen`. A fixed sleep assumed the request had arrived by then; on a
67
+ // loaded runner it had not, and the step that followed acted on a request
68
+ // the server had not seen yet.
69
+ const untilGenerateCalled = async (seen) => {
70
+ for (let attempt = 0; attempt < 300 && generateCalls <= seen; attempt += 1) {
71
+ await new Promise((resolve) => setTimeout(resolve, 10));
72
+ }
73
+ if (generateCalls <= seen) throw new Error('the route never asked the service to generate');
74
+ };
75
+
60
76
  it('answers a generation request that nobody interrupted', async () => {
77
+ const seen = generateCalls;
61
78
  const pending = generate();
62
- await new Promise((resolve) => setTimeout(resolve, 20));
79
+ await untilGenerateCalled(seen);
63
80
  releaseJob();
64
81
 
65
82
  const body = await (await pending).json();
@@ -69,8 +86,9 @@ describe('walkthrough routes', () => {
69
86
 
70
87
  it('delivers the result to a client that reconnected after a refresh', async () => {
71
88
  const controller = new AbortController();
89
+ const seen = generateCalls;
72
90
  generate(controller.signal).catch(() => {});
73
- await new Promise((resolve) => setTimeout(resolve, 20));
91
+ await untilGenerateCalled(seen);
74
92
  controller.abort();
75
93
  await new Promise((resolve) => setTimeout(resolve, 20));
76
94
 
@@ -80,8 +98,9 @@ describe('walkthrough routes', () => {
80
98
  )).json();
81
99
  expect(read.generating).toBe(true);
82
100
 
101
+ const seenBeforeReattach = generateCalls;
83
102
  const reattached = generate();
84
- await new Promise((resolve) => setTimeout(resolve, 20));
103
+ await untilGenerateCalled(seenBeforeReattach);
85
104
  releaseJob();
86
105
 
87
106
  const body = await (await reattached).json();
@@ -108,12 +127,13 @@ describe('walkthrough routes', () => {
108
127
  );
109
128
  expect(lastArgs.language).toBe('uk');
110
129
 
130
+ const seen = generateCalls;
111
131
  const pending = fetch(`${base}/api/walkthrough/generate`, {
112
132
  method: 'POST',
113
133
  headers: { 'Content-Type': 'application/json' },
114
134
  body: JSON.stringify({ directory: '/repo', source: SOURCE, language: 'ja' }),
115
135
  });
116
- await new Promise((resolve) => setTimeout(resolve, 20));
136
+ await untilGenerateCalled(seen);
117
137
  releaseJob();
118
138
  await pending;
119
139
 
@@ -129,8 +149,9 @@ describe('walkthrough routes', () => {
129
149
  });
130
150
 
131
151
  it('cancels through its own endpoint rather than a dropped connection', async () => {
152
+ const seen = generateCalls;
132
153
  generate().catch(() => {});
133
- await new Promise((resolve) => setTimeout(resolve, 20));
154
+ await untilGenerateCalled(seen);
134
155
 
135
156
  const response = await fetch(`${base}/api/walkthrough/cancel`, {
136
157
  method: 'POST',
@@ -1,4 +1,4 @@
1
- import { getDiff, getRangeDiff, getUntrackedDiffs, listUntrackedPaths } from '../git/service.js';
1
+ import { getDiff, getRangeDiff, getCommitDiff, getUntrackedDiffs, listUntrackedPaths } from '../git/service.js';
2
2
 
3
3
  // A walkthrough source resolves to one or more diff *sections*. A section is a
4
4
  // patch plus the scope its hunk ids live in; keeping staged and working-tree
@@ -48,6 +48,18 @@ export function parseSource(raw) {
48
48
  return { kind: 'pr', number };
49
49
  }
50
50
 
51
+ if (raw.kind === 'commit') {
52
+ // Sources are content-addressed: accept a full object id, never a moving ref.
53
+ if (!/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i.test(raw.hash)) {
54
+ throw new WalkthroughSourceError('commit sources require a full commit hash');
55
+ }
56
+ try {
57
+ return { kind: 'commit', hash: raw.hash.toLowerCase() };
58
+ } catch {
59
+ throw new WalkthroughSourceError('commit sources require a full commit hash');
60
+ }
61
+ }
62
+
51
63
  throw new WalkthroughSourceError(`Unknown source kind "${String(raw.kind)}"`);
52
64
  }
53
65
 
@@ -58,6 +70,7 @@ export function parseSource(raw) {
58
70
  export function sourceKey(source) {
59
71
  if (source.kind === 'working-tree') return `working-tree:${source.scope}`;
60
72
  if (source.kind === 'branch') return `branch:${source.baseRef}...${source.headRef}`;
73
+ if (source.kind === 'commit') return `commit:${source.hash}`;
61
74
  return `pr:${source.number}`;
62
75
  }
63
76
 
@@ -97,13 +110,21 @@ export async function loadSourceSections(directory, source, { getPullRequestDiff
97
110
  }
98
111
 
99
112
  if (source.kind === 'branch') {
100
- const patch = await getRangeDiff(directory, { base: source.baseRef, head: source.headRef });
113
+ const patch = await getRangeDiff(directory, { base: source.baseRef, head: source.headRef, includeWorkingTree: true });
101
114
  return {
102
115
  sections: patch && patch.trim() ? [{ scope: 'branch', patch }] : [],
103
116
  meta: { baseRef: source.baseRef, headRef: source.headRef },
104
117
  };
105
118
  }
106
119
 
120
+ if (source.kind === 'commit') {
121
+ const patch = await getCommitDiff(directory, { hash: source.hash });
122
+ return {
123
+ sections: patch.trim() ? [{ scope: 'commit', patch }] : [],
124
+ meta: { hash: source.hash },
125
+ };
126
+ }
127
+
107
128
  if (typeof getPullRequestDiff !== 'function') {
108
129
  throw new WalkthroughSourceError('Pull request diffs are unavailable', 500);
109
130
  }
@@ -1 +0,0 @@
1
- import{R as S,f as oe,j as s}from"./vendor-react-BUCujlKS.js";import{u as Ae}from"./vendor-tanstack-react-virtual-g05Cx3z9.js";import{f as Q,ap as ze,a6 as fe,a7 as me,I as R,a8 as ue,h as Z,B as J,a1 as Ee,h4 as Ie,bG as pe,bH as ge,bI as xe,bJ as be,bK as ye,bL as ve,b5 as Te}from"./useAppFontEffects-COAeIX-D.js";import{u as Ce}from"./index-qES19dlJ.js";const ke={"?":{code:"?",color:"var(--status-info)",description:"Untracked file"},A:{code:"A",color:"var(--status-success)",description:"New file"},D:{code:"D",color:"var(--status-error)",description:"Deleted file"},R:{code:"R",color:"var(--status-info)",description:"Renamed file"},C:{code:"C",color:"var(--status-info)",description:"Copied file"},M:{code:"M",color:"var(--status-warning)",description:"Modified file"}},Me=ke.M;function He(p){const e=p.index?.trim(),t=p.working_dir?.trim();return e&&e!=="?"?e.charAt(0):t?t.charAt(0):e?.charAt(0)||t?.charAt(0)||"M"}function Re(p){const e=He(p);return ke[e]??Me}const $e=S.memo(function(e){const t=oe.c(58),{file:o,actionLabel:x,actionSymbol:b,onAction:m,onViewDiff:f,onRevert:l,isReverting:d,stats:z,rowPaddingClassName:g,indentPx:y,actionAtStart:A,showRevert:$}=e,j=y===void 0?0:y,r=A===void 0?!1:A,w=$===void 0?!0:$;let N;t[0]!==o?(N=Re(o),t[0]=o,t[1]=N):N=t[1];const h=N,{t:E}=Q(),F=h.description,M=z?.insertions??0,C=z?.deletions??0;let D;t[2]!==m||t[3]!==f?(D=U=>{U.key===" "?(U.preventDefault(),m()):U.key==="Enter"&&(U.preventDefault(),f())},t[2]=m,t[3]=f,t[4]=D):D=t[4];const V=D;let I;t[5]!==m?(I=U=>{U.preventDefault(),U.stopPropagation(),m()},t[5]=m,t[6]=I):I=t[6];const u=I;let P;t[7]!==l?(P=U=>{U.preventDefault(),U.stopPropagation(),l()},t[7]=l,t[8]=P):P=t[8];const W=P;let L;t[9]!==x||t[10]!==b||t[11]!==u?(L=s.jsx("button",{type:"button",onClick:u,className:"flex size-5 shrink-0 items-center justify-center rounded typography-micro font-semibold text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--interactive-focus-ring)]","aria-label":x,title:x,children:b}),t[9]=x,t[10]=b,t[11]=u,t[12]=L):L=t[12];const H=L,X=`group flex items-center gap-2 py-1.5 cursor-pointer ${g??"px-3"}`;let T;t[13]!==j?(T=j>0?{paddingLeft:`${j}px`}:void 0,t[13]=j,t[14]=T):T=t[14];const Y=r?H:null;let K;t[15]!==h.color?(K={color:h.color},t[15]=h.color,t[16]=K):K=t[16];let G;t[17]!==h.code||t[18]!==F||t[19]!==K?(G=s.jsx("span",{className:"typography-micro font-semibold w-4 text-center uppercase",style:K,title:F,"aria-label":F,children:h.code}),t[17]=h.code,t[18]=F,t[19]=K,t[20]=G):G=t[20];let O;t[21]!==o.path?(O=s.jsx(ze,{filePath:o.path,className:"h-3.5 w-3.5 shrink-0"}),t[21]=o.path,t[22]=O):O=t[22];let B;if(t[23]!==o.path){e:{const U=o.path.lastIndexOf("/");if(U===-1){let ne;t[25]===Symbol.for("react.memo_cache_sentinel")?(ne={direction:"rtl",textAlign:"left",unicodeBidi:"plaintext"},t[25]=ne):ne=t[25],B=s.jsx("span",{className:"flex-1 min-w-0 truncate typography-ui-label text-foreground",style:ne,title:o.path,children:o.path});break e}const De=o.path.slice(0,U),Ve=o.path.slice(U);let te;t[26]===Symbol.for("react.memo_cache_sentinel")?(te={direction:"rtl",textAlign:"left",unicodeBidi:"plaintext"},t[26]=te):te=t[26];let se;t[27]===Symbol.for("react.memo_cache_sentinel")?(se=s.jsx("span",{className:"text-muted-foreground",children:"/"}),t[27]=se):se=t[27];const re=s.jsx("span",{className:"text-foreground",children:Ve.slice(1)});let ie;t[28]!==re?(ie=s.jsxs("span",{className:"flex-shrink-0 typography-ui-label",children:[se,re]}),t[28]=re,t[29]=ie):ie=t[29],B=s.jsxs("span",{className:"flex-1 min-w-0 flex items-baseline overflow-hidden",title:o.path,children:[s.jsx("span",{className:"min-w-0 truncate typography-ui-label text-muted-foreground",style:te,children:De}),ie]})}t[23]=o.path,t[24]=B}else B=t[24];let q;t[30]===Symbol.for("react.memo_cache_sentinel")?(q={color:"var(--status-success)"},t[30]=q):q=t[30];let i;t[31]!==M?(i=s.jsxs("span",{style:q,children:["+",M]}),t[31]=M,t[32]=i):i=t[32];let n,a;t[33]===Symbol.for("react.memo_cache_sentinel")?(n=s.jsx("span",{className:"text-muted-foreground mx-0.5",children:"/"}),a={color:"var(--status-error)"},t[33]=n,t[34]=a):(n=t[33],a=t[34]);let c;t[35]!==C?(c=s.jsxs("span",{style:a,children:["-",C]}),t[35]=C,t[36]=c):c=t[36];let k;t[37]!==i||t[38]!==c?(k=s.jsxs("span",{className:"shrink-0 typography-micro",children:[i,n,c]}),t[37]=i,t[38]=c,t[39]=k):k=t[39];let v;t[40]!==o.path||t[41]!==W||t[42]!==d||t[43]!==w||t[44]!==E?(v=w?s.jsxs(fe,{children:[s.jsx(me,{asChild:!0,children:s.jsx("button",{type:"button",onClick:W,disabled:d,className:"flex size-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary disabled:cursor-not-allowed disabled:opacity-50","aria-label":E("gitView.changes.revertFileAria",{path:o.path}),children:d?s.jsx(R,{name:"loader-4",className:"size-3.5 animate-spin"}):s.jsx(R,{name:"arrow-go-back",className:"size-3.5"})})}),s.jsx(ue,{sideOffset:8,children:E("gitView.changes.revertFileTooltip")})]}):null,t[40]=o.path,t[41]=W,t[42]=d,t[43]=w,t[44]=E,t[45]=v):v=t[45];const _=r?null:H;let ee;return t[46]!==V||t[47]!==f||t[48]!==T||t[49]!==Y||t[50]!==G||t[51]!==O||t[52]!==B||t[53]!==k||t[54]!==v||t[55]!==_||t[56]!==X?(ee=s.jsxs("div",{className:X,role:"button",tabIndex:0,onClick:f,onKeyDown:V,style:T,children:[Y,G,O,B,k,v,_]}),t[46]=V,t[47]=f,t[48]=T,t[49]=Y,t[50]=G,t[51]=O,t[52]=B,t[53]=k,t[54]=v,t[55]=_,t[56]=X,t[57]=ee):ee=t[57],ee}),je=14,Se=p=>p.replace(/\\/g,"/").replace(/^\/+/,"").trim(),we=(p,e)=>({id:`dir:${p}`,path:p,name:e,children:new Map,directFiles:[],files:[]}),Fe=p=>{const e=we("","");for(const t of p){const o=Se(t.path);if(!o)continue;const b=o.split("/").filter(Boolean).slice(0,-1);let m=e;if(m.files.push(t),b.length>0){let f="";for(const l of b){f=f?`${f}/${l}`:l;const d=m.children.get(l);if(d){d.files.push(t),m=d;continue}const z=we(f,l);z.files.push(t),m.children.set(l,z),m=z}}m.directFiles.push(t)}return e},Pe=(p,e)=>{const t=[],o=(x,b)=>{const m=Array.from(x.children.values()).sort((l,d)=>l.path.localeCompare(d.path));for(const l of m)t.push({key:l.id,kind:"directory",depth:b,directory:l}),e.has(l.path)&&o(l,b+1);const f=[...x.directFiles].sort((l,d)=>l.path.localeCompare(d.path));for(const l of f)t.push({key:`file:${Se(l.path)}`,kind:"file",depth:b,file:l})};return o(p,0),t},Le=1e3,Ne=34,ce=30,le="pl-0 pr-2",de=(p,e)=>`${p} ${e}`,Ye=({groups:p,diffStats:e,revertingPaths:t,isRevertingAll:o=!1,headerBackgroundClassName:x="bg-sidebar",onVisiblePathsChange:b,onRevertAll:m,onRevertDirectory:f})=>{const{t:l}=Q(),d=S.useRef(null),g=Ce(i=>i.gitChangesViewMode)==="tree",y=S.useMemo(()=>p.filter(i=>i.entries.length>0),[p]),[A,$]=S.useState(new Set),[j,r]=S.useState(new Set),[w,N]=S.useState(!1),[h,E]=S.useState(null),F=S.useMemo(()=>y.map(i=>Fe(i.entries)),[y]),M=S.useMemo(()=>{const i=[];return y.forEach((n,a)=>{Array.from(F[a]?.children.values()??[]).forEach(c=>{i.push(de(n.id,c.path))})}),i},[F,y]);S.useEffect(()=>{g&&r(i=>{const n=new Set,a=new Set(M);return i.forEach(c=>{(c.slice(c.indexOf(" ")+1).includes("/")||a.has(c))&&n.add(c)}),M.forEach(c=>n.add(c)),n})},[g,M]);const C=S.useMemo(()=>{const i=[];return y.forEach((n,a)=>{if(i.push({type:"header",key:`header:${n.id}`,groupIndex:a}),!A.has(n.id)){if(g){const c=new Set;j.forEach(v=>{v.startsWith(`${n.id} `)&&c.add(v.slice(n.id.length+1))}),Pe(F[a],c).forEach(v=>{v.kind==="file"?i.push({type:"file",key:`${n.id}:${v.key}`,groupIndex:a,file:v.file,depth:v.depth}):i.push({type:"directory",key:`${n.id}:${v.key}`,groupIndex:a,directory:v.directory,depth:v.depth})});return}n.entries.forEach(c=>{i.push({type:"file",key:`${n.id}:file:${c.path}`,groupIndex:a,file:c,depth:0})})}}),m&&y.length>0&&i.push({type:"revert-all",key:"revert-all"}),i},[A,j,g,m,F,y]),D=C.length,V=D>=Le,I=Ae({count:D,enabled:V,getScrollElement:()=>d.current,estimateSize:()=>Ne,overscan:12,getItemKey:i=>C[i]?.key??i}),u=I.getVirtualItems(),P=S.useMemo(()=>{if(!V)return 0;const i=d.current?.scrollTop??0;return u.find(a=>a.end>i)?.index??0},[V,u,d]);S.useEffect(()=>{if(!b)return;const i=n=>n&&n.type==="file"?n.file.path:null;if(D===0){b([]);return}if(!V){const n=[];for(const a of C)if(a.type==="file"&&(n.push(a.file.path),n.length>=ce))break;b(n);return}b(C.slice(P,P+Math.ceil((d.current?.clientHeight??0)/Ne)+ce).map(n=>i(n)).filter(n=>!!n).slice(0,ce))},[b,D,C,V,P]);const W=S.useCallback(i=>{$(n=>{const a=new Set(n);return a.has(i)?a.delete(i):a.add(i),a})},[]),L=S.useCallback((i,n)=>{r(a=>{const c=new Set(a),k=de(i,n);return c.has(k)?c.delete(k):c.add(k),c})},[]),H=S.useMemo(()=>{const i=new Set;return y.forEach(n=>n.entries.forEach(a=>i.add(a.path))),Array.from(i)},[y]),X=H.length,T=h?o||h.paths.some(i=>t.has(i)):!1,Y=S.useCallback(async()=>{!m||o||H.length===0||(await m(H),N(!1))},[H,o,m]),K=S.useCallback(async()=>{!f||!h||T||(await f(h.paths),E(null))},[T,f,h]),G=S.useCallback((i,n)=>{const a=A.has(i.id),c=i.entries.length;return s.jsxs("div",{className:Z("sticky top-0 z-10 flex items-center gap-2 py-2",x,le,!n&&"mt-1 border-t border-border/40"),children:[s.jsx("button",{type:"button",onClick:()=>i.onActionAll(i.entries.map(k=>k.path)),className:"flex size-5 shrink-0 items-center justify-center rounded typography-micro font-semibold text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--interactive-focus-ring)]","aria-label":i.actionAllLabel,title:i.actionAllLabel,children:i.actionSymbol}),s.jsxs("button",{type:"button",onClick:()=>W(i.id),className:"flex min-w-0 flex-1 items-center gap-2 rounded text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--interactive-focus-ring)]","aria-expanded":!a,children:[s.jsx("h3",{className:"truncate typography-ui-header font-semibold text-foreground",children:i.title}),s.jsx("span",{className:"typography-meta text-muted-foreground",children:c}),s.jsx(R,{name:"arrow-down-s",className:Z("size-3.5 shrink-0 text-muted-foreground transition-transform",a&&"-rotate-90")})]})]})},[A,x,W]),O=S.useCallback((i,n,a)=>{const c=j.has(de(i.id,n.path)),k=n.files.map(_=>_.path),v=o||k.some(_=>t.has(_));return s.jsxs("div",{className:Z("group flex items-center gap-2 py-1.5",le),style:{paddingLeft:`${a*je}px`},children:[s.jsxs("button",{type:"button",onClick:()=>L(i.id,n.path),className:"flex min-w-0 flex-1 items-center gap-2 rounded text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary","aria-label":c?l("gitView.changes.collapseDirectoryAria",{path:n.path}):l("gitView.changes.expandDirectoryAria",{path:n.path}),children:[c?s.jsx(R,{name:"folder-open-fill",className:"h-4 w-4 flex-shrink-0 text-primary/60"}):s.jsx(R,{name:"folder-3-fill",className:"h-4 w-4 flex-shrink-0 text-primary/60"}),s.jsx("span",{className:"min-w-0 flex-1 truncate typography-ui-label text-foreground",title:n.path,children:n.name}),s.jsx("span",{className:"ml-auto shrink-0 typography-micro text-muted-foreground",children:n.files.length})]}),i.showRevertActions!==!1&&f?s.jsx("button",{type:"button",onClick:()=>E({path:n.path,paths:k,count:k.length}),disabled:v,className:"flex size-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--interactive-focus-ring)] disabled:cursor-not-allowed disabled:opacity-50","aria-label":l("gitView.changes.revertDirectoryAria",{path:n.path}),title:l("gitView.changes.revertDirectoryTooltip"),children:v?s.jsx(R,{name:"loader-4",className:"size-3.5 animate-spin"}):s.jsx(R,{name:"arrow-go-back",className:"size-3.5"})}):null,s.jsx("button",{type:"button",onClick:()=>i.onActionAll(n.files.map(_=>_.path)),className:"flex size-5 shrink-0 items-center justify-center rounded typography-micro font-semibold text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--interactive-focus-ring)]","aria-label":l(i.actionSymbol==="+"?"gitView.changes.stageDirectoryAria":"gitView.changes.unstageDirectoryAria",{path:n.path}),title:l(i.actionSymbol==="+"?"gitView.changes.stageDirectoryAria":"gitView.changes.unstageDirectoryAria",{path:n.path}),children:i.actionSymbol})]})},[j,o,f,t,l,L]),B=S.useCallback((i,n)=>{if(i.type==="revert-all")return s.jsx("div",{className:Z("flex justify-end py-2",le),children:s.jsxs(J,{variant:"ghost",size:"sm",onClick:()=>N(!0),disabled:o,className:"gap-1.5 text-[var(--status-error)] hover:bg-[var(--status-error)]/10 hover:text-[var(--status-error)]",children:[s.jsx(R,{name:"arrow-go-back",className:"size-3.5"}),l("gitView.changes.revertAll")]})});const a=y[i.groupIndex];if(!a)return null;if(i.type==="header")return G(a,n);if(i.type==="directory")return O(a,i.directory,i.depth);const c=i.file;return s.jsx($e,{file:c,actionLabel:a.getActionLabel(c.path),actionSymbol:a.actionSymbol,onAction:()=>a.onActionFile(c.path),stats:e?.[c.path],onViewDiff:()=>a.onViewDiff(c.path),onRevert:()=>a.onRevertFile(c.path),isReverting:t.has(c.path)||o,rowPaddingClassName:le,indentPx:i.depth*je,actionAtStart:!g,showRevert:a.showRevertActions!==!1})},[e,o,g,O,G,t,l,y]),q=S.useCallback(i=>{const n=C[i],a=C[i-1];return!n||!a||n.type!=="file"&&n.type!=="directory"||a.type!=="file"&&a.type!=="directory"?!1:a.groupIndex===n.groupIndex},[C]);return s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"relative flex h-full min-h-0 w-full flex-col overflow-hidden",children:[s.jsx(Ee,{ref:d,className:"overlay-scrollbar-target overlay-scrollbar-container min-h-0 w-full flex-1 overflow-x-hidden overflow-y-auto",children:V?s.jsx("div",{style:{height:I.getTotalSize(),position:"relative"},children:u.map(i=>{const n=C[i.index];return n?s.jsx("div",{"data-index":i.index,ref:I.measureElement,style:{position:"absolute",top:0,left:0,width:"100%",transform:`translateY(${i.start}px)`},className:Z(q(i.index)&&"before:pointer-events-none before:absolute before:left-0 before:right-2 before:top-0 before:border-t before:border-border/60"),children:B(n,i.index===0)},n.key):null})}):s.jsx("div",{role:"list","aria-label":l("gitView.changes.changedFilesAria"),children:C.map((i,n)=>s.jsx("div",{className:Z("relative",q(n)&&"before:pointer-events-none before:absolute before:left-0 before:right-2 before:top-0 before:border-t before:border-border/60"),children:B(i,n===0)},i.key))})}),s.jsx(Ie,{containerRef:d,disableHorizontal:!0})]}),s.jsx(pe,{open:w,onOpenChange:i=>{!o&&!i&&N(!1)},children:s.jsxs(ge,{className:"max-w-md",children:[s.jsxs(xe,{children:[s.jsx(be,{children:l("gitView.changes.revertAllDialogTitle")}),s.jsx(ye,{children:X===1?l("gitView.changes.revertAllDescriptionSingle",{count:X}):l("gitView.changes.revertAllDescriptionPlural",{count:X})})]}),s.jsxs(ve,{children:[s.jsx(J,{variant:"outline",size:"sm",onClick:()=>N(!1),disabled:o,children:l("gitView.common.cancel")}),s.jsx(J,{variant:"destructive",size:"sm",onClick:()=>{Y()},disabled:o,children:l(o?"gitView.changes.reverting":"gitView.changes.revertAll")})]})]})}),s.jsx(pe,{open:!!h,onOpenChange:i=>{!T&&!i&&E(null)},children:s.jsxs(ge,{className:"max-w-md",children:[s.jsxs(xe,{children:[s.jsx(be,{children:l("gitView.changes.revertDirectoryDialogTitle")}),s.jsx(ye,{children:h?h.count===1?l("gitView.changes.revertDirectoryDescriptionSingle",{count:h.count,path:h.path}):l("gitView.changes.revertDirectoryDescriptionPlural",{count:h.count,path:h.path}):null})]}),s.jsxs(ve,{children:[s.jsx(J,{variant:"outline",size:"sm",onClick:()=>E(null),disabled:T,children:l("gitView.common.cancel")}),s.jsx(J,{variant:"destructive",size:"sm",onClick:()=>{K()},disabled:T||!h,children:l(T?"gitView.changes.reverting":"gitView.changes.revertDirectory")})]})]})})]})},he=38,ae=200,Ge=p=>{const e=oe.c(23),{value:t,onChange:o,onSubmit:x,placeholder:b,disabled:m,hasTouchInput:f,isMobile:l}=p,d=m===void 0?!1:m,z=f===void 0?!1:f,g=l===void 0?!1:l,{t:y}=Q(),A=S.useRef(null),$=Ce(Oe);let j;e[0]===Symbol.for("react.memo_cache_sentinel")?(j=()=>{const u=A.current;if(!u)return;const P=document.activeElement===u,W=()=>{u.style.height=`${he}px`;const H=u.scrollHeight,X=Math.min(Math.max(H,he),ae);u.style.height=`${X}px`,u.style.overflowY=H>ae?"auto":"hidden",H>ae&&!P&&(u.scrollTop=u.scrollHeight)};W();const L=window.requestAnimationFrame(W);return()=>{window.cancelAnimationFrame(L)}},e[0]=j):j=e[0];let r;e[1]!==t?(r=[t],e[1]=t,e[2]=r):r=e[2],S.useLayoutEffect(j,r);let w;e[3]!==o?(w=u=>o(u.target.value),e[3]=o,e[4]=w):w=e[4];let N;e[5]!==x?(N=u=>{u.key==="Enter"&&(u.metaKey||u.ctrlKey)&&!u.shiftKey&&!u.altKey&&(u.preventDefault(),x?.())},e[5]=x,e[6]=N):N=e[6];let h;e[7]!==b||e[8]!==y?(h=b??y("gitView.commit.messagePlaceholder"),e[7]=b,e[8]=y,e[9]=h):h=e[9];const E=z?"on":"off",F=z?"sentences":"off",M=g||$,C=d&&"opacity-50";let D;e[10]!==C?(D=Z("w-full rounded-lg border border-border/60 bg-surface-elevated px-3 py-2 typography-ui-label text-foreground placeholder:text-muted-foreground","resize-none outline-none transition-[border-color,box-shadow] duration-150","focus-visible:ring-2 focus-visible:ring-[var(--interactive-focus-ring)]",C),e[10]=C,e[11]=D):D=e[11];let V;e[12]===Symbol.for("react.memo_cache_sentinel")?(V={minHeight:he,maxHeight:ae},e[12]=V):V=e[12];let I;return e[13]!==d||e[14]!==F||e[15]!==M||e[16]!==D||e[17]!==w||e[18]!==N||e[19]!==h||e[20]!==E||e[21]!==t?(I=s.jsx("textarea",{ref:A,value:t,onChange:w,onKeyDown:N,placeholder:h,rows:1,disabled:d,autoCorrect:E,autoCapitalize:F,spellCheck:M,className:D,style:V}),e[13]=d,e[14]=F,e[15]=M,e[16]=D,e[17]=w,e[18]=N,e[19]=h,e[20]=E,e[21]=t,e[22]=I):I=e[22],I};function Oe(p){return p.inputSpellcheckEnabled}const Ke=p=>{const e=oe.c(30),{highlights:t,onInsert:o}=p,{t:x}=Q();if(t.length===0)return null;let b;e[0]!==t||e[1]!==o?(b=()=>{o(t)},e[0]=t,e[1]=o,e[2]=b):b=e[2];const m=b;let f;e[3]!==x?(f=x("gitView.commit.aiHighlights.title"),e[3]=x,e[4]=f):f=e[4];let l;e[5]!==f?(l=s.jsx("p",{className:"typography-micro text-muted-foreground",children:f}),e[5]=f,e[6]=l):l=e[6];let d;e[7]!==x?(d=x("gitView.commit.aiHighlights.insertAria"),e[7]=x,e[8]=d):d=e[8];let z;e[9]===Symbol.for("react.memo_cache_sentinel")?(z=s.jsx(R,{name:"arrow-down",className:"size-4"}),e[9]=z):z=e[9];let g;e[10]!==m||e[11]!==d?(g=s.jsx(me,{asChild:!0,children:s.jsx(J,{variant:"ghost",size:"icon",className:"size-6",onClick:m,"aria-label":d,children:z})}),e[10]=m,e[11]=d,e[12]=g):g=e[12];let y;e[13]!==x?(y=x("gitView.commit.aiHighlights.insertTooltip"),e[13]=x,e[14]=y):y=e[14];let A;e[15]!==y?(A=s.jsx(ue,{sideOffset:8,children:y}),e[15]=y,e[16]=A):A=e[16];let $;e[17]!==g||e[18]!==A?($=s.jsxs(fe,{children:[g,A]}),e[17]=g,e[18]=A,e[19]=$):$=e[19];let j;e[20]!==l||e[21]!==$?(j=s.jsxs("div",{className:"flex items-center justify-between gap-2",children:[l,$]}),e[20]=l,e[21]=$,e[22]=j):j=e[22];let r;e[23]!==t?(r=t.map(Be),e[23]=t,e[24]=r):r=e[24];let w;e[25]!==r?(w=s.jsx("ul",{className:"space-y-1",children:r}),e[25]=r,e[26]=w):w=e[26];let N;return e[27]!==j||e[28]!==w?(N=s.jsxs("div",{className:"space-y-2 rounded-xl border border-border/60 bg-transparent px-3 py-2",children:[j,w]}),e[27]=j,e[28]=w,e[29]=N):N=e[29],N};function Be(p,e){return s.jsx("li",{className:"typography-meta text-foreground",children:p},`${p}-${e}`)}const qe=p=>{const e=oe.c(80),{stagedCount:t,commitMessage:o,onCommitMessageChange:x,generatedHighlights:b,onInsertHighlights:m,onGenerateMessage:f,isGeneratingMessage:l,onCommit:d,onCommitAndPush:z,commitAction:g,hasPendingIndexMutation:y,gitmojiEnabled:A,onOpenGitmojiPicker:$}=p,j=y===void 0?!1:y,{t:r}=Q(),w=t>0;let N;e[0]!==g||e[1]!==o||e[2]!==j||e[3]!==w?(N=o.trim()&&w&&g===null&&!j,e[0]=g,e[1]=o,e[2]=j,e[3]=w,e[4]=N):N=e[4];const h=N,{isMobile:E,hasTouchInput:F}=Te();let M;e[5]!==r?(M=r("gitView.commit.title"),e[5]=r,e[6]=M):M=e[6];let C;e[7]!==M?(C=s.jsx("h3",{className:"typography-ui-header font-semibold text-foreground",children:M}),e[7]=M,e[8]=C):C=e[8];let D;e[9]!==w||e[10]!==r?(D=w?null:s.jsx("span",{className:"min-w-0 truncate typography-meta text-muted-foreground",children:r("gitView.commit.stageFilesHint")}),e[9]=w,e[10]=r,e[11]=D):D=e[11];let V;e[12]!==C||e[13]!==D?(V=s.jsxs("div",{className:"flex w-full items-baseline gap-2 px-0 pt-2 pb-1",children:[C,D]}),e[12]=C,e[13]=D,e[14]=V):V=e[14];let I;e[15]!==b||e[16]!==m?(I=s.jsx(Ke,{highlights:b,onInsert:m}),e[15]=b,e[16]=m,e[17]=I):I=e[17];let u;e[18]!==h||e[19]!==l||e[20]!==d?(u=()=>{h&&!l&&d()},e[18]=h,e[19]=l,e[20]=d,e[21]=u):u=e[21];let P;e[22]!==r?(P=r("gitView.commit.messagePlaceholder"),e[22]=r,e[23]=P):P=e[23];const W=g!==null;let L;e[24]!==o||e[25]!==F||e[26]!==E||e[27]!==x||e[28]!==W||e[29]!==u||e[30]!==P?(L=s.jsx(Ge,{value:o,onChange:x,onSubmit:u,placeholder:P,disabled:W,hasTouchInput:F,isMobile:E}),e[24]=o,e[25]=F,e[26]=E,e[27]=x,e[28]=W,e[29]=u,e[30]=P,e[31]=L):L=e[31];let H;e[32]!==A||e[33]!==$||e[34]!==r?(H=A&&s.jsxs(J,{variant:"outline",size:"sm",onClick:$,className:"w-fit",type:"button",children:[s.jsx(R,{name:"emotion-happy",className:"size-4"}),r("gitView.commit.addGitmoji")]}),e[32]=A,e[33]=$,e[34]=r,e[35]=H):H=e[35];const X=l||g!==null||j||t===0;let T;e[36]!==r?(T=r("gitView.commit.generateAria"),e[36]=r,e[37]=T):T=e[37];let Y;e[38]!==l?(Y=l?s.jsx(R,{name:"loader-4",className:"size-4 animate-spin"}):s.jsx(R,{name:"ai-generate-2",className:"size-4 text-primary"}),e[38]=l,e[39]=Y):Y=e[39];let K;e[40]!==r?(K=r("gitView.commit.generate"),e[40]=r,e[41]=K):K=e[41];let G;e[42]!==K?(G=s.jsx("span",{className:"commit-actions__label",children:K}),e[42]=K,e[43]=G):G=e[43];let O;e[44]!==f||e[45]!==X||e[46]!==T||e[47]!==Y||e[48]!==G?(O=s.jsxs(J,{variant:"outline",size:"sm",onClick:f,disabled:X,type:"button","aria-label":T,className:"commit-actions__btn",children:[Y,G]}),e[44]=f,e[45]=X,e[46]=T,e[47]=Y,e[48]=G,e[49]=O):O=e[49];let B;e[50]===Symbol.for("react.memo_cache_sentinel")?(B=s.jsx("div",{className:"flex-1"}),e[50]=B):B=e[50];const q=!h||l;let i;e[51]!==r?(i=r("gitView.commit.commitAria"),e[51]=r,e[52]=i):i=e[52];let n;e[53]!==g||e[54]!==r?(n=g==="commit"?s.jsxs(s.Fragment,{children:[s.jsx(R,{name:"loader-4",className:"size-4 animate-spin"}),s.jsx("span",{className:"commit-actions__label",children:r("gitView.commit.committing")})]}):s.jsxs(s.Fragment,{children:[s.jsx(R,{name:"git-commit",className:"size-4"}),s.jsx("span",{className:"commit-actions__label",children:r("gitView.commit.commit")})]}),e[53]=g,e[54]=r,e[55]=n):n=e[55];let a;e[56]!==d||e[57]!==q||e[58]!==i||e[59]!==n?(a=s.jsx(J,{size:"sm",variant:"outline",onClick:d,disabled:q,className:"commit-actions__btn whitespace-nowrap","aria-label":i,children:n}),e[56]=d,e[57]=q,e[58]=i,e[59]=n,e[60]=a):a=e[60];let c;e[61]!==h||e[62]!==g||e[63]!==l||e[64]!==E||e[65]!==z||e[66]!==r?(c=E?s.jsxs(fe,{children:[s.jsx(me,{asChild:!0,children:s.jsx(J,{variant:"default",size:"sm",onClick:()=>z(),disabled:!h||l,className:"h-7 w-7 p-0","aria-label":r("gitView.commit.pushAria"),children:g==="commitAndPush"?s.jsx(R,{name:"loader-4",className:"size-4 animate-spin"}):s.jsx(R,{name:"arrow-up",className:"size-3.5"})})}),s.jsx(ue,{side:"top",children:s.jsx("p",{children:r("gitView.commit.push")})})]}):s.jsx(J,{size:"sm",variant:"default",onClick:()=>z(),disabled:!h||l,className:"commit-actions__btn","aria-label":r("gitView.commit.pushAria"),children:g==="commitAndPush"?s.jsxs(s.Fragment,{children:[s.jsx(R,{name:"loader-4",className:"size-4 animate-spin"}),s.jsx("span",{className:"commit-actions__label commit-actions__label--push",children:r("gitView.commit.pushing")})]}):s.jsxs(s.Fragment,{children:[s.jsx(R,{name:"arrow-up",className:"size-3.5"}),s.jsx("span",{className:"commit-actions__label commit-actions__label--push",children:r("gitView.commit.push")})]})}),e[61]=h,e[62]=g,e[63]=l,e[64]=E,e[65]=z,e[66]=r,e[67]=c):c=e[67];let k;e[68]!==O||e[69]!==a||e[70]!==c?(k=s.jsxs("div",{className:"@container/commit-actions flex items-center gap-2 min-w-0",children:[O,B,a,c]}),e[68]=O,e[69]=a,e[70]=c,e[71]=k):k=e[71];let v;e[72]!==L||e[73]!==H||e[74]!==k||e[75]!==I?(v=s.jsxs("div",{className:"flex flex-col gap-3 px-0 pt-1 pb-3",children:[I,L,H,k]}),e[72]=L,e[73]=H,e[74]=k,e[75]=I,e[76]=v):v=e[76];let _;return e[77]!==v||e[78]!==V?(_=s.jsxs("section",{className:"border-0 bg-transparent rounded-none",children:[V,v]}),e[77]=v,e[78]=V,e[79]=_):_=e[79],_};export{Ye as C,qe as a};
@@ -1,4 +0,0 @@
1
- import{R as o,j as n,f as he}from"./vendor-react-BUCujlKS.js";import{X as wn,a as ct,u as Y,F as Pe}from"./index-qES19dlJ.js";import{f as ge,V as Tt,ab as yn,ac as vn,b5 as jn,ae as Sn,ad as Nn,af as Fn,ag as Z,y as Ft,k as kn,hQ as Cn,hR as Rn,hS as Dn,cC as An,t as Ke,hT as En,an as Ve,B as pe,I as A,h as ue,a6 as Bn,a7 as Vn,a8 as Ln,hD as Mt,hU as Tn,fD as Mn,fI as Ge,a0 as In,c2 as at,ap as It,am as _n,b1 as On,b3 as zn,fJ as Pn,b4 as Gn}from"./useAppFontEffects-COAeIX-D.js";import{b as Kn}from"./runtimeEndpointReset-CRGn1gVj.js";import{c as $n,p as Hn}from"./vendor-zustand-BAGL70zf.js";import{P as Wn}from"./PierreDiffViewer-Ct2A13NO.js";import{u as Un,v as qn,g as Xn,W as Jn}from"./main-CYgSu6dx.js";import{f as Qn}from"./patchFileDiff-BpMQZnYu.js";import"./vendor-scheduler-7OC5HNn7.js";import"./vendor-vite-runtime-DD1OZmLC.js";import"./vendor-zod-BLfBSgBh.js";import"./vendor-opencode-sdk-BJ73u-bH.js";import"./vendor-simplewebauthn-browser-VDA66rT_.js";import"./vendor-base-ui-BeMD8X_w.js";import"./vendor-floating-ui-utils-D6FqdtJt.js";import"./vendor-floating-ui-react-dom-DxYCWdHj.js";import"./vendor-floating-ui-dom-BTvzWks8.js";import"./vendor-floating-ui-core-PuGzNPnN.js";import"./vendor-use-sync-external-store-D6wYuSt-.js";import"./contextPanelEmbeddedChat-C9EcRSDF.js";import"./vendor-class-variance-authority-5VPnzWs2.js";import"./vendor-clsx-B-dksMZM.js";import"./vendor-dnd-kit-core-BZknOX2w.js";import"./vendor-dnd-kit-utilities-B_MdXhJC.js";import"./vendor-dnd-kit-accessibility-BHxJPORy.js";import"./vendor-dnd-kit-sortable-CsEagZ81.js";import"./vendor-framer-motion-livSKyyV.js";import"./vendor-motion-dom-D_o3BTI3.js";import"./vendor-motion-utils-BGh8QBgx.js";import"./vendor-tanstack-react-virtual-g05Cx3z9.js";import"./vendor-tanstack-virtual-core-Dubg10g5.js";import"./vendor-sonner-DFyL3AvE.js";import"./vendor-cmdk-DgLInKvT.js";import"./vendor-radix-ui-react-dialog-B94Bt2qq.js";import"./vendor-radix-ui-primitive-Dc_FVRD7.js";import"./vendor-radix-ui-react-compose-refs-DcAh5WdT.js";import"./vendor-radix-ui-react-context-Czxm7Z62.js";import"./vendor-radix-ui-react-id-f5BLKEVw.js";import"./vendor-radix-ui-react-use-layout-effect-D_3IhJdJ.js";import"./vendor-radix-ui-react-use-controllable-state-BFT5YmkA.js";import"./vendor-radix-ui-react-dismissable-layer-D7kXcwgJ.js";import"./vendor-radix-ui-react-primitive-DhVoX9SD.js";import"./vendor-radix-ui-react-slot-BQgQOasS.js";import"./vendor-radix-ui-react-use-callback-ref-BZPnuXAC.js";import"./vendor-radix-ui-react-use-escape-keydown-oph88g-F.js";import"./vendor-radix-ui-react-focus-scope-CiaxW4dD.js";import"./vendor-radix-ui-react-portal-BMJYHWck.js";import"./vendor-radix-ui-react-presence-CNxf-uq4.js";import"./vendor-radix-ui-react-focus-guards-B6qJXYua.js";import"./vendor-react-remove-scroll-DO7dCTnK.js";import"./vendor-tslib-De9GV7Vy.js";import"./vendor-react-remove-scroll-bar-BcFYyj3E.js";import"./vendor-react-style-singleton-q6EMHnwf.js";import"./vendor-get-nonce-C-Z93AgS.js";import"./vendor-use-sidecar-zDC0RhA3.js";import"./vendor-use-callback-ref-D3RC8gqK.js";import"./vendor-aria-hidden-DvXkyWUv.js";import"./vendor-codemirror-language-BgPj_McA.js";import"./vendor-lezer-common-B3-cUCR_.js";import"./vendor-codemirror-state-C9awkmn-.js";import"./vendor-marijn-find-cluster-break-DXwl3gUT.js";import"./vendor-codemirror-view-CiLROUVV.js";import"./vendor-style-mod-NZ5MEPvj.js";import"./vendor-w3c-keyname-Vcq4gwWv.js";import"./vendor-crelt-C8TCjufn.js";import"./vendor-lezer-highlight-CDMHUZ74.js";import"./vendor-codemirror-lang-javascript-Cc2ZYbgX.js";import"./vendor-lezer-javascript-D7Tj24ot.js";import"./vendor-lezer-lr-bhwg1HMg.js";import"./vendor-codemirror-autocomplete-DzPz9Wgq.js";import"./vendor-codemirror-lang-json-CMBS2tG9.js";import"./vendor-lezer-json-Iaex0UN-.js";import"./vendor-codemirror-lang-css-O0cZX78y.js";import"./vendor-lezer-css-C5xB6jxd.js";import"./vendor-codemirror-lang-html-CfgK872x.js";import"./vendor-lezer-html-C0I1p52t.js";import"./vendor-codemirror-lang-markdown-BPGOH9ye.js";import"./vendor-lezer-markdown-C6g-d6P3.js";import"./vendor-codemirror-language-data-BG3v1Ghq.js";import"./vendor-codemirror-lang-python-HahnQaAS.js";import"./vendor-lezer-python-CvuFxeZl.js";import"./vendor-codemirror-commands-B7H_j0iU.js";import"./vendor-legendapp-list-gg7YLRW7.js";import"./vendor-tailwind-merge-CPcsbTWB.js";import"./vendor-fuse.js-Dw8P0qyA.js";import"./web-components-BNMwa0qm.js";import"./computeVirtualFileMetrics-DtyozJdt.js";import"./vendor-shiki-Bbf2GEcE.js";import"./vendor-shikijs-core-CGM_jqPK.js";import"./vendor-shikijs-types-CPSbSeK6.js";import"./vendor-shikijs-vscode-textmate-BgLrS_2D.js";import"./vendor-hast-util-to-html-BKBhbTDb.js";import"./vendor-html-void-elements-CkdplsNl.js";import"./vendor-property-information-rJCbAzvX.js";import"./vendor-zwitch-C2o2j-tx.js";import"./vendor-stringify-entities-CsH1VEn9.js";import"./vendor-character-entities-legacy-BpoLgcEt.js";import"./vendor-character-entities-html4-D7taRCQ7.js";import"./vendor-ccount-c2V3InAJ.js";import"./vendor-comma-separated-tokens-D8TqSuIK.js";import"./vendor-space-separated-tokens-DD3iYX1K.js";import"./vendor-hast-util-whitespace-D4Wp6AEg.js";import"./vendor-shikijs-engine-oniguruma-DPWuIF1G.js";import"./themeResolver-BmJyTmjJ.js";import"./vendor-pierre-theming-C6Z4M5_u.js";import"./vendor-shikijs-engine-javascript-Cme4830A.js";import"./vendor-oniguruma-to-es-DLBnFDCE.js";import"./vendor-oniguruma-parser-C0D4_9rT.js";import"./vendor-regex-BBWcyTkg.js";import"./vendor-regex-utilities-2BQyy0xI.js";import"./vendor-regex-recursion-JU4mF-dD.js";import"./vendor-shikijs-transformers-CZWsLLKm.js";import"./VirtualizedFileDiff-Dpz2ra8h.js";import"./isDiffPlainText-XyulMHxx.js";import"./vendor-diff-C3JhlQdm.js";import"./Virtualizer-D_a8gKmg.js";import"./useInlineCommentController-JsBboQwt.js";import"./appThemeRegistry-BK0dHKa6.js";import"./registerCustomTheme-BBXUCRnG.js";import"./useRootScrollLock-C0N9mCwz.js";import"./scheduledTasksApi-BSRCtP6T.js";import"./vendor-cron-parser-CUcP7OfX.js";import"./vendor-luxon-BZ0puJYg.js";const Yn="openchamber.git-base-branch",Zn=100,$e=(s,e)=>JSON.stringify([ct(),s,e]),kt=$n()(Hn((s,e)=>({overrides:{},getOverride:(i,a)=>!i||!a?null:e().overrides[$e(i,a)]??null,setOverride:(i,a,d)=>{!i||!a||!d||s(f=>{const h=$e(i,a),x=Object.entries({...f.overrides,[h]:d});for(;x.length>Zn;)x.shift();return{overrides:Object.fromEntries(x)}})},clearOverride:(i,a)=>{!i||!a||s(d=>{const f=$e(i,a);if(!(f in d.overrides))return d;const h={...d.overrides};return delete h[f],{overrides:h}})}}),{name:Yn,storage:wn(),partialize:s=>({overrides:s.overrides})})),es=(s,e)=>!!s&&e!==null&&s!==e,ts=(s,e,i,a)=>i?s===null||a&&e===null?!0:e!==null&&s===e:!1,ns=(s,e)=>s==="branch"&&!e?"working":s,ss=(s,e,i)=>JSON.stringify([s,e,i]),rs=(s,e,i,a,d,f)=>{const h=o.useRef({directory:"",attempts:0}),[x,u]=o.useState(()=>({directory:"",exhausted:!1})),p=o.useRef(d);p.current=d;const b=!!s&&x.directory===s&&x.exhausted;return o.useEffect(()=>{if(!s||!e||a||i)return;const w=h.current.directory===s?h.current.attempts:0;if(w>=f){x.directory===s&&x.exhausted||u({directory:s,exhausted:!0});return}h.current={directory:s,attempts:w+1},p.current()},[s,x,a,e,i,f]),b},is=(s,e,i,a)=>{const[d,f]=o.useState(()=>new Map),h=o.useRef(d);h.current=d;const x=o.useRef(i);x.current=i;const u=o.useCallback((p,b)=>{const w=new Map(h.current);if(b===null){if(!w.delete(p))return}else w.set(p,b);h.current=w,f(w)},[]);return o.useEffect(()=>{s&&(h.current=new Map,f(h.current))},[s]),o.useEffect(()=>{const p=x.current;if(!s||!p||!e)return;let b=!1;const w=new Set;for(const y of e.split("\0"))h.current.has(y)||(w.add(y),u(y,a),p(y).then(j=>{b||(w.delete(y),u(y,j))}).catch(()=>{b||(w.delete(y),u(y,null))}));return()=>{b=!0;for(const y of w)u(y,null)}},[e,a,s,u]),d},Ct=(s,e)=>{if(e.length===0)return null;let i=null,a=null;for(const f of e)f.top<=s?(!i||f.top>i.top)&&(i=f):(!a||f.top<a.top)&&(a=f);const d=i??a;return d?{path:d.path,topOffset:d.top-s}:null},os=(s,e,i,a)=>Math.min(Math.max(0,a),Math.max(0,s+i-e)),Rt=s=>{if(!s)return null;const e=s.split(`
2
- `);let i=null;for(const a of e){const d=a.match(/^@@\s*-\d+(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s*@@/);if(d){const f=Number.parseInt(d[1]??"",10);i=Number.isFinite(f)&&f>=1?f:null;continue}if(i!==null){if(a.startsWith(" ")){i+=1;continue}if(a.startsWith("+"))return i;if(a.startsWith("-"))return Math.max(1,i)}}return null},as=1100,ls=15e3,Dt=500,At=300,cs=1e6,us=3,fs=s=>s<=6?s:s<=12?6:s<=25?4:2,ds={original:"",modified:"",isBinary:!1,contextMode:"patch"},ps=3,ms=o.memo(()=>{const s=he.c(4),{t:e}=ge();let i;s[0]!==e?(i=e("diffView.binary.unavailable"),s[0]=e,s[1]=i):i=s[1];let a;return s[2]!==i?(a=n.jsx("div",{className:"rounded-lg border border-border/60 bg-background px-3 py-2",children:n.jsx("div",{className:"typography-meta text-muted-foreground",children:i})}),s[2]=i,s[3]=a):a=s[3],a}),_t={"?":{code:"?",color:"var(--status-info)",descriptionKey:"diffView.change.untracked"},A:{code:"A",color:"var(--status-success)",descriptionKey:"diffView.change.new"},D:{code:"D",color:"var(--status-error)",descriptionKey:"diffView.change.deleted"},R:{code:"R",color:"var(--status-info)",descriptionKey:"diffView.change.renamed"},C:{code:"C",color:"var(--status-info)",descriptionKey:"diffView.change.copied"},M:{code:"M",color:"var(--status-warning)",descriptionKey:"diffView.change.modified"}},hs=_t.M,gs=s=>{const e=s.index?.trim(),i=s.working_dir?.trim();return e&&e!=="?"?e.charAt(0):i?i.charAt(0):e?.charAt(0)||i?.charAt(0)||"M"},Ot=s=>{const e=gs(s);return _t[e]??hs},xs=s=>{const{index:e,working_dir:i}=s;return e==="A"||i==="A"||e==="?"||i==="?"},Et=s=>{const e=s.index?.trim();return!!(e&&e!=="?")},Bt=s=>!!s.working_dir?.trim()||s.index==="?",bs=(s,e)=>Mn(s,e),Vt=s=>(s||"").replace(/\\/g,"/").replace(/\/+$/,""),Lt=(s,e)=>{const i=s.split(`
3
- `),a=e.split(`
4
- `),d=Math.min(i.length,a.length);for(let f=0;f<d;f+=1)if(i[f]!==a[f])return f+1;return a.length>i.length?i.length+1:i.length>a.length?Math.max(1,a.length):1},ws=s=>/^Binary files .+ differ$/m.test(s)||/^GIT binary patch$/m.test(s),ys=s=>Array.isArray(s)?s.filter(e=>!e||typeof e!="object"?!1:typeof e.file=="string"):[],vs=s=>s==="added"?"A":s==="deleted"?"D":"M",lt=(s,e,i)=>ws(e)?{original:"",modified:"",isBinary:!0,patch:e,contextMode:i}:{original:"",modified:"",patch:e,fileDiff:Qn(s,e),contextMode:i},zt=(s,e,i)=>{const a=s??0,d=e??0;return!a&&!d?null:n.jsxs("span",{className:ue("typography-meta flex items-center gap-1 text-xs whitespace-nowrap","flex-shrink-0",i?.className),children:[a?n.jsxs("span",{style:{color:"var(--status-success)"},children:["+",a]}):null,d?n.jsxs("span",{style:{color:"var(--status-error)"},children:["-",d]}):null]})},js=o.memo(s=>{const e=he.c(58),{scope:i,workingCount:a,stagedCount:d,turnCount:f,branchCount:h,showBranchOption:x,onScopeChange:u}=s,{t:p}=ge(),[b,w]=o.useState(!1),y=i==="staged"?d:i==="turn"?f:i==="branch"?h??0:a;let j;e[0]!==i||e[1]!==p?(j=p(i==="staged"?"diffView.scope.staged":i==="turn"?"diffView.scope.lastTurn":i==="branch"?"diffView.scope.branch":"diffView.scope.changed"),e[0]=i,e[1]=p,e[2]=j):j=e[2];const P=j;let m;e[3]!==p?(m=p("diffView.scope.selectorAria"),e[3]=p,e[4]=m):m=e[4];let le;e[5]!==y?(le=n.jsxs("span",{className:"diff-toolbar__scope-count",children:[": ",y]}),e[5]=y,e[6]=le):le=e[6];let k;e[7]!==P||e[8]!==le?(k=n.jsxs("span",{className:"whitespace-nowrap",children:[P,le]}),e[7]=P,e[8]=le,e[9]=k):k=e[9];let E;e[10]===Symbol.for("react.memo_cache_sentinel")?(E=n.jsx(A,{name:"arrow-down-s",className:"size-4 flex-shrink-0 opacity-60"}),e[10]=E):E=e[10];let L;e[11]!==m||e[12]!==k?(L=n.jsx(On,{asChild:!0,children:n.jsxs("button",{type:"button",className:"flex h-7 flex-shrink-0 items-center gap-1.5 rounded-md px-2 typography-ui-label font-semibold text-foreground outline-none hover:bg-interactive-hover focus-visible:ring-2 focus-visible:ring-ring","aria-label":m,children:[k,E]})}),e[11]=m,e[12]=k,e[13]=L):L=e[13];let W;e[14]!==u?(W=B=>{(B==="working"||B==="staged"||B==="turn"||B==="branch")&&(u?.(B),w(!1))},e[14]=u,e[15]=W):W=e[15];let N;e[16]!==p?(N=p("diffView.scope.changed"),e[16]=p,e[17]=N):N=e[17];let ee;e[18]!==N?(ee=n.jsx("span",{children:N}),e[18]=N,e[19]=ee):ee=e[19];let U;e[20]!==a?(U=n.jsx("span",{className:"typography-meta text-muted-foreground",children:a}),e[20]=a,e[21]=U):U=e[21];let q;e[22]!==U||e[23]!==ee?(q=n.jsx(Ge,{value:"working",children:n.jsxs("span",{className:"flex min-w-0 flex-1 items-center justify-between gap-3",children:[ee,U]})}),e[22]=U,e[23]=ee,e[24]=q):q=e[24];let G;e[25]!==p?(G=p("diffView.scope.staged"),e[25]=p,e[26]=G):G=e[26];let K;e[27]!==G?(K=n.jsx("span",{children:G}),e[27]=G,e[28]=K):K=e[28];let te;e[29]!==d?(te=n.jsx("span",{className:"typography-meta text-muted-foreground",children:d}),e[29]=d,e[30]=te):te=e[30];let I;e[31]!==K||e[32]!==te?(I=n.jsx(Ge,{value:"staged",children:n.jsxs("span",{className:"flex min-w-0 flex-1 items-center justify-between gap-3",children:[K,te]})}),e[31]=K,e[32]=te,e[33]=I):I=e[33];let _;e[34]!==p?(_=p("diffView.scope.lastTurn"),e[34]=p,e[35]=_):_=e[35];let V;e[36]!==_?(V=n.jsx("span",{children:_}),e[36]=_,e[37]=V):V=e[37];let O;e[38]!==f?(O=n.jsx("span",{className:"typography-meta text-muted-foreground",children:f}),e[38]=f,e[39]=O):O=e[39];let ne;e[40]!==V||e[41]!==O?(ne=n.jsx(Ge,{value:"turn",children:n.jsxs("span",{className:"flex min-w-0 flex-1 items-center justify-between gap-3",children:[V,O]})}),e[40]=V,e[41]=O,e[42]=ne):ne=e[42];let T;e[43]!==h||e[44]!==x||e[45]!==p?(T=x?n.jsx(Ge,{value:"branch",children:n.jsxs("span",{className:"flex min-w-0 flex-1 items-center justify-between gap-3",children:[n.jsx("span",{children:p("diffView.scope.branch")}),n.jsx("span",{className:"typography-meta text-muted-foreground",children:h??"…"})]})}):null,e[43]=h,e[44]=x,e[45]=p,e[46]=T):T=e[46];let se;e[47]!==i||e[48]!==q||e[49]!==I||e[50]!==ne||e[51]!==T||e[52]!==W?(se=n.jsx(zn,{align:"start",className:"w-40",children:n.jsxs(Pn,{value:i,onValueChange:W,children:[q,I,ne,T]})}),e[47]=i,e[48]=q,e[49]=I,e[50]=ne,e[51]=T,e[52]=W,e[53]=se):se=e[53];let re;return e[54]!==b||e[55]!==se||e[56]!==L?(re=n.jsxs(Gn,{open:b,onOpenChange:w,children:[L,se]}),e[54]=b,e[55]=se,e[56]=L,e[57]=re):re=e[57],re}),Ss=o.memo(s=>{const e=he.c(11),{changedFiles:i,selectedFile:a,onSelectFile:d}=s,{t:f}=ge();if(i.length===0)return null;let h;if(e[0]!==i||e[1]!==d||e[2]!==a||e[3]!==f){let u;e[5]!==d||e[6]!==a||e[7]!==f?(u=p=>{const b=Ot(p),w=a===p.path;return n.jsx("li",{children:n.jsxs("button",{type:"button",onClick:()=>d(p.path),className:ue("flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left transition-colors",w?"bg-interactive-selection text-interactive-selection-foreground":"text-muted-foreground hover:bg-interactive-hover hover:text-foreground"),children:[n.jsx(It,{filePath:p.path,className:"h-3.5 w-3.5 flex-shrink-0"}),n.jsx("span",{className:"typography-micro font-semibold w-4 text-center uppercase",style:{color:b.color},title:f(b.descriptionKey),"aria-label":f(b.descriptionKey),children:b.code}),n.jsx("span",{className:"min-w-0 flex-1 truncate typography-meta",style:{direction:"rtl",textAlign:"left",unicodeBidi:"plaintext"},title:p.path,children:p.path}),zt(p.insertions,p.deletions)]})},p.path)},e[5]=d,e[6]=a,e[7]=f,e[8]=u):u=e[8],h=i.map(u),e[0]=i,e[1]=d,e[2]=a,e[3]=f,e[4]=h}else h=e[4];let x;return e[9]!==h?(x=n.jsx(at,{outerClassName:"flex-1 min-h-0",className:"px-2 py-2",children:n.jsx("ul",{className:"flex flex-col gap-1",children:h})}),e[9]=h,e[10]=x):x=e[10],x}),Ns=o.memo(s=>{const e=he.c(20),{filePath:i,diff:a,renderSideBySide:d}=s,{t:f}=ge(),h=a.original.length>0,x=a.modified.length>0,u=d?"flex flex-row gap-6 items-start justify-center":"flex flex-col gap-4 items-center",p=d?"flex flex-col items-center gap-2 flex-1 min-w-0":"flex flex-col items-center gap-2";let b;e[0]===Symbol.for("react.memo_cache_sentinel")?(b={contain:"layout"},e[0]=b):b=e[0];let w;e[1]!==a.original||e[2]!==i||e[3]!==h||e[4]!==p||e[5]!==d||e[6]!==f?(w=h&&n.jsxs("div",{className:p,children:[n.jsx("span",{className:"typography-meta text-muted-foreground font-medium",children:f("diffView.image.original")}),n.jsx("img",{src:a.original,alt:f("diffView.image.originalAlt",{path:i}),className:d?"max-w-full max-h-[70vh] object-contain":"max-w-full object-contain",style:{imageRendering:"auto"}})]}),e[1]=a.original,e[2]=i,e[3]=h,e[4]=p,e[5]=d,e[6]=f,e[7]=w):w=e[7];let y;e[8]!==a.modified||e[9]!==i||e[10]!==x||e[11]!==h||e[12]!==p||e[13]!==d||e[14]!==f?(y=x&&n.jsxs("div",{className:p,children:[n.jsx("span",{className:"typography-meta text-muted-foreground font-medium",children:f(h?"diffView.image.modified":"diffView.image.new")}),n.jsx("img",{src:a.modified,alt:f("diffView.image.modifiedAlt",{path:i}),className:d?"max-w-full max-h-[70vh] object-contain":"max-w-full object-contain",style:{imageRendering:"auto"}})]}),e[8]=a.modified,e[9]=i,e[10]=x,e[11]=h,e[12]=p,e[13]=d,e[14]=f,e[15]=y):y=e[15];let j;return e[16]!==u||e[17]!==w||e[18]!==y?(j=n.jsx("div",{className:"w-full overflow-auto p-4",style:b,children:n.jsxs("div",{className:u,children:[w,y]})}),e[16]=u,e[17]=w,e[18]=y,e[19]=j):j=e[19],j}),Fs=o.memo(s=>{const e=he.c(16),{filePath:i,diff:a,renderSideBySide:d,wrapLines:f}=s;let h;e[0]!==i?(h=_n(i)||"text",e[0]=i,e[1]=h):h=e[1];const x=h;if(a.isBinary){let b;return e[2]===Symbol.for("react.memo_cache_sentinel")?(b=n.jsx(ms,{}),e[2]=b):b=e[2],b}if(Ve(i)){let b;return e[3]!==a||e[4]!==i||e[5]!==d?(b=n.jsx(Ns,{filePath:i,diff:a,renderSideBySide:d}),e[3]=a,e[4]=i,e[5]=d,e[6]=b):b=e[6],b}let u;e[7]===Symbol.for("react.memo_cache_sentinel")?(u={contain:"layout"},e[7]=u):u=e[7];let p;return e[8]!==a.fileDiff||e[9]!==a.modified||e[10]!==a.original||e[11]!==i||e[12]!==x||e[13]!==d||e[14]!==f?(p=n.jsx("div",{className:"w-full",style:u,children:n.jsx(Wn,{original:a.original,modified:a.modified,fileDiff:a.fileDiff,language:x,fileName:i,renderSideBySide:d,wrapLines:f,layout:"inline"})}),e[8]=a.fileDiff,e[9]=a.modified,e[10]=a.original,e[11]=i,e[12]=x,e[13]=d,e[14]=f,e[15]=p):p=e[15],p}),ks=o.memo(s=>{const e=he.c(7),{filePath:i,staged:a,busyAction:d,disabled:f,onAction:h}=s,{t:x}=ge();let u;return e[0]!==d||e[1]!==f||e[2]!==i||e[3]!==h||e[4]!==a||e[5]!==x?(u=n.jsx("div",{className:"flex items-center gap-0.5 rounded-full border border-[var(--interactive-border)]/45 bg-[var(--surface-background)]/95 px-1 py-0.5 shadow-sm backdrop-blur-md",children:a?n.jsx(ot,{label:x("gitView.changes.unstageFileAria",{path:i}),icon:"arrow-go-back",loading:d==="unstage",disabled:f,onClick:()=>h("unstage")}):n.jsxs(n.Fragment,{children:[n.jsx(ot,{label:x("gitView.changes.revertFileAria",{path:i}),icon:"arrow-go-back",loading:d==="discard",disabled:f,tone:"failure",onClick:()=>h("discard")}),n.jsx(ot,{label:x("gitView.changes.stageFileAria",{path:i}),icon:"add",loading:d==="stage",disabled:f,tone:"success",onClick:()=>h("stage")})]})}),e[0]=d,e[1]=f,e[2]=i,e[3]=h,e[4]=a,e[5]=x,e[6]=u):u=e[6],u}),ot=s=>{const e=he.c(14),{label:i,icon:a,loading:d,disabled:f,tone:h,onClick:x}=s,u=h==="failure"&&"text-[var(--status-error)] hover:text-[var(--status-error)]",p=h==="success"&&"text-[var(--status-success)] hover:text-[var(--status-success)]";let b;e[0]!==u||e[1]!==p?(b=ue("h-6 w-6 rounded-none bg-transparent p-0 text-muted-foreground opacity-70 hover:bg-transparent hover:text-foreground hover:opacity-100",u,p),e[0]=u,e[1]=p,e[2]=b):b=e[2];let w;e[3]!==x?(w=P=>{P.stopPropagation(),x()},e[3]=x,e[4]=w):w=e[4];let y;e[5]!==a||e[6]!==d?(y=d?n.jsx(A,{name:"loader-4",className:"size-3.5 animate-spin"}):n.jsx(A,{name:a,className:a==="add"?"size-4":"size-3.5"}),e[5]=a,e[6]=d,e[7]=y):y=e[7];let j;return e[8]!==f||e[9]!==i||e[10]!==b||e[11]!==w||e[12]!==y?(j=n.jsx(pe,{variant:"ghost",size:"sm",className:b,disabled:f,title:i,"aria-label":i,onClick:w,children:y}),e[8]=f,e[9]=i,e[10]=b,e[11]=w,e[12]=y,e[13]=j):j=e[13],j},Cs=o.memo(({directory:s,file:e,layout:i,wrapLines:a,isSelected:d,isExpanded:f,isMounted:h,onSelect:x,onExpandedChange:u,registerSectionRef:p,showOpenInEditorAction:b=!1,isOpeningInEditor:w=!1,onOpenInEditor:y,staged:j=!1,loadFullFiles:P=!1,initialDiffData:m=null,readOnlyActions:le=!1})=>{const{t:k}=ge(),{git:E}=Tt(),L=Z(o.useCallback(c=>c.directories.get(s)?.diffCache.get(e.path)??null,[s,e.path])),W=Z(c=>c.setDiff),N=Z(c=>c.fetchStatus),ee=Y(c=>c.setDiffFileLayout),[U,q]=o.useState(0),[G,K]=o.useState(null),[te,I]=o.useState(!1),[_,V]=o.useState(null),[O,ne]=o.useState(!1),[T,se]=o.useState(null),[re,B]=o.useState(null),ie=o.useRef(null),He=o.useRef(null),ce=o.useMemo(()=>Ot(e),[e]),fe=i==="side-by-side",xe=P?"full":"patch",Ce=`${e.index}:${e.working_dir}:${e.insertions}:${e.deletions}`,X=o.useMemo(()=>m||(j?re:T||(L?{original:L.original,modified:L.modified,isBinary:L.isBinary,contextMode:"full"}:null)),[L,m,T,j,re]),Re=X?.contextMode===xe,We=o.useCallback(c=>{He.current=c,p(e.path,c)},[e.path,p]),Le=o.useCallback(c=>{u(e.path,c)},[e.path,u]),be=o.useCallback(()=>{x(e.path)},[e.path,x]);o.useEffect(()=>{j?B(null):se(null),K(null),ie.current=null},[Ce,j]),o.useEffect(()=>{if(!f||!h)return;if(!s||m||X&&Re){ie.current=null,I(!1);return}const c=`${s}::${e.path}::${j?"staged":"unstaged"}::${Ce}::${xe}::${U}`;if(ie.current===c)return;ie.current=c,K(null),I(!0);let C=!1;const oe=ct(),Me=P?cs:us,de=Ve(e.path)?E.getGitFileDiff(s,{path:e.path,staged:j}):E.getGitDiff(s,{path:e.path,staged:j,contextLines:Me}),De=ls,Ae=new Promise(($,J)=>{setTimeout(()=>J(new Error(`Timed out after ${De}ms`)),De)});return Promise.race([de,Ae]).then($=>{if(!C){if("diff"in $){const J=lt(e.path,$.diff,xe);j?B(J):se(J)}else{const J={original:$.original??"",modified:$.modified??"",isBinary:$.isBinary,contextMode:"full"};j?B(J):W(s,e.path,J,oe)}I(!1)}}).catch($=>{if(C)return;const J=$ instanceof Error?$.message:String($);K(J),I(!1)}),()=>{C=!0,ie.current===c&&(ie.current=null)}},[xe,X,Re,U,s,e.path,Ce,E,m,f,h,P,W,j]);const we=o.useCallback(()=>{Le(!f),be()},[Le,be,f]),Te=o.useCallback(async c=>{if(!(!s||_!==null)){V(c);try{c==="stage"?await E.stageGitFile(s,e.path):c==="unstage"?await E.unstageGitFile(s,e.path):await E.revertGitFile(s,e.path,{scope:"working"}),q(C=>C+1),await N(s,E)}catch(C){const oe=c==="unstage"?"gitView.toast.unstageFileFailed":c==="stage"?"gitView.toast.stageFileFailed":"gitView.toast.revertFailed";Ke.error(C instanceof Error?C.message:k(oe))}finally{V(C=>C===c?null:C)}}},[s,N,e.path,_,E,k]);return n.jsxs("div",{ref:We,className:"scroll-mt-9 border-b border-[var(--interactive-border)]/40 last:border-b-0",children:[n.jsx("div",{className:"sticky top-0 z-30 border-b border-[var(--interactive-border)]/35 bg-[var(--surface-elevated)]/90 backdrop-blur-md supports-[backdrop-filter]:bg-[var(--surface-elevated)]/80",children:n.jsxs("div",{role:"button",tabIndex:0,onClick:we,onKeyDown:c=>{c.target===c.currentTarget&&(c.key==="Enter"||c.key===" ")&&(c.preventDefault(),we())},className:ue("cursor-pointer","group/header relative grid min-h-9 w-full min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-2 overflow-hidden px-3 py-2","bg-transparent","text-muted-foreground hover:text-foreground",d?"bg-[var(--interactive-selection)]/35":null),children:[n.jsx("div",{className:"absolute inset-0 pointer-events-none group-hover/header:bg-[var(--interactive-hover)]/50"}),n.jsxs("div",{className:"relative flex min-w-0 flex-1 items-center gap-2",children:[n.jsx("span",{className:"flex size-5 items-center justify-center opacity-70 group-hover/header:opacity-100",children:f?n.jsx(A,{name:"arrow-down-s",className:"size-4"}):n.jsx(A,{name:"arrow-right-s",className:"size-4"})}),n.jsx("span",{className:"typography-micro font-semibold leading-none w-4 text-center uppercase",style:{color:ce.color},title:k(ce.descriptionKey),"aria-label":k(ce.descriptionKey),children:ce.code}),n.jsx("span",{className:"min-w-0 flex-1 overflow-hidden typography-ui-label",title:e.path,children:n.jsxs("span",{className:"flex min-w-0 items-center gap-2",children:[n.jsx(It,{filePath:e.path,className:"h-3.5 w-3.5 flex-shrink-0 align-middle"}),(()=>{const c=e.path.lastIndexOf("/");if(c===-1)return n.jsx("span",{className:"block min-w-0 truncate typography-ui-label text-foreground",style:{direction:"rtl",textAlign:"left",unicodeBidi:"plaintext"},children:e.path});const C=e.path.slice(0,c),oe=e.path.slice(c+1);return n.jsxs("span",{className:"flex min-w-0 items-baseline overflow-hidden",children:[n.jsx("span",{className:"min-w-0 truncate typography-ui-label text-muted-foreground",style:{direction:"rtl",textAlign:"left",unicodeBidi:"plaintext"},children:C}),n.jsxs("span",{className:"flex-shrink-0 typography-ui-label",children:[n.jsx("span",{className:"text-muted-foreground",children:"/"}),n.jsx("span",{className:"text-foreground",children:oe})]})]})})()]})})]}),n.jsxs("div",{className:"relative flex shrink-0 items-center justify-self-end gap-2",children:[zt(e.insertions,e.deletions),b&&y?n.jsx(pe,{variant:"ghost",size:"sm",className:"h-5 w-5 p-0 opacity-70 hover:opacity-100",title:k("diffView.actions.openFileInEditorAtChange"),onClick:c=>{c.stopPropagation(),y(e.path,X)},disabled:w,children:w?n.jsx(A,{name:"loader-4",className:"size-3.5 animate-spin"}):n.jsx(A,{name:"edit",className:"size-3.5"})}):null,n.jsx(Mt,{mode:fe?"side-by-side":"unified",onModeChange:c=>{const C=c==="side-by-side"?"side-by-side":"inline";ee(e.path,C)},className:"opacity-70"})]})]})}),f&&n.jsxs("div",{className:"relative bg-background overflow-hidden",children:[!h&&!G?n.jsx("div",{className:"h-40 border border-border/40 bg-background/40"}):null,G?n.jsxs("div",{className:"flex flex-col items-center gap-2 px-4 py-8 text-sm text-muted-foreground",children:[n.jsx("div",{className:"typography-ui-label font-semibold text-foreground",children:k("diffView.state.failedToLoadDiff")}),n.jsx("div",{className:"typography-meta text-muted-foreground max-w-[32rem] text-center",children:G}),n.jsx("button",{type:"button",className:"typography-ui-label text-primary hover:underline",onClick:()=>q(c=>c+1),children:k("diffView.actions.retry")})]}):null,h&&te&&!X&&!G?n.jsxs("div",{className:"flex items-center justify-center gap-2 px-4 py-8 text-sm text-muted-foreground",children:[n.jsx(A,{name:"loader-4",className:"size-4 animate-spin"}),k("diffView.state.loadingDiff")]}):null,h&&X&&!O&&e.insertions+e.deletions>Dt?n.jsxs("div",{className:"flex flex-col items-center gap-2 px-4 py-8 text-sm text-muted-foreground",children:[n.jsx("div",{className:"typography-ui-label font-semibold text-foreground",children:k("diffView.state.largeDiff",{count:e.insertions+e.deletions})}),n.jsx("div",{className:"typography-meta text-muted-foreground",children:k("diffView.state.largeDiffDescription")}),n.jsx("button",{type:"button",className:"typography-ui-label text-primary hover:underline",onClick:()=>ne(!0),children:k("diffView.actions.renderAnyway")})]}):null,h&&X&&(O||e.insertions+e.deletions<=Dt)?n.jsxs(n.Fragment,{children:[n.jsx(Fs,{filePath:e.path,diff:X,renderSideBySide:fe,wrapLines:a}),n.jsx("div",{className:"pointer-events-none absolute bottom-3 right-3 z-20",children:n.jsx("div",{className:"pointer-events-auto",children:le?null:n.jsx(ks,{filePath:e.path,staged:j,busyAction:_,disabled:_!==null,onAction:Te})})})]}):null]})]})}),Ki=({hideStackedFileSidebar:s=!1,stackedDefaultCollapsedAll:e=!1,pinSelectedFileHeaderToTopOnNavigate:i=!1,showOpenInEditorAction:a=!1,diffScope:d="all",onDiffScopeChange:f,targetFilePath:h=null,flushContent:x=!1})=>{const{t:u}=ge(),{git:p,files:b}=Tt(),w=yn(),{rootIsGitRepo:y,gitDirectory:j,nestedRepos:P}=vn(w??null),m=j??w,le=Y(t=>t.openContextSurface),k=Un(t=>t.requestSource),{screenWidth:E,isMobile:L}=jn(),W=Sn(m??null),N=Nn(m??null),ee=Fn(m??null),U=Z(t=>t.setActiveDirectory),q=Z(t=>t.ensureStatus),G=Z(t=>t.selectNestedRepo),K=Z(t=>t.fetchStatus),te=Z(t=>t.fetchBranches),I=Z(t=>t.clearDiffCache),_=Z(t=>t.setDiff),[V,O]=o.useState(null),[ne,T]=o.useState(!1),[se,re]=o.useState(null),[B,ie]=o.useState(()=>new Set),[He,ce]=o.useState(()=>new Set),[fe,xe]=o.useState(!1),[Ce,X]=o.useState(0),[Re,We]=o.useState(()=>new Map),[Le,be]=o.useState(!1),[we,Te]=o.useState(!1),[c,C]=o.useState(d);o.useEffect(()=>{C(d)},[d]);const oe=Y(t=>t.pendingDiffFile),Me=Y(t=>t.pendingDiffStaged),de=Y(t=>t.pendingDiffScope),De=Y(t=>t.setPendingDiffFile),Ae=Y(t=>t.diffLayoutPreference),$=Y(t=>t.diffFileLayout),J=Y(t=>t.setDiffFileLayout),ut=Y(t=>t.diffWrapLines),Pt=Y(t=>t.setDiffWrapLines),ft=Y(t=>t.openContextFileAtLine),ye=Ft(t=>t.currentSessionId),Ue=kn(ye??"",w??void 0),qe=ut,Xe=c==="staged"?!0:c==="working"?!1:null,Ie=Xe??ne,Je=L||E<=768,Gt=!!ye&&c!=="turn"&&!Je&&!Pe(),Kt=c!=="turn"&&!Je&&!Pe(),$t=!s&&!Je&&E>=1024,ve=o.useRef(null),Ee=o.useRef(new Map),me=o.useRef(null),z=o.useRef(null),je=o.useRef(!1),Se=o.useRef(null),dt=o.useRef(null),Qe=o.useRef(null),Ye=o.useRef(null),pt=o.useCallback(()=>{const t=ve.current;if(!t)return null;const r=t.getBoundingClientRect().top,l=[];for(const[g,v]of Ee.current)v&&l.push({path:g,top:v.getBoundingClientRect().top});return Ct(r,l)},[]),Ne=o.useCallback(()=>{me.current=null,je.current=!1,re(null),z.current!==null&&(window.cancelAnimationFrame(z.current),z.current=null)},[]),Fe=o.useCallback(t=>{ie(r=>{if(r.has(t))return r;const l=new Set(r);return l.add(t),l})},[]),Be=o.useMemo(()=>{for(let t=Ue.length-1;t>=0;t-=1){const r=Ue[t];if(r.role==="user")return ys(r.summary?.diffs)}return[]},[Ue]),Ht=o.useMemo(()=>{const t=new Map;for(const r of Be)if(r.file){if(typeof r.patch=="string"){t.set(r.file,lt(r.file,r.patch,"patch"));continue}t.set(r.file,{original:r.before??"",modified:r.after??"",contextMode:"full"})}return t},[Be]),Wt=o.useMemo(()=>N?.files?N.files.filter(Bt).length:0,[N]),Ut=o.useMemo(()=>N?.files?N.files.filter(Et).length:0,[N]),qt=Be.length,R=N?.current??null,ke=Z(t=>m?t.directories.get(m)?.branches??null:null),Xt=Z(t=>m?t.directories.get(m)?.isLoadingBranches??!1:!1),Jt=o.useCallback(()=>{m&&te(m,p)},[m,te,p]),Qt=rs(m??null,W!==!1,Xt,!!ke,Jt,ps),mt=o.useMemo(()=>{const t=N?.tracking?.trim().split("/")[0];return(t&&ke?.defaultBranches?.[t])??ke?.defaultBranches?.origin??null},[ke,N?.tracking]),Ze=!Pe()&&es(R,mt),Yt=N!==null,ht=Pe()||Qt||ts(R,mt,Yt,ke!==null),Zt=kt(t=>t.setOverride),en=kt(o.useCallback(t=>m&&R?t.overrides[$e(m,R)]??null:null,[R,m])),[tn,et]=o.useState(null),[nn,tt]=o.useState(!1),[gt,sn]=o.useState("");o.useEffect(()=>{const t=ns(c,!ht);t!==c&&(C(t),t==="working"&&f?.("working"))},[c,ht,f]),o.useEffect(()=>{if(!Ze||!m||!R){et(null),tt(!1);return}let t=!1;return tt(!1),Cn(m,R).then(r=>{t||et(r.base)}).catch(()=>{t||et(null)}).finally(()=>{t||tt(!0)}),()=>{t=!0}},[R,m,Ze]);const ae=en??tn,[_e,xt]=o.useState(null),[bt,wt]=o.useState(null),Oe=o.useRef(0),nt=o.useCallback(()=>{if(!m||!R||!ae)return;const t=Oe.current+1;Oe.current=t,xt(null),wt(null),Rn(m,{base:ae,head:R}).then(r=>{Oe.current===t&&xt(r)}).catch(r=>{Oe.current===t&&wt(r instanceof Error?r.message:u("diffView.branch.loadError"))})},[ae,R,m,u]);o.useEffect(()=>{c==="branch"&&nt()},[c,nt]);const yt=c==="branch"&&m&&R&&ae?ss(m,ae,R):null,rn=o.useMemo(()=>c==="branch"?Array.from(B).sort().join("\0"):"",[c,B]),on=o.useCallback(t=>!m||!ae||!R?Promise.reject(new Error("branch range is unavailable")):Dn(m,{base:ae,head:R,path:t}).then(r=>lt(t,r.diff,"patch")),[ae,R,m]),an=is(yt,rn,yt?on:null,ds),ln=_e?.length??null,S=o.useMemo(()=>{if(c==="branch")return(_e??[]).map(l=>({path:l.path,index:"",working_dir:l.status,insertions:0,deletions:0,isNew:l.status==="A"})).sort((l,g)=>l.path.localeCompare(g.path));if(c==="turn")return Be.map(l=>({path:l.file??"",index:"",working_dir:vs(l.status),insertions:l.additions??0,deletions:l.deletions??0,isNew:l.status==="added"})).filter(l=>l.path).sort((l,g)=>l.path.localeCompare(g.path));if(!N?.files)return[];const t=N.diffStats??{},r=c==="staged"?Et:c==="working"?Bt:()=>!0;return N.files.filter(r).map(l=>({...l,insertions:t[l.path]?.insertions??0,deletions:t[l.path]?.deletions??0,isNew:xs(l)})).sort((l,g)=>l.path.localeCompare(g.path))},[c,_e,Be,N]),st=o.useMemo(()=>S.map(t=>t.path).join("\0"),[S]);o.useEffect(()=>{const t=st?st.split("\0"):[],r=new Set(t),l=`${m??""}:${c}:${e?"collapsed":"default"}`,g=dt.current!==l;dt.current=l,ie(v=>{if(g){const D=e?0:fs(t.length);return new Set(t.slice(0,D))}let M=!1;const F=new Set;for(const D of v){if(!r.has(D)){M=!0;continue}F.add(D)}return M?F:v}),ce(v=>{if(g)return new Set;let M=!1;const F=new Set;for(const D of v){if(!r.has(D)){M=!0;continue}F.add(D)}return M?F:v})},[c,st,m,e]);const vt=o.useCallback(()=>{Se.current=null;const t=ve.current;if(!t)return;const r=t.getBoundingClientRect(),l=r.top-At,g=r.bottom+At,v={},M=[];for(const[F,D]of Ee.current){if(!D)continue;const H=D.getBoundingClientRect();M.push({path:F,top:H.top}),B.has(F)&&(H.bottom<l||H.top>g||(v[F]=!0))}Qe.current=Ct(r.top,M),ce(F=>{let D=!1;const H=new Set(F);for(const Nt of Object.keys(v))H.has(Nt)||(H.add(Nt),D=!0);return D?H:F})},[B]),Q=o.useCallback(()=>{typeof window>"u"||Se.current===null&&(Se.current=window.requestAnimationFrame(vt))},[vt]);o.useEffect(()=>{const t=ve.current;if(t)return Q(),t.addEventListener("scroll",Q,{passive:!0}),window.addEventListener("resize",Q),()=>{t.removeEventListener("scroll",Q),window.removeEventListener("resize",Q),Se.current!==null&&(window.cancelAnimationFrame(Se.current),Se.current=null)}},[S,B,Q]);const rt=o.useCallback(t=>{const r=$[t.path];if(r)return r;if(Ae==="inline")return"inline";if(Ae==="side-by-side")return"side-by-side";const l=E<as;return t.isNew||l?"inline":"side-by-side"},[$,Ae,E]),jt=o.useMemo(()=>S.length===0?null:S.every(t=>rt(t)==="side-by-side")?"side-by-side":"inline",[S,rt]);o.useEffect(()=>{m&&(U(m),q(m,p))},[m,U,q,p]),o.useEffect(()=>{if(m)return An.onGitRefreshHint(t=>{Vt(t.directory)===Vt(m)&&(t.paths?.length&&(Ye.current=pt()??Qe.current,I(m,t.paths),We(r=>{const l=new Map(r);for(const g of t.paths??[])l.set(g,(l.get(g)??0)+1);return l})),K(m,p,{silent:!0}))})},[pt,I,m,K,p]),o.useLayoutEffect(()=>{const t=Ye.current;if(!t)return;Ye.current=null;const r=ve.current,l=Ee.current.get(t.path);if(!r||!l)return;const g=r.getBoundingClientRect().top,v=l.getBoundingClientRect().top-g;r.scrollTop=os(r.scrollTop,t.topOffset,v,r.scrollHeight-r.clientHeight),Qe.current=t},[Re]),o.useEffect(()=>{c!=="all"&&!de||oe&&(de&&C(de),O(oe),T(de==="staged"||!de&&Me),De(null),je.current=!0,me.current=oe,Fe(oe),X(t=>t+1))},[c,Fe,oe,de,Me,De]),o.useEffect(()=>{if(c==="all")return;const t=h?.trim();t&&(O(t),T(c==="staged"),je.current=!0,me.current=t,Fe(t),X(r=>r+1))},[c,Fe,h]),o.useEffect(()=>{if(!V)return;S.some(r=>r.path===V)||(O(null),T(!1))},[S,V]);const cn=o.useCallback((t,r)=>{const l=Ee.current;r?l.set(t,r):l.delete(t),Q()},[Q]),un=o.useCallback((t,r)=>{Ne(),ie(l=>{const g=l.has(t);if(r===g)return l;const v=new Set(l);return r?v.add(t):v.delete(t),v}),r||ce(l=>{if(!l.has(t))return l;const g=new Set(l);return g.delete(t),g}),Q()},[Ne,Q]),fn=o.useCallback(()=>{Ne(),ie(t=>t.size>0?new Set:new Set(S.map(r=>r.path))),ce(new Set),Q()},[Ne,S,Q]),dn=o.useCallback(async t=>{if(!ye)return;const r=Ft.getState().getDirectoryForSession(ye)||w||"";if(!r){Ke.error(u("diffView.reviewDialog.toast.noSessionDirectory"));return}Te(!0);try{await En({originalSessionID:ye,directory:r,providerID:t.providerID,modelID:t.modelID,agent:t.agent||void 0,variant:t.variant||void 0,generateHandoff:t.generateHandoff,returnAfterHandoffRequest:t.generateHandoff,autoReview:t.autoReview}),be(!1)}catch(l){console.error("[review-flow] failed to start review flow",l),Ke.error(l instanceof Error?l.message:u("diffView.reviewDialog.toast.startFailed"))}finally{Te(!1)}},[ye,w,u]),ze=o.useCallback(t=>{const r=Ee.current.get(t),l=ve.current;if(!r||!l)return!1;const g=r.getBoundingClientRect().top-l.getBoundingClientRect().top;return l.scrollTo({top:l.scrollTop+g,behavior:"auto"}),!0},[]);o.useEffect(()=>{if(!me.current)return;let r=0;const l=20;let g=!1;const v=(F=!0)=>{g||(g=!0,me.current=null,je.current=!1,F&&re(null),z.current!==null&&(window.cancelAnimationFrame(z.current),z.current=null))},M=()=>{if(g){z.current=null;return}const F=me.current;if(!F){v(),z.current=null;return}if(!ze(F)){r+=1,r<l?z.current=window.requestAnimationFrame(M):(v(),z.current=null);return}if(i&&je.current){re(F),v(!1);return}v()};return z.current=window.requestAnimationFrame(M),()=>{g=!0,z.current!==null&&(window.cancelAnimationFrame(z.current),z.current=null)}},[i,Ce,ze]);const pn=o.useCallback(t=>{},[]),it=o.useCallback(t=>{Ne(),O(t),T(!1),je.current=!0,me.current=t,Fe(t),X(r=>r+1),ze(t)},[Ne,Fe,ze]);o.useEffect(()=>{const t=r=>{if(!r.altKey||r.metaKey||r.ctrlKey||r.shiftKey||r.key!=="ArrowDown"&&r.key!=="ArrowUp")return;const l=r.target;if(l instanceof HTMLElement&&(l.isContentEditable||l.tagName==="INPUT"||l.tagName==="TEXTAREA"||l.closest('[role="dialog"]'))||S.length===0)return;const g=r.key==="ArrowDown"?1:-1,v=V?S.findIndex(D=>D.path===V):-1,M=v===-1?g>0?0:S.length-1:v+g,F=S[M];F&&(r.preventDefault(),it(F.path))};return window.addEventListener("keydown",t),()=>window.removeEventListener("keydown",t)},[S,V,it]);const mn=o.useCallback(t=>{const r=t==="side-by-side"?"side-by-side":"inline";S.forEach(l=>{J(l.path,r)})},[S,J]),[hn,St]=o.useState(null),gn=o.useCallback(async(t,r)=>{if(!m||!t)return;St(t);const l=ct();try{let g=null;if(r?.patch&&!r.isBinary&&!Ve(t)?g=Rt(r.patch):r&&r.contextMode==="full"&&!r.isBinary&&!Ve(t)&&(g=Lt(r.original,r.modified)),g===null)try{const H=await p.getGitDiff(m,{path:t,staged:Ie,contextLines:3});g=Rt(H.diff)}catch{g=null}let v=r;if(g===null||!v){const H=await p.getGitFileDiff(m,{path:t,staged:Ie});v={original:H.original??"",modified:H.modified??"",isBinary:H.isBinary},Ie||_(m,t,v,l)}const M=g??(v.isBinary||Ve(t)?1:Lt(v.original,v.modified)),F=bs(m,t),D=await qn(b,F,{directory:m});if(!D.ok){Ke.error(Xn(D.reason));return}ft(m,F,M,1)}finally{St(g=>g===t?null:g)}},[Ie,m,b,p,ft,_]),xn=()=>{if(!m)return null;const t=r=>Xe!==null?Xe:ne&&r===V;return n.jsxs("div",{className:ue("flex min-w-0 flex-1 min-h-0 h-full",x?"gap-0":"gap-3 px-3 pb-3 pt-2"),children:[$t&&n.jsxs("section",{className:"hidden lg:flex w-72 flex-col rounded-xl border border-border/60 bg-background/70 overflow-hidden",children:[n.jsxs("div",{className:"flex items-center justify-between px-3 py-1.5 border-b border-border/40",children:[n.jsx("span",{className:"typography-ui-header font-semibold text-foreground",children:u("diffView.section.files")}),n.jsx("span",{className:"typography-meta text-muted-foreground",children:S.length})]}),n.jsx(Ss,{changedFiles:S,selectedFile:null,onSelectFile:it})]}),n.jsx("div",{className:"relative flex-1 min-w-0 min-h-0 h-full",children:n.jsx(at,{ref:ve,outerClassName:"min-h-0 h-full",className:"[overflow-anchor:none] pb-16",disableHorizontal:!0,observeMutations:!1,preventOverscroll:!0,"data-diff-virtual-root":!0,children:n.jsx("div",{className:"flex flex-col [overflow-anchor:none]","data-diff-virtual-content":!0,children:S.map(r=>n.jsx(Cs,{directory:m,file:r,layout:rt(r),wrapLines:qe,isSelected:!1,isExpanded:B.has(r.path),isMounted:He.has(r.path)||r.path===se,onSelect:pn,onExpandedChange:un,registerSectionRef:cn,showOpenInEditorAction:a&&c!=="turn",isOpeningInEditor:hn===r.path,onOpenInEditor:(l,g)=>{gn(l,g)},staged:t(r.path),loadFullFiles:fe,readOnlyActions:c==="branch",initialDiffData:c==="turn"?Ht.get(r.path)??null:c==="branch"?an.get(r.path)??null:null},`${r.path}:${Re.get(r.path)??0}`))})})})]})},bn=()=>{if(!m)return n.jsx("div",{className:"flex flex-1 items-center justify-center text-sm text-muted-foreground",children:u("diffView.state.selectSessionDirectory")});if(c!=="turn"&&ee&&!N)return n.jsxs("div",{className:"flex flex-1 items-center justify-center gap-2 text-sm text-muted-foreground",children:[n.jsx(A,{name:"loader-4",className:"size-4 animate-spin"}),u("diffView.state.loadingRepositoryStatus")]});if(c!=="turn"&&W===!1)return n.jsx("div",{className:"flex flex-1 items-center justify-center text-sm text-muted-foreground",children:u("diffView.state.notGitRepository")});if(c==="branch"){if(!nn)return n.jsxs("div",{className:"flex flex-1 items-center justify-center gap-2 text-sm text-muted-foreground",children:[n.jsx(A,{name:"loader-4",className:"size-4 animate-spin"}),u("diffView.branch.resolvingBase")]});if(!ae){const t=(ke?.all??[]).map(l=>l.replace(/^remotes\//,"")).filter(l=>l!==R&&!l.endsWith(`/${R}`)).sort(),r=In(t,gt,l=>[l]);return n.jsxs("div",{className:"flex flex-1 flex-col items-center justify-center gap-3 px-6 text-center",children:[n.jsx(A,{name:"git-branch",className:"size-6 text-muted-foreground"}),n.jsx("div",{className:"typography-ui-label font-semibold text-foreground",children:u("diffView.branch.noBaseTitle")}),n.jsx("div",{className:"max-w-sm typography-micro text-muted-foreground",children:u("diffView.branch.noBaseDescription")}),n.jsx("input",{type:"text",value:gt,onChange:l=>sn(l.target.value),placeholder:u("gitView.branch.searchPlaceholder"),"aria-label":u("gitView.branch.searchPlaceholder"),className:"w-full max-w-sm rounded-md border border-border/60 bg-[var(--surface-elevated)] px-2.5 py-1.5 typography-meta text-foreground outline-none placeholder:text-muted-foreground focus-visible:ring-2 focus-visible:ring-[var(--interactive-focus-ring)]"}),n.jsx(at,{outerClassName:"max-h-48 w-full max-w-sm min-h-0",className:"px-1 py-1",children:r.length===0?n.jsx("div",{className:"px-2 py-3 typography-meta text-muted-foreground",children:u("gitView.branch.empty")}):n.jsx("div",{className:"flex flex-col gap-0.5",children:r.map(l=>n.jsxs("button",{type:"button",onClick:()=>m&&R&&Zt(m,R,l),className:"flex items-center gap-2 rounded-md px-2 py-1.5 text-left hover:bg-interactive-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--interactive-focus-ring)]",children:[n.jsx(A,{name:"git-branch",className:"size-3.5 text-primary"}),n.jsx("span",{className:"truncate typography-ui-label text-foreground",title:l,children:l})]},l))})})]})}if(bt)return n.jsxs("div",{className:"flex flex-1 flex-col items-center justify-center gap-3 px-6 text-center",children:[n.jsx("div",{className:"typography-ui-label font-semibold text-foreground",children:u("diffView.branch.loadError")}),n.jsx("div",{className:"max-w-sm typography-micro text-muted-foreground",children:bt}),n.jsx(pe,{variant:"outline",size:"sm",onClick:()=>nt(),children:u("diffView.actions.retry")})]});if(_e===null)return n.jsxs("div",{className:"flex flex-1 items-center justify-center gap-2 text-sm text-muted-foreground",children:[n.jsx(A,{name:"loader-4",className:"size-4 animate-spin"}),u("diffView.branch.loadingFiles")]})}return S.length===0?n.jsx("div",{className:"flex flex-1 items-center justify-center text-sm text-muted-foreground",children:c==="turn"?u("diffView.state.noLastTurnChanges"):c==="branch"&&ae?u("diffView.branch.empty",{base:ae}):u("diffView.state.cleanWorkingTree")}):xn()};return n.jsxs("div",{className:"flex h-full flex-col overflow-hidden bg-background",children:[n.jsxs("div",{className:"@container/diff-toolbar flex min-w-0 items-center gap-2 px-3 py-2 bg-background",children:[y===!1&&Array.isArray(P)&&P.length>0?n.jsx(Kn,{repositories:P,selectedRepository:j??null,onSelectRepository:t=>{w&&G(w,t)},repositoryRoot:w??void 0}):null,!L&&(c==="working"||c==="staged"||c==="turn"||c==="branch"?n.jsx(js,{scope:c,workingCount:Wt,stagedCount:Ut,turnCount:qt,branchCount:ln,showBranchOption:Ze,onScopeChange:t=>{C(t),f?.(t)}}):n.jsx("div",{className:"flex items-center gap-1 rounded-md px-2 py-1 text-muted-foreground shrink-0",children:n.jsx("span",{className:"typography-ui-label font-semibold text-foreground",children:ee&&!N?u("diffView.state.loadingChanges"):S.length===1?u("diffView.summary.changedFilesSingle",{count:S.length}):u("diffView.summary.changedFilesPlural",{count:S.length})})})),S.length>0&&n.jsxs(pe,{variant:"ghost",size:"sm",onClick:fn,className:ue("diff-toolbar__expand-button h-7 flex-shrink-0 gap-1 px-1.5 text-muted-foreground hover:text-foreground","ml-auto"),title:B.size>0?u("diffView.actions.collapseAll"):u("diffView.actions.expandAll"),children:[n.jsx(A,{name:"expand-up-down",className:"size-4"}),n.jsx("span",{className:"diff-toolbar__expand-label typography-ui-label",children:B.size>0?u("diffView.actions.collapseAll"):u("diffView.actions.expandAll")})]}),S.length>0&&Gt&&n.jsxs(pe,{variant:"default",size:"sm",onClick:()=>be(!0),disabled:we,className:"diff-toolbar__review-button h-7 flex-shrink-0 gap-1.5 px-2","aria-label":u("diffView.actions.reviewAria"),children:[we?n.jsx(A,{name:"loader-4",className:"size-4 animate-spin"}):n.jsx(A,{name:"search-eye",className:"size-4"}),n.jsx("span",{className:"diff-toolbar__review-label typography-ui-label",children:u("diffView.actions.review")})]}),S.length>0&&Kt&&n.jsxs(pe,{variant:"outline",size:"sm",onClick:()=>{const t=m??"";k(t,{kind:"working-tree",scope:c==="staged"||c==="working"?c:"all"}),le(t,"walkthrough")},className:ue("diff-toolbar__walkthrough-button h-7 flex-shrink-0 gap-1.5 px-2",Jn),"aria-label":u("walkthrough.action.open"),children:[n.jsx(A,{name:"route",className:"size-4"}),n.jsx("span",{className:"diff-toolbar__walkthrough-label typography-ui-label",children:u("walkthrough.action.open")})]}),S.length>0&&n.jsxs(Bn,{children:[n.jsx(Vn,{asChild:!0,children:n.jsx(pe,{variant:"ghost",size:"sm",onClick:()=>xe(t=>!t),"aria-pressed":fe,"aria-label":u(fe?"diffView.actions.disableFullFiles":"diffView.actions.loadFullFiles"),className:ue("h-7 w-7 flex-shrink-0 p-0 text-muted-foreground hover:text-foreground",fe&&"bg-interactive-selection text-interactive-selection-foreground"),children:n.jsx(A,{name:"file-download",className:"size-4"})})}),n.jsx(Ln,{children:n.jsx("p",{children:u(fe?"diffView.actions.disableFullFiles":"diffView.actions.loadFullFiles")})})]}),S.length>0&&n.jsx(pe,{variant:"ghost",size:"sm",onClick:()=>Pt(!ut),className:ue("h-5 w-5 p-0 transition-opacity",qe?"text-foreground opacity-100":"text-muted-foreground opacity-60 hover:opacity-100"),title:u(qe?"diffView.actions.disableLineWrap":"diffView.actions.enableLineWrap"),children:n.jsx(A,{name:"text-wrap",className:"size-4"})}),jt&&n.jsx(Mt,{mode:jt==="side-by-side"?"side-by-side":"unified",onModeChange:mn})]}),n.jsx(Tn,{open:Le,onOpenChange:be,projectDirectory:m??null,submitting:we,onConfirm:dn}),bn()]})};export{Ki as DiffView};