@akiojin/gwt 4.10.0 → 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 (579) 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.js +4 -4
  156. package/dist/config/builtin-coding-agents.js.map +1 -1
  157. package/dist/config/index.d.ts +2 -0
  158. package/dist/config/index.d.ts.map +1 -1
  159. package/dist/config/index.js +2 -0
  160. package/dist/config/index.js.map +1 -1
  161. package/dist/gemini.d.ts +1 -0
  162. package/dist/gemini.d.ts.map +1 -1
  163. package/dist/gemini.js +42 -37
  164. package/dist/gemini.js.map +1 -1
  165. package/dist/index.d.ts +1 -1
  166. package/dist/index.d.ts.map +1 -1
  167. package/dist/index.js +122 -102
  168. package/dist/index.js.map +1 -1
  169. package/dist/launcher.d.ts.map +1 -1
  170. package/dist/launcher.js +18 -3
  171. package/dist/launcher.js.map +1 -1
  172. package/dist/logging/logger.d.ts.map +1 -1
  173. package/dist/logging/logger.js +26 -9
  174. package/dist/logging/logger.js.map +1 -1
  175. package/dist/opentui/highlights-eq9cgrbb.scm +604 -0
  176. package/dist/opentui/highlights-ghv9g403.scm +205 -0
  177. package/dist/opentui/highlights-hk7bwhj4.scm +284 -0
  178. package/dist/opentui/highlights-r812a2qc.scm +150 -0
  179. package/dist/opentui/highlights-x6tmsnaa.scm +115 -0
  180. package/dist/opentui/index.solid.d.ts +2 -0
  181. package/dist/opentui/index.solid.d.ts.map +1 -0
  182. package/dist/opentui/index.solid.js +52034 -0
  183. package/dist/opentui/index.solid.js.map +1 -0
  184. package/dist/opentui/injections-73j83es3.scm +27 -0
  185. package/dist/opentui/tree-sitter-javascript-nd0q4pe9.wasm +0 -0
  186. package/dist/opentui/tree-sitter-markdown-411r6y9b.wasm +0 -0
  187. package/dist/opentui/tree-sitter-markdown_inline-j5349f42.wasm +0 -0
  188. package/dist/opentui/tree-sitter-typescript-zxjzwt75.wasm +0 -0
  189. package/dist/opentui/tree-sitter-zig-e78zbjpm.wasm +0 -0
  190. package/dist/repositories/worktree.repository.d.ts +1 -0
  191. package/dist/repositories/worktree.repository.d.ts.map +1 -1
  192. package/dist/repositories/worktree.repository.js +7 -0
  193. package/dist/repositories/worktree.repository.js.map +1 -1
  194. package/dist/services/codingAgentResolver.d.ts +2 -0
  195. package/dist/services/codingAgentResolver.d.ts.map +1 -1
  196. package/dist/services/codingAgentResolver.js +30 -4
  197. package/dist/services/codingAgentResolver.js.map +1 -1
  198. package/dist/services/dependency-installer.d.ts.map +1 -1
  199. package/dist/services/dependency-installer.js +0 -5
  200. package/dist/services/dependency-installer.js.map +1 -1
  201. package/dist/types/api.d.ts +3 -0
  202. package/dist/types/api.d.ts.map +1 -1
  203. package/dist/types/coding-agent.d.ts +62 -0
  204. package/dist/types/coding-agent.d.ts.map +1 -0
  205. package/dist/types/coding-agent.js +29 -0
  206. package/dist/types/coding-agent.js.map +1 -0
  207. package/dist/types/tools.d.ts +17 -0
  208. package/dist/types/tools.d.ts.map +1 -1
  209. package/dist/utils/coding-agent-colors.d.ts +88 -0
  210. package/dist/utils/coding-agent-colors.d.ts.map +1 -0
  211. package/dist/utils/coding-agent-colors.js +137 -0
  212. package/dist/utils/coding-agent-colors.js.map +1 -0
  213. package/dist/utils/command.d.ts +1 -1
  214. package/dist/utils/command.js +1 -1
  215. package/dist/utils/error-utils.d.ts +27 -0
  216. package/dist/utils/error-utils.d.ts.map +1 -0
  217. package/dist/utils/error-utils.js +98 -0
  218. package/dist/utils/error-utils.js.map +1 -0
  219. package/dist/utils/npmRegistry.d.ts +61 -0
  220. package/dist/utils/npmRegistry.d.ts.map +1 -0
  221. package/dist/utils/npmRegistry.js +180 -0
  222. package/dist/utils/npmRegistry.js.map +1 -0
  223. package/dist/utils/prompt.d.ts +1 -1
  224. package/dist/utils/prompt.js +1 -1
  225. package/dist/utils/session/parsers/codex.d.ts.map +1 -1
  226. package/dist/utils/session/parsers/codex.js +8 -1
  227. package/dist/utils/session/parsers/codex.js.map +1 -1
  228. package/dist/utils/terminal.d.ts +1 -0
  229. package/dist/utils/terminal.d.ts.map +1 -1
  230. package/dist/utils/terminal.js +20 -0
  231. package/dist/utils/terminal.js.map +1 -1
  232. package/dist/utils.d.ts +9 -0
  233. package/dist/utils.d.ts.map +1 -1
  234. package/dist/utils.js +33 -2
  235. package/dist/utils.js.map +1 -1
  236. package/dist/web/client/src/components/CodingAgentLaunchModal.d.ts.map +1 -1
  237. package/dist/web/client/src/components/CodingAgentLaunchModal.js +7 -16
  238. package/dist/web/client/src/components/CodingAgentLaunchModal.js.map +1 -1
  239. package/dist/web/client/src/components/branch-detail/BranchInfoCards.d.ts.map +1 -1
  240. package/dist/web/client/src/components/branch-detail/BranchInfoCards.js +7 -2
  241. package/dist/web/client/src/components/branch-detail/BranchInfoCards.js.map +1 -1
  242. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.d.ts.map +1 -1
  243. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js +2 -1
  244. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js.map +1 -1
  245. package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts +2 -2
  246. package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts.map +1 -1
  247. package/dist/web/client/src/components/branch-detail/ToolLauncher.js +5 -5
  248. package/dist/web/client/src/components/branch-detail/ToolLauncher.js.map +1 -1
  249. package/dist/web/client/src/lib/coding-agent-colors.d.ts +86 -0
  250. package/dist/web/client/src/lib/coding-agent-colors.d.ts.map +1 -0
  251. package/dist/web/client/src/lib/coding-agent-colors.js +135 -0
  252. package/dist/web/client/src/lib/coding-agent-colors.js.map +1 -0
  253. package/dist/web/client/src/pages/BranchDetailPage.js +10 -10
  254. package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
  255. package/dist/web/server/pty/manager.d.ts +2 -0
  256. package/dist/web/server/pty/manager.d.ts.map +1 -1
  257. package/dist/web/server/pty/manager.js +104 -0
  258. package/dist/web/server/pty/manager.js.map +1 -1
  259. package/dist/web/server/routes/sessions.d.ts.map +1 -1
  260. package/dist/web/server/routes/sessions.js +5 -1
  261. package/dist/web/server/routes/sessions.js.map +1 -1
  262. package/dist/web/server/services/branches.d.ts.map +1 -1
  263. package/dist/web/server/services/branches.js +10 -8
  264. package/dist/web/server/services/branches.js.map +1 -1
  265. package/dist/web/server/services/worktrees.js +2 -2
  266. package/dist/web/server/services/worktrees.js.map +1 -1
  267. package/dist/worktree.d.ts +47 -1
  268. package/dist/worktree.d.ts.map +1 -1
  269. package/dist/worktree.js +280 -94
  270. package/dist/worktree.js.map +1 -1
  271. package/package.json +12 -14
  272. package/src/claude.ts +68 -70
  273. package/src/cli/ui/App.solid.tsx +1823 -0
  274. package/src/cli/ui/__tests__/solid/AppSolid.cleanup.test.tsx +255 -0
  275. package/src/cli/ui/__tests__/solid/BranchListScreen.test.tsx +243 -0
  276. package/src/cli/ui/__tests__/solid/components/QuickStartStep.test.tsx +237 -0
  277. package/src/cli/ui/__tests__/solid/components/WizardPopup.test.tsx +231 -0
  278. package/src/cli/ui/__tests__/solid/components/WizardSteps.test.tsx +238 -0
  279. package/src/cli/ui/__tests__/utils/branchFormatter.test.ts +7 -289
  280. package/src/cli/ui/__tests__/utils/clipboard.test.ts +3 -3
  281. package/src/cli/ui/__tests__/utils/statisticsCalculator.test.ts +1 -1
  282. package/src/cli/ui/components/solid/Footer.tsx +36 -0
  283. package/src/cli/ui/components/{parts → solid}/Header.tsx +17 -28
  284. package/src/cli/ui/components/solid/HelpOverlay.tsx +194 -0
  285. package/src/cli/ui/components/solid/QuickStartStep.tsx +197 -0
  286. package/src/cli/ui/components/{parts → solid}/ScrollableList.tsx +7 -8
  287. package/src/cli/ui/components/solid/SearchInput.tsx +42 -0
  288. package/src/cli/ui/components/solid/SelectInput.tsx +84 -0
  289. package/src/cli/ui/components/solid/Stats.tsx +92 -0
  290. package/src/cli/ui/components/solid/TextInput.tsx +49 -0
  291. package/src/cli/ui/components/solid/WizardController.tsx +384 -0
  292. package/src/cli/ui/components/solid/WizardPopup.tsx +135 -0
  293. package/src/cli/ui/components/solid/WizardSteps.tsx +793 -0
  294. package/src/cli/ui/core/index.ts +17 -0
  295. package/src/cli/ui/core/keybindings.ts +367 -0
  296. package/src/cli/ui/core/theme.ts +234 -0
  297. package/src/cli/ui/core/types.ts +235 -0
  298. package/src/cli/ui/hooks/solid/useAsyncOperation.ts +76 -0
  299. package/src/cli/ui/hooks/solid/useFilter.ts +86 -0
  300. package/src/cli/ui/hooks/solid/useGitOperations.ts +80 -0
  301. package/src/cli/ui/hooks/solid/useKeyHandler.ts +103 -0
  302. package/src/cli/ui/hooks/solid/useScrollableList.ts +149 -0
  303. package/src/cli/ui/hooks/solid/useSelection.ts +77 -0
  304. package/src/cli/ui/hooks/solid/useTerminalSize.ts +22 -0
  305. package/src/cli/ui/index.solid.ts +28 -0
  306. package/src/cli/ui/screens/solid/BranchListScreen.tsx +1050 -0
  307. package/src/cli/ui/screens/solid/ConfirmScreen.tsx +74 -0
  308. package/src/cli/ui/screens/solid/EnvironmentScreen.tsx +159 -0
  309. package/src/cli/ui/screens/solid/ErrorScreen.tsx +42 -0
  310. package/src/cli/ui/screens/solid/InputScreen.tsx +55 -0
  311. package/src/cli/ui/screens/solid/LoadingIndicator.tsx +77 -0
  312. package/src/cli/ui/screens/solid/LogDetailScreen.tsx +75 -0
  313. package/src/cli/ui/screens/solid/LogScreen.tsx +175 -0
  314. package/src/cli/ui/screens/solid/ProfileEnvScreen.tsx +192 -0
  315. package/src/cli/ui/screens/solid/ProfileScreen.tsx +98 -0
  316. package/src/cli/ui/screens/solid/SelectorScreen.tsx +170 -0
  317. package/src/cli/ui/screens/solid/SettingsScreen.tsx +50 -0
  318. package/src/cli/ui/screens/solid/WorktreeCreateScreen.tsx +136 -0
  319. package/src/cli/ui/screens/solid/WorktreeDeleteScreen.tsx +40 -0
  320. package/src/cli/ui/stores/appStore.ts +208 -0
  321. package/src/cli/ui/stores/branchStore.ts +357 -0
  322. package/src/cli/ui/stores/index.ts +31 -0
  323. package/src/cli/ui/stores/uiStore.ts +226 -0
  324. package/src/cli/ui/types.ts +20 -3
  325. package/src/cli/ui/utils/__tests__/branchFormatter.test.ts +180 -0
  326. package/src/cli/ui/utils/branchFormatter.ts +8 -215
  327. package/src/cli/ui/utils/continueSession.ts +44 -0
  328. package/src/cli/ui/utils/modelOptions.test.ts +1 -1
  329. package/src/codex.ts +100 -43
  330. package/src/config/__tests__/saveSession.test.ts +143 -0
  331. package/src/config/builtin-coding-agents.ts +4 -4
  332. package/src/config/index.ts +4 -0
  333. package/src/gemini.ts +58 -43
  334. package/src/index.test.ts +12 -12
  335. package/src/index.ts +164 -142
  336. package/src/launcher.ts +22 -3
  337. package/src/logging/logger.ts +32 -10
  338. package/src/opentui/index.solid.ts +1 -0
  339. package/src/repositories/worktree.repository.ts +8 -0
  340. package/src/services/__tests__/BatchMergeService.test.ts +62 -66
  341. package/src/services/__tests__/WorktreeOrchestrator.test.ts +8 -7
  342. package/src/services/codingAgentResolver.ts +30 -4
  343. package/src/services/dependency-installer.ts +0 -7
  344. package/src/types/api.ts +3 -0
  345. package/src/types/coding-agent.ts +85 -0
  346. package/src/types/tools.ts +19 -0
  347. package/src/utils/__tests__/npmRegistry.test.ts +250 -0
  348. package/src/utils/__tests__/prompt.test.ts +4 -5
  349. package/src/utils/coding-agent-colors.ts +165 -0
  350. package/src/utils/command.ts +1 -1
  351. package/src/utils/error-utils.ts +133 -0
  352. package/src/utils/npmRegistry.ts +249 -0
  353. package/src/utils/prompt.ts +1 -1
  354. package/src/utils/session/parsers/codex.ts +9 -1
  355. package/src/utils/terminal.ts +24 -0
  356. package/src/utils.test.ts +1 -1
  357. package/src/utils.ts +37 -4
  358. package/src/web/client/src/components/CodingAgentLaunchModal.tsx +12 -21
  359. package/src/web/client/src/components/branch-detail/BranchInfoCards.tsx +16 -1
  360. package/src/web/client/src/components/branch-detail/SessionHistoryTable.tsx +7 -1
  361. package/src/web/client/src/components/branch-detail/ToolLauncher.tsx +11 -6
  362. package/src/web/client/src/lib/coding-agent-colors.ts +149 -0
  363. package/src/web/client/src/pages/BranchDetailPage.tsx +11 -11
  364. package/src/web/server/pty/manager.ts +139 -0
  365. package/src/web/server/routes/sessions.ts +6 -0
  366. package/src/web/server/services/branches.ts +11 -8
  367. package/src/web/server/services/worktrees.ts +2 -2
  368. package/src/worktree.ts +366 -107
  369. package/dist/cli/ui/components/App.d.ts +0 -25
  370. package/dist/cli/ui/components/App.d.ts.map +0 -1
  371. package/dist/cli/ui/components/App.js +0 -1006
  372. package/dist/cli/ui/components/App.js.map +0 -1
  373. package/dist/cli/ui/components/common/Confirm.d.ts +0 -13
  374. package/dist/cli/ui/components/common/Confirm.d.ts.map +0 -1
  375. package/dist/cli/ui/components/common/Confirm.js +0 -20
  376. package/dist/cli/ui/components/common/Confirm.js.map +0 -1
  377. package/dist/cli/ui/components/common/ErrorBoundary.d.ts +0 -23
  378. package/dist/cli/ui/components/common/ErrorBoundary.d.ts.map +0 -1
  379. package/dist/cli/ui/components/common/ErrorBoundary.js +0 -37
  380. package/dist/cli/ui/components/common/ErrorBoundary.js.map +0 -1
  381. package/dist/cli/ui/components/common/Input.d.ts +0 -19
  382. package/dist/cli/ui/components/common/Input.d.ts.map +0 -1
  383. package/dist/cli/ui/components/common/Input.js +0 -22
  384. package/dist/cli/ui/components/common/Input.js.map +0 -1
  385. package/dist/cli/ui/components/common/LoadingIndicator.d.ts +0 -19
  386. package/dist/cli/ui/components/common/LoadingIndicator.d.ts.map +0 -1
  387. package/dist/cli/ui/components/common/LoadingIndicator.js +0 -61
  388. package/dist/cli/ui/components/common/LoadingIndicator.js.map +0 -1
  389. package/dist/cli/ui/components/common/Select.d.ts +0 -38
  390. package/dist/cli/ui/components/common/Select.d.ts.map +0 -1
  391. package/dist/cli/ui/components/common/Select.js +0 -151
  392. package/dist/cli/ui/components/common/Select.js.map +0 -1
  393. package/dist/cli/ui/components/common/SpinnerIcon.d.ts +0 -20
  394. package/dist/cli/ui/components/common/SpinnerIcon.d.ts.map +0 -1
  395. package/dist/cli/ui/components/common/SpinnerIcon.js +0 -61
  396. package/dist/cli/ui/components/common/SpinnerIcon.js.map +0 -1
  397. package/dist/cli/ui/components/parts/Footer.d.ts +0 -15
  398. package/dist/cli/ui/components/parts/Footer.d.ts.map +0 -1
  399. package/dist/cli/ui/components/parts/Footer.js +0 -20
  400. package/dist/cli/ui/components/parts/Footer.js.map +0 -1
  401. package/dist/cli/ui/components/parts/Header.d.ts.map +0 -1
  402. package/dist/cli/ui/components/parts/Header.js +0 -24
  403. package/dist/cli/ui/components/parts/Header.js.map +0 -1
  404. package/dist/cli/ui/components/parts/MergeStatusList.d.ts +0 -13
  405. package/dist/cli/ui/components/parts/MergeStatusList.d.ts.map +0 -1
  406. package/dist/cli/ui/components/parts/MergeStatusList.js +0 -52
  407. package/dist/cli/ui/components/parts/MergeStatusList.js.map +0 -1
  408. package/dist/cli/ui/components/parts/ProgressBar.d.ts +0 -13
  409. package/dist/cli/ui/components/parts/ProgressBar.d.ts.map +0 -1
  410. package/dist/cli/ui/components/parts/ProgressBar.js +0 -53
  411. package/dist/cli/ui/components/parts/ProgressBar.js.map +0 -1
  412. package/dist/cli/ui/components/parts/ScrollableList.d.ts +0 -12
  413. package/dist/cli/ui/components/parts/ScrollableList.d.ts.map +0 -1
  414. package/dist/cli/ui/components/parts/ScrollableList.js +0 -11
  415. package/dist/cli/ui/components/parts/ScrollableList.js.map +0 -1
  416. package/dist/cli/ui/components/parts/Stats.d.ts +0 -10
  417. package/dist/cli/ui/components/parts/Stats.d.ts.map +0 -1
  418. package/dist/cli/ui/components/parts/Stats.js +0 -55
  419. package/dist/cli/ui/components/parts/Stats.js.map +0 -1
  420. package/dist/cli/ui/components/screens/BatchMergeProgressScreen.d.ts +0 -17
  421. package/dist/cli/ui/components/screens/BatchMergeProgressScreen.d.ts.map +0 -1
  422. package/dist/cli/ui/components/screens/BatchMergeProgressScreen.js +0 -42
  423. package/dist/cli/ui/components/screens/BatchMergeProgressScreen.js.map +0 -1
  424. package/dist/cli/ui/components/screens/BatchMergeResultScreen.d.ts +0 -17
  425. package/dist/cli/ui/components/screens/BatchMergeResultScreen.d.ts.map +0 -1
  426. package/dist/cli/ui/components/screens/BatchMergeResultScreen.js +0 -72
  427. package/dist/cli/ui/components/screens/BatchMergeResultScreen.js.map +0 -1
  428. package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts +0 -18
  429. package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts.map +0 -1
  430. package/dist/cli/ui/components/screens/BranchCreatorScreen.js +0 -151
  431. package/dist/cli/ui/components/screens/BranchCreatorScreen.js.map +0 -1
  432. package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +0 -1
  433. package/dist/cli/ui/components/screens/BranchListScreen.js +0 -476
  434. package/dist/cli/ui/components/screens/BranchListScreen.js.map +0 -1
  435. package/dist/cli/ui/components/screens/BranchQuickStartScreen.d.ts +0 -30
  436. package/dist/cli/ui/components/screens/BranchQuickStartScreen.d.ts.map +0 -1
  437. package/dist/cli/ui/components/screens/BranchQuickStartScreen.js +0 -148
  438. package/dist/cli/ui/components/screens/BranchQuickStartScreen.js.map +0 -1
  439. package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.d.ts +0 -27
  440. package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.d.ts.map +0 -1
  441. package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.js +0 -93
  442. package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.js.map +0 -1
  443. package/dist/cli/ui/components/screens/EnvironmentProfileScreen.d.ts +0 -19
  444. package/dist/cli/ui/components/screens/EnvironmentProfileScreen.d.ts.map +0 -1
  445. package/dist/cli/ui/components/screens/EnvironmentProfileScreen.js +0 -577
  446. package/dist/cli/ui/components/screens/EnvironmentProfileScreen.js.map +0 -1
  447. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts +0 -45
  448. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts.map +0 -1
  449. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js +0 -95
  450. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js.map +0 -1
  451. package/dist/cli/ui/components/screens/LogDatePickerScreen.d.ts +0 -10
  452. package/dist/cli/ui/components/screens/LogDatePickerScreen.d.ts.map +0 -1
  453. package/dist/cli/ui/components/screens/LogDatePickerScreen.js +0 -44
  454. package/dist/cli/ui/components/screens/LogDatePickerScreen.js.map +0 -1
  455. package/dist/cli/ui/components/screens/LogDetailScreen.d.ts.map +0 -1
  456. package/dist/cli/ui/components/screens/LogDetailScreen.js +0 -34
  457. package/dist/cli/ui/components/screens/LogDetailScreen.js.map +0 -1
  458. package/dist/cli/ui/components/screens/LogListScreen.d.ts.map +0 -1
  459. package/dist/cli/ui/components/screens/LogListScreen.js +0 -107
  460. package/dist/cli/ui/components/screens/LogListScreen.js.map +0 -1
  461. package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts +0 -24
  462. package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts.map +0 -1
  463. package/dist/cli/ui/components/screens/ModelSelectorScreen.js +0 -197
  464. package/dist/cli/ui/components/screens/ModelSelectorScreen.js.map +0 -1
  465. package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts +0 -29
  466. package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts.map +0 -1
  467. package/dist/cli/ui/components/screens/PRCleanupScreen.js +0 -92
  468. package/dist/cli/ui/components/screens/PRCleanupScreen.js.map +0 -1
  469. package/dist/cli/ui/components/screens/SessionSelectorScreen.d.ts +0 -31
  470. package/dist/cli/ui/components/screens/SessionSelectorScreen.d.ts.map +0 -1
  471. package/dist/cli/ui/components/screens/SessionSelectorScreen.js +0 -67
  472. package/dist/cli/ui/components/screens/SessionSelectorScreen.js.map +0 -1
  473. package/dist/cli/ui/hooks/useAppInput.d.ts +0 -21
  474. package/dist/cli/ui/hooks/useAppInput.d.ts.map +0 -1
  475. package/dist/cli/ui/hooks/useAppInput.js +0 -138
  476. package/dist/cli/ui/hooks/useAppInput.js.map +0 -1
  477. package/dist/cli/ui/hooks/useBatchMerge.d.ts +0 -17
  478. package/dist/cli/ui/hooks/useBatchMerge.d.ts.map +0 -1
  479. package/dist/cli/ui/hooks/useBatchMerge.js +0 -77
  480. package/dist/cli/ui/hooks/useBatchMerge.js.map +0 -1
  481. package/dist/cli/ui/hooks/useGitData.d.ts +0 -21
  482. package/dist/cli/ui/hooks/useGitData.d.ts.map +0 -1
  483. package/dist/cli/ui/hooks/useGitData.js +0 -229
  484. package/dist/cli/ui/hooks/useGitData.js.map +0 -1
  485. package/dist/cli/ui/hooks/useProfiles.d.ts +0 -41
  486. package/dist/cli/ui/hooks/useProfiles.d.ts.map +0 -1
  487. package/dist/cli/ui/hooks/useProfiles.js +0 -136
  488. package/dist/cli/ui/hooks/useProfiles.js.map +0 -1
  489. package/dist/cli/ui/hooks/useScreenState.d.ts +0 -12
  490. package/dist/cli/ui/hooks/useScreenState.d.ts.map +0 -1
  491. package/dist/cli/ui/hooks/useScreenState.js +0 -30
  492. package/dist/cli/ui/hooks/useScreenState.js.map +0 -1
  493. package/dist/cli/ui/hooks/useTerminalSize.d.ts +0 -9
  494. package/dist/cli/ui/hooks/useTerminalSize.d.ts.map +0 -1
  495. package/dist/cli/ui/hooks/useTerminalSize.js +0 -24
  496. package/dist/cli/ui/hooks/useTerminalSize.js.map +0 -1
  497. package/dist/cli/ui/hooks/useToolStatus.d.ts +0 -30
  498. package/dist/cli/ui/hooks/useToolStatus.d.ts.map +0 -1
  499. package/dist/cli/ui/hooks/useToolStatus.js +0 -49
  500. package/dist/cli/ui/hooks/useToolStatus.js.map +0 -1
  501. package/dist/cli/ui/screens/BranchActionSelectorScreen.d.ts +0 -24
  502. package/dist/cli/ui/screens/BranchActionSelectorScreen.d.ts.map +0 -1
  503. package/dist/cli/ui/screens/BranchActionSelectorScreen.js +0 -65
  504. package/dist/cli/ui/screens/BranchActionSelectorScreen.js.map +0 -1
  505. package/dist/client/assets/index-LNPtOrn3.js +0 -78
  506. package/src/cli/ui/__tests__/SKIPPED_TESTS.md +0 -119
  507. package/src/cli/ui/__tests__/acceptance/branchList.acceptance.test.tsx.skip +0 -239
  508. package/src/cli/ui/__tests__/acceptance/navigation.acceptance.test.tsx +0 -225
  509. package/src/cli/ui/__tests__/acceptance/realtimeUpdate.acceptance.test.tsx.skip +0 -219
  510. package/src/cli/ui/__tests__/components/App.protected-branch.test.tsx +0 -212
  511. package/src/cli/ui/__tests__/components/App.shortcuts.test.tsx +0 -440
  512. package/src/cli/ui/__tests__/components/App.test.tsx +0 -365
  513. package/src/cli/ui/__tests__/components/ModelSelectorScreen.initial.test.tsx +0 -91
  514. package/src/cli/ui/__tests__/components/common/Confirm.test.tsx +0 -80
  515. package/src/cli/ui/__tests__/components/common/ErrorBoundary.test.tsx +0 -104
  516. package/src/cli/ui/__tests__/components/common/Input.test.tsx +0 -100
  517. package/src/cli/ui/__tests__/components/common/LoadingIndicator.test.tsx +0 -148
  518. package/src/cli/ui/__tests__/components/common/Select.memo.test.tsx +0 -255
  519. package/src/cli/ui/__tests__/components/common/Select.test.tsx +0 -335
  520. package/src/cli/ui/__tests__/components/parts/Footer.test.tsx +0 -65
  521. package/src/cli/ui/__tests__/components/parts/Header.test.tsx +0 -55
  522. package/src/cli/ui/__tests__/components/parts/ScrollableList.test.tsx +0 -69
  523. package/src/cli/ui/__tests__/components/parts/Stats.test.tsx +0 -148
  524. package/src/cli/ui/__tests__/components/screens/BranchCreatorScreen.test.tsx +0 -253
  525. package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +0 -1070
  526. package/src/cli/ui/__tests__/components/screens/BranchQuickStartScreen.test.tsx +0 -142
  527. package/src/cli/ui/__tests__/components/screens/CodingAgentSelectorScreen.test.tsx +0 -174
  528. package/src/cli/ui/__tests__/components/screens/ExecutionModeSelectorScreen.test.tsx +0 -182
  529. package/src/cli/ui/__tests__/components/screens/LogDetailScreen.test.tsx +0 -57
  530. package/src/cli/ui/__tests__/components/screens/LogListScreen.test.tsx +0 -102
  531. package/src/cli/ui/__tests__/components/screens/PRCleanupScreen.test.tsx +0 -216
  532. package/src/cli/ui/__tests__/components/screens/SessionSelectorScreen.test.tsx +0 -147
  533. package/src/cli/ui/__tests__/hooks/useGitData.nonblocking.test.tsx +0 -206
  534. package/src/cli/ui/__tests__/hooks/useGitData.test.ts +0 -197
  535. package/src/cli/ui/__tests__/hooks/useGitData.test.ts.skip +0 -228
  536. package/src/cli/ui/__tests__/hooks/useScreenState.test.ts +0 -147
  537. package/src/cli/ui/__tests__/hooks/useTerminalSize.test.ts +0 -99
  538. package/src/cli/ui/__tests__/integration/branchList.test.tsx.skip +0 -253
  539. package/src/cli/ui/__tests__/integration/edgeCases.test.tsx +0 -436
  540. package/src/cli/ui/__tests__/integration/navigation.test.tsx +0 -514
  541. package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx +0 -509
  542. package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx.skip +0 -216
  543. package/src/cli/ui/__tests__/performance/branchList.performance.test.tsx +0 -193
  544. package/src/cli/ui/__tests__/performance/useMemoOptimization.test.tsx +0 -234
  545. package/src/cli/ui/components/App.tsx +0 -1478
  546. package/src/cli/ui/components/common/Confirm.tsx +0 -44
  547. package/src/cli/ui/components/common/ErrorBoundary.tsx +0 -60
  548. package/src/cli/ui/components/common/Input.tsx +0 -58
  549. package/src/cli/ui/components/common/LoadingIndicator.tsx +0 -98
  550. package/src/cli/ui/components/common/Select.tsx +0 -247
  551. package/src/cli/ui/components/common/SpinnerIcon.tsx +0 -86
  552. package/src/cli/ui/components/parts/Footer.tsx +0 -41
  553. package/src/cli/ui/components/parts/Header.test.tsx +0 -75
  554. package/src/cli/ui/components/parts/MergeStatusList.tsx +0 -75
  555. package/src/cli/ui/components/parts/ProgressBar.tsx +0 -73
  556. package/src/cli/ui/components/parts/Stats.tsx +0 -88
  557. package/src/cli/ui/components/screens/BatchMergeProgressScreen.tsx +0 -74
  558. package/src/cli/ui/components/screens/BatchMergeResultScreen.tsx +0 -108
  559. package/src/cli/ui/components/screens/BranchCreatorScreen.tsx +0 -242
  560. package/src/cli/ui/components/screens/BranchListScreen.tsx +0 -744
  561. package/src/cli/ui/components/screens/BranchQuickStartScreen.tsx +0 -244
  562. package/src/cli/ui/components/screens/CodingAgentSelectorScreen.tsx +0 -159
  563. package/src/cli/ui/components/screens/EnvironmentProfileScreen.tsx +0 -928
  564. package/src/cli/ui/components/screens/ExecutionModeSelectorScreen.tsx +0 -176
  565. package/src/cli/ui/components/screens/LogDatePickerScreen.tsx +0 -83
  566. package/src/cli/ui/components/screens/LogDetailScreen.tsx +0 -67
  567. package/src/cli/ui/components/screens/LogListScreen.tsx +0 -192
  568. package/src/cli/ui/components/screens/ModelSelectorScreen.tsx +0 -320
  569. package/src/cli/ui/components/screens/PRCleanupScreen.tsx +0 -171
  570. package/src/cli/ui/components/screens/SessionSelectorScreen.tsx +0 -135
  571. package/src/cli/ui/hooks/useAppInput.ts +0 -172
  572. package/src/cli/ui/hooks/useBatchMerge.ts +0 -96
  573. package/src/cli/ui/hooks/useGitData.ts +0 -347
  574. package/src/cli/ui/hooks/useProfiles.ts +0 -211
  575. package/src/cli/ui/hooks/useScreenState.ts +0 -44
  576. package/src/cli/ui/hooks/useTerminalSize.ts +0 -33
  577. package/src/cli/ui/hooks/useToolStatus.ts +0 -68
  578. package/src/cli/ui/screens/BranchActionSelectorScreen.tsx +0 -111
  579. package/src/cli/ui/screens/__tests__/BranchActionSelectorScreen.test.tsx +0 -264
@@ -1,744 +0,0 @@
1
- import React, { useCallback, useState, useMemo, useEffect } from "react";
2
- import { Box, Text } from "ink";
3
- import { Header } from "../parts/Header.js";
4
- import { Stats } from "../parts/Stats.js";
5
- import { Footer } from "../parts/Footer.js";
6
- import { Select } from "../common/Select.js";
7
- import { Input } from "../common/Input.js";
8
- import { LoadingIndicator } from "../common/LoadingIndicator.js";
9
- import { useSpinnerFrame } from "../common/SpinnerIcon.js";
10
- import { useAppInput } from "../../hooks/useAppInput.js";
11
- import { useTerminalSize } from "../../hooks/useTerminalSize.js";
12
- import type { BranchItem, Statistics, BranchViewMode } from "../../types.js";
13
- import type { ToolStatus } from "../../hooks/useToolStatus.js";
14
- import { getLatestActivityTimestamp } from "../../utils/branchFormatter.js";
15
- import stringWidth from "string-width";
16
- import stripAnsi from "strip-ansi";
17
- import chalk from "chalk";
18
-
19
- // Emoji 幅は端末によって 1 または 2 になることがあるため、最小幅を上書きして
20
- // 実測より小さくならないようにする(過小評価=折り返しの原因を防ぐ)
21
- const WIDTH_OVERRIDES: Record<string, number> = {
22
- // Remote icon
23
- "☁": 1,
24
- // Branch type icons
25
- "⚡": 1,
26
- "✨": 1,
27
- "🐛": 1,
28
- "🔥": 1,
29
- "🚀": 1,
30
- "📌": 1,
31
- // Worktree status icons
32
- "🟢": 2,
33
- "⚪": 2,
34
- "🔴": 2,
35
- // Change status icons
36
- "👉": 1,
37
- "💾": 1,
38
- "📤": 1,
39
- "🔃": 1,
40
- "✅": 2,
41
- "⚠": 2,
42
- "⚠️": 2,
43
- "🛡": 2,
44
- // Remote markers
45
- "🔗": 2,
46
- "💻": 2,
47
- "☁️": 2,
48
- "☑": 2,
49
- "☐": 2,
50
- };
51
-
52
- const getCharWidth = (char: string): number => {
53
- const baseWidth = stringWidth(char);
54
- const override = WIDTH_OVERRIDES[char];
55
- return override !== undefined ? Math.max(baseWidth, override) : baseWidth;
56
- };
57
-
58
- const measureDisplayWidth = (value: string): number => {
59
- let width = 0;
60
- for (const char of Array.from(value)) {
61
- width += getCharWidth(char);
62
- }
63
- return width;
64
- };
65
-
66
- type IndicatorColor = "cyan" | "green" | "yellow" | "red";
67
-
68
- interface CleanupIndicator {
69
- icon: string;
70
- isSpinning?: boolean;
71
- color?: IndicatorColor;
72
- }
73
-
74
- interface CleanupFooterMessage {
75
- text: string;
76
- isSpinning?: boolean;
77
- color?: IndicatorColor;
78
- }
79
-
80
- interface CleanupUIState {
81
- indicators: Record<string, CleanupIndicator>;
82
- footerMessage: CleanupFooterMessage | null;
83
- inputLocked: boolean;
84
- }
85
-
86
- /**
87
- * Props for `BranchListScreen`.
88
- */
89
- export interface BranchListScreenProps {
90
- branches: BranchItem[];
91
- stats: Statistics;
92
- onSelect: (branch: BranchItem) => void;
93
- onQuit?: () => void;
94
- onCleanupCommand?: () => void;
95
- onRefresh?: () => void;
96
- onOpenProfiles?: () => void;
97
- onOpenLogs?: () => void;
98
- loading?: boolean;
99
- error?: Error | null;
100
- lastUpdated?: Date | null;
101
- loadingIndicatorDelay?: number;
102
- cleanupUI?: CleanupUIState;
103
- version?: string | null;
104
- workingDirectory?: string;
105
- activeProfile?: string | null;
106
- // Test support: allow external control of filter mode and query
107
- testFilterMode?: boolean;
108
- testOnFilterModeChange?: (mode: boolean) => void;
109
- testFilterQuery?: string;
110
- testOnFilterQueryChange?: (query: string) => void;
111
- testViewMode?: BranchViewMode;
112
- testOnViewModeChange?: (mode: BranchViewMode) => void;
113
- selectedBranches?: string[];
114
- onToggleSelect?: (branchName: string) => void;
115
- /**
116
- * AIツールのインストール状態配列
117
- * @see specs/SPEC-3b0ed29b/spec.md FR-019, FR-021
118
- */
119
- toolStatuses?: ToolStatus[] | undefined;
120
- }
121
-
122
- /**
123
- * BranchListScreen - Main screen for branch selection
124
- * Layout: Header + Stats + Branch List + Footer
125
- */
126
- export const BranchListScreen = React.memo(function BranchListScreen({
127
- branches,
128
- stats,
129
- onSelect,
130
- onCleanupCommand,
131
- onRefresh,
132
- onOpenProfiles,
133
- onOpenLogs,
134
- loading = false,
135
- error = null,
136
- lastUpdated = null,
137
- loadingIndicatorDelay = 300,
138
- cleanupUI,
139
- version,
140
- workingDirectory,
141
- activeProfile,
142
- testFilterMode,
143
- testOnFilterModeChange,
144
- testFilterQuery,
145
- testOnFilterQueryChange,
146
- testViewMode,
147
- testOnViewModeChange,
148
- selectedBranches = [],
149
- onToggleSelect,
150
- toolStatuses,
151
- }: BranchListScreenProps) {
152
- const { rows } = useTerminalSize();
153
- const selectedSet = useMemo(
154
- () => new Set(selectedBranches),
155
- [selectedBranches],
156
- );
157
-
158
- // Check if any indicator needs spinner animation
159
- const hasSpinningIndicator = useMemo(() => {
160
- if (!cleanupUI?.indicators) return false;
161
- return Object.values(cleanupUI.indicators).some((ind) => ind.isSpinning);
162
- }, [cleanupUI?.indicators]);
163
-
164
- // Also check footer message for spinner
165
- const hasSpinningFooter = cleanupUI?.footerMessage?.isSpinning ?? false;
166
-
167
- // Get spinner frame for all spinning elements
168
- const spinnerFrame = useSpinnerFrame(
169
- hasSpinningIndicator || hasSpinningFooter,
170
- );
171
-
172
- // Filter state - allow test control via props
173
- const [internalFilterQuery, setInternalFilterQuery] = useState("");
174
- const filterQuery =
175
- testFilterQuery !== undefined ? testFilterQuery : internalFilterQuery;
176
- const setFilterQuery = useCallback(
177
- (query: string) => {
178
- setInternalFilterQuery(query);
179
- testOnFilterQueryChange?.(query);
180
- },
181
- [testOnFilterQueryChange],
182
- );
183
-
184
- // Focus management: true = filter mode, false = branch selection mode
185
- // Allow test control via props
186
- const [internalFilterMode, setInternalFilterMode] = useState(false);
187
- const filterMode =
188
- testFilterMode !== undefined ? testFilterMode : internalFilterMode;
189
- const setFilterMode = useCallback(
190
- (mode: boolean) => {
191
- setInternalFilterMode(mode);
192
- testOnFilterModeChange?.(mode);
193
- },
194
- [testOnFilterModeChange],
195
- );
196
-
197
- // View mode state for filtering by local/remote
198
- const [internalViewMode, setInternalViewMode] =
199
- useState<BranchViewMode>("all");
200
- const viewMode = testViewMode !== undefined ? testViewMode : internalViewMode;
201
- const setViewMode = useCallback(
202
- (mode: BranchViewMode) => {
203
- setInternalViewMode(mode);
204
- testOnViewModeChange?.(mode);
205
- },
206
- [testOnViewModeChange],
207
- );
208
-
209
- // Cycle view mode: all → local → remote → all
210
- const cycleViewMode = useCallback(() => {
211
- const modes: BranchViewMode[] = ["all", "local", "remote"];
212
- const currentIndex = modes.indexOf(viewMode);
213
- const nextIndex = (currentIndex + 1) % modes.length;
214
- const nextMode = modes[nextIndex];
215
- if (nextMode !== undefined) {
216
- setViewMode(nextMode);
217
- }
218
- }, [viewMode, setViewMode]);
219
-
220
- // Cursor position for Select (controlled to enable space toggle)
221
- const [selectedIndex, setSelectedIndex] = useState(0);
222
-
223
- // Handle keyboard input
224
- // Note: Input component blocks specific keys (c/r/f) using blockKeys prop
225
- // This prevents shortcuts from triggering while typing in the filter
226
- useAppInput((input, key) => {
227
- if (cleanupUI?.inputLocked) {
228
- return;
229
- }
230
-
231
- // Escape key handling
232
- if (key.escape) {
233
- if (filterQuery) {
234
- // Clear filter query first
235
- setFilterQuery("");
236
- return;
237
- }
238
- if (filterMode) {
239
- // Exit filter mode if query is empty
240
- setFilterMode(false);
241
- return;
242
- }
243
- }
244
-
245
- // Enter filter mode with 'f' key (only in branch selection mode)
246
- if (input === "f" && !filterMode) {
247
- setFilterMode(true);
248
- return;
249
- }
250
-
251
- // Toggle selection with space (only in branch selection mode)
252
- if (input === " " && !filterMode) {
253
- const target = filteredBranches[selectedIndex];
254
- if (target) {
255
- onToggleSelect?.(target.name);
256
- }
257
- return;
258
- }
259
-
260
- // Tab key to cycle view mode (only in branch selection mode)
261
- if (key.tab && !filterMode) {
262
- cycleViewMode();
263
- setSelectedIndex(0); // Reset cursor position on mode change
264
- return;
265
- }
266
-
267
- // Disable global shortcuts while in filter mode
268
- if (filterMode) {
269
- return;
270
- }
271
-
272
- // Global shortcuts (blocked by Input component when typing in filter mode)
273
- if (input === "c") {
274
- onCleanupCommand?.();
275
- } else if (input === "r" && onRefresh) {
276
- onRefresh();
277
- } else if (input === "p" && onOpenProfiles) {
278
- onOpenProfiles();
279
- } else if (input === "l" && onOpenLogs) {
280
- onOpenLogs();
281
- }
282
- });
283
-
284
- // Filter branches based on view mode and query
285
- const filteredBranches = useMemo(() => {
286
- let result = branches;
287
-
288
- // Apply view mode filter
289
- if (viewMode === "local") {
290
- result = result.filter((branch) => branch.type === "local");
291
- } else if (viewMode === "remote") {
292
- // リモート専用ブランチ OR ローカルだがリモートにも存在するブランチ
293
- result = result.filter(
294
- (branch) =>
295
- branch.type === "remote" || branch.hasRemoteCounterpart === true,
296
- );
297
- }
298
-
299
- // Apply search filter
300
- if (filterQuery.trim()) {
301
- const query = filterQuery.toLowerCase();
302
- result = result.filter((branch) => {
303
- // Search in branch name
304
- if (branch.name.toLowerCase().includes(query)) {
305
- return true;
306
- }
307
-
308
- // Search in PR title if available (only openPR has title)
309
- if (branch.openPR?.title?.toLowerCase().includes(query)) {
310
- return true;
311
- }
312
-
313
- return false;
314
- });
315
- }
316
-
317
- return result;
318
- }, [branches, viewMode, filterQuery]);
319
-
320
- useEffect(() => {
321
- setSelectedIndex((prev) => {
322
- if (filteredBranches.length === 0) {
323
- return 0;
324
- }
325
- return Math.min(prev, filteredBranches.length - 1);
326
- });
327
- }, [filteredBranches.length]);
328
-
329
- // Calculate available space for branch list
330
- // Header: 2 lines (title + divider)
331
- // Filter input: 1 line
332
- // Stats: 1 line
333
- // Empty line: 1 line
334
- // Footer: 1 line
335
- // Total fixed: 6 lines
336
- const headerLines = 2;
337
- const filterLines = 1;
338
- const statsLines = 1;
339
- const emptyLine = 1;
340
- const footerLines = 1;
341
- const fixedLines =
342
- headerLines + filterLines + statsLines + emptyLine + footerLines;
343
- const contentHeight = rows - fixedLines;
344
- const limit = Math.max(5, contentHeight); // Minimum 5 items visible
345
-
346
- // Footer actions
347
- const footerActions = [
348
- { key: "enter", description: "Select" },
349
- { key: "f", description: "Filter" },
350
- { key: "tab", description: "Mode" },
351
- { key: "r", description: "Refresh" },
352
- { key: "c", description: "Cleanup" },
353
- { key: "p", description: "Profiles" },
354
- { key: "l", description: "Logs" },
355
- ];
356
-
357
- const formatLatestCommit = useCallback((timestamp?: number) => {
358
- if (!timestamp || Number.isNaN(timestamp)) {
359
- return "---";
360
- }
361
-
362
- const date = new Date(timestamp * 1000);
363
- const year = date.getFullYear();
364
- const month = String(date.getMonth() + 1).padStart(2, "0");
365
- const day = String(date.getDate()).padStart(2, "0");
366
- const hours = String(date.getHours()).padStart(2, "0");
367
- const minutes = String(date.getMinutes()).padStart(2, "0");
368
-
369
- return `${year}-${month}-${day} ${hours}:${minutes}`;
370
- }, []);
371
-
372
- const truncateToWidth = useCallback((value: string, maxWidth: number) => {
373
- if (maxWidth <= 0) {
374
- return "";
375
- }
376
-
377
- if (measureDisplayWidth(value) <= maxWidth) {
378
- return value;
379
- }
380
-
381
- const ellipsis = "…";
382
- const ellipsisWidth = measureDisplayWidth(ellipsis);
383
- if (ellipsisWidth >= maxWidth) {
384
- return ellipsis;
385
- }
386
-
387
- let currentWidth = 0;
388
- let result = "";
389
-
390
- for (const char of Array.from(value)) {
391
- const charWidth = getCharWidth(char);
392
- if (currentWidth + charWidth + ellipsisWidth > maxWidth) {
393
- break;
394
- }
395
- result += char;
396
- currentWidth += charWidth;
397
- }
398
-
399
- return result + ellipsis;
400
- }, []);
401
-
402
- const colorToolLabel = useCallback(
403
- (label: string, toolId?: string | null) => {
404
- switch (toolId) {
405
- case "claude-code":
406
- return chalk.hex("#ffaf00")(label); // orange-ish
407
- case "codex-cli":
408
- return chalk.cyan(label);
409
- case "gemini-cli":
410
- return chalk.magenta(label);
411
- default: {
412
- const trimmed = label.trim().toLowerCase();
413
- if (!toolId || trimmed === "unknown") {
414
- return chalk.gray(label);
415
- }
416
- return chalk.white(label);
417
- }
418
- }
419
- },
420
- [],
421
- );
422
-
423
- const renderBranchRow = useCallback(
424
- (item: BranchItem, isSelected: boolean, context: { columns: number }) => {
425
- // 端末幅ピッタリでの自動折返しを避けるため、1桁だけ余白を取る
426
- const columns = Math.max(20, context.columns - 1);
427
- const visibleWidth = (value: string) =>
428
- measureDisplayWidth(stripAnsi(value));
429
- // FR-041: Display latest activity time (max of git commit and tool usage)
430
- let commitText = "---";
431
- const latestActivitySec = getLatestActivityTimestamp(item);
432
- if (latestActivitySec > 0) {
433
- commitText = formatLatestCommit(latestActivitySec);
434
- }
435
- const toolLabelRaw =
436
- item.lastToolUsageLabel?.split("|")?.[0]?.trim() ??
437
- item.lastToolUsage?.toolId ??
438
- "Unknown";
439
-
440
- const formatFixedWidth = (value: string, targetWidth: number) => {
441
- let v = value;
442
- if (measureDisplayWidth(v) > targetWidth) {
443
- v = truncateToWidth(v, targetWidth);
444
- }
445
- const padding = Math.max(0, targetWidth - measureDisplayWidth(v));
446
- return v + " ".repeat(padding);
447
- };
448
-
449
- const TOOL_WIDTH = 7;
450
- const DATE_WIDTH = 16; // "YYYY-MM-DD HH:mm"
451
- const paddedTool = formatFixedWidth(toolLabelRaw, TOOL_WIDTH);
452
- const paddedDate =
453
- commitText === "---"
454
- ? " ".repeat(DATE_WIDTH)
455
- : commitText.padStart(DATE_WIDTH, " ");
456
- const timestampText = `${paddedTool} | ${paddedDate}`;
457
- const displayTimestampText = `${colorToolLabel(
458
- paddedTool,
459
- item.lastToolUsage?.toolId,
460
- )} | ${paddedDate}`;
461
- const timestampWidth = measureDisplayWidth(timestampText);
462
-
463
- // Determine the leading indicator (cursor or cleanup status)
464
- const indicatorInfo = cleanupUI?.indicators?.[item.name];
465
- let leadingIndicator: string;
466
- if (indicatorInfo) {
467
- // Use static spinner icon if isSpinning to avoid re-render dependency
468
- // The static "⠋" provides visual feedback without causing flicker
469
- let indicatorIcon = indicatorInfo.isSpinning ? "⠋" : indicatorInfo.icon;
470
- if (indicatorIcon && indicatorInfo.color && !isSelected) {
471
- switch (indicatorInfo.color) {
472
- case "cyan":
473
- indicatorIcon = chalk.cyan(indicatorIcon);
474
- break;
475
- case "green":
476
- indicatorIcon = chalk.green(indicatorIcon);
477
- break;
478
- case "yellow":
479
- indicatorIcon = chalk.yellow(indicatorIcon);
480
- break;
481
- case "red":
482
- indicatorIcon = chalk.red(indicatorIcon);
483
- break;
484
- default:
485
- break;
486
- }
487
- }
488
- leadingIndicator = indicatorIcon;
489
- } else {
490
- // Normal cursor
491
- leadingIndicator = isSelected ? ">" : " ";
492
- }
493
-
494
- const isChecked = selectedSet.has(item.name);
495
- const isWarning = Boolean(item.hasUnpushedCommits) || !item.mergedPR;
496
- const selectionIcon = isChecked
497
- ? isWarning
498
- ? chalk.red("[*]")
499
- : "[*]"
500
- : "[ ]";
501
- let worktreeIcon = chalk.gray("⚪");
502
- if (item.worktreeStatus === "active") {
503
- worktreeIcon = chalk.green("🟢");
504
- } else if (item.worktreeStatus === "inaccessible") {
505
- worktreeIcon = chalk.red("🔴");
506
- }
507
- const safeIcon =
508
- item.safeToCleanup === true ? chalk.green("🛡") : chalk.yellow("⚠");
509
- const stateCluster = `${selectionIcon} ${worktreeIcon} ${safeIcon}`;
510
-
511
- const staticPrefix = `${leadingIndicator} ${stateCluster} `;
512
- const staticPrefixWidth = visibleWidth(staticPrefix);
513
- const maxLeftDisplayWidth = Math.max(0, columns - timestampWidth - 1);
514
- const maxLabelWidth = Math.max(
515
- 0,
516
- maxLeftDisplayWidth - staticPrefixWidth,
517
- );
518
- const displayLabel =
519
- item.type === "remote" && item.remoteName ? item.remoteName : item.name;
520
- let truncatedLabel = truncateToWidth(displayLabel, maxLabelWidth);
521
- let leftText = `${staticPrefix}${truncatedLabel}`;
522
-
523
- let leftDisplayWidth = visibleWidth(leftText);
524
- // Gap between labelとツール/日時。右端に寄せるため必要分だけ確保。
525
- let gapWidth = Math.max(1, columns - leftDisplayWidth - timestampWidth);
526
-
527
- // もしまだオーバーする場合、隙間→ラベルの順で削って収める
528
- let totalWidth = leftDisplayWidth + gapWidth + timestampWidth;
529
- if (totalWidth > columns) {
530
- const overflow = totalWidth - columns;
531
- const reducedGap = Math.max(1, gapWidth - overflow);
532
- gapWidth = reducedGap;
533
- totalWidth = leftDisplayWidth + gapWidth + timestampWidth;
534
- }
535
- if (leftDisplayWidth + gapWidth + timestampWidth > columns) {
536
- const extra = leftDisplayWidth + gapWidth + timestampWidth - columns;
537
- const newLabelWidth = Math.max(
538
- 0,
539
- measureDisplayWidth(truncatedLabel) - extra,
540
- );
541
- truncatedLabel = truncateToWidth(displayLabel, newLabelWidth);
542
- leftText = `${staticPrefix}${truncatedLabel}`;
543
- leftDisplayWidth = visibleWidth(leftText);
544
- gapWidth = Math.max(1, columns - leftDisplayWidth - timestampWidth);
545
- }
546
-
547
- const buildLine = () =>
548
- `${leftText}${" ".repeat(gapWidth)}${timestampText}`;
549
-
550
- let line = buildLine();
551
- // Replace timestamp with colorized tool name (keep alignment from width calc)
552
- let lineWithColoredTimestamp = line.replace(
553
- timestampText,
554
- displayTimestampText,
555
- );
556
-
557
- // 端末幅を超えた場合は隙間→ラベルの順で詰めて収める
558
- const clampToWidth = () => {
559
- const finalWidth = measureDisplayWidth(
560
- stripAnsi(lineWithColoredTimestamp),
561
- );
562
- if (finalWidth <= columns) {
563
- return;
564
- }
565
- const overflow = finalWidth - columns;
566
- const reducedGap = Math.max(1, gapWidth - overflow);
567
- gapWidth = reducedGap;
568
- line = buildLine();
569
- lineWithColoredTimestamp = line.replace(
570
- timestampText,
571
- displayTimestampText,
572
- );
573
- const widthAfterGap = measureDisplayWidth(
574
- stripAnsi(lineWithColoredTimestamp),
575
- );
576
- if (widthAfterGap > columns) {
577
- const extra = widthAfterGap - columns;
578
- const newLabelWidth = Math.max(
579
- 0,
580
- measureDisplayWidth(truncatedLabel) - extra,
581
- );
582
- truncatedLabel = truncateToWidth(displayLabel, newLabelWidth);
583
- leftText = `${staticPrefix}${truncatedLabel}`;
584
- leftDisplayWidth = visibleWidth(leftText);
585
- gapWidth = Math.max(1, columns - leftDisplayWidth - timestampWidth);
586
- line = buildLine();
587
- lineWithColoredTimestamp = line.replace(
588
- timestampText,
589
- displayTimestampText,
590
- );
591
- }
592
- };
593
-
594
- clampToWidth();
595
-
596
- const output = isSelected
597
- ? `\u001b[46m\u001b[30m${lineWithColoredTimestamp}\u001b[0m`
598
- : lineWithColoredTimestamp;
599
- return <Text>{output}</Text>;
600
- },
601
- [
602
- cleanupUI,
603
- formatLatestCommit,
604
- truncateToWidth,
605
- selectedSet,
606
- colorToolLabel,
607
- ],
608
- );
609
-
610
- return (
611
- <Box flexDirection="column" height={rows}>
612
- {/* Header */}
613
- <Header
614
- title="gwt - Branch Selection"
615
- titleColor="cyan"
616
- version={version}
617
- {...(workingDirectory !== undefined && { workingDirectory })}
618
- activeProfile={activeProfile}
619
- />
620
-
621
- {/* Filter Input - Always visible */}
622
- <Box>
623
- <Text dimColor>Filter: </Text>
624
- {filterMode ? (
625
- <Input
626
- value={filterQuery}
627
- onChange={setFilterQuery}
628
- onSubmit={() => {}} // No-op: filter is applied in real-time
629
- placeholder="Type to search..."
630
- blockKeys={["c", "r", "f", "l"]} // Block shortcuts while typing
631
- />
632
- ) : (
633
- <Text dimColor>{filterQuery || "(press f to filter)"}</Text>
634
- )}
635
- {filterQuery && (
636
- <Text dimColor>
637
- {" "}
638
- (Showing {filteredBranches.length} of {branches.length})
639
- </Text>
640
- )}
641
- </Box>
642
-
643
- {/* Tool Status - FR-019, FR-021, FR-022 */}
644
- {toolStatuses && toolStatuses.length > 0 && (
645
- <Box>
646
- <Text dimColor>Tools: </Text>
647
- {toolStatuses.map((tool, index) => (
648
- <React.Fragment key={tool.id}>
649
- <Text>{tool.name}: </Text>
650
- <Text color={tool.status === "installed" ? "green" : "yellow"}>
651
- {tool.status === "installed" && tool.version
652
- ? tool.version
653
- : tool.status}
654
- </Text>
655
- {index < toolStatuses.length - 1 && <Text dimColor> | </Text>}
656
- </React.Fragment>
657
- ))}
658
- </Box>
659
- )}
660
-
661
- {/* Stats */}
662
- <Box>
663
- <Stats stats={stats} lastUpdated={lastUpdated} viewMode={viewMode} />
664
- </Box>
665
-
666
- {/* Content */}
667
- <Box flexDirection="column" flexGrow={1}>
668
- <LoadingIndicator
669
- isLoading={Boolean(loading)}
670
- delay={loadingIndicatorDelay}
671
- message="Loading Git information..."
672
- />
673
-
674
- {error && (
675
- <Box flexDirection="column">
676
- <Text color="red" bold>
677
- Error: {error.message}
678
- </Text>
679
- {process.env.DEBUG && error.stack && (
680
- <Box marginTop={1}>
681
- <Text color="gray">{error.stack}</Text>
682
- </Box>
683
- )}
684
- </Box>
685
- )}
686
-
687
- {!loading && !error && branches.length === 0 && (
688
- <Box>
689
- <Text dimColor>No branches found</Text>
690
- </Box>
691
- )}
692
-
693
- {!loading &&
694
- !error &&
695
- branches.length > 0 &&
696
- filteredBranches.length === 0 &&
697
- filterQuery && (
698
- <Box>
699
- <Text dimColor>No branches match your filter</Text>
700
- </Box>
701
- )}
702
-
703
- {!loading &&
704
- !error &&
705
- branches.length > 0 &&
706
- filteredBranches.length > 0 && (
707
- <>
708
- <Select
709
- items={filteredBranches}
710
- onSelect={onSelect}
711
- limit={limit}
712
- disabled={Boolean(cleanupUI?.inputLocked)}
713
- renderIndicator={() => null}
714
- renderItem={renderBranchRow}
715
- selectedIndex={selectedIndex}
716
- onSelectedIndexChange={setSelectedIndex}
717
- />
718
- </>
719
- )}
720
- </Box>
721
-
722
- {cleanupUI?.footerMessage && (
723
- <Box marginBottom={1}>
724
- {cleanupUI.footerMessage.color ? (
725
- <Text color={cleanupUI.footerMessage.color}>
726
- {cleanupUI.footerMessage.isSpinning && spinnerFrame
727
- ? `${spinnerFrame} ${cleanupUI.footerMessage.text}`
728
- : cleanupUI.footerMessage.text}
729
- </Text>
730
- ) : (
731
- <Text>
732
- {cleanupUI.footerMessage.isSpinning && spinnerFrame
733
- ? `${spinnerFrame} ${cleanupUI.footerMessage.text}`
734
- : cleanupUI.footerMessage.text}
735
- </Text>
736
- )}
737
- </Box>
738
- )}
739
-
740
- {/* Footer */}
741
- <Footer actions={footerActions} />
742
- </Box>
743
- );
744
- });