@akiojin/gwt 4.9.1 → 4.11.6

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 (605) hide show
  1. package/README.ja.md +4 -4
  2. package/README.md +4 -4
  3. package/dist/claude.d.ts +1 -0
  4. package/dist/claude.d.ts.map +1 -1
  5. package/dist/claude.js +52 -49
  6. package/dist/claude.js.map +1 -1
  7. package/dist/cli/ui/App.solid.d.ts +29 -0
  8. package/dist/cli/ui/App.solid.d.ts.map +1 -0
  9. package/dist/cli/ui/App.solid.js +1197 -0
  10. package/dist/cli/ui/App.solid.js.map +1 -0
  11. package/dist/cli/ui/components/solid/Footer.d.ts +10 -0
  12. package/dist/cli/ui/components/solid/Footer.d.ts.map +1 -0
  13. package/dist/cli/ui/components/solid/Footer.js +10 -0
  14. package/dist/cli/ui/components/solid/Footer.js.map +1 -0
  15. package/dist/cli/ui/components/{parts → solid}/Header.d.ts +1 -6
  16. package/dist/cli/ui/components/solid/Header.d.ts.map +1 -0
  17. package/dist/cli/ui/components/solid/Header.js +13 -0
  18. package/dist/cli/ui/components/solid/Header.js.map +1 -0
  19. package/dist/cli/ui/components/solid/HelpOverlay.d.ts +8 -0
  20. package/dist/cli/ui/components/solid/HelpOverlay.d.ts.map +1 -0
  21. package/dist/cli/ui/components/solid/HelpOverlay.js +118 -0
  22. package/dist/cli/ui/components/solid/HelpOverlay.js.map +1 -0
  23. package/dist/cli/ui/components/solid/QuickStartStep.d.ts +17 -0
  24. package/dist/cli/ui/components/solid/QuickStartStep.d.ts.map +1 -0
  25. package/dist/cli/ui/components/solid/QuickStartStep.js +139 -0
  26. package/dist/cli/ui/components/solid/QuickStartStep.js.map +1 -0
  27. package/dist/cli/ui/components/solid/SelectInput.d.ts +22 -0
  28. package/dist/cli/ui/components/solid/SelectInput.d.ts.map +1 -0
  29. package/dist/cli/ui/components/solid/SelectInput.js +44 -0
  30. package/dist/cli/ui/components/solid/SelectInput.js.map +1 -0
  31. package/dist/cli/ui/components/solid/TextInput.d.ts +12 -0
  32. package/dist/cli/ui/components/solid/TextInput.d.ts.map +1 -0
  33. package/dist/cli/ui/components/solid/TextInput.js +9 -0
  34. package/dist/cli/ui/components/solid/TextInput.js.map +1 -0
  35. package/dist/cli/ui/components/solid/WizardController.d.ts +34 -0
  36. package/dist/cli/ui/components/solid/WizardController.d.ts.map +1 -0
  37. package/dist/cli/ui/components/solid/WizardController.js +215 -0
  38. package/dist/cli/ui/components/solid/WizardController.js.map +1 -0
  39. package/dist/cli/ui/components/solid/WizardPopup.d.ts +26 -0
  40. package/dist/cli/ui/components/solid/WizardPopup.d.ts.map +1 -0
  41. package/dist/cli/ui/components/solid/WizardPopup.js +68 -0
  42. package/dist/cli/ui/components/solid/WizardPopup.js.map +1 -0
  43. package/dist/cli/ui/components/solid/WizardSteps.d.ts +52 -0
  44. package/dist/cli/ui/components/solid/WizardSteps.d.ts.map +1 -0
  45. package/dist/cli/ui/components/solid/WizardSteps.js +462 -0
  46. package/dist/cli/ui/components/solid/WizardSteps.js.map +1 -0
  47. package/dist/cli/ui/core/index.d.ts +12 -0
  48. package/dist/cli/ui/core/index.d.ts.map +1 -0
  49. package/dist/cli/ui/core/index.js +15 -0
  50. package/dist/cli/ui/core/index.js.map +1 -0
  51. package/dist/cli/ui/core/keybindings.d.ts +106 -0
  52. package/dist/cli/ui/core/keybindings.d.ts.map +1 -0
  53. package/dist/cli/ui/core/keybindings.js +270 -0
  54. package/dist/cli/ui/core/keybindings.js.map +1 -0
  55. package/dist/cli/ui/core/theme.d.ts +114 -0
  56. package/dist/cli/ui/core/theme.d.ts.map +1 -0
  57. package/dist/cli/ui/core/theme.js +170 -0
  58. package/dist/cli/ui/core/theme.js.map +1 -0
  59. package/dist/cli/ui/core/types.d.ts +156 -0
  60. package/dist/cli/ui/core/types.d.ts.map +1 -0
  61. package/dist/cli/ui/core/types.js +10 -0
  62. package/dist/cli/ui/core/types.js.map +1 -0
  63. package/dist/cli/ui/hooks/solid/useScrollableList.d.ts +26 -0
  64. package/dist/cli/ui/hooks/solid/useScrollableList.d.ts.map +1 -0
  65. package/dist/cli/ui/hooks/solid/useScrollableList.js +89 -0
  66. package/dist/cli/ui/hooks/solid/useScrollableList.js.map +1 -0
  67. package/dist/cli/ui/hooks/solid/useTerminalSize.d.ts +10 -0
  68. package/dist/cli/ui/hooks/solid/useTerminalSize.d.ts.map +1 -0
  69. package/dist/cli/ui/hooks/solid/useTerminalSize.js +16 -0
  70. package/dist/cli/ui/hooks/solid/useTerminalSize.js.map +1 -0
  71. package/dist/cli/ui/index.solid.d.ts +5 -0
  72. package/dist/cli/ui/index.solid.d.ts.map +1 -0
  73. package/dist/cli/ui/index.solid.js +21 -0
  74. package/dist/cli/ui/index.solid.js.map +1 -0
  75. package/dist/cli/ui/{components/screens → screens/solid}/BranchListScreen.d.ts +8 -22
  76. package/dist/cli/ui/screens/solid/BranchListScreen.d.ts.map +1 -0
  77. package/dist/cli/ui/screens/solid/BranchListScreen.js +756 -0
  78. package/dist/cli/ui/screens/solid/BranchListScreen.js.map +1 -0
  79. package/dist/cli/ui/screens/solid/ConfirmScreen.d.ts +10 -0
  80. package/dist/cli/ui/screens/solid/ConfirmScreen.d.ts.map +1 -0
  81. package/dist/cli/ui/screens/solid/ConfirmScreen.js +37 -0
  82. package/dist/cli/ui/screens/solid/ConfirmScreen.js.map +1 -0
  83. package/dist/cli/ui/screens/solid/EnvironmentScreen.d.ts +14 -0
  84. package/dist/cli/ui/screens/solid/EnvironmentScreen.d.ts.map +1 -0
  85. package/dist/cli/ui/screens/solid/EnvironmentScreen.js +91 -0
  86. package/dist/cli/ui/screens/solid/EnvironmentScreen.js.map +1 -0
  87. package/dist/cli/ui/screens/solid/ErrorScreen.d.ts +8 -0
  88. package/dist/cli/ui/screens/solid/ErrorScreen.d.ts.map +1 -0
  89. package/dist/cli/ui/screens/solid/ErrorScreen.js +18 -0
  90. package/dist/cli/ui/screens/solid/ErrorScreen.js.map +1 -0
  91. package/dist/cli/ui/screens/solid/InputScreen.d.ts +13 -0
  92. package/dist/cli/ui/screens/solid/InputScreen.d.ts.map +1 -0
  93. package/dist/cli/ui/screens/solid/InputScreen.js +17 -0
  94. package/dist/cli/ui/screens/solid/InputScreen.js.map +1 -0
  95. package/dist/cli/ui/screens/solid/LoadingIndicator.d.ts +9 -0
  96. package/dist/cli/ui/screens/solid/LoadingIndicator.d.ts.map +1 -0
  97. package/dist/cli/ui/screens/solid/LoadingIndicator.js +43 -0
  98. package/dist/cli/ui/screens/solid/LoadingIndicator.js.map +1 -0
  99. package/dist/cli/ui/{components/screens → screens/solid}/LogDetailScreen.d.ts +2 -2
  100. package/dist/cli/ui/screens/solid/LogDetailScreen.d.ts.map +1 -0
  101. package/dist/cli/ui/screens/solid/LogDetailScreen.js +34 -0
  102. package/dist/cli/ui/screens/solid/LogDetailScreen.js.map +1 -0
  103. package/dist/cli/ui/{components/screens/LogListScreen.d.ts → screens/solid/LogScreen.d.ts} +4 -4
  104. package/dist/cli/ui/screens/solid/LogScreen.d.ts.map +1 -0
  105. package/dist/cli/ui/screens/solid/LogScreen.js +95 -0
  106. package/dist/cli/ui/screens/solid/LogScreen.js.map +1 -0
  107. package/dist/cli/ui/screens/solid/ProfileEnvScreen.d.ts +17 -0
  108. package/dist/cli/ui/screens/solid/ProfileEnvScreen.d.ts.map +1 -0
  109. package/dist/cli/ui/screens/solid/ProfileEnvScreen.js +112 -0
  110. package/dist/cli/ui/screens/solid/ProfileEnvScreen.js.map +1 -0
  111. package/dist/cli/ui/screens/solid/ProfileScreen.d.ts +17 -0
  112. package/dist/cli/ui/screens/solid/ProfileScreen.d.ts.map +1 -0
  113. package/dist/cli/ui/screens/solid/ProfileScreen.js +50 -0
  114. package/dist/cli/ui/screens/solid/ProfileScreen.js.map +1 -0
  115. package/dist/cli/ui/screens/solid/SelectorScreen.d.ts +20 -0
  116. package/dist/cli/ui/screens/solid/SelectorScreen.d.ts.map +1 -0
  117. package/dist/cli/ui/screens/solid/SelectorScreen.js +90 -0
  118. package/dist/cli/ui/screens/solid/SelectorScreen.js.map +1 -0
  119. package/dist/cli/ui/screens/solid/WorktreeCreateScreen.d.ts +13 -0
  120. package/dist/cli/ui/screens/solid/WorktreeCreateScreen.d.ts.map +1 -0
  121. package/dist/cli/ui/screens/solid/WorktreeCreateScreen.js +59 -0
  122. package/dist/cli/ui/screens/solid/WorktreeCreateScreen.js.map +1 -0
  123. package/dist/cli/ui/stores/appStore.d.ts +143 -0
  124. package/dist/cli/ui/stores/appStore.d.ts.map +1 -0
  125. package/dist/cli/ui/stores/appStore.js +158 -0
  126. package/dist/cli/ui/stores/appStore.js.map +1 -0
  127. package/dist/cli/ui/stores/branchStore.d.ts +159 -0
  128. package/dist/cli/ui/stores/branchStore.d.ts.map +1 -0
  129. package/dist/cli/ui/stores/branchStore.js +275 -0
  130. package/dist/cli/ui/stores/branchStore.js.map +1 -0
  131. package/dist/cli/ui/stores/index.d.ts +11 -0
  132. package/dist/cli/ui/stores/index.d.ts.map +1 -0
  133. package/dist/cli/ui/stores/index.js +14 -0
  134. package/dist/cli/ui/stores/index.js.map +1 -0
  135. package/dist/cli/ui/stores/uiStore.d.ts +146 -0
  136. package/dist/cli/ui/stores/uiStore.d.ts.map +1 -0
  137. package/dist/cli/ui/stores/uiStore.js +166 -0
  138. package/dist/cli/ui/stores/uiStore.js.map +1 -0
  139. package/dist/cli/ui/types.d.ts +16 -1
  140. package/dist/cli/ui/types.d.ts.map +1 -1
  141. package/dist/cli/ui/utils/branchFormatter.d.ts.map +1 -1
  142. package/dist/cli/ui/utils/branchFormatter.js +7 -210
  143. package/dist/cli/ui/utils/branchFormatter.js.map +1 -1
  144. package/dist/cli/ui/utils/continueSession.d.ts +4 -0
  145. package/dist/cli/ui/utils/continueSession.d.ts.map +1 -1
  146. package/dist/cli/ui/utils/continueSession.js +30 -0
  147. package/dist/cli/ui/utils/continueSession.js.map +1 -1
  148. package/dist/client/assets/{index-ChHC-Puh.css → index-BbfV7Wuj.css} +1 -1
  149. package/dist/client/assets/index-CoAyq5x1.js +78 -0
  150. package/dist/client/index.html +2 -2
  151. package/dist/codex.d.ts +1 -0
  152. package/dist/codex.d.ts.map +1 -1
  153. package/dist/codex.js +86 -45
  154. package/dist/codex.js.map +1 -1
  155. package/dist/config/builtin-coding-agents.d.ts +4 -0
  156. package/dist/config/builtin-coding-agents.d.ts.map +1 -1
  157. package/dist/config/builtin-coding-agents.js +18 -3
  158. package/dist/config/builtin-coding-agents.js.map +1 -1
  159. package/dist/config/index.d.ts +2 -0
  160. package/dist/config/index.d.ts.map +1 -1
  161. package/dist/config/index.js +2 -0
  162. package/dist/config/index.js.map +1 -1
  163. package/dist/config/tools.d.ts.map +1 -1
  164. package/dist/config/tools.js +11 -0
  165. package/dist/config/tools.js.map +1 -1
  166. package/dist/gemini.d.ts +1 -0
  167. package/dist/gemini.d.ts.map +1 -1
  168. package/dist/gemini.js +42 -37
  169. package/dist/gemini.js.map +1 -1
  170. package/dist/index.d.ts +1 -1
  171. package/dist/index.d.ts.map +1 -1
  172. package/dist/index.js +122 -102
  173. package/dist/index.js.map +1 -1
  174. package/dist/launcher.d.ts.map +1 -1
  175. package/dist/launcher.js +18 -3
  176. package/dist/launcher.js.map +1 -1
  177. package/dist/logging/logger.d.ts.map +1 -1
  178. package/dist/logging/logger.js +26 -9
  179. package/dist/logging/logger.js.map +1 -1
  180. package/dist/opentui/highlights-eq9cgrbb.scm +604 -0
  181. package/dist/opentui/highlights-ghv9g403.scm +205 -0
  182. package/dist/opentui/highlights-hk7bwhj4.scm +284 -0
  183. package/dist/opentui/highlights-r812a2qc.scm +150 -0
  184. package/dist/opentui/highlights-x6tmsnaa.scm +115 -0
  185. package/dist/opentui/index.solid.d.ts +2 -0
  186. package/dist/opentui/index.solid.d.ts.map +1 -0
  187. package/dist/opentui/index.solid.js +52034 -0
  188. package/dist/opentui/index.solid.js.map +1 -0
  189. package/dist/opentui/injections-73j83es3.scm +27 -0
  190. package/dist/opentui/tree-sitter-javascript-nd0q4pe9.wasm +0 -0
  191. package/dist/opentui/tree-sitter-markdown-411r6y9b.wasm +0 -0
  192. package/dist/opentui/tree-sitter-markdown_inline-j5349f42.wasm +0 -0
  193. package/dist/opentui/tree-sitter-typescript-zxjzwt75.wasm +0 -0
  194. package/dist/opentui/tree-sitter-zig-e78zbjpm.wasm +0 -0
  195. package/dist/repositories/worktree.repository.d.ts +1 -0
  196. package/dist/repositories/worktree.repository.d.ts.map +1 -1
  197. package/dist/repositories/worktree.repository.js +7 -0
  198. package/dist/repositories/worktree.repository.js.map +1 -1
  199. package/dist/services/codingAgentResolver.d.ts +2 -0
  200. package/dist/services/codingAgentResolver.d.ts.map +1 -1
  201. package/dist/services/codingAgentResolver.js +30 -4
  202. package/dist/services/codingAgentResolver.js.map +1 -1
  203. package/dist/services/dependency-installer.d.ts.map +1 -1
  204. package/dist/services/dependency-installer.js +0 -5
  205. package/dist/services/dependency-installer.js.map +1 -1
  206. package/dist/types/api.d.ts +3 -0
  207. package/dist/types/api.d.ts.map +1 -1
  208. package/dist/types/coding-agent.d.ts +62 -0
  209. package/dist/types/coding-agent.d.ts.map +1 -0
  210. package/dist/types/coding-agent.js +29 -0
  211. package/dist/types/coding-agent.js.map +1 -0
  212. package/dist/types/tools.d.ts +17 -0
  213. package/dist/types/tools.d.ts.map +1 -1
  214. package/dist/utils/coding-agent-colors.d.ts +88 -0
  215. package/dist/utils/coding-agent-colors.d.ts.map +1 -0
  216. package/dist/utils/coding-agent-colors.js +137 -0
  217. package/dist/utils/coding-agent-colors.js.map +1 -0
  218. package/dist/utils/command.d.ts +1 -1
  219. package/dist/utils/command.d.ts.map +1 -1
  220. package/dist/utils/command.js +10 -1
  221. package/dist/utils/command.js.map +1 -1
  222. package/dist/utils/error-utils.d.ts +27 -0
  223. package/dist/utils/error-utils.d.ts.map +1 -0
  224. package/dist/utils/error-utils.js +98 -0
  225. package/dist/utils/error-utils.js.map +1 -0
  226. package/dist/utils/npmRegistry.d.ts +61 -0
  227. package/dist/utils/npmRegistry.d.ts.map +1 -0
  228. package/dist/utils/npmRegistry.js +180 -0
  229. package/dist/utils/npmRegistry.js.map +1 -0
  230. package/dist/utils/prompt.d.ts +1 -1
  231. package/dist/utils/prompt.js +1 -1
  232. package/dist/utils/session/index.d.ts +5 -3
  233. package/dist/utils/session/index.d.ts.map +1 -1
  234. package/dist/utils/session/index.js +5 -2
  235. package/dist/utils/session/index.js.map +1 -1
  236. package/dist/utils/session/parsers/codex.d.ts.map +1 -1
  237. package/dist/utils/session/parsers/codex.js +8 -1
  238. package/dist/utils/session/parsers/codex.js.map +1 -1
  239. package/dist/utils/session/parsers/index.d.ts +1 -0
  240. package/dist/utils/session/parsers/index.d.ts.map +1 -1
  241. package/dist/utils/session/parsers/index.js +2 -0
  242. package/dist/utils/session/parsers/index.js.map +1 -1
  243. package/dist/utils/session/parsers/opencode.d.ts +23 -0
  244. package/dist/utils/session/parsers/opencode.d.ts.map +1 -0
  245. package/dist/utils/session/parsers/opencode.js +89 -0
  246. package/dist/utils/session/parsers/opencode.js.map +1 -0
  247. package/dist/utils/session/types.d.ts +4 -0
  248. package/dist/utils/session/types.d.ts.map +1 -1
  249. package/dist/utils/terminal.d.ts +1 -0
  250. package/dist/utils/terminal.d.ts.map +1 -1
  251. package/dist/utils/terminal.js +20 -0
  252. package/dist/utils/terminal.js.map +1 -1
  253. package/dist/utils.d.ts +9 -0
  254. package/dist/utils.d.ts.map +1 -1
  255. package/dist/utils.js +33 -2
  256. package/dist/utils.js.map +1 -1
  257. package/dist/web/client/src/components/CodingAgentLaunchModal.d.ts.map +1 -1
  258. package/dist/web/client/src/components/CodingAgentLaunchModal.js +7 -16
  259. package/dist/web/client/src/components/CodingAgentLaunchModal.js.map +1 -1
  260. package/dist/web/client/src/components/branch-detail/BranchInfoCards.d.ts.map +1 -1
  261. package/dist/web/client/src/components/branch-detail/BranchInfoCards.js +7 -2
  262. package/dist/web/client/src/components/branch-detail/BranchInfoCards.js.map +1 -1
  263. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.d.ts.map +1 -1
  264. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js +2 -1
  265. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js.map +1 -1
  266. package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts +2 -2
  267. package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts.map +1 -1
  268. package/dist/web/client/src/components/branch-detail/ToolLauncher.js +5 -5
  269. package/dist/web/client/src/components/branch-detail/ToolLauncher.js.map +1 -1
  270. package/dist/web/client/src/lib/coding-agent-colors.d.ts +86 -0
  271. package/dist/web/client/src/lib/coding-agent-colors.d.ts.map +1 -0
  272. package/dist/web/client/src/lib/coding-agent-colors.js +135 -0
  273. package/dist/web/client/src/lib/coding-agent-colors.js.map +1 -0
  274. package/dist/web/client/src/pages/BranchDetailPage.js +10 -10
  275. package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
  276. package/dist/web/server/pty/manager.d.ts +2 -0
  277. package/dist/web/server/pty/manager.d.ts.map +1 -1
  278. package/dist/web/server/pty/manager.js +104 -0
  279. package/dist/web/server/pty/manager.js.map +1 -1
  280. package/dist/web/server/routes/sessions.d.ts.map +1 -1
  281. package/dist/web/server/routes/sessions.js +5 -1
  282. package/dist/web/server/routes/sessions.js.map +1 -1
  283. package/dist/web/server/services/branches.d.ts.map +1 -1
  284. package/dist/web/server/services/branches.js +10 -8
  285. package/dist/web/server/services/branches.js.map +1 -1
  286. package/dist/web/server/services/worktrees.js +2 -2
  287. package/dist/web/server/services/worktrees.js.map +1 -1
  288. package/dist/worktree.d.ts +47 -1
  289. package/dist/worktree.d.ts.map +1 -1
  290. package/dist/worktree.js +280 -94
  291. package/dist/worktree.js.map +1 -1
  292. package/package.json +12 -14
  293. package/src/claude.ts +68 -70
  294. package/src/cli/ui/App.solid.tsx +1823 -0
  295. package/src/cli/ui/__tests__/solid/AppSolid.cleanup.test.tsx +255 -0
  296. package/src/cli/ui/__tests__/solid/BranchListScreen.test.tsx +243 -0
  297. package/src/cli/ui/__tests__/solid/components/QuickStartStep.test.tsx +237 -0
  298. package/src/cli/ui/__tests__/solid/components/WizardPopup.test.tsx +231 -0
  299. package/src/cli/ui/__tests__/solid/components/WizardSteps.test.tsx +238 -0
  300. package/src/cli/ui/__tests__/utils/branchFormatter.test.ts +7 -289
  301. package/src/cli/ui/__tests__/utils/clipboard.test.ts +3 -3
  302. package/src/cli/ui/__tests__/utils/statisticsCalculator.test.ts +1 -1
  303. package/src/cli/ui/components/solid/Footer.tsx +36 -0
  304. package/src/cli/ui/components/{parts → solid}/Header.tsx +17 -28
  305. package/src/cli/ui/components/solid/HelpOverlay.tsx +194 -0
  306. package/src/cli/ui/components/solid/QuickStartStep.tsx +197 -0
  307. package/src/cli/ui/components/{parts → solid}/ScrollableList.tsx +7 -8
  308. package/src/cli/ui/components/solid/SearchInput.tsx +42 -0
  309. package/src/cli/ui/components/solid/SelectInput.tsx +84 -0
  310. package/src/cli/ui/components/solid/Stats.tsx +92 -0
  311. package/src/cli/ui/components/solid/TextInput.tsx +49 -0
  312. package/src/cli/ui/components/solid/WizardController.tsx +384 -0
  313. package/src/cli/ui/components/solid/WizardPopup.tsx +135 -0
  314. package/src/cli/ui/components/solid/WizardSteps.tsx +793 -0
  315. package/src/cli/ui/core/index.ts +17 -0
  316. package/src/cli/ui/core/keybindings.ts +367 -0
  317. package/src/cli/ui/core/theme.ts +234 -0
  318. package/src/cli/ui/core/types.ts +235 -0
  319. package/src/cli/ui/hooks/solid/useAsyncOperation.ts +76 -0
  320. package/src/cli/ui/hooks/solid/useFilter.ts +86 -0
  321. package/src/cli/ui/hooks/solid/useGitOperations.ts +80 -0
  322. package/src/cli/ui/hooks/solid/useKeyHandler.ts +103 -0
  323. package/src/cli/ui/hooks/solid/useScrollableList.ts +149 -0
  324. package/src/cli/ui/hooks/solid/useSelection.ts +77 -0
  325. package/src/cli/ui/hooks/solid/useTerminalSize.ts +22 -0
  326. package/src/cli/ui/index.solid.ts +28 -0
  327. package/src/cli/ui/screens/solid/BranchListScreen.tsx +1050 -0
  328. package/src/cli/ui/screens/solid/ConfirmScreen.tsx +74 -0
  329. package/src/cli/ui/screens/solid/EnvironmentScreen.tsx +159 -0
  330. package/src/cli/ui/screens/solid/ErrorScreen.tsx +42 -0
  331. package/src/cli/ui/screens/solid/InputScreen.tsx +55 -0
  332. package/src/cli/ui/screens/solid/LoadingIndicator.tsx +77 -0
  333. package/src/cli/ui/screens/solid/LogDetailScreen.tsx +75 -0
  334. package/src/cli/ui/screens/solid/LogScreen.tsx +175 -0
  335. package/src/cli/ui/screens/solid/ProfileEnvScreen.tsx +192 -0
  336. package/src/cli/ui/screens/solid/ProfileScreen.tsx +98 -0
  337. package/src/cli/ui/screens/solid/SelectorScreen.tsx +170 -0
  338. package/src/cli/ui/screens/solid/SettingsScreen.tsx +50 -0
  339. package/src/cli/ui/screens/solid/WorktreeCreateScreen.tsx +136 -0
  340. package/src/cli/ui/screens/solid/WorktreeDeleteScreen.tsx +40 -0
  341. package/src/cli/ui/stores/appStore.ts +208 -0
  342. package/src/cli/ui/stores/branchStore.ts +357 -0
  343. package/src/cli/ui/stores/index.ts +31 -0
  344. package/src/cli/ui/stores/uiStore.ts +226 -0
  345. package/src/cli/ui/types.ts +20 -3
  346. package/src/cli/ui/utils/__tests__/branchFormatter.test.ts +180 -0
  347. package/src/cli/ui/utils/branchFormatter.ts +8 -215
  348. package/src/cli/ui/utils/continueSession.ts +44 -0
  349. package/src/cli/ui/utils/modelOptions.test.ts +1 -1
  350. package/src/codex.ts +100 -43
  351. package/src/config/__tests__/saveSession.test.ts +143 -0
  352. package/src/config/builtin-coding-agents.ts +19 -3
  353. package/src/config/index.ts +4 -0
  354. package/src/config/tools.ts +16 -0
  355. package/src/gemini.ts +58 -43
  356. package/src/index.test.ts +12 -12
  357. package/src/index.ts +164 -142
  358. package/src/launcher.ts +22 -3
  359. package/src/logging/logger.ts +32 -10
  360. package/src/opentui/index.solid.ts +1 -0
  361. package/src/repositories/worktree.repository.ts +8 -0
  362. package/src/services/__tests__/BatchMergeService.test.ts +62 -66
  363. package/src/services/__tests__/WorktreeOrchestrator.test.ts +8 -7
  364. package/src/services/codingAgentResolver.ts +30 -4
  365. package/src/services/dependency-installer.ts +0 -7
  366. package/src/types/api.ts +3 -0
  367. package/src/types/coding-agent.ts +85 -0
  368. package/src/types/tools.ts +19 -0
  369. package/src/utils/__tests__/npmRegistry.test.ts +250 -0
  370. package/src/utils/__tests__/prompt.test.ts +4 -5
  371. package/src/utils/coding-agent-colors.ts +165 -0
  372. package/src/utils/command.ts +10 -1
  373. package/src/utils/error-utils.ts +133 -0
  374. package/src/utils/npmRegistry.ts +249 -0
  375. package/src/utils/prompt.ts +1 -1
  376. package/src/utils/session/index.ts +10 -2
  377. package/src/utils/session/parsers/codex.ts +9 -1
  378. package/src/utils/session/parsers/index.ts +6 -0
  379. package/src/utils/session/parsers/opencode.ts +110 -0
  380. package/src/utils/session/types.ts +5 -0
  381. package/src/utils/terminal.ts +24 -0
  382. package/src/utils.test.ts +1 -1
  383. package/src/utils.ts +37 -4
  384. package/src/web/client/src/components/CodingAgentLaunchModal.tsx +12 -21
  385. package/src/web/client/src/components/branch-detail/BranchInfoCards.tsx +16 -1
  386. package/src/web/client/src/components/branch-detail/SessionHistoryTable.tsx +7 -1
  387. package/src/web/client/src/components/branch-detail/ToolLauncher.tsx +11 -6
  388. package/src/web/client/src/lib/coding-agent-colors.ts +149 -0
  389. package/src/web/client/src/pages/BranchDetailPage.tsx +11 -11
  390. package/src/web/server/pty/manager.ts +139 -0
  391. package/src/web/server/routes/sessions.ts +6 -0
  392. package/src/web/server/services/branches.ts +11 -8
  393. package/src/web/server/services/worktrees.ts +2 -2
  394. package/src/worktree.ts +366 -107
  395. package/dist/cli/ui/components/App.d.ts +0 -25
  396. package/dist/cli/ui/components/App.d.ts.map +0 -1
  397. package/dist/cli/ui/components/App.js +0 -988
  398. package/dist/cli/ui/components/App.js.map +0 -1
  399. package/dist/cli/ui/components/common/Confirm.d.ts +0 -13
  400. package/dist/cli/ui/components/common/Confirm.d.ts.map +0 -1
  401. package/dist/cli/ui/components/common/Confirm.js +0 -20
  402. package/dist/cli/ui/components/common/Confirm.js.map +0 -1
  403. package/dist/cli/ui/components/common/ErrorBoundary.d.ts +0 -23
  404. package/dist/cli/ui/components/common/ErrorBoundary.d.ts.map +0 -1
  405. package/dist/cli/ui/components/common/ErrorBoundary.js +0 -37
  406. package/dist/cli/ui/components/common/ErrorBoundary.js.map +0 -1
  407. package/dist/cli/ui/components/common/Input.d.ts +0 -19
  408. package/dist/cli/ui/components/common/Input.d.ts.map +0 -1
  409. package/dist/cli/ui/components/common/Input.js +0 -22
  410. package/dist/cli/ui/components/common/Input.js.map +0 -1
  411. package/dist/cli/ui/components/common/LoadingIndicator.d.ts +0 -19
  412. package/dist/cli/ui/components/common/LoadingIndicator.d.ts.map +0 -1
  413. package/dist/cli/ui/components/common/LoadingIndicator.js +0 -61
  414. package/dist/cli/ui/components/common/LoadingIndicator.js.map +0 -1
  415. package/dist/cli/ui/components/common/Select.d.ts +0 -38
  416. package/dist/cli/ui/components/common/Select.d.ts.map +0 -1
  417. package/dist/cli/ui/components/common/Select.js +0 -151
  418. package/dist/cli/ui/components/common/Select.js.map +0 -1
  419. package/dist/cli/ui/components/common/SpinnerIcon.d.ts +0 -20
  420. package/dist/cli/ui/components/common/SpinnerIcon.d.ts.map +0 -1
  421. package/dist/cli/ui/components/common/SpinnerIcon.js +0 -61
  422. package/dist/cli/ui/components/common/SpinnerIcon.js.map +0 -1
  423. package/dist/cli/ui/components/parts/Footer.d.ts +0 -15
  424. package/dist/cli/ui/components/parts/Footer.d.ts.map +0 -1
  425. package/dist/cli/ui/components/parts/Footer.js +0 -20
  426. package/dist/cli/ui/components/parts/Footer.js.map +0 -1
  427. package/dist/cli/ui/components/parts/Header.d.ts.map +0 -1
  428. package/dist/cli/ui/components/parts/Header.js +0 -24
  429. package/dist/cli/ui/components/parts/Header.js.map +0 -1
  430. package/dist/cli/ui/components/parts/MergeStatusList.d.ts +0 -13
  431. package/dist/cli/ui/components/parts/MergeStatusList.d.ts.map +0 -1
  432. package/dist/cli/ui/components/parts/MergeStatusList.js +0 -52
  433. package/dist/cli/ui/components/parts/MergeStatusList.js.map +0 -1
  434. package/dist/cli/ui/components/parts/ProgressBar.d.ts +0 -13
  435. package/dist/cli/ui/components/parts/ProgressBar.d.ts.map +0 -1
  436. package/dist/cli/ui/components/parts/ProgressBar.js +0 -53
  437. package/dist/cli/ui/components/parts/ProgressBar.js.map +0 -1
  438. package/dist/cli/ui/components/parts/ScrollableList.d.ts +0 -12
  439. package/dist/cli/ui/components/parts/ScrollableList.d.ts.map +0 -1
  440. package/dist/cli/ui/components/parts/ScrollableList.js +0 -11
  441. package/dist/cli/ui/components/parts/ScrollableList.js.map +0 -1
  442. package/dist/cli/ui/components/parts/Stats.d.ts +0 -10
  443. package/dist/cli/ui/components/parts/Stats.d.ts.map +0 -1
  444. package/dist/cli/ui/components/parts/Stats.js +0 -55
  445. package/dist/cli/ui/components/parts/Stats.js.map +0 -1
  446. package/dist/cli/ui/components/screens/BatchMergeProgressScreen.d.ts +0 -17
  447. package/dist/cli/ui/components/screens/BatchMergeProgressScreen.d.ts.map +0 -1
  448. package/dist/cli/ui/components/screens/BatchMergeProgressScreen.js +0 -42
  449. package/dist/cli/ui/components/screens/BatchMergeProgressScreen.js.map +0 -1
  450. package/dist/cli/ui/components/screens/BatchMergeResultScreen.d.ts +0 -17
  451. package/dist/cli/ui/components/screens/BatchMergeResultScreen.d.ts.map +0 -1
  452. package/dist/cli/ui/components/screens/BatchMergeResultScreen.js +0 -72
  453. package/dist/cli/ui/components/screens/BatchMergeResultScreen.js.map +0 -1
  454. package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts +0 -18
  455. package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts.map +0 -1
  456. package/dist/cli/ui/components/screens/BranchCreatorScreen.js +0 -151
  457. package/dist/cli/ui/components/screens/BranchCreatorScreen.js.map +0 -1
  458. package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +0 -1
  459. package/dist/cli/ui/components/screens/BranchListScreen.js +0 -476
  460. package/dist/cli/ui/components/screens/BranchListScreen.js.map +0 -1
  461. package/dist/cli/ui/components/screens/BranchQuickStartScreen.d.ts +0 -30
  462. package/dist/cli/ui/components/screens/BranchQuickStartScreen.d.ts.map +0 -1
  463. package/dist/cli/ui/components/screens/BranchQuickStartScreen.js +0 -145
  464. package/dist/cli/ui/components/screens/BranchQuickStartScreen.js.map +0 -1
  465. package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.d.ts +0 -27
  466. package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.d.ts.map +0 -1
  467. package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.js +0 -93
  468. package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.js.map +0 -1
  469. package/dist/cli/ui/components/screens/EnvironmentProfileScreen.d.ts +0 -19
  470. package/dist/cli/ui/components/screens/EnvironmentProfileScreen.d.ts.map +0 -1
  471. package/dist/cli/ui/components/screens/EnvironmentProfileScreen.js +0 -577
  472. package/dist/cli/ui/components/screens/EnvironmentProfileScreen.js.map +0 -1
  473. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts +0 -45
  474. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts.map +0 -1
  475. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js +0 -95
  476. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js.map +0 -1
  477. package/dist/cli/ui/components/screens/LogDatePickerScreen.d.ts +0 -10
  478. package/dist/cli/ui/components/screens/LogDatePickerScreen.d.ts.map +0 -1
  479. package/dist/cli/ui/components/screens/LogDatePickerScreen.js +0 -44
  480. package/dist/cli/ui/components/screens/LogDatePickerScreen.js.map +0 -1
  481. package/dist/cli/ui/components/screens/LogDetailScreen.d.ts.map +0 -1
  482. package/dist/cli/ui/components/screens/LogDetailScreen.js +0 -34
  483. package/dist/cli/ui/components/screens/LogDetailScreen.js.map +0 -1
  484. package/dist/cli/ui/components/screens/LogListScreen.d.ts.map +0 -1
  485. package/dist/cli/ui/components/screens/LogListScreen.js +0 -107
  486. package/dist/cli/ui/components/screens/LogListScreen.js.map +0 -1
  487. package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts +0 -24
  488. package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts.map +0 -1
  489. package/dist/cli/ui/components/screens/ModelSelectorScreen.js +0 -197
  490. package/dist/cli/ui/components/screens/ModelSelectorScreen.js.map +0 -1
  491. package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts +0 -29
  492. package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts.map +0 -1
  493. package/dist/cli/ui/components/screens/PRCleanupScreen.js +0 -92
  494. package/dist/cli/ui/components/screens/PRCleanupScreen.js.map +0 -1
  495. package/dist/cli/ui/components/screens/SessionSelectorScreen.d.ts +0 -31
  496. package/dist/cli/ui/components/screens/SessionSelectorScreen.d.ts.map +0 -1
  497. package/dist/cli/ui/components/screens/SessionSelectorScreen.js +0 -67
  498. package/dist/cli/ui/components/screens/SessionSelectorScreen.js.map +0 -1
  499. package/dist/cli/ui/hooks/useAppInput.d.ts +0 -21
  500. package/dist/cli/ui/hooks/useAppInput.d.ts.map +0 -1
  501. package/dist/cli/ui/hooks/useAppInput.js +0 -138
  502. package/dist/cli/ui/hooks/useAppInput.js.map +0 -1
  503. package/dist/cli/ui/hooks/useBatchMerge.d.ts +0 -17
  504. package/dist/cli/ui/hooks/useBatchMerge.d.ts.map +0 -1
  505. package/dist/cli/ui/hooks/useBatchMerge.js +0 -77
  506. package/dist/cli/ui/hooks/useBatchMerge.js.map +0 -1
  507. package/dist/cli/ui/hooks/useGitData.d.ts +0 -21
  508. package/dist/cli/ui/hooks/useGitData.d.ts.map +0 -1
  509. package/dist/cli/ui/hooks/useGitData.js +0 -229
  510. package/dist/cli/ui/hooks/useGitData.js.map +0 -1
  511. package/dist/cli/ui/hooks/useProfiles.d.ts +0 -41
  512. package/dist/cli/ui/hooks/useProfiles.d.ts.map +0 -1
  513. package/dist/cli/ui/hooks/useProfiles.js +0 -136
  514. package/dist/cli/ui/hooks/useProfiles.js.map +0 -1
  515. package/dist/cli/ui/hooks/useScreenState.d.ts +0 -12
  516. package/dist/cli/ui/hooks/useScreenState.d.ts.map +0 -1
  517. package/dist/cli/ui/hooks/useScreenState.js +0 -30
  518. package/dist/cli/ui/hooks/useScreenState.js.map +0 -1
  519. package/dist/cli/ui/hooks/useTerminalSize.d.ts +0 -9
  520. package/dist/cli/ui/hooks/useTerminalSize.d.ts.map +0 -1
  521. package/dist/cli/ui/hooks/useTerminalSize.js +0 -24
  522. package/dist/cli/ui/hooks/useTerminalSize.js.map +0 -1
  523. package/dist/cli/ui/hooks/useToolStatus.d.ts +0 -30
  524. package/dist/cli/ui/hooks/useToolStatus.d.ts.map +0 -1
  525. package/dist/cli/ui/hooks/useToolStatus.js +0 -49
  526. package/dist/cli/ui/hooks/useToolStatus.js.map +0 -1
  527. package/dist/cli/ui/screens/BranchActionSelectorScreen.d.ts +0 -24
  528. package/dist/cli/ui/screens/BranchActionSelectorScreen.d.ts.map +0 -1
  529. package/dist/cli/ui/screens/BranchActionSelectorScreen.js +0 -65
  530. package/dist/cli/ui/screens/BranchActionSelectorScreen.js.map +0 -1
  531. package/dist/client/assets/index-LNPtOrn3.js +0 -78
  532. package/src/cli/ui/__tests__/SKIPPED_TESTS.md +0 -119
  533. package/src/cli/ui/__tests__/acceptance/branchList.acceptance.test.tsx.skip +0 -239
  534. package/src/cli/ui/__tests__/acceptance/navigation.acceptance.test.tsx +0 -225
  535. package/src/cli/ui/__tests__/acceptance/realtimeUpdate.acceptance.test.tsx.skip +0 -219
  536. package/src/cli/ui/__tests__/components/App.protected-branch.test.tsx +0 -212
  537. package/src/cli/ui/__tests__/components/App.shortcuts.test.tsx +0 -440
  538. package/src/cli/ui/__tests__/components/App.test.tsx +0 -365
  539. package/src/cli/ui/__tests__/components/ModelSelectorScreen.initial.test.tsx +0 -91
  540. package/src/cli/ui/__tests__/components/common/Confirm.test.tsx +0 -80
  541. package/src/cli/ui/__tests__/components/common/ErrorBoundary.test.tsx +0 -104
  542. package/src/cli/ui/__tests__/components/common/Input.test.tsx +0 -100
  543. package/src/cli/ui/__tests__/components/common/LoadingIndicator.test.tsx +0 -148
  544. package/src/cli/ui/__tests__/components/common/Select.memo.test.tsx +0 -255
  545. package/src/cli/ui/__tests__/components/common/Select.test.tsx +0 -335
  546. package/src/cli/ui/__tests__/components/parts/Footer.test.tsx +0 -65
  547. package/src/cli/ui/__tests__/components/parts/Header.test.tsx +0 -55
  548. package/src/cli/ui/__tests__/components/parts/ScrollableList.test.tsx +0 -69
  549. package/src/cli/ui/__tests__/components/parts/Stats.test.tsx +0 -148
  550. package/src/cli/ui/__tests__/components/screens/BranchCreatorScreen.test.tsx +0 -253
  551. package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +0 -1070
  552. package/src/cli/ui/__tests__/components/screens/BranchQuickStartScreen.test.tsx +0 -142
  553. package/src/cli/ui/__tests__/components/screens/CodingAgentSelectorScreen.test.tsx +0 -174
  554. package/src/cli/ui/__tests__/components/screens/ExecutionModeSelectorScreen.test.tsx +0 -182
  555. package/src/cli/ui/__tests__/components/screens/LogDetailScreen.test.tsx +0 -57
  556. package/src/cli/ui/__tests__/components/screens/LogListScreen.test.tsx +0 -102
  557. package/src/cli/ui/__tests__/components/screens/PRCleanupScreen.test.tsx +0 -216
  558. package/src/cli/ui/__tests__/components/screens/SessionSelectorScreen.test.tsx +0 -147
  559. package/src/cli/ui/__tests__/hooks/useGitData.nonblocking.test.tsx +0 -206
  560. package/src/cli/ui/__tests__/hooks/useGitData.test.ts +0 -197
  561. package/src/cli/ui/__tests__/hooks/useGitData.test.ts.skip +0 -228
  562. package/src/cli/ui/__tests__/hooks/useScreenState.test.ts +0 -147
  563. package/src/cli/ui/__tests__/hooks/useTerminalSize.test.ts +0 -99
  564. package/src/cli/ui/__tests__/integration/branchList.test.tsx.skip +0 -253
  565. package/src/cli/ui/__tests__/integration/edgeCases.test.tsx +0 -436
  566. package/src/cli/ui/__tests__/integration/navigation.test.tsx +0 -514
  567. package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx +0 -509
  568. package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx.skip +0 -216
  569. package/src/cli/ui/__tests__/performance/branchList.performance.test.tsx +0 -193
  570. package/src/cli/ui/__tests__/performance/useMemoOptimization.test.tsx +0 -234
  571. package/src/cli/ui/components/App.tsx +0 -1456
  572. package/src/cli/ui/components/common/Confirm.tsx +0 -44
  573. package/src/cli/ui/components/common/ErrorBoundary.tsx +0 -60
  574. package/src/cli/ui/components/common/Input.tsx +0 -58
  575. package/src/cli/ui/components/common/LoadingIndicator.tsx +0 -98
  576. package/src/cli/ui/components/common/Select.tsx +0 -247
  577. package/src/cli/ui/components/common/SpinnerIcon.tsx +0 -86
  578. package/src/cli/ui/components/parts/Footer.tsx +0 -41
  579. package/src/cli/ui/components/parts/Header.test.tsx +0 -75
  580. package/src/cli/ui/components/parts/MergeStatusList.tsx +0 -75
  581. package/src/cli/ui/components/parts/ProgressBar.tsx +0 -73
  582. package/src/cli/ui/components/parts/Stats.tsx +0 -88
  583. package/src/cli/ui/components/screens/BatchMergeProgressScreen.tsx +0 -74
  584. package/src/cli/ui/components/screens/BatchMergeResultScreen.tsx +0 -108
  585. package/src/cli/ui/components/screens/BranchCreatorScreen.tsx +0 -242
  586. package/src/cli/ui/components/screens/BranchListScreen.tsx +0 -744
  587. package/src/cli/ui/components/screens/BranchQuickStartScreen.tsx +0 -241
  588. package/src/cli/ui/components/screens/CodingAgentSelectorScreen.tsx +0 -159
  589. package/src/cli/ui/components/screens/EnvironmentProfileScreen.tsx +0 -928
  590. package/src/cli/ui/components/screens/ExecutionModeSelectorScreen.tsx +0 -176
  591. package/src/cli/ui/components/screens/LogDatePickerScreen.tsx +0 -83
  592. package/src/cli/ui/components/screens/LogDetailScreen.tsx +0 -67
  593. package/src/cli/ui/components/screens/LogListScreen.tsx +0 -192
  594. package/src/cli/ui/components/screens/ModelSelectorScreen.tsx +0 -320
  595. package/src/cli/ui/components/screens/PRCleanupScreen.tsx +0 -171
  596. package/src/cli/ui/components/screens/SessionSelectorScreen.tsx +0 -135
  597. package/src/cli/ui/hooks/useAppInput.ts +0 -172
  598. package/src/cli/ui/hooks/useBatchMerge.ts +0 -96
  599. package/src/cli/ui/hooks/useGitData.ts +0 -347
  600. package/src/cli/ui/hooks/useProfiles.ts +0 -211
  601. package/src/cli/ui/hooks/useScreenState.ts +0 -44
  602. package/src/cli/ui/hooks/useTerminalSize.ts +0 -33
  603. package/src/cli/ui/hooks/useToolStatus.ts +0 -68
  604. package/src/cli/ui/screens/BranchActionSelectorScreen.tsx +0 -111
  605. package/src/cli/ui/screens/__tests__/BranchActionSelectorScreen.test.tsx +0 -264
@@ -1,1456 +0,0 @@
1
- import React, {
2
- useCallback,
3
- useEffect,
4
- useMemo,
5
- useRef,
6
- useState,
7
- } from "react";
8
- import { useApp } from "ink";
9
- import { ErrorBoundary } from "./common/ErrorBoundary.js";
10
- import {
11
- BranchListScreen,
12
- type BranchListScreenProps,
13
- } from "./screens/BranchListScreen.js";
14
- import { LogListScreen } from "./screens/LogListScreen.js";
15
- import { LogDetailScreen } from "./screens/LogDetailScreen.js";
16
- import { LogDatePickerScreen } from "./screens/LogDatePickerScreen.js";
17
- import { BranchCreatorScreen } from "./screens/BranchCreatorScreen.js";
18
- import { BranchActionSelectorScreen } from "../screens/BranchActionSelectorScreen.js";
19
- import { CodingAgentSelectorScreen } from "./screens/CodingAgentSelectorScreen.js";
20
- import { ExecutionModeSelectorScreen } from "./screens/ExecutionModeSelectorScreen.js";
21
- import type { ExecutionMode } from "./screens/ExecutionModeSelectorScreen.js";
22
- import { BranchQuickStartScreen } from "./screens/BranchQuickStartScreen.js";
23
- import type { QuickStartAction } from "./screens/BranchQuickStartScreen.js";
24
- import {
25
- ModelSelectorScreen,
26
- type ModelSelectionResult,
27
- } from "./screens/ModelSelectorScreen.js";
28
- import { EnvironmentProfileScreen } from "./screens/EnvironmentProfileScreen.js";
29
- import { useGitData } from "../hooks/useGitData.js";
30
- import { useProfiles } from "../hooks/useProfiles.js";
31
- import { useScreenState } from "../hooks/useScreenState.js";
32
- import { useToolStatus } from "../hooks/useToolStatus.js";
33
- import { formatBranchItems } from "../utils/branchFormatter.js";
34
- import { calculateStatistics } from "../utils/statisticsCalculator.js";
35
- import { copyToClipboard } from "../utils/clipboard.js";
36
- import {
37
- parseLogLines,
38
- type FormattedLogEntry,
39
- } from "../../../logging/formatter.js";
40
- import {
41
- buildLogFilePath,
42
- getTodayLogDate,
43
- listRecentLogFiles,
44
- readLogFileLines,
45
- resolveLogDir,
46
- type LogFileInfo,
47
- } from "../../../logging/reader.js";
48
- import type {
49
- CodingAgentId,
50
- BranchInfo,
51
- BranchItem,
52
- CleanupTarget,
53
- InferenceLevel,
54
- SelectedBranchState,
55
- } from "../types.js";
56
- import { getRepositoryRoot, deleteBranch } from "../../../git.js";
57
- import { loadSession } from "../../../config/index.js";
58
- import {
59
- createWorktree,
60
- generateWorktreePath,
61
- isProtectedBranchName,
62
- removeWorktree,
63
- switchToProtectedBranch,
64
- } from "../../../worktree.js";
65
- import { getPackageVersion } from "../../../utils.js";
66
- import {
67
- resolveBaseBranchLabel,
68
- resolveBaseBranchRef,
69
- } from "../utils/baseBranch.js";
70
- import {
71
- getDefaultInferenceForModel,
72
- getDefaultModelOption,
73
- normalizeModelId,
74
- } from "../utils/modelOptions.js";
75
- import {
76
- resolveContinueSessionId,
77
- findLatestBranchSessionsByTool,
78
- } from "../utils/continueSession.js";
79
- import {
80
- findLatestCodexSession,
81
- findLatestCodexSessionId,
82
- findLatestClaudeSession,
83
- findLatestGeminiSession,
84
- } from "../../../utils/session.js";
85
- import type { ToolSessionEntry } from "../../../config/index.js";
86
-
87
- const COMPLETION_HOLD_DURATION_MS = 3000;
88
- const PROTECTED_BRANCH_WARNING =
89
- "Root branches operate directly in the repository root. Create a new branch if you need a dedicated worktree.";
90
-
91
- export interface SelectionResult {
92
- branch: string; // Local branch name (without remote prefix)
93
- displayName: string; // Name that was selected in the UI (may include remote prefix)
94
- branchType: "local" | "remote";
95
- remoteBranch?: string; // Full remote ref when branchType === 'remote'
96
- tool: CodingAgentId;
97
- mode: ExecutionMode;
98
- skipPermissions: boolean;
99
- model?: string | null;
100
- inferenceLevel?: InferenceLevel;
101
- sessionId?: string | null;
102
- }
103
-
104
- export interface AppProps {
105
- onExit: (result?: SelectionResult) => void;
106
- loadingIndicatorDelay?: number;
107
- }
108
-
109
- /**
110
- * App - Top-level component for Ink.js UI
111
- * Integrates ErrorBoundary, data fetching, screen navigation, and all screens
112
- */
113
- export function App({ onExit, loadingIndicatorDelay = 300 }: AppProps) {
114
- const { exit } = useApp();
115
-
116
- // 起動ディレクトリの取得
117
- const workingDirectory = process.cwd();
118
-
119
- const { branches, worktrees, loading, error, refresh, lastUpdated } =
120
- useGitData({
121
- enableAutoRefresh: false, // Manual refresh with 'r' key
122
- });
123
- const { currentScreen, navigateTo, goBack } = useScreenState();
124
-
125
- // Profile state
126
- const { activeProfileName, refresh: refreshProfiles } = useProfiles();
127
-
128
- // Tool status state (FR-017: 起動時に検出してキャッシュ)
129
- const { tools: toolStatuses } = useToolStatus();
130
-
131
- // Version state
132
- const [version, setVersion] = useState<string | null>(null);
133
- const [repoRoot, setRepoRoot] = useState<string | null>(null);
134
- const [continueSessionId, setContinueSessionId] = useState<string | null>(
135
- null,
136
- );
137
- const [branchQuickStart, setBranchQuickStart] = useState<
138
- {
139
- toolId: CodingAgentId;
140
- toolLabel: string;
141
- model?: string | null;
142
- sessionId?: string | null;
143
- inferenceLevel?: InferenceLevel | null;
144
- skipPermissions?: boolean | null;
145
- timestamp?: number | null;
146
- }[]
147
- >([]);
148
- const [branchQuickStartLoading, setBranchQuickStartLoading] = useState(false);
149
-
150
- // Log viewer state
151
- const logDir = useMemo(
152
- () => resolveLogDir(workingDirectory),
153
- [workingDirectory],
154
- );
155
- const [logEntries, setLogEntries] = useState<FormattedLogEntry[]>([]);
156
- const [logLoading, setLogLoading] = useState(false);
157
- const [logError, setLogError] = useState<string | null>(null);
158
- const [logSelectedDate, setLogSelectedDate] = useState<string | null>(
159
- getTodayLogDate(),
160
- );
161
- const [logDates, setLogDates] = useState<LogFileInfo[]>([]);
162
- const [logSelectedEntry, setLogSelectedEntry] =
163
- useState<FormattedLogEntry | null>(null);
164
- const [logNotification, setLogNotification] = useState<{
165
- message: string;
166
- tone: "success" | "error";
167
- } | null>(null);
168
- const logNotificationTimerRef = useRef<NodeJS.Timeout | null>(null);
169
-
170
- // Selection state (for branch → tool → mode flow)
171
- const [selectedBranch, setSelectedBranch] =
172
- useState<SelectedBranchState | null>(null);
173
- const [creationSourceBranch, setCreationSourceBranch] =
174
- useState<SelectedBranchState | null>(null);
175
- const [selectedTool, setSelectedTool] = useState<CodingAgentId | null>(null);
176
- const [selectedModel, setSelectedModel] =
177
- useState<ModelSelectionResult | null>(null);
178
- const [lastModelByTool, setLastModelByTool] = useState<
179
- Record<CodingAgentId, ModelSelectionResult | undefined>
180
- >({});
181
- const [preferredToolId, setPreferredToolId] = useState<CodingAgentId | null>(
182
- null,
183
- );
184
-
185
- // PR cleanup feedback
186
- const [cleanupIndicators, setCleanupIndicators] = useState<
187
- Record<
188
- string,
189
- {
190
- icon: string;
191
- isSpinning?: boolean;
192
- color?: "cyan" | "green" | "yellow" | "red";
193
- }
194
- >
195
- >({});
196
- const [_cleanupProcessingBranch, setCleanupProcessingBranch] = useState<
197
- string | null
198
- >(null);
199
- const [cleanupInputLocked, setCleanupInputLocked] = useState(false);
200
- const [cleanupFooterMessage, setCleanupFooterMessage] = useState<{
201
- text: string;
202
- isSpinning?: boolean;
203
- color?: "cyan" | "green" | "yellow" | "red";
204
- } | null>(null);
205
- const [hiddenBranches, setHiddenBranches] = useState<string[]>([]);
206
- const [selectedBranches, setSelectedBranches] = useState<string[]>([]);
207
- const completionTimerRef = useRef<NodeJS.Timeout | null>(null);
208
-
209
- // Fetch version on mount
210
- useEffect(() => {
211
- getPackageVersion()
212
- .then(setVersion)
213
- .catch(() => setVersion(null));
214
- }, []);
215
-
216
- // Fetch repository root once for session lookups
217
- useEffect(() => {
218
- getRepositoryRoot()
219
- .then(setRepoRoot)
220
- .catch(() => setRepoRoot(null));
221
- }, []);
222
-
223
- const showLogNotification = useCallback(
224
- (message: string, tone: "success" | "error" = "success") => {
225
- setLogNotification({ message, tone });
226
- if (logNotificationTimerRef.current) {
227
- clearTimeout(logNotificationTimerRef.current);
228
- }
229
- logNotificationTimerRef.current = setTimeout(() => {
230
- setLogNotification(null);
231
- }, 2000);
232
- },
233
- [],
234
- );
235
-
236
- useEffect(() => {
237
- return () => {
238
- if (logNotificationTimerRef.current) {
239
- clearTimeout(logNotificationTimerRef.current);
240
- }
241
- };
242
- }, []);
243
-
244
- const loadLogEntries = useCallback(
245
- async (date: string | null) => {
246
- const targetDate = date ?? getTodayLogDate();
247
- setLogLoading(true);
248
- setLogError(null);
249
- try {
250
- const filePath = buildLogFilePath(logDir, targetDate);
251
- const lines = await readLogFileLines(filePath);
252
- const parsed = parseLogLines(lines, { limit: 100 });
253
- setLogEntries(parsed);
254
- } catch (error) {
255
- setLogEntries([]);
256
- setLogError(
257
- error instanceof Error ? error.message : "Failed to load logs",
258
- );
259
- } finally {
260
- setLogLoading(false);
261
- }
262
- },
263
- [logDir],
264
- );
265
-
266
- const loadLogDates = useCallback(async () => {
267
- try {
268
- const files = await listRecentLogFiles(logDir, 7);
269
- setLogDates(files);
270
- } catch {
271
- setLogDates([]);
272
- }
273
- }, [logDir]);
274
-
275
- useEffect(() => {
276
- if (currentScreen === "log-list") {
277
- void loadLogEntries(logSelectedDate);
278
- }
279
- }, [currentScreen, loadLogEntries, logSelectedDate]);
280
-
281
- useEffect(() => {
282
- if (currentScreen === "log-date-picker") {
283
- void loadLogDates();
284
- }
285
- }, [currentScreen, loadLogDates]);
286
-
287
- useEffect(() => {
288
- if (!hiddenBranches.length) {
289
- return;
290
- }
291
-
292
- const existing = new Set(branches.map((branch) => branch.name));
293
- const filtered = hiddenBranches.filter((name) => existing.has(name));
294
-
295
- if (filtered.length !== hiddenBranches.length) {
296
- setHiddenBranches(filtered);
297
- }
298
- }, [branches, hiddenBranches]);
299
-
300
- // Remove selections that no longer exist (hidden or disappeared)
301
- useEffect(() => {
302
- setSelectedBranches((prev) =>
303
- prev.filter(
304
- (name) =>
305
- branches.some((b) => b.name === name) &&
306
- !hiddenBranches.includes(name),
307
- ),
308
- );
309
- }, [branches, hiddenBranches]);
310
-
311
- // Load quick start options for selected branch (latest per tool)
312
- useEffect(() => {
313
- if (!selectedBranch) {
314
- setBranchQuickStart([]);
315
- return;
316
- }
317
- let cancelled = false;
318
- setBranchQuickStartLoading(true);
319
- (async () => {
320
- try {
321
- const root = repoRoot ?? (await getRepositoryRoot());
322
- if (!repoRoot && root) {
323
- setRepoRoot(root);
324
- }
325
- if (!root) {
326
- if (!cancelled) setBranchQuickStart([]);
327
- return;
328
- }
329
- const sessionData = await loadSession(root);
330
- const history = sessionData?.history ?? [];
331
-
332
- const combinedHistory = [...history];
333
- if (
334
- sessionData?.lastSessionId &&
335
- sessionData.lastBranch === selectedBranch.name &&
336
- sessionData.lastUsedTool
337
- ) {
338
- const synthetic: ToolSessionEntry = {
339
- branch: sessionData.lastBranch,
340
- worktreePath: sessionData.lastWorktreePath ?? null,
341
- toolId: sessionData.lastUsedTool,
342
- toolLabel: sessionData.toolLabel ?? sessionData.lastUsedTool,
343
- sessionId: sessionData.lastSessionId,
344
- mode: sessionData.mode ?? null,
345
- model: sessionData.model ?? null,
346
- reasoningLevel: sessionData.reasoningLevel ?? null,
347
- skipPermissions: sessionData.skipPermissions ?? null,
348
- timestamp: sessionData.timestamp ?? Date.now(),
349
- };
350
- combinedHistory.push(synthetic);
351
- }
352
- const latestPerTool = findLatestBranchSessionsByTool(
353
- combinedHistory,
354
- selectedBranch.name,
355
- selectedWorktreePath,
356
- );
357
-
358
- const mapped = await Promise.all(
359
- latestPerTool.map(async (entry) => {
360
- let sessionId = entry.sessionId ?? null;
361
- const worktree = selectedWorktreePath ?? workingDirectory;
362
-
363
- // For Codex, prefer a newer filesystem session over stale history
364
- if (!sessionId && entry.toolId === "codex-cli") {
365
- try {
366
- const historyTs = entry.timestamp ?? null;
367
- const latestCodex = await findLatestCodexSession({
368
- ...(historyTs
369
- ? {
370
- since: historyTs - 60_000,
371
- preferClosestTo: historyTs,
372
- windowMs: 60 * 60 * 1000,
373
- }
374
- : {}),
375
- cwd: worktree,
376
- });
377
- sessionId =
378
- latestCodex?.id ??
379
- (await findLatestCodexSessionId({ cwd: worktree })) ??
380
- null;
381
- } catch {
382
- // ignore lookup failure
383
- }
384
- }
385
-
386
- // For Claude Code, prefer the newest session file in the worktree even if history is stale.
387
- if (!sessionId && entry.toolId === "claude-code") {
388
- try {
389
- // Always resolve freshest on-disk session for this worktree (no window restriction)
390
- const latestAny = await findLatestClaudeSession(worktree);
391
- sessionId = latestAny?.id ?? null;
392
- } catch {
393
- // ignore lookup failure
394
- }
395
- }
396
-
397
- // For Gemini, prefer newest session file (Gemini keeps per-project chats)
398
- if (!sessionId && entry.toolId === "gemini-cli") {
399
- try {
400
- const gemOptions: Parameters<
401
- typeof findLatestGeminiSession
402
- >[0] = {
403
- windowMs: 60 * 60 * 1000,
404
- cwd: worktree,
405
- };
406
- if (entry.timestamp !== null && entry.timestamp !== undefined) {
407
- gemOptions.since = entry.timestamp - 60_000;
408
- gemOptions.preferClosestTo = entry.timestamp;
409
- }
410
- const gemSession = await findLatestGeminiSession(gemOptions);
411
- sessionId = gemSession?.id ?? null;
412
- } catch {
413
- // ignore
414
- }
415
- }
416
-
417
- const normalizedModel = normalizeModelId(
418
- entry.toolId as CodingAgentId,
419
- entry.model ?? null,
420
- );
421
-
422
- return {
423
- toolId: entry.toolId as CodingAgentId,
424
- toolLabel: entry.toolLabel,
425
- model: normalizedModel ?? null,
426
- inferenceLevel: (entry.reasoningLevel ??
427
- sessionData?.reasoningLevel ??
428
- null) as InferenceLevel | null,
429
- sessionId,
430
- skipPermissions:
431
- entry.skipPermissions ?? sessionData?.skipPermissions ?? null,
432
- timestamp: entry.timestamp ?? null,
433
- };
434
- }),
435
- );
436
-
437
- if (!cancelled) {
438
- setBranchQuickStart(mapped);
439
- }
440
- } catch {
441
- if (!cancelled) setBranchQuickStart([]);
442
- } finally {
443
- if (!cancelled) setBranchQuickStartLoading(false);
444
- }
445
- })();
446
-
447
- return () => {
448
- cancelled = true;
449
- };
450
- }, [selectedBranch, repoRoot]);
451
-
452
- // Load last session ID for "Continue" label when entering execution mode selector
453
- useEffect(() => {
454
- if (currentScreen !== "execution-mode-selector") {
455
- return;
456
- }
457
- if (!selectedTool || !selectedBranch) {
458
- setContinueSessionId(null);
459
- return;
460
- }
461
- (async () => {
462
- try {
463
- const root = repoRoot ?? (await getRepositoryRoot());
464
- if (!repoRoot && root) {
465
- setRepoRoot(root);
466
- }
467
- const sessionData = root ? await loadSession(root) : null;
468
- const history = sessionData?.history ?? [];
469
-
470
- const found = await resolveContinueSessionId({
471
- history,
472
- sessionData,
473
- branch: selectedBranch.name,
474
- toolId: selectedTool,
475
- repoRoot: root,
476
- });
477
-
478
- setContinueSessionId(found ?? null);
479
- } catch {
480
- setContinueSessionId(null);
481
- }
482
- })();
483
- }, [currentScreen, selectedTool, selectedBranch, repoRoot]);
484
-
485
- // Update preferred tool when branch or data changes
486
- useEffect(() => {
487
- if (!selectedBranch) return;
488
- const branchMatch =
489
- branches.find((b) => b.name === selectedBranch.name) ||
490
- branches.find(
491
- (b) =>
492
- selectedBranch.branchType === "remote" &&
493
- b.name === selectedBranch.displayName,
494
- );
495
- setPreferredToolId(branchMatch?.lastToolUsage?.toolId ?? null);
496
- }, [branches, selectedBranch]);
497
-
498
- useEffect(
499
- () => () => {
500
- if (completionTimerRef.current) {
501
- clearTimeout(completionTimerRef.current);
502
- completionTimerRef.current = null;
503
- }
504
- },
505
- [],
506
- );
507
-
508
- const visibleBranches = useMemo(
509
- () => branches.filter((branch) => !hiddenBranches.includes(branch.name)),
510
- [branches, hiddenBranches],
511
- );
512
-
513
- const selectedWorktreePath = useMemo(() => {
514
- if (!selectedBranch) return null;
515
- const wt = worktrees.find((w) => w.branch === selectedBranch.name);
516
- return wt?.path ?? null;
517
- }, [selectedBranch, worktrees]);
518
-
519
- // Helper function to create content-based hash for branches
520
- const branchHash = useMemo(
521
- () =>
522
- visibleBranches
523
- .map((b) => `${b.name}-${b.type}-${b.isCurrent}`)
524
- .join(","),
525
- [visibleBranches],
526
- );
527
-
528
- // Helper function to create content-based hash for worktrees
529
- const worktreeHash = useMemo(
530
- () => worktrees.map((w) => `${w.branch}-${w.path}`).join(","),
531
- [worktrees],
532
- );
533
-
534
- // Format branches to BranchItems (memoized for performance with content-based dependencies)
535
- const branchItems: BranchItem[] = useMemo(() => {
536
- // Build worktreeMap for sorting
537
- const worktreeMap = new Map();
538
- for (const wt of worktrees) {
539
- worktreeMap.set(wt.branch, {
540
- path: wt.path,
541
- locked: false,
542
- prunable: wt.isAccessible === false,
543
- isAccessible: wt.isAccessible ?? true,
544
- ...(wt.hasUncommittedChanges !== undefined
545
- ? { hasUncommittedChanges: wt.hasUncommittedChanges }
546
- : {}),
547
- });
548
- }
549
- const baseItems = formatBranchItems(visibleBranches, worktreeMap);
550
- return baseItems.map((item) => {
551
- const hasUncommitted = item.worktree?.hasUncommittedChanges ?? false;
552
- const hasUnpushed = Boolean(item.hasUnpushedCommits);
553
- const isMerged = Boolean(item.mergedPR);
554
- const safeToCleanup =
555
- item.type === "local" && isMerged && !hasUncommitted && !hasUnpushed;
556
- return { ...item, safeToCleanup };
557
- });
558
- }, [branchHash, worktreeHash, visibleBranches, worktrees]);
559
-
560
- // Calculate statistics (memoized for performance)
561
- const stats = useMemo(
562
- () => calculateStatistics(visibleBranches),
563
- [visibleBranches],
564
- );
565
-
566
- const resolveBaseBranch = useCallback(() => {
567
- const localMain = branches.find(
568
- (branch) =>
569
- branch.type === "local" &&
570
- (branch.name === "main" || branch.name === "master"),
571
- );
572
- if (localMain) {
573
- return localMain.name;
574
- }
575
-
576
- const develop = branches.find(
577
- (branch) =>
578
- branch.type === "local" &&
579
- (branch.name === "develop" || branch.name === "dev"),
580
- );
581
- if (develop) {
582
- return develop.name;
583
- }
584
-
585
- return "main";
586
- }, [branches]);
587
-
588
- const baseBranchLabel = useMemo(
589
- () =>
590
- resolveBaseBranchLabel(
591
- creationSourceBranch,
592
- selectedBranch,
593
- resolveBaseBranch,
594
- ),
595
- [creationSourceBranch, resolveBaseBranch, selectedBranch],
596
- );
597
-
598
- // Handle branch selection
599
- const toLocalBranchName = useCallback((remoteName: string) => {
600
- const segments = remoteName.split("/");
601
- if (segments.length <= 1) {
602
- return remoteName;
603
- }
604
- return segments.slice(1).join("/");
605
- }, []);
606
-
607
- const inferBranchCategory = useCallback(
608
- (branchName: string): BranchInfo["branchType"] => {
609
- const matched = branches.find((branch) => branch.name === branchName);
610
- if (matched) {
611
- return matched.branchType;
612
- }
613
- if (branchName === "main" || branchName === "master") {
614
- return "main";
615
- }
616
- if (branchName === "develop" || branchName === "dev") {
617
- return "develop";
618
- }
619
- if (branchName.startsWith("feature/")) {
620
- return "feature";
621
- }
622
- if (branchName.startsWith("hotfix/")) {
623
- return "hotfix";
624
- }
625
- if (branchName.startsWith("release/")) {
626
- return "release";
627
- }
628
- return "other";
629
- },
630
- [branches],
631
- );
632
-
633
- const isProtectedSelection = useCallback(
634
- (branch: SelectedBranchState | null): boolean => {
635
- if (!branch) {
636
- return false;
637
- }
638
- return (
639
- isProtectedBranchName(branch.name) ||
640
- isProtectedBranchName(branch.displayName) ||
641
- (branch.remoteBranch
642
- ? isProtectedBranchName(branch.remoteBranch)
643
- : false) ||
644
- branch.branchCategory === "main" ||
645
- branch.branchCategory === "develop"
646
- );
647
- },
648
- [isProtectedBranchName],
649
- );
650
-
651
- const toggleBranchSelection = useCallback(
652
- (branchName: string) => {
653
- const branch = branches.find((b) => b.name === branchName);
654
- if (!branch || branch.type === "remote") {
655
- return;
656
- }
657
- if (
658
- isProtectedBranchName(branch.name) ||
659
- branch.branchType === "main" ||
660
- branch.branchType === "develop"
661
- ) {
662
- return;
663
- }
664
- setSelectedBranches((prev) => {
665
- const set = new Set(prev);
666
- if (set.has(branchName)) {
667
- set.delete(branchName);
668
- } else {
669
- set.add(branchName);
670
- }
671
- return Array.from(set);
672
- });
673
- },
674
- [branches, isProtectedBranchName],
675
- );
676
-
677
- const protectedBranchInfo = useMemo(() => {
678
- if (!selectedBranch) {
679
- return null;
680
- }
681
- if (!isProtectedSelection(selectedBranch)) {
682
- return null;
683
- }
684
- const label = selectedBranch.displayName ?? selectedBranch.name;
685
- return {
686
- label,
687
- message: `${label} is a root branch. Switch within the repository root instead of creating a worktree.`,
688
- };
689
- }, [selectedBranch, isProtectedSelection]);
690
-
691
- const handleSelect = useCallback(
692
- (item: BranchItem) => {
693
- const selection: SelectedBranchState =
694
- item.type === "remote"
695
- ? {
696
- name: toLocalBranchName(item.name),
697
- displayName: item.name,
698
- branchType: "remote",
699
- branchCategory: item.branchType,
700
- remoteBranch: item.name,
701
- }
702
- : {
703
- name: item.name,
704
- displayName: item.name,
705
- branchType: "local",
706
- branchCategory: item.branchType,
707
- };
708
-
709
- const protectedSelected = isProtectedSelection(selection);
710
-
711
- setSelectedBranch(selection);
712
- setSelectedTool(null);
713
- setSelectedModel(null);
714
- setCreationSourceBranch(null);
715
- setPreferredToolId(item.lastToolUsage?.toolId ?? null);
716
-
717
- if (protectedSelected) {
718
- setCleanupFooterMessage({
719
- text: PROTECTED_BRANCH_WARNING,
720
- color: "yellow",
721
- });
722
- } else {
723
- setCleanupFooterMessage(null);
724
- }
725
-
726
- navigateTo("branch-action-selector");
727
- },
728
- [
729
- isProtectedSelection,
730
- navigateTo,
731
- setCleanupFooterMessage,
732
- setCreationSourceBranch,
733
- setSelectedTool,
734
- toLocalBranchName,
735
- ],
736
- );
737
-
738
- // Handle branch action selection
739
- const handleProtectedBranchSwitch = useCallback(async () => {
740
- if (!selectedBranch) {
741
- return;
742
- }
743
-
744
- try {
745
- setCleanupFooterMessage({
746
- text: `Preparing root branch '${selectedBranch.displayName ?? selectedBranch.name}'...`,
747
- color: "cyan",
748
- });
749
- const repoRoot = await getRepositoryRoot();
750
- const remoteRef =
751
- selectedBranch.remoteBranch ??
752
- (selectedBranch.branchType === "remote"
753
- ? (selectedBranch.displayName ?? selectedBranch.name)
754
- : null);
755
-
756
- const result = await switchToProtectedBranch({
757
- branchName: selectedBranch.name,
758
- repoRoot,
759
- remoteRef: remoteRef ?? null,
760
- });
761
-
762
- let successMessage = `'${selectedBranch.displayName ?? selectedBranch.name}' will use the repository root.`;
763
- if (result === "remote") {
764
- successMessage = `Created a local tracking branch for '${selectedBranch.displayName ?? selectedBranch.name}' and switched to the protected branch.`;
765
- } else if (result === "local") {
766
- successMessage = `Checked out '${selectedBranch.displayName ?? selectedBranch.name}' in the repository root.`;
767
- }
768
-
769
- setCleanupFooterMessage({
770
- text: successMessage,
771
- color: "green",
772
- });
773
- refresh();
774
- const nextScreen =
775
- branchQuickStart.length || branchQuickStartLoading
776
- ? "branch-quick-start"
777
- : "coding-agent-selector";
778
- navigateTo(nextScreen);
779
- } catch (error) {
780
- const message = error instanceof Error ? error.message : String(error);
781
- setCleanupFooterMessage({
782
- text: `Failed to switch root branch: ${message}`,
783
- color: "red",
784
- });
785
- console.error("Failed to switch protected branch:", error);
786
- }
787
- }, [
788
- branchQuickStart,
789
- branchQuickStartLoading,
790
- navigateTo,
791
- refresh,
792
- selectedBranch,
793
- setCleanupFooterMessage,
794
- ]);
795
-
796
- const handleUseExistingBranch = useCallback(() => {
797
- if (selectedBranch && isProtectedSelection(selectedBranch)) {
798
- void handleProtectedBranchSwitch();
799
- return;
800
- }
801
- if (branchQuickStart.length) {
802
- navigateTo("branch-quick-start");
803
- } else {
804
- navigateTo("coding-agent-selector");
805
- }
806
- }, [
807
- handleProtectedBranchSwitch,
808
- isProtectedSelection,
809
- navigateTo,
810
- branchQuickStart.length,
811
- selectedBranch,
812
- ]);
813
-
814
- const handleCreateNewBranch = useCallback(() => {
815
- setCreationSourceBranch(selectedBranch);
816
- navigateTo("branch-creator");
817
- }, [navigateTo, selectedBranch]);
818
-
819
- // Handle quit
820
- const handleQuit = useCallback(() => {
821
- onExit();
822
- exit();
823
- }, [onExit, exit]);
824
-
825
- const handleOpenLogs = useCallback(() => {
826
- setLogSelectedDate(getTodayLogDate());
827
- setLogSelectedEntry(null);
828
- navigateTo("log-list");
829
- }, [navigateTo]);
830
-
831
- const handleSelectLogEntry = useCallback(
832
- (entry: FormattedLogEntry) => {
833
- setLogSelectedEntry(entry);
834
- navigateTo("log-detail");
835
- },
836
- [navigateTo],
837
- );
838
-
839
- const handleCopyLogEntry = useCallback(
840
- async (entry: FormattedLogEntry) => {
841
- try {
842
- await copyToClipboard(entry.json);
843
- showLogNotification("Copied to clipboard.", "success");
844
- } catch {
845
- showLogNotification("Failed to copy to clipboard.", "error");
846
- }
847
- },
848
- [showLogNotification],
849
- );
850
-
851
- const handleOpenLogDates = useCallback(() => {
852
- navigateTo("log-date-picker");
853
- }, [navigateTo]);
854
-
855
- const handleSelectLogDate = useCallback(
856
- (date: string) => {
857
- setLogSelectedDate(date);
858
- setLogSelectedEntry(null);
859
- navigateTo("log-list");
860
- },
861
- [navigateTo],
862
- );
863
-
864
- // Handle branch creation
865
- const handleCreate = useCallback(
866
- async (branchName: string) => {
867
- try {
868
- const repoRoot = await getRepositoryRoot();
869
- const worktreePath = await generateWorktreePath(repoRoot, branchName);
870
- // Use selectedBranch as base if available, otherwise resolve from repo
871
- const baseBranch = resolveBaseBranchRef(
872
- creationSourceBranch,
873
- selectedBranch,
874
- resolveBaseBranch,
875
- );
876
-
877
- await createWorktree({
878
- branchName,
879
- worktreePath,
880
- repoRoot,
881
- isNewBranch: true,
882
- baseBranch,
883
- });
884
-
885
- refresh();
886
- setCreationSourceBranch(null);
887
- setSelectedBranch({
888
- name: branchName,
889
- displayName: branchName,
890
- branchType: "local",
891
- branchCategory: inferBranchCategory(branchName),
892
- });
893
- setSelectedTool(null);
894
- setSelectedModel(null);
895
- setPreferredToolId(null);
896
- setCleanupFooterMessage(null);
897
-
898
- navigateTo("coding-agent-selector");
899
- } catch (error) {
900
- // On error, go back to branch list
901
- console.error("Failed to create branch:", error);
902
- goBack();
903
- refresh();
904
- }
905
- },
906
- [
907
- navigateTo,
908
- goBack,
909
- refresh,
910
- resolveBaseBranch,
911
- selectedBranch,
912
- creationSourceBranch,
913
- inferBranchCategory,
914
- setCleanupFooterMessage,
915
- ],
916
- );
917
-
918
- const handleCleanupCommand = useCallback(async () => {
919
- if (cleanupInputLocked) {
920
- return;
921
- }
922
-
923
- if (completionTimerRef.current) {
924
- clearTimeout(completionTimerRef.current);
925
- completionTimerRef.current = null;
926
- }
927
-
928
- if (selectedBranches.length === 0) {
929
- setCleanupIndicators({});
930
- setCleanupFooterMessage({
931
- text: "No cleanup targets selected.",
932
- color: "yellow",
933
- });
934
- setCleanupInputLocked(false);
935
- completionTimerRef.current = setTimeout(() => {
936
- setCleanupFooterMessage(null);
937
- completionTimerRef.current = null;
938
- }, COMPLETION_HOLD_DURATION_MS);
939
- return;
940
- }
941
-
942
- const succeededBranches: string[] = [];
943
-
944
- const resetAfterWait = () => {
945
- setCleanupIndicators({});
946
- setCleanupInputLocked(false);
947
- setCleanupFooterMessage(null);
948
- if (succeededBranches.length > 0) {
949
- setHiddenBranches((prev) => {
950
- const merged = new Set(prev);
951
- succeededBranches.forEach((branch) => merged.add(branch));
952
- return Array.from(merged);
953
- });
954
- setSelectedBranches((prev) =>
955
- prev.filter((name) => !succeededBranches.includes(name)),
956
- );
957
- }
958
- refresh();
959
- completionTimerRef.current = null;
960
- };
961
-
962
- // Provide immediate feedback before fetching targets
963
- setCleanupInputLocked(true);
964
- setCleanupIndicators({});
965
- setCleanupFooterMessage({
966
- text: "Processing...",
967
- isSpinning: true,
968
- color: "cyan",
969
- });
970
- setCleanupProcessingBranch(null);
971
-
972
- const branchMap = new Map(branches.map((branch) => [branch.name, branch]));
973
- const worktreeMap = new Map(
974
- worktrees.map((worktree) => [worktree.branch, worktree]),
975
- );
976
- const targets = selectedBranches.reduce<CleanupTarget[]>((acc, name) => {
977
- const branch = branchMap.get(name);
978
- if (!branch || branch.type === "remote") {
979
- return acc;
980
- }
981
- if (
982
- isProtectedBranchName(branch.name) ||
983
- branch.branchType === "main" ||
984
- branch.branchType === "develop"
985
- ) {
986
- return acc;
987
- }
988
-
989
- const worktree = worktreeMap.get(branch.name);
990
- const hasRemoteBranch =
991
- typeof branch.hasRemoteCounterpart === "boolean"
992
- ? branch.hasRemoteCounterpart
993
- : undefined;
994
- const isAccessible =
995
- typeof worktree?.isAccessible === "boolean"
996
- ? worktree.isAccessible
997
- : undefined;
998
- acc.push({
999
- branch: branch.name,
1000
- pullRequest: null,
1001
- worktreePath: worktree?.path ?? null,
1002
- cleanupType: worktree ? "worktree-and-branch" : "branch-only",
1003
- hasUncommittedChanges: worktree?.hasUncommittedChanges ?? false,
1004
- hasUnpushedCommits: Boolean(branch.hasUnpushedCommits),
1005
- ...(hasRemoteBranch !== undefined ? { hasRemoteBranch } : {}),
1006
- ...(isAccessible !== undefined ? { isAccessible } : {}),
1007
- });
1008
- return acc;
1009
- }, []);
1010
-
1011
- if (targets.length === 0) {
1012
- setCleanupIndicators({});
1013
- setCleanupFooterMessage({
1014
- text: "⚠️ No cleanup candidates among selected branches.",
1015
- color: "yellow",
1016
- });
1017
- setCleanupInputLocked(false);
1018
- completionTimerRef.current = setTimeout(() => {
1019
- setCleanupFooterMessage(null);
1020
- completionTimerRef.current = null;
1021
- }, COMPLETION_HOLD_DURATION_MS);
1022
- return;
1023
- }
1024
-
1025
- // Reset hidden branches that may already be gone
1026
- setHiddenBranches((prev) =>
1027
- prev.filter(
1028
- (name) => targets.find((t) => t.branch === name) === undefined,
1029
- ),
1030
- );
1031
-
1032
- const initialIndicators = targets.reduce<
1033
- Record<
1034
- string,
1035
- {
1036
- icon: string;
1037
- isSpinning?: boolean;
1038
- color?: "cyan" | "green" | "yellow" | "red";
1039
- }
1040
- >
1041
- >((acc, target, index) => {
1042
- if (index === 0) {
1043
- acc[target.branch] = { icon: "", isSpinning: true, color: "cyan" };
1044
- } else {
1045
- acc[target.branch] = { icon: "⏳", color: "yellow" };
1046
- }
1047
- return acc;
1048
- }, {});
1049
-
1050
- setCleanupIndicators(initialIndicators);
1051
- const firstTarget = targets.length > 0 ? targets[0] : undefined;
1052
- setCleanupProcessingBranch(firstTarget ? firstTarget.branch : null);
1053
- setCleanupFooterMessage({
1054
- text: "Processing...",
1055
- isSpinning: true,
1056
- color: "cyan",
1057
- });
1058
-
1059
- for (let index = 0; index < targets.length; index += 1) {
1060
- const currentTarget = targets[index];
1061
- if (!currentTarget) {
1062
- continue;
1063
- }
1064
- const target = currentTarget;
1065
-
1066
- setCleanupProcessingBranch(target.branch);
1067
-
1068
- setCleanupIndicators((prev) => {
1069
- const updated = { ...prev };
1070
- updated[target.branch] = { icon: "", isSpinning: true, color: "cyan" };
1071
- for (const pending of targets.slice(index + 1)) {
1072
- const current = updated[pending.branch];
1073
- if (!current || current.icon !== "⏳") {
1074
- updated[pending.branch] = { icon: "⏳", color: "yellow" };
1075
- }
1076
- }
1077
- return updated;
1078
- });
1079
-
1080
- const shouldSkip =
1081
- target.hasUncommittedChanges ||
1082
- target.hasUnpushedCommits ||
1083
- (target.cleanupType === "worktree-and-branch" &&
1084
- (!target.worktreePath || target.isAccessible === false));
1085
-
1086
- if (shouldSkip) {
1087
- setCleanupIndicators((prev) => ({
1088
- ...prev,
1089
- [target.branch]: { icon: "⏭️", color: "yellow" },
1090
- }));
1091
- setCleanupProcessingBranch(null);
1092
- continue;
1093
- }
1094
-
1095
- try {
1096
- if (
1097
- target.cleanupType === "worktree-and-branch" &&
1098
- target.worktreePath
1099
- ) {
1100
- await removeWorktree(target.worktreePath, true);
1101
- }
1102
-
1103
- await deleteBranch(target.branch, true);
1104
-
1105
- // 自動クリーンアップではリモートブランチは削除しない
1106
- // リモートブランチはユーザーが明示的に削除する必要がある
1107
-
1108
- succeededBranches.push(target.branch);
1109
- setCleanupIndicators((prev) => ({
1110
- ...prev,
1111
- [target.branch]: { icon: "✅", color: "green" },
1112
- }));
1113
- } catch {
1114
- const icon = "❌";
1115
- setCleanupIndicators((prev) => ({
1116
- ...prev,
1117
- [target.branch]: { icon, color: "red" },
1118
- }));
1119
- }
1120
-
1121
- setCleanupProcessingBranch(null);
1122
- }
1123
-
1124
- setCleanupProcessingBranch(null);
1125
- setCleanupInputLocked(false);
1126
- setCleanupFooterMessage({
1127
- text: "Cleanup completed. Finalizing...",
1128
- color: "green",
1129
- });
1130
-
1131
- const holdDuration =
1132
- typeof process !== "undefined" && process.env?.NODE_ENV === "test"
1133
- ? 0
1134
- : COMPLETION_HOLD_DURATION_MS;
1135
-
1136
- completionTimerRef.current = setTimeout(resetAfterWait, holdDuration);
1137
- }, [
1138
- cleanupInputLocked,
1139
- branches,
1140
- deleteBranch,
1141
- refresh,
1142
- removeWorktree,
1143
- selectedBranches,
1144
- worktrees,
1145
- ]);
1146
-
1147
- // Handle AI tool selection
1148
- const handleToolSelect = useCallback(
1149
- (tool: CodingAgentId) => {
1150
- setSelectedTool(tool);
1151
- setSelectedModel(lastModelByTool[tool] ?? null);
1152
- navigateTo("model-selector");
1153
- },
1154
- [lastModelByTool, navigateTo],
1155
- );
1156
-
1157
- const handleModelSelect = useCallback(
1158
- (selection: ModelSelectionResult) => {
1159
- setSelectedModel(selection);
1160
- setLastModelByTool((prev) => ({
1161
- ...prev,
1162
- ...(selectedTool ? { [selectedTool]: selection } : {}),
1163
- }));
1164
- navigateTo("execution-mode-selector");
1165
- },
1166
- [navigateTo, selectedTool],
1167
- );
1168
-
1169
- const completeSelection = useCallback(
1170
- (
1171
- executionMode: ExecutionMode,
1172
- skip: boolean,
1173
- sessionId?: string | null,
1174
- ) => {
1175
- if (selectedBranch && selectedTool) {
1176
- const defaultModel = getDefaultModelOption(selectedTool);
1177
- const resolvedModel = selectedModel?.model ?? defaultModel?.id ?? null;
1178
- const normalizedModel = normalizeModelId(selectedTool, resolvedModel);
1179
- const resolvedInference =
1180
- selectedModel?.inferenceLevel ??
1181
- getDefaultInferenceForModel(defaultModel ?? undefined);
1182
-
1183
- const payload: SelectionResult = {
1184
- branch: selectedBranch.name,
1185
- displayName: selectedBranch.displayName,
1186
- branchType: selectedBranch.branchType,
1187
- tool: selectedTool,
1188
- mode: executionMode,
1189
- skipPermissions: skip,
1190
- ...(normalizedModel !== undefined ? { model: normalizedModel } : {}),
1191
- ...(resolvedInference !== undefined
1192
- ? { inferenceLevel: resolvedInference }
1193
- : {}),
1194
- ...(selectedBranch.remoteBranch
1195
- ? { remoteBranch: selectedBranch.remoteBranch }
1196
- : {}),
1197
- ...(sessionId ? { sessionId } : {}),
1198
- };
1199
-
1200
- onExit(payload);
1201
- exit();
1202
- }
1203
- },
1204
- [
1205
- selectedBranch,
1206
- selectedTool,
1207
- selectedModel,
1208
- onExit,
1209
- exit,
1210
- getDefaultModelOption,
1211
- getDefaultInferenceForModel,
1212
- ],
1213
- );
1214
-
1215
- const handleQuickStartSelect = useCallback(
1216
- (action: QuickStartAction, toolId?: CodingAgentId | null) => {
1217
- if (action === "manual" || !branchQuickStart.length) {
1218
- navigateTo("coding-agent-selector");
1219
- return;
1220
- }
1221
-
1222
- const selected =
1223
- branchQuickStart.find((opt) => opt.toolId === toolId) ??
1224
- branchQuickStart[0];
1225
- if (!selected) {
1226
- navigateTo("coding-agent-selector");
1227
- return;
1228
- }
1229
-
1230
- setSelectedTool(selected.toolId);
1231
- setPreferredToolId(selected.toolId);
1232
- const normalizedQuickStartModel = normalizeModelId(
1233
- selected.toolId as CodingAgentId,
1234
- selected.model ?? null,
1235
- );
1236
- setSelectedModel(
1237
- normalizedQuickStartModel
1238
- ? ({
1239
- model: normalizedQuickStartModel,
1240
- inferenceLevel: selected.inferenceLevel ?? undefined,
1241
- } as ModelSelectionResult)
1242
- : null,
1243
- );
1244
-
1245
- const skip = selected.skipPermissions ?? false;
1246
-
1247
- if (action === "reuse-continue") {
1248
- const hasSession = Boolean(selected.sessionId);
1249
- const mode: ExecutionMode = hasSession ? "resume" : "continue";
1250
- completeSelection(mode, skip, selected.sessionId ?? null);
1251
- return;
1252
- }
1253
-
1254
- // "Start new with previous settings" skips the execution mode screen and launches immediately
1255
- completeSelection("normal", skip, null);
1256
- },
1257
- [
1258
- branchQuickStart,
1259
- navigateTo,
1260
- setPreferredToolId,
1261
- setSelectedModel,
1262
- setSelectedTool,
1263
- completeSelection,
1264
- ],
1265
- );
1266
-
1267
- // Handle execution mode and skipPermissions selection
1268
- const handleModeSelect = useCallback(
1269
- (result: { mode: ExecutionMode; skipPermissions: boolean }) => {
1270
- completeSelection(result.mode, result.skipPermissions, null);
1271
- },
1272
- [completeSelection],
1273
- );
1274
-
1275
- // Render screen based on currentScreen
1276
- const renderScreen = () => {
1277
- const renderBranchListScreen = (
1278
- additionalProps?: Partial<BranchListScreenProps>,
1279
- ) => (
1280
- <BranchListScreen
1281
- branches={branchItems}
1282
- stats={stats}
1283
- onSelect={handleSelect}
1284
- onQuit={handleQuit}
1285
- onRefresh={refresh}
1286
- loading={loading}
1287
- error={error}
1288
- lastUpdated={lastUpdated}
1289
- loadingIndicatorDelay={loadingIndicatorDelay}
1290
- version={version}
1291
- workingDirectory={workingDirectory}
1292
- activeProfile={activeProfileName}
1293
- onOpenProfiles={() => navigateTo("environment-profile")}
1294
- onOpenLogs={handleOpenLogs}
1295
- toolStatuses={toolStatuses}
1296
- {...additionalProps}
1297
- />
1298
- );
1299
-
1300
- switch (currentScreen) {
1301
- case "branch-list":
1302
- return renderBranchListScreen({
1303
- onCleanupCommand: handleCleanupCommand,
1304
- cleanupUI: {
1305
- indicators: cleanupIndicators,
1306
- footerMessage: cleanupFooterMessage,
1307
- inputLocked: cleanupInputLocked,
1308
- },
1309
- selectedBranches,
1310
- onToggleSelect: toggleBranchSelection,
1311
- });
1312
-
1313
- case "log-list":
1314
- return (
1315
- <LogListScreen
1316
- entries={logEntries}
1317
- loading={logLoading}
1318
- error={logError}
1319
- onBack={goBack}
1320
- onSelect={handleSelectLogEntry}
1321
- onCopy={handleCopyLogEntry}
1322
- onPickDate={handleOpenLogDates}
1323
- notification={logNotification}
1324
- version={version}
1325
- selectedDate={logSelectedDate}
1326
- />
1327
- );
1328
-
1329
- case "log-detail":
1330
- return (
1331
- <LogDetailScreen
1332
- entry={logSelectedEntry}
1333
- onBack={goBack}
1334
- onCopy={handleCopyLogEntry}
1335
- notification={logNotification}
1336
- version={version}
1337
- />
1338
- );
1339
-
1340
- case "log-date-picker":
1341
- return (
1342
- <LogDatePickerScreen
1343
- dates={logDates}
1344
- onBack={goBack}
1345
- onSelect={handleSelectLogDate}
1346
- version={version}
1347
- />
1348
- );
1349
-
1350
- case "branch-creator":
1351
- return (
1352
- <BranchCreatorScreen
1353
- onBack={goBack}
1354
- onCreate={handleCreate}
1355
- baseBranch={baseBranchLabel}
1356
- version={version}
1357
- />
1358
- );
1359
-
1360
- case "branch-action-selector": {
1361
- const isProtected = Boolean(protectedBranchInfo);
1362
- const baseProps = {
1363
- selectedBranch: selectedBranch?.displayName ?? "",
1364
- onUseExisting: handleUseExistingBranch,
1365
- onCreateNew: handleCreateNewBranch,
1366
- onBack: goBack,
1367
- canCreateNew: Boolean(selectedBranch),
1368
- };
1369
-
1370
- if (isProtected) {
1371
- return (
1372
- <BranchActionSelectorScreen
1373
- {...baseProps}
1374
- mode="protected"
1375
- infoMessage={protectedBranchInfo?.message ?? null}
1376
- primaryLabel="Use root branch (no worktree)"
1377
- secondaryLabel="Create new branch from this branch"
1378
- />
1379
- );
1380
- }
1381
-
1382
- return <BranchActionSelectorScreen {...baseProps} />;
1383
- }
1384
-
1385
- case "branch-quick-start":
1386
- return (
1387
- <BranchQuickStartScreen
1388
- branchName={selectedBranch?.displayName ?? ""}
1389
- previousOptions={branchQuickStart.map((opt) => ({
1390
- toolId: opt.toolId,
1391
- toolLabel: opt.toolLabel,
1392
- model: opt.model ?? null,
1393
- inferenceLevel: opt.inferenceLevel ?? null,
1394
- skipPermissions: opt.skipPermissions ?? null,
1395
- sessionId: opt.sessionId ?? null,
1396
- }))}
1397
- loading={branchQuickStartLoading}
1398
- onBack={goBack}
1399
- onSelect={handleQuickStartSelect}
1400
- version={version}
1401
- />
1402
- );
1403
-
1404
- case "coding-agent-selector":
1405
- return (
1406
- <CodingAgentSelectorScreen
1407
- onBack={goBack}
1408
- onSelect={handleToolSelect}
1409
- version={version}
1410
- initialAgentId={selectedTool ?? preferredToolId ?? null}
1411
- />
1412
- );
1413
-
1414
- case "model-selector":
1415
- if (!selectedTool) {
1416
- goBack();
1417
- return null;
1418
- }
1419
- return (
1420
- <ModelSelectorScreen
1421
- tool={selectedTool}
1422
- onBack={goBack}
1423
- onSelect={handleModelSelect}
1424
- version={version}
1425
- initialSelection={selectedModel}
1426
- />
1427
- );
1428
-
1429
- case "execution-mode-selector":
1430
- return (
1431
- <ExecutionModeSelectorScreen
1432
- onBack={goBack}
1433
- onSelect={handleModeSelect}
1434
- version={version}
1435
- continueSessionId={continueSessionId}
1436
- />
1437
- );
1438
-
1439
- case "environment-profile":
1440
- return (
1441
- <EnvironmentProfileScreen
1442
- onBack={() => {
1443
- void refreshProfiles();
1444
- goBack();
1445
- }}
1446
- version={version}
1447
- />
1448
- );
1449
-
1450
- default:
1451
- return renderBranchListScreen();
1452
- }
1453
- };
1454
-
1455
- return <ErrorBoundary>{renderScreen()}</ErrorBoundary>;
1456
- }