@akiojin/gwt 4.10.0 → 4.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (630) hide show
  1. package/README.ja.md +4 -4
  2. package/README.md +4 -4
  3. package/bin/gwt.js +1 -1
  4. package/dist/claude.d.ts +2 -0
  5. package/dist/claude.d.ts.map +1 -1
  6. package/dist/claude.js +97 -68
  7. package/dist/claude.js.map +1 -1
  8. package/dist/cli/ui/App.solid.d.ts +29 -0
  9. package/dist/cli/ui/App.solid.d.ts.map +1 -0
  10. package/dist/cli/ui/App.solid.js +1395 -0
  11. package/dist/cli/ui/App.solid.js.map +1 -0
  12. package/dist/cli/ui/components/solid/Footer.d.ts +10 -0
  13. package/dist/cli/ui/components/solid/Footer.d.ts.map +1 -0
  14. package/dist/cli/ui/components/solid/Footer.js +10 -0
  15. package/dist/cli/ui/components/solid/Footer.js.map +1 -0
  16. package/dist/cli/ui/components/{parts → solid}/Header.d.ts +1 -6
  17. package/dist/cli/ui/components/solid/Header.d.ts.map +1 -0
  18. package/dist/cli/ui/components/solid/Header.js +13 -0
  19. package/dist/cli/ui/components/solid/Header.js.map +1 -0
  20. package/dist/cli/ui/components/solid/HelpOverlay.d.ts +8 -0
  21. package/dist/cli/ui/components/solid/HelpOverlay.d.ts.map +1 -0
  22. package/dist/cli/ui/components/solid/HelpOverlay.js +118 -0
  23. package/dist/cli/ui/components/solid/HelpOverlay.js.map +1 -0
  24. package/dist/cli/ui/components/solid/QuickStartStep.d.ts +17 -0
  25. package/dist/cli/ui/components/solid/QuickStartStep.d.ts.map +1 -0
  26. package/dist/cli/ui/components/solid/QuickStartStep.js +152 -0
  27. package/dist/cli/ui/components/solid/QuickStartStep.js.map +1 -0
  28. package/dist/cli/ui/components/solid/SelectInput.d.ts +22 -0
  29. package/dist/cli/ui/components/solid/SelectInput.d.ts.map +1 -0
  30. package/dist/cli/ui/components/solid/SelectInput.js +45 -0
  31. package/dist/cli/ui/components/solid/SelectInput.js.map +1 -0
  32. package/dist/cli/ui/components/solid/TextInput.d.ts +12 -0
  33. package/dist/cli/ui/components/solid/TextInput.d.ts.map +1 -0
  34. package/dist/cli/ui/components/solid/TextInput.js +9 -0
  35. package/dist/cli/ui/components/solid/TextInput.js.map +1 -0
  36. package/dist/cli/ui/components/solid/WizardController.d.ts +34 -0
  37. package/dist/cli/ui/components/solid/WizardController.d.ts.map +1 -0
  38. package/dist/cli/ui/components/solid/WizardController.js +223 -0
  39. package/dist/cli/ui/components/solid/WizardController.js.map +1 -0
  40. package/dist/cli/ui/components/solid/WizardPopup.d.ts +26 -0
  41. package/dist/cli/ui/components/solid/WizardPopup.d.ts.map +1 -0
  42. package/dist/cli/ui/components/solid/WizardPopup.js +68 -0
  43. package/dist/cli/ui/components/solid/WizardPopup.js.map +1 -0
  44. package/dist/cli/ui/components/solid/WizardSteps.d.ts +52 -0
  45. package/dist/cli/ui/components/solid/WizardSteps.d.ts.map +1 -0
  46. package/dist/cli/ui/components/solid/WizardSteps.js +419 -0
  47. package/dist/cli/ui/components/solid/WizardSteps.js.map +1 -0
  48. package/dist/cli/ui/core/index.d.ts +12 -0
  49. package/dist/cli/ui/core/index.d.ts.map +1 -0
  50. package/dist/cli/ui/core/index.js +15 -0
  51. package/dist/cli/ui/core/index.js.map +1 -0
  52. package/dist/cli/ui/core/keybindings.d.ts +106 -0
  53. package/dist/cli/ui/core/keybindings.d.ts.map +1 -0
  54. package/dist/cli/ui/core/keybindings.js +270 -0
  55. package/dist/cli/ui/core/keybindings.js.map +1 -0
  56. package/dist/cli/ui/core/theme.d.ts +123 -0
  57. package/dist/cli/ui/core/theme.d.ts.map +1 -0
  58. package/dist/cli/ui/core/theme.js +191 -0
  59. package/dist/cli/ui/core/theme.js.map +1 -0
  60. package/dist/cli/ui/core/types.d.ts +156 -0
  61. package/dist/cli/ui/core/types.d.ts.map +1 -0
  62. package/dist/cli/ui/core/types.js +10 -0
  63. package/dist/cli/ui/core/types.js.map +1 -0
  64. package/dist/cli/ui/hooks/solid/useScrollableList.d.ts +26 -0
  65. package/dist/cli/ui/hooks/solid/useScrollableList.d.ts.map +1 -0
  66. package/dist/cli/ui/hooks/solid/useScrollableList.js +89 -0
  67. package/dist/cli/ui/hooks/solid/useScrollableList.js.map +1 -0
  68. package/dist/cli/ui/hooks/solid/useTerminalSize.d.ts +10 -0
  69. package/dist/cli/ui/hooks/solid/useTerminalSize.d.ts.map +1 -0
  70. package/dist/cli/ui/hooks/solid/useTerminalSize.js +16 -0
  71. package/dist/cli/ui/hooks/solid/useTerminalSize.js.map +1 -0
  72. package/dist/cli/ui/index.solid.d.ts +5 -0
  73. package/dist/cli/ui/index.solid.d.ts.map +1 -0
  74. package/dist/cli/ui/index.solid.js +21 -0
  75. package/dist/cli/ui/index.solid.js.map +1 -0
  76. package/dist/cli/ui/screens/solid/BranchListScreen.d.ts +53 -0
  77. package/dist/cli/ui/screens/solid/BranchListScreen.d.ts.map +1 -0
  78. package/dist/cli/ui/screens/solid/BranchListScreen.js +829 -0
  79. package/dist/cli/ui/screens/solid/BranchListScreen.js.map +1 -0
  80. package/dist/cli/ui/screens/solid/ConfirmScreen.d.ts +11 -0
  81. package/dist/cli/ui/screens/solid/ConfirmScreen.d.ts.map +1 -0
  82. package/dist/cli/ui/screens/solid/ConfirmScreen.js +45 -0
  83. package/dist/cli/ui/screens/solid/ConfirmScreen.js.map +1 -0
  84. package/dist/cli/ui/screens/solid/EnvironmentScreen.d.ts +14 -0
  85. package/dist/cli/ui/screens/solid/EnvironmentScreen.d.ts.map +1 -0
  86. package/dist/cli/ui/screens/solid/EnvironmentScreen.js +90 -0
  87. package/dist/cli/ui/screens/solid/EnvironmentScreen.js.map +1 -0
  88. package/dist/cli/ui/screens/solid/ErrorScreen.d.ts +8 -0
  89. package/dist/cli/ui/screens/solid/ErrorScreen.d.ts.map +1 -0
  90. package/dist/cli/ui/screens/solid/ErrorScreen.js +18 -0
  91. package/dist/cli/ui/screens/solid/ErrorScreen.js.map +1 -0
  92. package/dist/cli/ui/screens/solid/InputScreen.d.ts +13 -0
  93. package/dist/cli/ui/screens/solid/InputScreen.d.ts.map +1 -0
  94. package/dist/cli/ui/screens/solid/InputScreen.js +17 -0
  95. package/dist/cli/ui/screens/solid/InputScreen.js.map +1 -0
  96. package/dist/cli/ui/screens/solid/LoadingIndicator.d.ts +9 -0
  97. package/dist/cli/ui/screens/solid/LoadingIndicator.d.ts.map +1 -0
  98. package/dist/cli/ui/screens/solid/LoadingIndicator.js +43 -0
  99. package/dist/cli/ui/screens/solid/LoadingIndicator.js.map +1 -0
  100. package/dist/cli/ui/{components/screens → screens/solid}/LogDetailScreen.d.ts +2 -2
  101. package/dist/cli/ui/screens/solid/LogDetailScreen.d.ts.map +1 -0
  102. package/dist/cli/ui/screens/solid/LogDetailScreen.js +34 -0
  103. package/dist/cli/ui/screens/solid/LogDetailScreen.js.map +1 -0
  104. package/dist/cli/ui/{components/screens/LogListScreen.d.ts → screens/solid/LogScreen.d.ts} +10 -4
  105. package/dist/cli/ui/screens/solid/LogScreen.d.ts.map +1 -0
  106. package/dist/cli/ui/screens/solid/LogScreen.js +333 -0
  107. package/dist/cli/ui/screens/solid/LogScreen.js.map +1 -0
  108. package/dist/cli/ui/screens/solid/ProfileEnvScreen.d.ts +17 -0
  109. package/dist/cli/ui/screens/solid/ProfileEnvScreen.d.ts.map +1 -0
  110. package/dist/cli/ui/screens/solid/ProfileEnvScreen.js +115 -0
  111. package/dist/cli/ui/screens/solid/ProfileEnvScreen.js.map +1 -0
  112. package/dist/cli/ui/screens/solid/ProfileScreen.d.ts +17 -0
  113. package/dist/cli/ui/screens/solid/ProfileScreen.d.ts.map +1 -0
  114. package/dist/cli/ui/screens/solid/ProfileScreen.js +50 -0
  115. package/dist/cli/ui/screens/solid/ProfileScreen.js.map +1 -0
  116. package/dist/cli/ui/screens/solid/SelectorScreen.d.ts +20 -0
  117. package/dist/cli/ui/screens/solid/SelectorScreen.d.ts.map +1 -0
  118. package/dist/cli/ui/screens/solid/SelectorScreen.js +98 -0
  119. package/dist/cli/ui/screens/solid/SelectorScreen.js.map +1 -0
  120. package/dist/cli/ui/screens/solid/WorktreeCreateScreen.d.ts +13 -0
  121. package/dist/cli/ui/screens/solid/WorktreeCreateScreen.d.ts.map +1 -0
  122. package/dist/cli/ui/screens/solid/WorktreeCreateScreen.js +59 -0
  123. package/dist/cli/ui/screens/solid/WorktreeCreateScreen.js.map +1 -0
  124. package/dist/cli/ui/stores/appStore.d.ts +143 -0
  125. package/dist/cli/ui/stores/appStore.d.ts.map +1 -0
  126. package/dist/cli/ui/stores/appStore.js +158 -0
  127. package/dist/cli/ui/stores/appStore.js.map +1 -0
  128. package/dist/cli/ui/stores/branchStore.d.ts +159 -0
  129. package/dist/cli/ui/stores/branchStore.d.ts.map +1 -0
  130. package/dist/cli/ui/stores/branchStore.js +275 -0
  131. package/dist/cli/ui/stores/branchStore.js.map +1 -0
  132. package/dist/cli/ui/stores/index.d.ts +11 -0
  133. package/dist/cli/ui/stores/index.d.ts.map +1 -0
  134. package/dist/cli/ui/stores/index.js +14 -0
  135. package/dist/cli/ui/stores/index.js.map +1 -0
  136. package/dist/cli/ui/stores/uiStore.d.ts +146 -0
  137. package/dist/cli/ui/stores/uiStore.d.ts.map +1 -0
  138. package/dist/cli/ui/stores/uiStore.js +166 -0
  139. package/dist/cli/ui/stores/uiStore.js.map +1 -0
  140. package/dist/cli/ui/types.d.ts +17 -1
  141. package/dist/cli/ui/types.d.ts.map +1 -1
  142. package/dist/cli/ui/utils/branchFormatter.d.ts +1 -0
  143. package/dist/cli/ui/utils/branchFormatter.d.ts.map +1 -1
  144. package/dist/cli/ui/utils/branchFormatter.js +36 -217
  145. package/dist/cli/ui/utils/branchFormatter.js.map +1 -1
  146. package/dist/cli/ui/utils/continueSession.d.ts +18 -0
  147. package/dist/cli/ui/utils/continueSession.d.ts.map +1 -1
  148. package/dist/cli/ui/utils/continueSession.js +90 -2
  149. package/dist/cli/ui/utils/continueSession.js.map +1 -1
  150. package/dist/cli/ui/utils/versionCache.d.ts +37 -0
  151. package/dist/cli/ui/utils/versionCache.d.ts.map +1 -0
  152. package/dist/cli/ui/utils/versionCache.js +70 -0
  153. package/dist/cli/ui/utils/versionCache.js.map +1 -0
  154. package/dist/cli/ui/utils/versionFetcher.d.ts +41 -0
  155. package/dist/cli/ui/utils/versionFetcher.d.ts.map +1 -0
  156. package/dist/cli/ui/utils/versionFetcher.js +89 -0
  157. package/dist/cli/ui/utils/versionFetcher.js.map +1 -0
  158. package/dist/client/assets/{index-ChHC-Puh.css → index-BbfV7Wuj.css} +1 -1
  159. package/dist/client/assets/index-CoAyq5x1.js +78 -0
  160. package/dist/client/index.html +2 -2
  161. package/dist/codex.d.ts +2 -0
  162. package/dist/codex.d.ts.map +1 -1
  163. package/dist/codex.js +109 -39
  164. package/dist/codex.js.map +1 -1
  165. package/dist/config/builtin-coding-agents.js +4 -4
  166. package/dist/config/builtin-coding-agents.js.map +1 -1
  167. package/dist/config/index.d.ts +2 -0
  168. package/dist/config/index.d.ts.map +1 -1
  169. package/dist/config/index.js +11 -0
  170. package/dist/config/index.js.map +1 -1
  171. package/dist/gemini.d.ts +2 -0
  172. package/dist/gemini.d.ts.map +1 -1
  173. package/dist/gemini.js +77 -39
  174. package/dist/gemini.js.map +1 -1
  175. package/dist/index.d.ts +1 -1
  176. package/dist/index.d.ts.map +1 -1
  177. package/dist/index.js +153 -103
  178. package/dist/index.js.map +1 -1
  179. package/dist/launcher.d.ts.map +1 -1
  180. package/dist/launcher.js +56 -6
  181. package/dist/launcher.js.map +1 -1
  182. package/dist/logging/agentOutput.d.ts +21 -0
  183. package/dist/logging/agentOutput.d.ts.map +1 -0
  184. package/dist/logging/agentOutput.js +164 -0
  185. package/dist/logging/agentOutput.js.map +1 -0
  186. package/dist/logging/formatter.d.ts.map +1 -1
  187. package/dist/logging/formatter.js +18 -4
  188. package/dist/logging/formatter.js.map +1 -1
  189. package/dist/logging/logger.d.ts.map +1 -1
  190. package/dist/logging/logger.js +28 -9
  191. package/dist/logging/logger.js.map +1 -1
  192. package/dist/logging/reader.d.ts +21 -0
  193. package/dist/logging/reader.d.ts.map +1 -1
  194. package/dist/logging/reader.js +79 -0
  195. package/dist/logging/reader.js.map +1 -1
  196. package/dist/opentui/highlights-eq9cgrbb.scm +604 -0
  197. package/dist/opentui/highlights-ghv9g403.scm +205 -0
  198. package/dist/opentui/highlights-hk7bwhj4.scm +284 -0
  199. package/dist/opentui/highlights-r812a2qc.scm +150 -0
  200. package/dist/opentui/highlights-x6tmsnaa.scm +115 -0
  201. package/dist/opentui/index.solid.d.ts +2 -0
  202. package/dist/opentui/index.solid.d.ts.map +1 -0
  203. package/dist/opentui/index.solid.js +53687 -0
  204. package/dist/opentui/index.solid.js.map +1 -0
  205. package/dist/opentui/injections-73j83es3.scm +27 -0
  206. package/dist/opentui/tree-sitter-javascript-nd0q4pe9.wasm +0 -0
  207. package/dist/opentui/tree-sitter-markdown-411r6y9b.wasm +0 -0
  208. package/dist/opentui/tree-sitter-markdown_inline-j5349f42.wasm +0 -0
  209. package/dist/opentui/tree-sitter-typescript-zxjzwt75.wasm +0 -0
  210. package/dist/opentui/tree-sitter-zig-e78zbjpm.wasm +0 -0
  211. package/dist/repositories/worktree.repository.d.ts +1 -0
  212. package/dist/repositories/worktree.repository.d.ts.map +1 -1
  213. package/dist/repositories/worktree.repository.js +7 -0
  214. package/dist/repositories/worktree.repository.js.map +1 -1
  215. package/dist/services/codingAgentResolver.d.ts +2 -0
  216. package/dist/services/codingAgentResolver.d.ts.map +1 -1
  217. package/dist/services/codingAgentResolver.js +30 -4
  218. package/dist/services/codingAgentResolver.js.map +1 -1
  219. package/dist/services/dependency-installer.d.ts.map +1 -1
  220. package/dist/services/dependency-installer.js +2 -7
  221. package/dist/services/dependency-installer.js.map +1 -1
  222. package/dist/types/api.d.ts +3 -0
  223. package/dist/types/api.d.ts.map +1 -1
  224. package/dist/types/coding-agent.d.ts +62 -0
  225. package/dist/types/coding-agent.d.ts.map +1 -0
  226. package/dist/types/coding-agent.js +29 -0
  227. package/dist/types/coding-agent.js.map +1 -0
  228. package/dist/types/tools.d.ts +17 -0
  229. package/dist/types/tools.d.ts.map +1 -1
  230. package/dist/utils/coding-agent-colors.d.ts +88 -0
  231. package/dist/utils/coding-agent-colors.d.ts.map +1 -0
  232. package/dist/utils/coding-agent-colors.js +137 -0
  233. package/dist/utils/coding-agent-colors.js.map +1 -0
  234. package/dist/utils/command.d.ts +1 -1
  235. package/dist/utils/command.js +1 -1
  236. package/dist/utils/error-utils.d.ts +27 -0
  237. package/dist/utils/error-utils.d.ts.map +1 -0
  238. package/dist/utils/error-utils.js +98 -0
  239. package/dist/utils/error-utils.js.map +1 -0
  240. package/dist/utils/npmRegistry.d.ts +61 -0
  241. package/dist/utils/npmRegistry.d.ts.map +1 -0
  242. package/dist/utils/npmRegistry.js +180 -0
  243. package/dist/utils/npmRegistry.js.map +1 -0
  244. package/dist/utils/prompt.d.ts +1 -1
  245. package/dist/utils/prompt.js +1 -1
  246. package/dist/utils/session/common.d.ts +8 -0
  247. package/dist/utils/session/common.d.ts.map +1 -1
  248. package/dist/utils/session/common.js +22 -0
  249. package/dist/utils/session/common.js.map +1 -1
  250. package/dist/utils/session/parsers/claude.d.ts +10 -4
  251. package/dist/utils/session/parsers/claude.d.ts.map +1 -1
  252. package/dist/utils/session/parsers/claude.js +64 -18
  253. package/dist/utils/session/parsers/claude.js.map +1 -1
  254. package/dist/utils/session/parsers/codex.d.ts.map +1 -1
  255. package/dist/utils/session/parsers/codex.js +47 -20
  256. package/dist/utils/session/parsers/codex.js.map +1 -1
  257. package/dist/utils/session/parsers/gemini.d.ts.map +1 -1
  258. package/dist/utils/session/parsers/gemini.js +43 -6
  259. package/dist/utils/session/parsers/gemini.js.map +1 -1
  260. package/dist/utils/session/parsers/opencode.d.ts.map +1 -1
  261. package/dist/utils/session/parsers/opencode.js +43 -6
  262. package/dist/utils/session/parsers/opencode.js.map +1 -1
  263. package/dist/utils/session/types.d.ts +7 -0
  264. package/dist/utils/session/types.d.ts.map +1 -1
  265. package/dist/utils/terminal.d.ts +1 -0
  266. package/dist/utils/terminal.d.ts.map +1 -1
  267. package/dist/utils/terminal.js +20 -0
  268. package/dist/utils/terminal.js.map +1 -1
  269. package/dist/utils.d.ts +9 -0
  270. package/dist/utils.d.ts.map +1 -1
  271. package/dist/utils.js +33 -2
  272. package/dist/utils.js.map +1 -1
  273. package/dist/web/client/src/components/CodingAgentLaunchModal.d.ts.map +1 -1
  274. package/dist/web/client/src/components/CodingAgentLaunchModal.js +7 -16
  275. package/dist/web/client/src/components/CodingAgentLaunchModal.js.map +1 -1
  276. package/dist/web/client/src/components/branch-detail/BranchInfoCards.d.ts.map +1 -1
  277. package/dist/web/client/src/components/branch-detail/BranchInfoCards.js +7 -2
  278. package/dist/web/client/src/components/branch-detail/BranchInfoCards.js.map +1 -1
  279. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.d.ts.map +1 -1
  280. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js +2 -1
  281. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js.map +1 -1
  282. package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts +2 -2
  283. package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts.map +1 -1
  284. package/dist/web/client/src/components/branch-detail/ToolLauncher.js +5 -5
  285. package/dist/web/client/src/components/branch-detail/ToolLauncher.js.map +1 -1
  286. package/dist/web/client/src/components/ui/alert.d.ts +1 -1
  287. package/dist/web/client/src/lib/coding-agent-colors.d.ts +86 -0
  288. package/dist/web/client/src/lib/coding-agent-colors.d.ts.map +1 -0
  289. package/dist/web/client/src/lib/coding-agent-colors.js +135 -0
  290. package/dist/web/client/src/lib/coding-agent-colors.js.map +1 -0
  291. package/dist/web/client/src/pages/BranchDetailPage.js +10 -10
  292. package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
  293. package/dist/web/server/pty/manager.d.ts +2 -0
  294. package/dist/web/server/pty/manager.d.ts.map +1 -1
  295. package/dist/web/server/pty/manager.js +104 -0
  296. package/dist/web/server/pty/manager.js.map +1 -1
  297. package/dist/web/server/routes/sessions.d.ts.map +1 -1
  298. package/dist/web/server/routes/sessions.js +5 -1
  299. package/dist/web/server/routes/sessions.js.map +1 -1
  300. package/dist/web/server/services/branches.d.ts.map +1 -1
  301. package/dist/web/server/services/branches.js +10 -8
  302. package/dist/web/server/services/branches.js.map +1 -1
  303. package/dist/web/server/services/worktrees.js +2 -2
  304. package/dist/web/server/services/worktrees.js.map +1 -1
  305. package/dist/worktree.d.ts +50 -1
  306. package/dist/worktree.d.ts.map +1 -1
  307. package/dist/worktree.js +292 -100
  308. package/dist/worktree.js.map +1 -1
  309. package/package.json +13 -14
  310. package/src/claude.ts +129 -95
  311. package/src/cli/ui/App.solid.tsx +2096 -0
  312. package/src/cli/ui/__tests__/solid/AppSolid.cleanup.test.tsx +1084 -0
  313. package/src/cli/ui/__tests__/solid/BranchListScreen.test.tsx +343 -0
  314. package/src/cli/ui/__tests__/solid/ConfirmScreen.test.tsx +77 -0
  315. package/src/cli/ui/__tests__/solid/LogScreen.test.tsx +351 -0
  316. package/src/cli/ui/__tests__/solid/components/QuickStartStep.test.tsx +308 -0
  317. package/src/cli/ui/__tests__/solid/components/WizardPopup.test.tsx +231 -0
  318. package/src/cli/ui/__tests__/solid/components/WizardSteps.test.tsx +241 -0
  319. package/src/cli/ui/__tests__/utils/branchFormatter.test.ts +79 -334
  320. package/src/cli/ui/__tests__/utils/clipboard.test.ts +3 -3
  321. package/src/cli/ui/__tests__/utils/statisticsCalculator.test.ts +1 -1
  322. package/src/cli/ui/components/solid/Footer.tsx +36 -0
  323. package/src/cli/ui/components/{parts → solid}/Header.tsx +17 -28
  324. package/src/cli/ui/components/solid/HelpOverlay.tsx +194 -0
  325. package/src/cli/ui/components/solid/QuickStartStep.tsx +209 -0
  326. package/src/cli/ui/components/{parts → solid}/ScrollableList.tsx +7 -8
  327. package/src/cli/ui/components/solid/SearchInput.tsx +42 -0
  328. package/src/cli/ui/components/solid/SelectInput.tsx +88 -0
  329. package/src/cli/ui/components/solid/Stats.tsx +92 -0
  330. package/src/cli/ui/components/solid/TextInput.tsx +49 -0
  331. package/src/cli/ui/components/solid/WizardController.tsx +393 -0
  332. package/src/cli/ui/components/solid/WizardPopup.tsx +135 -0
  333. package/src/cli/ui/components/solid/WizardSteps.tsx +736 -0
  334. package/src/cli/ui/core/index.ts +17 -0
  335. package/src/cli/ui/core/keybindings.ts +367 -0
  336. package/src/cli/ui/core/theme.ts +266 -0
  337. package/src/cli/ui/core/types.ts +235 -0
  338. package/src/cli/ui/hooks/solid/useAsyncOperation.ts +78 -0
  339. package/src/cli/ui/hooks/solid/useFilter.ts +86 -0
  340. package/src/cli/ui/hooks/solid/useGitOperations.ts +81 -0
  341. package/src/cli/ui/hooks/solid/useKeyHandler.ts +103 -0
  342. package/src/cli/ui/hooks/solid/useScrollableList.ts +149 -0
  343. package/src/cli/ui/hooks/solid/useSelection.ts +77 -0
  344. package/src/cli/ui/hooks/solid/useTerminalSize.ts +22 -0
  345. package/src/cli/ui/index.solid.ts +28 -0
  346. package/src/cli/ui/screens/solid/BranchListScreen.tsx +1153 -0
  347. package/src/cli/ui/screens/solid/ConfirmScreen.tsx +86 -0
  348. package/src/cli/ui/screens/solid/EnvironmentScreen.tsx +161 -0
  349. package/src/cli/ui/screens/solid/ErrorScreen.tsx +42 -0
  350. package/src/cli/ui/screens/solid/InputScreen.tsx +55 -0
  351. package/src/cli/ui/screens/solid/LoadingIndicator.tsx +77 -0
  352. package/src/cli/ui/screens/solid/LogDetailScreen.tsx +75 -0
  353. package/src/cli/ui/screens/solid/LogScreen.tsx +504 -0
  354. package/src/cli/ui/screens/solid/ProfileEnvScreen.tsx +196 -0
  355. package/src/cli/ui/screens/solid/ProfileScreen.tsx +98 -0
  356. package/src/cli/ui/screens/solid/SelectorScreen.tsx +181 -0
  357. package/src/cli/ui/screens/solid/SettingsScreen.tsx +52 -0
  358. package/src/cli/ui/screens/solid/WorktreeCreateScreen.tsx +136 -0
  359. package/src/cli/ui/screens/solid/WorktreeDeleteScreen.tsx +40 -0
  360. package/src/cli/ui/stores/appStore.ts +208 -0
  361. package/src/cli/ui/stores/branchStore.ts +357 -0
  362. package/src/cli/ui/stores/index.ts +31 -0
  363. package/src/cli/ui/stores/uiStore.ts +226 -0
  364. package/src/cli/ui/types.ts +21 -3
  365. package/src/cli/ui/utils/__tests__/branchFormatter.test.ts +227 -0
  366. package/src/cli/ui/utils/branchFormatter.ts +43 -222
  367. package/src/cli/ui/utils/continueSession.ts +133 -2
  368. package/src/cli/ui/utils/modelOptions.test.ts +1 -1
  369. package/src/cli/ui/utils/versionCache.ts +93 -0
  370. package/src/cli/ui/utils/versionFetcher.ts +120 -0
  371. package/src/codex.ts +138 -39
  372. package/src/config/__tests__/saveSession.test.ts +143 -0
  373. package/src/config/builtin-coding-agents.ts +4 -4
  374. package/src/config/index.ts +14 -0
  375. package/src/gemini.ts +107 -46
  376. package/src/index.test.ts +25 -19
  377. package/src/index.ts +202 -143
  378. package/src/launcher.ts +66 -6
  379. package/src/logging/agentOutput.ts +216 -0
  380. package/src/logging/formatter.ts +23 -4
  381. package/src/logging/logger.ts +34 -10
  382. package/src/logging/reader.ts +117 -0
  383. package/src/opentui/index.solid.ts +1 -0
  384. package/src/repositories/worktree.repository.ts +8 -0
  385. package/src/services/__tests__/BatchMergeService.test.ts +83 -67
  386. package/src/services/__tests__/WorktreeOrchestrator.test.ts +8 -7
  387. package/src/services/codingAgentResolver.ts +30 -4
  388. package/src/services/dependency-installer.ts +2 -9
  389. package/src/types/api.ts +3 -0
  390. package/src/types/coding-agent.ts +85 -0
  391. package/src/types/tools.ts +19 -0
  392. package/src/utils/__tests__/npmRegistry.test.ts +250 -0
  393. package/src/utils/__tests__/prompt.test.ts +4 -5
  394. package/src/utils/coding-agent-colors.ts +165 -0
  395. package/src/utils/command.ts +1 -1
  396. package/src/utils/error-utils.ts +133 -0
  397. package/src/utils/npmRegistry.ts +249 -0
  398. package/src/utils/prompt.ts +1 -1
  399. package/src/utils/session/common.ts +28 -0
  400. package/src/utils/session/parsers/claude.ts +79 -29
  401. package/src/utils/session/parsers/codex.ts +50 -18
  402. package/src/utils/session/parsers/gemini.ts +46 -5
  403. package/src/utils/session/parsers/opencode.ts +46 -5
  404. package/src/utils/session/types.ts +4 -0
  405. package/src/utils/terminal.ts +24 -0
  406. package/src/utils.test.ts +1 -1
  407. package/src/utils.ts +37 -4
  408. package/src/web/client/src/components/CodingAgentLaunchModal.tsx +12 -21
  409. package/src/web/client/src/components/branch-detail/BranchInfoCards.tsx +16 -1
  410. package/src/web/client/src/components/branch-detail/SessionHistoryTable.tsx +7 -1
  411. package/src/web/client/src/components/branch-detail/ToolLauncher.tsx +11 -6
  412. package/src/web/client/src/lib/coding-agent-colors.ts +149 -0
  413. package/src/web/client/src/pages/BranchDetailPage.tsx +11 -11
  414. package/src/web/server/pty/manager.ts +139 -0
  415. package/src/web/server/routes/sessions.ts +6 -0
  416. package/src/web/server/services/branches.ts +11 -8
  417. package/src/web/server/services/worktrees.ts +2 -2
  418. package/src/worktree.ts +386 -114
  419. package/dist/cli/ui/components/App.d.ts +0 -25
  420. package/dist/cli/ui/components/App.d.ts.map +0 -1
  421. package/dist/cli/ui/components/App.js +0 -1006
  422. package/dist/cli/ui/components/App.js.map +0 -1
  423. package/dist/cli/ui/components/common/Confirm.d.ts +0 -13
  424. package/dist/cli/ui/components/common/Confirm.d.ts.map +0 -1
  425. package/dist/cli/ui/components/common/Confirm.js +0 -20
  426. package/dist/cli/ui/components/common/Confirm.js.map +0 -1
  427. package/dist/cli/ui/components/common/ErrorBoundary.d.ts +0 -23
  428. package/dist/cli/ui/components/common/ErrorBoundary.d.ts.map +0 -1
  429. package/dist/cli/ui/components/common/ErrorBoundary.js +0 -37
  430. package/dist/cli/ui/components/common/ErrorBoundary.js.map +0 -1
  431. package/dist/cli/ui/components/common/Input.d.ts +0 -19
  432. package/dist/cli/ui/components/common/Input.d.ts.map +0 -1
  433. package/dist/cli/ui/components/common/Input.js +0 -22
  434. package/dist/cli/ui/components/common/Input.js.map +0 -1
  435. package/dist/cli/ui/components/common/LoadingIndicator.d.ts +0 -19
  436. package/dist/cli/ui/components/common/LoadingIndicator.d.ts.map +0 -1
  437. package/dist/cli/ui/components/common/LoadingIndicator.js +0 -61
  438. package/dist/cli/ui/components/common/LoadingIndicator.js.map +0 -1
  439. package/dist/cli/ui/components/common/Select.d.ts +0 -38
  440. package/dist/cli/ui/components/common/Select.d.ts.map +0 -1
  441. package/dist/cli/ui/components/common/Select.js +0 -151
  442. package/dist/cli/ui/components/common/Select.js.map +0 -1
  443. package/dist/cli/ui/components/common/SpinnerIcon.d.ts +0 -20
  444. package/dist/cli/ui/components/common/SpinnerIcon.d.ts.map +0 -1
  445. package/dist/cli/ui/components/common/SpinnerIcon.js +0 -61
  446. package/dist/cli/ui/components/common/SpinnerIcon.js.map +0 -1
  447. package/dist/cli/ui/components/parts/Footer.d.ts +0 -15
  448. package/dist/cli/ui/components/parts/Footer.d.ts.map +0 -1
  449. package/dist/cli/ui/components/parts/Footer.js +0 -20
  450. package/dist/cli/ui/components/parts/Footer.js.map +0 -1
  451. package/dist/cli/ui/components/parts/Header.d.ts.map +0 -1
  452. package/dist/cli/ui/components/parts/Header.js +0 -24
  453. package/dist/cli/ui/components/parts/Header.js.map +0 -1
  454. package/dist/cli/ui/components/parts/MergeStatusList.d.ts +0 -13
  455. package/dist/cli/ui/components/parts/MergeStatusList.d.ts.map +0 -1
  456. package/dist/cli/ui/components/parts/MergeStatusList.js +0 -52
  457. package/dist/cli/ui/components/parts/MergeStatusList.js.map +0 -1
  458. package/dist/cli/ui/components/parts/ProgressBar.d.ts +0 -13
  459. package/dist/cli/ui/components/parts/ProgressBar.d.ts.map +0 -1
  460. package/dist/cli/ui/components/parts/ProgressBar.js +0 -53
  461. package/dist/cli/ui/components/parts/ProgressBar.js.map +0 -1
  462. package/dist/cli/ui/components/parts/ScrollableList.d.ts +0 -12
  463. package/dist/cli/ui/components/parts/ScrollableList.d.ts.map +0 -1
  464. package/dist/cli/ui/components/parts/ScrollableList.js +0 -11
  465. package/dist/cli/ui/components/parts/ScrollableList.js.map +0 -1
  466. package/dist/cli/ui/components/parts/Stats.d.ts +0 -10
  467. package/dist/cli/ui/components/parts/Stats.d.ts.map +0 -1
  468. package/dist/cli/ui/components/parts/Stats.js +0 -55
  469. package/dist/cli/ui/components/parts/Stats.js.map +0 -1
  470. package/dist/cli/ui/components/screens/BatchMergeProgressScreen.d.ts +0 -17
  471. package/dist/cli/ui/components/screens/BatchMergeProgressScreen.d.ts.map +0 -1
  472. package/dist/cli/ui/components/screens/BatchMergeProgressScreen.js +0 -42
  473. package/dist/cli/ui/components/screens/BatchMergeProgressScreen.js.map +0 -1
  474. package/dist/cli/ui/components/screens/BatchMergeResultScreen.d.ts +0 -17
  475. package/dist/cli/ui/components/screens/BatchMergeResultScreen.d.ts.map +0 -1
  476. package/dist/cli/ui/components/screens/BatchMergeResultScreen.js +0 -72
  477. package/dist/cli/ui/components/screens/BatchMergeResultScreen.js.map +0 -1
  478. package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts +0 -18
  479. package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts.map +0 -1
  480. package/dist/cli/ui/components/screens/BranchCreatorScreen.js +0 -151
  481. package/dist/cli/ui/components/screens/BranchCreatorScreen.js.map +0 -1
  482. package/dist/cli/ui/components/screens/BranchListScreen.d.ts +0 -60
  483. package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +0 -1
  484. package/dist/cli/ui/components/screens/BranchListScreen.js +0 -476
  485. package/dist/cli/ui/components/screens/BranchListScreen.js.map +0 -1
  486. package/dist/cli/ui/components/screens/BranchQuickStartScreen.d.ts +0 -30
  487. package/dist/cli/ui/components/screens/BranchQuickStartScreen.d.ts.map +0 -1
  488. package/dist/cli/ui/components/screens/BranchQuickStartScreen.js +0 -148
  489. package/dist/cli/ui/components/screens/BranchQuickStartScreen.js.map +0 -1
  490. package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.d.ts +0 -27
  491. package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.d.ts.map +0 -1
  492. package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.js +0 -93
  493. package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.js.map +0 -1
  494. package/dist/cli/ui/components/screens/EnvironmentProfileScreen.d.ts +0 -19
  495. package/dist/cli/ui/components/screens/EnvironmentProfileScreen.d.ts.map +0 -1
  496. package/dist/cli/ui/components/screens/EnvironmentProfileScreen.js +0 -577
  497. package/dist/cli/ui/components/screens/EnvironmentProfileScreen.js.map +0 -1
  498. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts +0 -45
  499. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts.map +0 -1
  500. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js +0 -95
  501. package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js.map +0 -1
  502. package/dist/cli/ui/components/screens/LogDatePickerScreen.d.ts +0 -10
  503. package/dist/cli/ui/components/screens/LogDatePickerScreen.d.ts.map +0 -1
  504. package/dist/cli/ui/components/screens/LogDatePickerScreen.js +0 -44
  505. package/dist/cli/ui/components/screens/LogDatePickerScreen.js.map +0 -1
  506. package/dist/cli/ui/components/screens/LogDetailScreen.d.ts.map +0 -1
  507. package/dist/cli/ui/components/screens/LogDetailScreen.js +0 -34
  508. package/dist/cli/ui/components/screens/LogDetailScreen.js.map +0 -1
  509. package/dist/cli/ui/components/screens/LogListScreen.d.ts.map +0 -1
  510. package/dist/cli/ui/components/screens/LogListScreen.js +0 -107
  511. package/dist/cli/ui/components/screens/LogListScreen.js.map +0 -1
  512. package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts +0 -24
  513. package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts.map +0 -1
  514. package/dist/cli/ui/components/screens/ModelSelectorScreen.js +0 -197
  515. package/dist/cli/ui/components/screens/ModelSelectorScreen.js.map +0 -1
  516. package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts +0 -29
  517. package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts.map +0 -1
  518. package/dist/cli/ui/components/screens/PRCleanupScreen.js +0 -92
  519. package/dist/cli/ui/components/screens/PRCleanupScreen.js.map +0 -1
  520. package/dist/cli/ui/components/screens/SessionSelectorScreen.d.ts +0 -31
  521. package/dist/cli/ui/components/screens/SessionSelectorScreen.d.ts.map +0 -1
  522. package/dist/cli/ui/components/screens/SessionSelectorScreen.js +0 -67
  523. package/dist/cli/ui/components/screens/SessionSelectorScreen.js.map +0 -1
  524. package/dist/cli/ui/hooks/useAppInput.d.ts +0 -21
  525. package/dist/cli/ui/hooks/useAppInput.d.ts.map +0 -1
  526. package/dist/cli/ui/hooks/useAppInput.js +0 -138
  527. package/dist/cli/ui/hooks/useAppInput.js.map +0 -1
  528. package/dist/cli/ui/hooks/useBatchMerge.d.ts +0 -17
  529. package/dist/cli/ui/hooks/useBatchMerge.d.ts.map +0 -1
  530. package/dist/cli/ui/hooks/useBatchMerge.js +0 -77
  531. package/dist/cli/ui/hooks/useBatchMerge.js.map +0 -1
  532. package/dist/cli/ui/hooks/useGitData.d.ts +0 -21
  533. package/dist/cli/ui/hooks/useGitData.d.ts.map +0 -1
  534. package/dist/cli/ui/hooks/useGitData.js +0 -229
  535. package/dist/cli/ui/hooks/useGitData.js.map +0 -1
  536. package/dist/cli/ui/hooks/useProfiles.d.ts +0 -41
  537. package/dist/cli/ui/hooks/useProfiles.d.ts.map +0 -1
  538. package/dist/cli/ui/hooks/useProfiles.js +0 -136
  539. package/dist/cli/ui/hooks/useProfiles.js.map +0 -1
  540. package/dist/cli/ui/hooks/useScreenState.d.ts +0 -12
  541. package/dist/cli/ui/hooks/useScreenState.d.ts.map +0 -1
  542. package/dist/cli/ui/hooks/useScreenState.js +0 -30
  543. package/dist/cli/ui/hooks/useScreenState.js.map +0 -1
  544. package/dist/cli/ui/hooks/useTerminalSize.d.ts +0 -9
  545. package/dist/cli/ui/hooks/useTerminalSize.d.ts.map +0 -1
  546. package/dist/cli/ui/hooks/useTerminalSize.js +0 -24
  547. package/dist/cli/ui/hooks/useTerminalSize.js.map +0 -1
  548. package/dist/cli/ui/hooks/useToolStatus.d.ts +0 -30
  549. package/dist/cli/ui/hooks/useToolStatus.d.ts.map +0 -1
  550. package/dist/cli/ui/hooks/useToolStatus.js +0 -49
  551. package/dist/cli/ui/hooks/useToolStatus.js.map +0 -1
  552. package/dist/cli/ui/screens/BranchActionSelectorScreen.d.ts +0 -24
  553. package/dist/cli/ui/screens/BranchActionSelectorScreen.d.ts.map +0 -1
  554. package/dist/cli/ui/screens/BranchActionSelectorScreen.js +0 -65
  555. package/dist/cli/ui/screens/BranchActionSelectorScreen.js.map +0 -1
  556. package/dist/client/assets/index-LNPtOrn3.js +0 -78
  557. package/src/cli/ui/__tests__/SKIPPED_TESTS.md +0 -119
  558. package/src/cli/ui/__tests__/acceptance/branchList.acceptance.test.tsx.skip +0 -239
  559. package/src/cli/ui/__tests__/acceptance/navigation.acceptance.test.tsx +0 -225
  560. package/src/cli/ui/__tests__/acceptance/realtimeUpdate.acceptance.test.tsx.skip +0 -219
  561. package/src/cli/ui/__tests__/components/App.protected-branch.test.tsx +0 -212
  562. package/src/cli/ui/__tests__/components/App.shortcuts.test.tsx +0 -440
  563. package/src/cli/ui/__tests__/components/App.test.tsx +0 -365
  564. package/src/cli/ui/__tests__/components/ModelSelectorScreen.initial.test.tsx +0 -91
  565. package/src/cli/ui/__tests__/components/common/Confirm.test.tsx +0 -80
  566. package/src/cli/ui/__tests__/components/common/ErrorBoundary.test.tsx +0 -104
  567. package/src/cli/ui/__tests__/components/common/Input.test.tsx +0 -100
  568. package/src/cli/ui/__tests__/components/common/LoadingIndicator.test.tsx +0 -148
  569. package/src/cli/ui/__tests__/components/common/Select.memo.test.tsx +0 -255
  570. package/src/cli/ui/__tests__/components/common/Select.test.tsx +0 -335
  571. package/src/cli/ui/__tests__/components/parts/Footer.test.tsx +0 -65
  572. package/src/cli/ui/__tests__/components/parts/Header.test.tsx +0 -55
  573. package/src/cli/ui/__tests__/components/parts/ScrollableList.test.tsx +0 -69
  574. package/src/cli/ui/__tests__/components/parts/Stats.test.tsx +0 -148
  575. package/src/cli/ui/__tests__/components/screens/BranchCreatorScreen.test.tsx +0 -253
  576. package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +0 -1070
  577. package/src/cli/ui/__tests__/components/screens/BranchQuickStartScreen.test.tsx +0 -142
  578. package/src/cli/ui/__tests__/components/screens/CodingAgentSelectorScreen.test.tsx +0 -174
  579. package/src/cli/ui/__tests__/components/screens/ExecutionModeSelectorScreen.test.tsx +0 -182
  580. package/src/cli/ui/__tests__/components/screens/LogDetailScreen.test.tsx +0 -57
  581. package/src/cli/ui/__tests__/components/screens/LogListScreen.test.tsx +0 -102
  582. package/src/cli/ui/__tests__/components/screens/PRCleanupScreen.test.tsx +0 -216
  583. package/src/cli/ui/__tests__/components/screens/SessionSelectorScreen.test.tsx +0 -147
  584. package/src/cli/ui/__tests__/hooks/useGitData.nonblocking.test.tsx +0 -206
  585. package/src/cli/ui/__tests__/hooks/useGitData.test.ts +0 -197
  586. package/src/cli/ui/__tests__/hooks/useGitData.test.ts.skip +0 -228
  587. package/src/cli/ui/__tests__/hooks/useScreenState.test.ts +0 -147
  588. package/src/cli/ui/__tests__/hooks/useTerminalSize.test.ts +0 -99
  589. package/src/cli/ui/__tests__/integration/branchList.test.tsx.skip +0 -253
  590. package/src/cli/ui/__tests__/integration/edgeCases.test.tsx +0 -436
  591. package/src/cli/ui/__tests__/integration/navigation.test.tsx +0 -514
  592. package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx +0 -509
  593. package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx.skip +0 -216
  594. package/src/cli/ui/__tests__/performance/branchList.performance.test.tsx +0 -193
  595. package/src/cli/ui/__tests__/performance/useMemoOptimization.test.tsx +0 -234
  596. package/src/cli/ui/components/App.tsx +0 -1478
  597. package/src/cli/ui/components/common/Confirm.tsx +0 -44
  598. package/src/cli/ui/components/common/ErrorBoundary.tsx +0 -60
  599. package/src/cli/ui/components/common/Input.tsx +0 -58
  600. package/src/cli/ui/components/common/LoadingIndicator.tsx +0 -98
  601. package/src/cli/ui/components/common/Select.tsx +0 -247
  602. package/src/cli/ui/components/common/SpinnerIcon.tsx +0 -86
  603. package/src/cli/ui/components/parts/Footer.tsx +0 -41
  604. package/src/cli/ui/components/parts/Header.test.tsx +0 -75
  605. package/src/cli/ui/components/parts/MergeStatusList.tsx +0 -75
  606. package/src/cli/ui/components/parts/ProgressBar.tsx +0 -73
  607. package/src/cli/ui/components/parts/Stats.tsx +0 -88
  608. package/src/cli/ui/components/screens/BatchMergeProgressScreen.tsx +0 -74
  609. package/src/cli/ui/components/screens/BatchMergeResultScreen.tsx +0 -108
  610. package/src/cli/ui/components/screens/BranchCreatorScreen.tsx +0 -242
  611. package/src/cli/ui/components/screens/BranchListScreen.tsx +0 -744
  612. package/src/cli/ui/components/screens/BranchQuickStartScreen.tsx +0 -244
  613. package/src/cli/ui/components/screens/CodingAgentSelectorScreen.tsx +0 -159
  614. package/src/cli/ui/components/screens/EnvironmentProfileScreen.tsx +0 -928
  615. package/src/cli/ui/components/screens/ExecutionModeSelectorScreen.tsx +0 -176
  616. package/src/cli/ui/components/screens/LogDatePickerScreen.tsx +0 -83
  617. package/src/cli/ui/components/screens/LogDetailScreen.tsx +0 -67
  618. package/src/cli/ui/components/screens/LogListScreen.tsx +0 -192
  619. package/src/cli/ui/components/screens/ModelSelectorScreen.tsx +0 -320
  620. package/src/cli/ui/components/screens/PRCleanupScreen.tsx +0 -171
  621. package/src/cli/ui/components/screens/SessionSelectorScreen.tsx +0 -135
  622. package/src/cli/ui/hooks/useAppInput.ts +0 -172
  623. package/src/cli/ui/hooks/useBatchMerge.ts +0 -96
  624. package/src/cli/ui/hooks/useGitData.ts +0 -347
  625. package/src/cli/ui/hooks/useProfiles.ts +0 -211
  626. package/src/cli/ui/hooks/useScreenState.ts +0 -44
  627. package/src/cli/ui/hooks/useTerminalSize.ts +0 -33
  628. package/src/cli/ui/hooks/useToolStatus.ts +0 -68
  629. package/src/cli/ui/screens/BranchActionSelectorScreen.tsx +0 -111
  630. package/src/cli/ui/screens/__tests__/BranchActionSelectorScreen.test.tsx +0 -264
package/src/worktree.ts CHANGED
@@ -1,12 +1,16 @@
1
1
  import { execa } from "execa";
2
- import fs from "node:fs/promises";
2
+ import { lstat, mkdir, readFile, rm } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import chalk from "chalk";
5
+ import { createLogger } from "./logging/logger.js";
6
+
7
+ const logger = createLogger({ category: "worktree" });
5
8
  import {
6
9
  WorktreeConfig,
7
10
  WorktreeWithPR,
8
11
  CleanupTarget,
9
12
  CleanupReason,
13
+ CleanupStatus,
10
14
  } from "./cli/ui/types.js";
11
15
  import { getPullRequestByBranch } from "./github.js";
12
16
  import {
@@ -44,6 +48,65 @@ async function getUpstreamBranch(branch: string): Promise<string | null> {
44
48
  }
45
49
  }
46
50
 
51
+ const parseRemoteRef = (
52
+ ref: string,
53
+ ): { remote: string; branch: string } | null => {
54
+ const segments = ref.split("/");
55
+ if (segments.length < 2) {
56
+ return null;
57
+ }
58
+ const [remote, ...rest] = segments;
59
+ const branch = rest.join("/");
60
+ if (!remote || !branch) {
61
+ return null;
62
+ }
63
+ return { remote, branch };
64
+ };
65
+
66
+ async function resolveUpstreamStatus(
67
+ branch: string,
68
+ repoRoot: string,
69
+ ): Promise<{ upstream: string | null; hasUpstream: boolean }> {
70
+ const upstream = await getUpstreamBranch(branch);
71
+ if (!upstream) {
72
+ return { upstream: null, hasUpstream: false };
73
+ }
74
+ const parsed = parseRemoteRef(upstream);
75
+ if (!parsed) {
76
+ return { upstream, hasUpstream: false };
77
+ }
78
+ if (parsed.branch !== branch) {
79
+ return { upstream, hasUpstream: false };
80
+ }
81
+ const exists = await checkRemoteBranchExists(parsed.branch, parsed.remote, {
82
+ cwd: repoRoot,
83
+ });
84
+ return { upstream, hasUpstream: exists };
85
+ }
86
+
87
+ const buildCleanupReasons = ({
88
+ hasUniqueCommits,
89
+ hasUncommitted,
90
+ hasUnpushed,
91
+ hasUpstream,
92
+ }: {
93
+ hasUniqueCommits: boolean;
94
+ hasUncommitted: boolean;
95
+ hasUnpushed: boolean;
96
+ hasUpstream: boolean;
97
+ }): CleanupReason[] => {
98
+ if (!hasUpstream) {
99
+ return [];
100
+ }
101
+ if (!hasUniqueCommits && !hasUncommitted && !hasUnpushed) {
102
+ return ["no-diff-with-base"];
103
+ }
104
+ if (hasUniqueCommits && !hasUncommitted && !hasUnpushed) {
105
+ return ["remote-synced"];
106
+ }
107
+ return [];
108
+ };
109
+
47
110
  // Re-export WorktreeConfig for external use
48
111
  export type { WorktreeConfig };
49
112
 
@@ -109,9 +172,13 @@ export interface WorktreeInfo {
109
172
  path: string;
110
173
  branch: string;
111
174
  head: string;
175
+ locked?: boolean;
176
+ prunable?: boolean;
112
177
  isAccessible?: boolean;
113
178
  invalidReason?: string;
114
179
  hasUncommittedChanges?: boolean;
180
+ isLocked?: boolean;
181
+ isPrunable?: boolean;
115
182
  }
116
183
 
117
184
  async function listWorktrees(): Promise<WorktreeInfo[]> {
@@ -131,11 +198,37 @@ async function listWorktrees(): Promise<WorktreeInfo[]> {
131
198
  if (currentWorktree.path) {
132
199
  worktrees.push(currentWorktree as WorktreeInfo);
133
200
  }
134
- currentWorktree = { path: line.substring(9) };
201
+ currentWorktree = {
202
+ path: line.substring(9),
203
+ locked: false,
204
+ prunable: false,
205
+ isLocked: false,
206
+ isPrunable: false,
207
+ };
135
208
  } else if (line.startsWith("HEAD ")) {
136
209
  currentWorktree.head = line.substring(5);
137
210
  } else if (line.startsWith("branch ")) {
138
211
  currentWorktree.branch = line.substring(7).replace("refs/heads/", "");
212
+ } else if (line === "locked" || line.startsWith("locked ")) {
213
+ currentWorktree.locked = true;
214
+ currentWorktree.isLocked = true;
215
+ if (line.startsWith("locked ")) {
216
+ const reason = line.substring(7).trim();
217
+ if (reason) {
218
+ currentWorktree.invalidReason ??= reason;
219
+ }
220
+ }
221
+ } else if (line === "prunable" || line.startsWith("prunable ")) {
222
+ currentWorktree.prunable = true;
223
+ currentWorktree.isPrunable = true;
224
+ if (line.startsWith("prunable ")) {
225
+ const reason = line.substring(9).trim();
226
+ if (reason) {
227
+ currentWorktree.invalidReason ??= reason;
228
+ }
229
+ }
230
+ } else if (line.startsWith("reason ")) {
231
+ currentWorktree.invalidReason = line.substring(7);
139
232
  } else if (line === "") {
140
233
  if (currentWorktree.path) {
141
234
  worktrees.push(currentWorktree as WorktreeInfo);
@@ -154,6 +247,10 @@ async function listWorktrees(): Promise<WorktreeInfo[]> {
154
247
  }
155
248
  }
156
249
 
250
+ export async function listAllWorktrees(): Promise<WorktreeInfo[]> {
251
+ return listWorktrees();
252
+ }
253
+
157
254
  /**
158
255
  * 追加のworktree(メインworktreeを除く)の一覧を取得
159
256
  * @returns {Promise<WorktreeInfo[]>} worktree情報の配列
@@ -173,7 +270,8 @@ export async function listAdditionalWorktrees(): Promise<WorktreeInfo[]> {
173
270
  .filter((worktree) => worktree.path !== repoRoot)
174
271
  .map((worktree) => {
175
272
  // パスの存在を確認
176
- const isAccessible = fs.existsSync(worktree.path);
273
+ const exists = fs.existsSync(worktree.path);
274
+ const isAccessible = exists && !worktree.prunable;
177
275
 
178
276
  const result: WorktreeInfo = {
179
277
  ...worktree,
@@ -181,7 +279,11 @@ export async function listAdditionalWorktrees(): Promise<WorktreeInfo[]> {
181
279
  };
182
280
 
183
281
  if (!isAccessible) {
184
- result.invalidReason = "Path not accessible in current environment";
282
+ if (!exists) {
283
+ result.invalidReason = "Path not accessible in current environment";
284
+ } else if (worktree.prunable && !result.invalidReason) {
285
+ result.invalidReason = "Worktree is marked prunable";
286
+ }
185
287
  }
186
288
 
187
289
  return result;
@@ -313,9 +415,9 @@ async function assessStaleWorktreeDirectory(
313
415
  return { status: "stale", reason: "missing .git" };
314
416
  }
315
417
 
316
- let gitMetaStat: Awaited<ReturnType<typeof fs.lstat>>;
418
+ let gitMetaStat: Awaited<ReturnType<typeof lstat>>;
317
419
  try {
318
- gitMetaStat = await fs.lstat(gitMetaPath);
420
+ gitMetaStat = await lstat(gitMetaPath);
319
421
  } catch {
320
422
  return { status: "unknown", reason: "unable to stat .git" };
321
423
  }
@@ -330,7 +432,7 @@ async function assessStaleWorktreeDirectory(
330
432
 
331
433
  let gitMetaContents = "";
332
434
  try {
333
- gitMetaContents = await fs.readFile(gitMetaPath, "utf8");
435
+ gitMetaContents = await readFile(gitMetaPath, "utf8");
334
436
  } catch {
335
437
  return { status: "unknown", reason: "unable to read .git" };
336
438
  }
@@ -371,7 +473,7 @@ export async function createWorktree(config: WorktreeConfig): Promise<void> {
371
473
  try {
372
474
  const staleness = await assessStaleWorktreeDirectory(config.worktreePath);
373
475
  if (staleness.status === "stale") {
374
- await fs.rm(config.worktreePath, { recursive: true, force: true });
476
+ await rm(config.worktreePath, { recursive: true, force: true });
375
477
  } else if (staleness.status === "unknown") {
376
478
  const reason = staleness.reason ? ` (${staleness.reason})` : "";
377
479
  throw new WorktreeError(
@@ -382,7 +484,7 @@ export async function createWorktree(config: WorktreeConfig): Promise<void> {
382
484
  const worktreeParentDir = path.dirname(config.worktreePath);
383
485
 
384
486
  try {
385
- await fs.mkdir(worktreeParentDir, { recursive: true });
487
+ await mkdir(worktreeParentDir, { recursive: true });
386
488
  } catch (error: unknown) {
387
489
  const errorWithCode = error as { code?: unknown; message?: unknown };
388
490
  const code =
@@ -536,6 +638,174 @@ export async function removeWorktree(
536
638
  }
537
639
  }
538
640
 
641
+ export interface RepairResult {
642
+ repairedCount: number;
643
+ failedCount: number;
644
+ failures: Array<{ path: string; error: string }>;
645
+ }
646
+
647
+ /**
648
+ * Worktreeパス修復の結果
649
+ */
650
+ export interface RepairPathResult {
651
+ /** 修復成功 (git worktree repair) */
652
+ repaired: boolean;
653
+ /** 古いメタデータ削除成功 (git worktree remove --force) */
654
+ removed: boolean;
655
+ /** 修復後の新しいパス (repaired=trueの場合のみ) */
656
+ newPath?: string;
657
+ }
658
+
659
+ /**
660
+ * 単一のworktreeパスを修復する共通関数
661
+ *
662
+ * パターンA: 期待されるパスにディレクトリが存在する
663
+ * → git worktree repair <expectedPath> で修復
664
+ *
665
+ * パターンB: ディレクトリが存在しない(リモート環境で作成されたメタデータのみ残っている)
666
+ * → git worktree remove --force <currentPath> でメタデータを削除
667
+ *
668
+ * @param branch ブランチ名
669
+ * @param currentPath 現在gitメタデータに記録されているパス
670
+ * @param repoRoot リポジトリルートパス
671
+ * @returns 修復結果
672
+ */
673
+ export async function repairWorktreePath(
674
+ branch: string,
675
+ currentPath: string,
676
+ repoRoot: string,
677
+ ): Promise<RepairPathResult> {
678
+ const expectedPath = await generateWorktreePath(repoRoot, branch);
679
+ const fsSync = await import("node:fs");
680
+
681
+ if (fsSync.existsSync(expectedPath)) {
682
+ // パターンA: ディレクトリが存在する → repair
683
+ logger.info(
684
+ { branch, expectedPath, currentPath },
685
+ "repairWorktreePath: directory exists, attempting repair",
686
+ );
687
+ try {
688
+ await execa("git", ["worktree", "repair", expectedPath], {
689
+ cwd: repoRoot,
690
+ });
691
+ return { repaired: true, removed: false, newPath: expectedPath };
692
+ } catch (error) {
693
+ logger.warn(
694
+ { branch, expectedPath, error },
695
+ "repairWorktreePath: repair failed",
696
+ );
697
+ return { repaired: false, removed: false };
698
+ }
699
+ } else {
700
+ // パターンB: ディレクトリが存在しない → 古いメタデータを削除
701
+ logger.info(
702
+ { branch, currentPath, expectedPath },
703
+ "repairWorktreePath: directory not found, removing stale metadata",
704
+ );
705
+ try {
706
+ await execa("git", ["worktree", "remove", "--force", currentPath], {
707
+ cwd: repoRoot,
708
+ });
709
+ return { repaired: false, removed: true };
710
+ } catch (error) {
711
+ logger.warn(
712
+ { branch, currentPath, error },
713
+ "repairWorktreePath: remove failed",
714
+ );
715
+ return { repaired: false, removed: false };
716
+ }
717
+ }
718
+ }
719
+
720
+ /**
721
+ * Worktreeのパス不整合を修復
722
+ * 共通関数repairWorktreePathを使用して各ブランチを修復
723
+ * @param targetBranches 修復対象のブランチ名配列
724
+ * @returns 修復結果(成功数、失敗数、失敗詳細)
725
+ */
726
+ export async function repairWorktrees(
727
+ targetBranches: string[],
728
+ ): Promise<RepairResult> {
729
+ const result: RepairResult = {
730
+ repairedCount: 0,
731
+ failedCount: 0,
732
+ failures: [],
733
+ };
734
+
735
+ if (targetBranches.length === 0) {
736
+ return result;
737
+ }
738
+
739
+ // 修復前のworktree一覧を取得(現在のパスを知るため)
740
+ const beforeWorktrees = await listAdditionalWorktrees();
741
+ const worktreePathMap = new Map(
742
+ beforeWorktrees.map((w) => [w.branch, w.path]),
743
+ );
744
+
745
+ // デバッグログ: worktreeリストのブランチ名を出力
746
+ logger.info(
747
+ {
748
+ targetBranches,
749
+ worktreeBranches: beforeWorktrees.map((w) => ({
750
+ branch: w.branch,
751
+ path: w.path,
752
+ isAccessible: w.isAccessible,
753
+ })),
754
+ },
755
+ "repairWorktrees: before state",
756
+ );
757
+
758
+ const repoRoot = await getRepositoryRoot();
759
+
760
+ // 対象ブランチごとに共通関数を使用して修復
761
+ for (const branch of targetBranches) {
762
+ const currentPath = worktreePathMap.get(branch);
763
+ if (!currentPath) {
764
+ logger.warn({ branch }, "repairWorktrees: branch not found in worktrees");
765
+ result.failedCount++;
766
+ result.failures.push({
767
+ path: branch,
768
+ error: "Branch not found in worktrees",
769
+ });
770
+ continue;
771
+ }
772
+
773
+ const repairResult = await repairWorktreePath(
774
+ branch,
775
+ currentPath,
776
+ repoRoot,
777
+ );
778
+
779
+ if (repairResult.repaired) {
780
+ result.repairedCount++;
781
+ } else if (repairResult.removed) {
782
+ // メタデータ削除は「修復」としてカウント(新規作成が可能になるため)
783
+ result.repairedCount++;
784
+ } else {
785
+ result.failedCount++;
786
+ result.failures.push({
787
+ path: branch,
788
+ error: "Worktree repair failed",
789
+ });
790
+ }
791
+ }
792
+
793
+ // 修復後のアクセス可能性を確認(デバッグログ用)
794
+ const afterWorktrees = await listAdditionalWorktrees();
795
+ logger.info(
796
+ {
797
+ afterWorktrees: afterWorktrees.map((w) => ({
798
+ branch: w.branch,
799
+ path: w.path,
800
+ isAccessible: w.isAccessible,
801
+ })),
802
+ },
803
+ "repairWorktrees: after state",
804
+ );
805
+
806
+ return result;
807
+ }
808
+
539
809
  async function getWorktreesWithPRStatus(): Promise<WorktreeWithPR[]> {
540
810
  const worktrees = await listAdditionalWorktrees();
541
811
  const worktreesWithPR: WorktreeWithPR[] = [];
@@ -558,13 +828,15 @@ async function getWorktreesWithPRStatus(): Promise<WorktreeWithPR[]> {
558
828
  * worktreeに存在しないローカルブランチのクリーンアップ候補を取得
559
829
  * @returns {Promise<CleanupTarget[]>} クリーンアップ候補の配列
560
830
  */
561
- async function getOrphanedLocalBranches({
831
+ async function getOrphanedLocalBranchStatuses({
562
832
  baseBranch,
563
833
  repoRoot,
834
+ onProgress,
564
835
  }: {
565
836
  baseBranch: string;
566
837
  repoRoot: string;
567
- }): Promise<CleanupTarget[]> {
838
+ onProgress?: (status: CleanupStatus) => void;
839
+ }): Promise<CleanupStatus[]> {
568
840
  try {
569
841
  // 並列実行で高速化
570
842
  const [localBranches, worktrees] = await Promise.all([
@@ -572,7 +844,7 @@ async function getOrphanedLocalBranches({
572
844
  listAdditionalWorktrees(),
573
845
  ]);
574
846
 
575
- const cleanupTargets: CleanupTarget[] = [];
847
+ const statuses: CleanupStatus[] = [];
576
848
  const worktreeBranches = new Set(
577
849
  worktrees.map((w) => w.branch).filter(Boolean),
578
850
  );
@@ -616,20 +888,23 @@ async function getOrphanedLocalBranches({
616
888
  hasUnpushed = true;
617
889
  }
618
890
 
619
- const reasons: CleanupReason[] = [];
620
-
621
- const upstreamBranch = await getUpstreamBranch(localBranch.name);
622
- const comparisonBase = upstreamBranch ?? baseBranch;
891
+ const { upstream, hasUpstream } = await resolveUpstreamStatus(
892
+ localBranch.name,
893
+ repoRoot,
894
+ );
623
895
 
624
896
  const hasUniqueCommits = await branchHasUniqueCommitsComparedToBase(
625
897
  localBranch.name,
626
- comparisonBase,
898
+ baseBranch,
627
899
  repoRoot,
628
900
  );
629
901
 
630
- if (!hasUniqueCommits) {
631
- reasons.push("no-diff-with-base");
632
- }
902
+ const reasons = buildCleanupReasons({
903
+ hasUniqueCommits,
904
+ hasUncommitted: false,
905
+ hasUnpushed,
906
+ hasUpstream,
907
+ });
633
908
 
634
909
  if (process.env.DEBUG_CLEANUP) {
635
910
  console.log(
@@ -639,41 +914,30 @@ async function getOrphanedLocalBranches({
639
914
  );
640
915
  }
641
916
 
642
- let hasRemoteBranch = false;
643
- try {
644
- hasRemoteBranch = await checkRemoteBranchExists(localBranch.name);
645
- } catch {
646
- hasRemoteBranch = false;
647
- }
648
-
649
- if (!hasUnpushed && hasRemoteBranch && hasUniqueCommits) {
650
- reasons.push("remote-synced");
651
- }
652
-
653
- if (reasons.length > 0) {
654
- cleanupTargets.push({
655
- worktreePath: null, // worktreeは存在しない
656
- branch: localBranch.name,
657
- pullRequest: null,
658
- hasUncommittedChanges: false, // worktreeが存在しないため常にfalse
659
- hasUnpushedCommits: hasUnpushed,
660
- cleanupType: "branch-only",
661
- hasRemoteBranch,
662
- reasons,
663
- });
664
- }
917
+ const status: CleanupStatus = {
918
+ worktreePath: null, // worktreeは存在しない
919
+ branch: localBranch.name,
920
+ hasUncommittedChanges: false, // worktreeが存在しないため常にfalse
921
+ hasUnpushedCommits: hasUnpushed,
922
+ cleanupType: "branch-only",
923
+ hasRemoteBranch: hasUpstream,
924
+ hasUniqueCommits,
925
+ hasUpstream,
926
+ upstream,
927
+ reasons,
928
+ };
929
+ statuses.push(status);
930
+ onProgress?.(status);
665
931
  }
666
932
  }
667
933
 
668
934
  if (process.env.DEBUG_CLEANUP) {
669
935
  console.log(
670
- chalk.cyan(
671
- `Debug: Found ${cleanupTargets.length} orphaned branch cleanup targets`,
672
- ),
936
+ chalk.cyan(`Debug: Found ${statuses.length} orphaned branch statuses`),
673
937
  );
674
938
  }
675
939
 
676
- return cleanupTargets;
940
+ return statuses;
677
941
  } catch (error) {
678
942
  console.error(chalk.red("Error: Failed to get orphaned local branches"));
679
943
  if (process.env.DEBUG_CLEANUP) {
@@ -683,11 +947,11 @@ async function getOrphanedLocalBranches({
683
947
  }
684
948
  }
685
949
 
686
- /**
687
- * マージ済みPRに関連するworktreeおよびローカルブランチのクリーンアップ候補を取得
688
- * @returns {Promise<CleanupTarget[]>} クリーンアップ候補の配列
689
- */
690
- export async function getMergedPRWorktrees(): Promise<CleanupTarget[]> {
950
+ export async function getCleanupStatus({
951
+ onProgress,
952
+ }: {
953
+ onProgress?: (status: CleanupStatus) => void;
954
+ } = {}): Promise<CleanupStatus[]> {
691
955
  const [config, repoRoot, worktreesWithPR] = await Promise.all([
692
956
  getConfig(),
693
957
  getRepositoryRoot(),
@@ -695,11 +959,12 @@ export async function getMergedPRWorktrees(): Promise<CleanupTarget[]> {
695
959
  ]);
696
960
  const baseBranch = config.defaultBaseBranch || GIT_CONFIG.DEFAULT_BASE_BRANCH;
697
961
 
698
- const orphanedBranches = await getOrphanedLocalBranches({
962
+ const orphanedStatuses = await getOrphanedLocalBranchStatuses({
699
963
  baseBranch,
700
964
  repoRoot,
965
+ ...(onProgress ? { onProgress } : {}),
701
966
  });
702
- const cleanupTargets: CleanupTarget[] = [];
967
+ const statuses: CleanupStatus[] = [];
703
968
 
704
969
  if (process.env.DEBUG_CLEANUP) {
705
970
  console.log(chalk.cyan("Debug: Available worktrees:"));
@@ -709,32 +974,19 @@ export async function getMergedPRWorktrees(): Promise<CleanupTarget[]> {
709
974
  }
710
975
 
711
976
  for (const worktree of worktreesWithPR) {
712
- // 保護対象ブランチはスキップ
713
- if (isProtectedBranchName(worktree.branch)) {
714
- if (process.env.DEBUG_CLEANUP) {
715
- console.log(
716
- chalk.yellow(`Debug: Skipping protected branch ${worktree.branch}`),
717
- );
718
- }
719
- continue;
720
- }
721
-
722
977
  if (process.env.DEBUG_CLEANUP) {
723
978
  console.log(chalk.gray(`Debug: Checking worktree ${worktree.branch}`));
724
979
  }
725
980
 
726
- const cleanupReasons: CleanupReason[] = [];
727
-
728
981
  // worktreeパスの存在を確認
729
- const fs = await import("node:fs");
730
- // Some test environments mock node:fs without existsSync on the module root.
982
+ const fsSync = await import("node:fs");
731
983
  const existsSync =
732
- typeof fs.existsSync === "function"
733
- ? fs.existsSync
734
- : typeof (fs as { default?: { existsSync?: unknown } }).default
984
+ typeof fsSync.existsSync === "function"
985
+ ? fsSync.existsSync
986
+ : typeof (fsSync as { default?: { existsSync?: unknown } }).default
735
987
  ?.existsSync === "function"
736
- ? (fs as { default: { existsSync: (p: string) => boolean } }).default
737
- .existsSync
988
+ ? (fsSync as { default: { existsSync: (p: string) => boolean } })
989
+ .default.existsSync
738
990
  : null;
739
991
 
740
992
  const isAccessible = existsSync ? existsSync(worktree.worktreePath) : false;
@@ -743,14 +995,12 @@ export async function getMergedPRWorktrees(): Promise<CleanupTarget[]> {
743
995
  let hasUnpushed = false;
744
996
 
745
997
  if (isAccessible) {
746
- // worktreeが存在する場合のみ状態をチェック
747
998
  try {
748
999
  [hasUncommitted, hasUnpushed] = await Promise.all([
749
1000
  hasUncommittedChanges(worktree.worktreePath),
750
1001
  hasUnpushedCommits(worktree.worktreePath, worktree.branch),
751
1002
  ]);
752
1003
  } catch (error) {
753
- // エラーが発生した場合はデフォルト値を使用
754
1004
  if (process.env.DEBUG_CLEANUP) {
755
1005
  console.log(
756
1006
  chalk.yellow(
@@ -761,77 +1011,99 @@ export async function getMergedPRWorktrees(): Promise<CleanupTarget[]> {
761
1011
  }
762
1012
  }
763
1013
 
764
- let hasRemoteBranch = false;
765
- try {
766
- hasRemoteBranch = await checkRemoteBranchExists(worktree.branch);
767
- } catch {
768
- hasRemoteBranch = false;
769
- }
770
-
771
- const upstreamBranch = await getUpstreamBranch(worktree.branch);
772
- const comparisonBase = upstreamBranch ?? baseBranch;
1014
+ const { upstream, hasUpstream } = await resolveUpstreamStatus(
1015
+ worktree.branch,
1016
+ repoRoot,
1017
+ );
773
1018
 
774
1019
  const hasUniqueCommits = await branchHasUniqueCommitsComparedToBase(
775
1020
  worktree.branch,
776
- comparisonBase,
1021
+ baseBranch,
777
1022
  repoRoot,
778
1023
  );
779
1024
 
780
- // 差分がない場合はベース同等としてクリーンアップ候補
781
- if (!hasUniqueCommits) {
782
- cleanupReasons.push("no-diff-with-base");
783
- } else if (!hasUncommitted && !hasUnpushed && hasRemoteBranch) {
784
- // 未マージでも、ローカルに未コミット/未プッシュがなくリモートが最新ならローカルのみクリーンアップ許可
785
- cleanupReasons.push("remote-synced");
786
- }
1025
+ const reasons = buildCleanupReasons({
1026
+ hasUniqueCommits,
1027
+ hasUncommitted,
1028
+ hasUnpushed,
1029
+ hasUpstream,
1030
+ });
787
1031
 
788
1032
  if (process.env.DEBUG_CLEANUP) {
789
1033
  console.log(
790
1034
  chalk.gray(
791
- `Debug: Cleanup reasons for ${worktree.branch}: ${cleanupReasons.length > 0 ? cleanupReasons.join(", ") : "none"}`,
1035
+ `Debug: Cleanup reasons for ${worktree.branch}: ${reasons.length > 0 ? reasons.join(", ") : "none"}`,
792
1036
  ),
793
1037
  );
794
1038
  }
795
1039
 
796
- if (cleanupReasons.length === 0) {
797
- continue;
798
- }
799
-
800
- const target: CleanupTarget = {
1040
+ const status: CleanupStatus = {
801
1041
  worktreePath: worktree.worktreePath,
802
1042
  branch: worktree.branch,
803
- pullRequest: null,
804
1043
  hasUncommittedChanges: hasUncommitted,
805
1044
  hasUnpushedCommits: hasUnpushed,
806
1045
  cleanupType: "worktree-and-branch",
807
- hasRemoteBranch,
1046
+ hasRemoteBranch: hasUpstream,
1047
+ hasUniqueCommits,
1048
+ hasUpstream,
1049
+ upstream,
808
1050
  isAccessible,
809
- reasons: cleanupReasons,
1051
+ reasons,
1052
+ ...(isAccessible
1053
+ ? {}
1054
+ : { invalidReason: "Path not accessible in current environment" }),
810
1055
  };
811
-
812
- if (!isAccessible) {
813
- target.invalidReason = "Path not accessible in current environment";
814
- }
815
-
816
- cleanupTargets.push(target);
1056
+ statuses.push(status);
1057
+ onProgress?.(status);
817
1058
  }
818
1059
 
819
- // orphanedBranches (ローカルブランチのみの削除対象) を追加
820
- cleanupTargets.push(...orphanedBranches);
1060
+ statuses.push(...orphanedStatuses);
821
1061
 
822
1062
  if (process.env.DEBUG_CLEANUP) {
823
- const worktreeTargets = cleanupTargets.filter(
824
- (t) => t.cleanupType === "worktree-and-branch",
1063
+ const worktreeTargets = statuses.filter(
1064
+ (t) => t.cleanupType === "worktree-and-branch" && t.reasons.length > 0,
825
1065
  ).length;
826
- const branchOnlyTargets = cleanupTargets.filter(
827
- (t) => t.cleanupType === "branch-only",
1066
+ const branchOnlyTargets = statuses.filter(
1067
+ (t) => t.cleanupType === "branch-only" && t.reasons.length > 0,
828
1068
  ).length;
829
1069
  console.log(
830
1070
  chalk.cyan(
831
- `Debug: Found ${cleanupTargets.length} cleanup targets (${worktreeTargets} worktree+branch, ${branchOnlyTargets} branch-only)`,
1071
+ `Debug: Found ${worktreeTargets + branchOnlyTargets} cleanup targets (${worktreeTargets} worktree+branch, ${branchOnlyTargets} branch-only)`,
832
1072
  ),
833
1073
  );
834
1074
  }
835
1075
 
1076
+ return statuses;
1077
+ }
1078
+
1079
+ /**
1080
+ * マージ済みPRに関連するworktreeおよびローカルブランチのクリーンアップ候補を取得
1081
+ * @returns {Promise<CleanupTarget[]>} クリーンアップ候補の配列
1082
+ */
1083
+ export async function getMergedPRWorktrees(): Promise<CleanupTarget[]> {
1084
+ const statuses = await getCleanupStatus();
1085
+ const cleanupTargets = statuses
1086
+ .filter((status) => status.reasons.length > 0)
1087
+ .filter((status) => !isProtectedBranchName(status.branch))
1088
+ .map((status) => {
1089
+ const target: CleanupTarget = {
1090
+ worktreePath: status.worktreePath,
1091
+ branch: status.branch,
1092
+ pullRequest: null,
1093
+ hasUncommittedChanges: status.hasUncommittedChanges,
1094
+ hasUnpushedCommits: status.hasUnpushedCommits,
1095
+ cleanupType: status.cleanupType,
1096
+ hasRemoteBranch: status.hasRemoteBranch,
1097
+ reasons: status.reasons,
1098
+ };
1099
+ if (status.isAccessible !== undefined) {
1100
+ target.isAccessible = status.isAccessible;
1101
+ }
1102
+ if (status.invalidReason) {
1103
+ target.invalidReason = status.invalidReason;
1104
+ }
1105
+ return target;
1106
+ });
1107
+
836
1108
  return cleanupTargets;
837
1109
  }