@akiojin/gwt 2.12.1 → 2.14.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 (344) hide show
  1. package/README.ja.md +33 -0
  2. package/README.md +31 -0
  3. package/dist/claude.d.ts.map +1 -1
  4. package/dist/claude.js +17 -11
  5. package/dist/claude.js.map +1 -1
  6. package/dist/cli/ui/components/App.d.ts +0 -6
  7. package/dist/cli/ui/components/App.d.ts.map +1 -1
  8. package/dist/cli/ui/components/App.js +93 -85
  9. package/dist/cli/ui/components/App.js.map +1 -1
  10. package/dist/cli/ui/components/common/Select.js +2 -2
  11. package/dist/cli/ui/components/common/Select.js.map +1 -1
  12. package/dist/cli/ui/components/screens/BranchListScreen.d.ts +3 -1
  13. package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +1 -1
  14. package/dist/cli/ui/components/screens/BranchListScreen.js +168 -34
  15. package/dist/cli/ui/components/screens/BranchListScreen.js.map +1 -1
  16. package/dist/cli/ui/components/screens/BranchQuickStartScreen.d.ts.map +1 -1
  17. package/dist/cli/ui/components/screens/BranchQuickStartScreen.js +3 -3
  18. package/dist/cli/ui/components/screens/BranchQuickStartScreen.js.map +1 -1
  19. package/dist/cli/ui/hooks/useGitData.d.ts.map +1 -1
  20. package/dist/cli/ui/hooks/useGitData.js +17 -0
  21. package/dist/cli/ui/hooks/useGitData.js.map +1 -1
  22. package/dist/cli/ui/types.d.ts +2 -0
  23. package/dist/cli/ui/types.d.ts.map +1 -1
  24. package/dist/cli/ui/utils/branchFormatter.d.ts.map +1 -1
  25. package/dist/cli/ui/utils/branchFormatter.js +7 -2
  26. package/dist/cli/ui/utils/branchFormatter.js.map +1 -1
  27. package/dist/cli/ui/utils/continueSession.d.ts.map +1 -1
  28. package/dist/cli/ui/utils/continueSession.js +1 -1
  29. package/dist/cli/ui/utils/continueSession.js.map +1 -1
  30. package/dist/cli/ui/utils/modelOptions.d.ts.map +1 -1
  31. package/dist/cli/ui/utils/modelOptions.js +7 -0
  32. package/dist/cli/ui/utils/modelOptions.js.map +1 -1
  33. package/dist/client/assets/index-DPWWHorC.js +72 -0
  34. package/dist/client/assets/index-DsDNCy5f.css +1 -0
  35. package/dist/client/index.html +2 -2
  36. package/dist/codex.d.ts.map +1 -1
  37. package/dist/codex.js +21 -11
  38. package/dist/codex.js.map +1 -1
  39. package/dist/config/builtin-tools.d.ts.map +1 -1
  40. package/dist/config/builtin-tools.js +3 -2
  41. package/dist/config/builtin-tools.js.map +1 -1
  42. package/dist/config/shared-env.d.ts +41 -0
  43. package/dist/config/shared-env.d.ts.map +1 -0
  44. package/dist/config/shared-env.js +114 -0
  45. package/dist/config/shared-env.js.map +1 -0
  46. package/dist/gemini.d.ts.map +1 -1
  47. package/dist/gemini.js +20 -17
  48. package/dist/gemini.js.map +1 -1
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +55 -7
  51. package/dist/index.js.map +1 -1
  52. package/dist/logging/logger.d.ts +24 -0
  53. package/dist/logging/logger.d.ts.map +1 -0
  54. package/dist/logging/logger.js +60 -0
  55. package/dist/logging/logger.js.map +1 -0
  56. package/dist/logging/rotation.d.ts +6 -0
  57. package/dist/logging/rotation.d.ts.map +1 -0
  58. package/dist/logging/rotation.js +26 -0
  59. package/dist/logging/rotation.js.map +1 -0
  60. package/dist/qwen.d.ts.map +1 -1
  61. package/dist/qwen.js +15 -11
  62. package/dist/qwen.js.map +1 -1
  63. package/dist/services/aiToolResolver.d.ts +41 -0
  64. package/dist/services/aiToolResolver.d.ts.map +1 -0
  65. package/dist/services/aiToolResolver.js +194 -0
  66. package/dist/services/aiToolResolver.js.map +1 -0
  67. package/dist/services/customToolResolver.d.ts +10 -0
  68. package/dist/services/customToolResolver.d.ts.map +1 -0
  69. package/dist/services/customToolResolver.js +71 -0
  70. package/dist/services/customToolResolver.js.map +1 -0
  71. package/dist/shared/aiToolConstants.d.ts +9 -0
  72. package/dist/shared/aiToolConstants.d.ts.map +1 -0
  73. package/dist/shared/aiToolConstants.js +29 -0
  74. package/dist/shared/aiToolConstants.js.map +1 -0
  75. package/dist/types/tools.d.ts +12 -0
  76. package/dist/types/tools.d.ts.map +1 -1
  77. package/dist/utils/prompt.d.ts.map +1 -1
  78. package/dist/utils/prompt.js.map +1 -1
  79. package/dist/utils/session.d.ts.map +1 -1
  80. package/dist/utils/session.js +15 -6
  81. package/dist/utils/session.js.map +1 -1
  82. package/dist/utils/terminal.d.ts +12 -3
  83. package/dist/utils/terminal.d.ts.map +1 -1
  84. package/dist/utils/terminal.js +5 -34
  85. package/dist/utils/terminal.js.map +1 -1
  86. package/dist/utils/webui.d.ts +8 -0
  87. package/dist/utils/webui.d.ts.map +1 -0
  88. package/dist/utils/webui.js +35 -0
  89. package/dist/utils/webui.js.map +1 -0
  90. package/dist/web/client/src/components/AIToolLaunchModal.d.ts +9 -0
  91. package/dist/web/client/src/components/AIToolLaunchModal.d.ts.map +1 -0
  92. package/dist/web/client/src/components/AIToolLaunchModal.js +363 -0
  93. package/dist/web/client/src/components/AIToolLaunchModal.js.map +1 -0
  94. package/dist/web/client/src/components/BranchGraph.d.ts.map +1 -1
  95. package/dist/web/client/src/components/BranchGraph.js +46 -49
  96. package/dist/web/client/src/components/BranchGraph.js.map +1 -1
  97. package/dist/web/client/src/components/CustomToolForm.d.ts +23 -0
  98. package/dist/web/client/src/components/CustomToolForm.d.ts.map +1 -0
  99. package/dist/web/client/src/components/CustomToolForm.js +209 -0
  100. package/dist/web/client/src/components/CustomToolForm.js.map +1 -0
  101. package/dist/web/client/src/components/CustomToolList.d.ts +10 -0
  102. package/dist/web/client/src/components/CustomToolList.d.ts.map +1 -0
  103. package/dist/web/client/src/components/CustomToolList.js +57 -0
  104. package/dist/web/client/src/components/CustomToolList.js.map +1 -0
  105. package/dist/web/client/src/components/EnvEditor.d.ts.map +1 -1
  106. package/dist/web/client/src/components/EnvEditor.js +33 -26
  107. package/dist/web/client/src/components/EnvEditor.js.map +1 -1
  108. package/dist/web/client/src/components/EnvironmentEditor.d.ts +17 -0
  109. package/dist/web/client/src/components/EnvironmentEditor.d.ts.map +1 -0
  110. package/dist/web/client/src/components/EnvironmentEditor.js +22 -0
  111. package/dist/web/client/src/components/EnvironmentEditor.js.map +1 -0
  112. package/dist/web/client/src/components/Terminal.d.ts.map +1 -1
  113. package/dist/web/client/src/components/Terminal.js +10 -3
  114. package/dist/web/client/src/components/Terminal.js.map +1 -1
  115. package/dist/web/client/src/components/branch-detail/BranchInfoCards.d.ts +10 -0
  116. package/dist/web/client/src/components/branch-detail/BranchInfoCards.d.ts.map +1 -0
  117. package/dist/web/client/src/components/branch-detail/BranchInfoCards.js +104 -0
  118. package/dist/web/client/src/components/branch-detail/BranchInfoCards.js.map +1 -0
  119. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.d.ts +22 -0
  120. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.d.ts.map +1 -0
  121. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js +79 -0
  122. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js.map +1 -0
  123. package/dist/web/client/src/components/branch-detail/TerminalPanel.d.ts +11 -0
  124. package/dist/web/client/src/components/branch-detail/TerminalPanel.d.ts.map +1 -0
  125. package/dist/web/client/src/components/branch-detail/TerminalPanel.js +32 -0
  126. package/dist/web/client/src/components/branch-detail/TerminalPanel.js.map +1 -0
  127. package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts +40 -0
  128. package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts.map +1 -0
  129. package/dist/web/client/src/components/branch-detail/ToolLauncher.js +147 -0
  130. package/dist/web/client/src/components/branch-detail/ToolLauncher.js.map +1 -0
  131. package/dist/web/client/src/components/branch-detail/index.d.ts +5 -0
  132. package/dist/web/client/src/components/branch-detail/index.d.ts.map +1 -0
  133. package/dist/web/client/src/components/branch-detail/index.js +5 -0
  134. package/dist/web/client/src/components/branch-detail/index.js.map +1 -0
  135. package/dist/web/client/src/components/common/BranchCard.d.ts +17 -0
  136. package/dist/web/client/src/components/common/BranchCard.d.ts.map +1 -0
  137. package/dist/web/client/src/components/common/BranchCard.js +36 -0
  138. package/dist/web/client/src/components/common/BranchCard.js.map +1 -0
  139. package/dist/web/client/src/components/common/MetricCard.d.ts +10 -0
  140. package/dist/web/client/src/components/common/MetricCard.d.ts.map +1 -0
  141. package/dist/web/client/src/components/common/MetricCard.js +10 -0
  142. package/dist/web/client/src/components/common/MetricCard.js.map +1 -0
  143. package/dist/web/client/src/components/common/PageHeader.d.ts +12 -0
  144. package/dist/web/client/src/components/common/PageHeader.d.ts.map +1 -0
  145. package/dist/web/client/src/components/common/PageHeader.js +14 -0
  146. package/dist/web/client/src/components/common/PageHeader.js.map +1 -0
  147. package/dist/web/client/src/components/common/SearchInput.d.ts +14 -0
  148. package/dist/web/client/src/components/common/SearchInput.d.ts.map +1 -0
  149. package/dist/web/client/src/components/common/SearchInput.js +15 -0
  150. package/dist/web/client/src/components/common/SearchInput.js.map +1 -0
  151. package/dist/web/client/src/components/common/StatusBadge.d.ts +10 -0
  152. package/dist/web/client/src/components/common/StatusBadge.d.ts.map +1 -0
  153. package/dist/web/client/src/components/common/StatusBadge.js +15 -0
  154. package/dist/web/client/src/components/common/StatusBadge.js.map +1 -0
  155. package/dist/web/client/src/components/common/index.d.ts +6 -0
  156. package/dist/web/client/src/components/common/index.d.ts.map +1 -0
  157. package/dist/web/client/src/components/common/index.js +6 -0
  158. package/dist/web/client/src/components/common/index.js.map +1 -0
  159. package/dist/web/client/src/components/ui/alert.d.ts +9 -0
  160. package/dist/web/client/src/components/ui/alert.d.ts.map +1 -0
  161. package/dist/web/client/src/components/ui/alert.js +25 -0
  162. package/dist/web/client/src/components/ui/alert.js.map +1 -0
  163. package/dist/web/client/src/components/ui/badge.d.ts +10 -0
  164. package/dist/web/client/src/components/ui/badge.d.ts.map +1 -0
  165. package/dist/web/client/src/components/ui/badge.js +25 -0
  166. package/dist/web/client/src/components/ui/badge.js.map +1 -0
  167. package/dist/web/client/src/components/ui/button.d.ts +12 -0
  168. package/dist/web/client/src/components/ui/button.d.ts.map +1 -0
  169. package/dist/web/client/src/components/ui/button.js +33 -0
  170. package/dist/web/client/src/components/ui/button.js.map +1 -0
  171. package/dist/web/client/src/components/ui/card.d.ts +9 -0
  172. package/dist/web/client/src/components/ui/card.d.ts.map +1 -0
  173. package/dist/web/client/src/components/ui/card.js +16 -0
  174. package/dist/web/client/src/components/ui/card.js.map +1 -0
  175. package/dist/web/client/src/components/ui/index.d.ts +8 -0
  176. package/dist/web/client/src/components/ui/index.d.ts.map +1 -0
  177. package/dist/web/client/src/components/ui/index.js +8 -0
  178. package/dist/web/client/src/components/ui/index.js.map +1 -0
  179. package/dist/web/client/src/components/ui/input.d.ts +4 -0
  180. package/dist/web/client/src/components/ui/input.d.ts.map +1 -0
  181. package/dist/web/client/src/components/ui/input.js +8 -0
  182. package/dist/web/client/src/components/ui/input.js.map +1 -0
  183. package/dist/web/client/src/components/ui/select.d.ts +14 -0
  184. package/dist/web/client/src/components/ui/select.d.ts.map +1 -0
  185. package/dist/web/client/src/components/ui/select.js +39 -0
  186. package/dist/web/client/src/components/ui/select.js.map +1 -0
  187. package/dist/web/client/src/components/ui/table.d.ts +11 -0
  188. package/dist/web/client/src/components/ui/table.d.ts.map +1 -0
  189. package/dist/web/client/src/components/ui/table.js +21 -0
  190. package/dist/web/client/src/components/ui/table.js.map +1 -0
  191. package/dist/web/client/src/hooks/useSessions.d.ts.map +1 -1
  192. package/dist/web/client/src/hooks/useSessions.js +6 -1
  193. package/dist/web/client/src/hooks/useSessions.js.map +1 -1
  194. package/dist/web/client/src/lib/utils.d.ts +7 -0
  195. package/dist/web/client/src/lib/utils.d.ts.map +1 -0
  196. package/dist/web/client/src/lib/utils.js +10 -0
  197. package/dist/web/client/src/lib/utils.js.map +1 -0
  198. package/dist/web/client/src/lib/websocket.d.ts +7 -0
  199. package/dist/web/client/src/lib/websocket.d.ts.map +1 -1
  200. package/dist/web/client/src/lib/websocket.js +44 -0
  201. package/dist/web/client/src/lib/websocket.js.map +1 -1
  202. package/dist/web/client/src/pages/BranchDetailPage.d.ts.map +1 -1
  203. package/dist/web/client/src/pages/BranchDetailPage.js +113 -361
  204. package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
  205. package/dist/web/client/src/pages/BranchListPage.d.ts.map +1 -1
  206. package/dist/web/client/src/pages/BranchListPage.js +89 -127
  207. package/dist/web/client/src/pages/BranchListPage.js.map +1 -1
  208. package/dist/web/client/src/pages/ConfigManagementPage.d.ts.map +1 -1
  209. package/dist/web/client/src/pages/ConfigManagementPage.js +46 -41
  210. package/dist/web/client/src/pages/ConfigManagementPage.js.map +1 -1
  211. package/dist/web/client/src/pages/ConfigPage.d.ts +3 -0
  212. package/dist/web/client/src/pages/ConfigPage.d.ts.map +1 -0
  213. package/dist/web/client/src/pages/ConfigPage.js +216 -0
  214. package/dist/web/client/src/pages/ConfigPage.js.map +1 -0
  215. package/dist/web/client/vite.config.d.ts.map +1 -1
  216. package/dist/web/client/vite.config.js +8 -1
  217. package/dist/web/client/vite.config.js.map +1 -1
  218. package/dist/web/server/index.d.ts +24 -2
  219. package/dist/web/server/index.d.ts.map +1 -1
  220. package/dist/web/server/index.js +49 -18
  221. package/dist/web/server/index.js.map +1 -1
  222. package/dist/web/server/pty/manager.d.ts +12 -10
  223. package/dist/web/server/pty/manager.d.ts.map +1 -1
  224. package/dist/web/server/pty/manager.js +76 -43
  225. package/dist/web/server/pty/manager.js.map +1 -1
  226. package/dist/web/server/routes/branches.d.ts +2 -2
  227. package/dist/web/server/routes/branches.d.ts.map +1 -1
  228. package/dist/web/server/routes/branches.js.map +1 -1
  229. package/dist/web/server/routes/config.d.ts +2 -2
  230. package/dist/web/server/routes/config.d.ts.map +1 -1
  231. package/dist/web/server/routes/config.js.map +1 -1
  232. package/dist/web/server/routes/index.d.ts +2 -2
  233. package/dist/web/server/routes/index.d.ts.map +1 -1
  234. package/dist/web/server/routes/index.js.map +1 -1
  235. package/dist/web/server/routes/sessions.d.ts +2 -2
  236. package/dist/web/server/routes/sessions.d.ts.map +1 -1
  237. package/dist/web/server/routes/sessions.js +35 -2
  238. package/dist/web/server/routes/sessions.js.map +1 -1
  239. package/dist/web/server/routes/worktrees.d.ts +2 -2
  240. package/dist/web/server/routes/worktrees.d.ts.map +1 -1
  241. package/dist/web/server/routes/worktrees.js +2 -2
  242. package/dist/web/server/routes/worktrees.js.map +1 -1
  243. package/dist/web/server/services/worktrees.d.ts.map +1 -1
  244. package/dist/web/server/services/worktrees.js +7 -1
  245. package/dist/web/server/services/worktrees.js.map +1 -1
  246. package/dist/web/server/tray.d.ts +24 -0
  247. package/dist/web/server/tray.d.ts.map +1 -0
  248. package/dist/web/server/tray.js +79 -0
  249. package/dist/web/server/tray.js.map +1 -0
  250. package/dist/web/server/types.d.ts +4 -0
  251. package/dist/web/server/types.d.ts.map +1 -0
  252. package/dist/web/server/types.js +2 -0
  253. package/dist/web/server/types.js.map +1 -0
  254. package/dist/web/server/websocket/handler.d.ts +18 -2
  255. package/dist/web/server/websocket/handler.d.ts.map +1 -1
  256. package/dist/web/server/websocket/handler.js +82 -9
  257. package/dist/web/server/websocket/handler.js.map +1 -1
  258. package/dist/worktree.d.ts +1 -0
  259. package/dist/worktree.d.ts.map +1 -1
  260. package/dist/worktree.js.map +1 -1
  261. package/package.json +17 -3
  262. package/src/claude.ts +26 -15
  263. package/src/cli/ui/__tests__/components/ModelSelectorScreen.initial.test.tsx +13 -13
  264. package/src/cli/ui/__tests__/components/common/Select.test.tsx +11 -0
  265. package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +97 -33
  266. package/src/cli/ui/__tests__/components/screens/BranchQuickStartScreen.test.tsx +4 -4
  267. package/src/cli/ui/__tests__/performance/branchList.performance.test.tsx +7 -3
  268. package/src/cli/ui/components/App.tsx +111 -125
  269. package/src/cli/ui/components/common/Select.tsx +2 -2
  270. package/src/cli/ui/components/screens/BranchListScreen.tsx +220 -34
  271. package/src/cli/ui/components/screens/BranchQuickStartScreen.tsx +41 -46
  272. package/src/cli/ui/hooks/useGitData.ts +20 -0
  273. package/src/cli/ui/types.ts +3 -0
  274. package/src/cli/ui/utils/branchFormatter.ts +7 -2
  275. package/src/cli/ui/utils/continueSession.ts +1 -7
  276. package/src/cli/ui/utils/modelOptions.test.ts +14 -0
  277. package/src/cli/ui/utils/modelOptions.ts +7 -0
  278. package/src/codex.ts +31 -22
  279. package/src/config/builtin-tools.ts +6 -2
  280. package/src/config/shared-env.ts +139 -0
  281. package/src/gemini.ts +35 -22
  282. package/src/index.ts +61 -7
  283. package/src/logging/logger.ts +82 -0
  284. package/src/logging/rotation.ts +25 -0
  285. package/src/qwen.ts +28 -19
  286. package/src/services/aiToolResolver.ts +276 -0
  287. package/src/services/customToolResolver.ts +98 -0
  288. package/src/shared/aiToolConstants.ts +30 -0
  289. package/src/trayicon.d.ts +30 -0
  290. package/src/types/tools.ts +15 -0
  291. package/src/utils/prompt.ts +15 -9
  292. package/src/utils/session.ts +80 -26
  293. package/src/utils/terminal.ts +11 -41
  294. package/src/utils/webui.ts +43 -0
  295. package/src/web/client/components.json +21 -0
  296. package/src/web/client/src/components/AIToolLaunchModal.tsx +575 -0
  297. package/src/web/client/src/components/BranchGraph.tsx +95 -75
  298. package/src/web/client/src/components/CustomToolForm.tsx +386 -0
  299. package/src/web/client/src/components/CustomToolList.tsx +119 -0
  300. package/src/web/client/src/components/EnvEditor.tsx +91 -81
  301. package/src/web/client/src/components/EnvironmentEditor.tsx +97 -0
  302. package/src/web/client/src/components/Terminal.tsx +11 -3
  303. package/src/web/client/src/components/branch-detail/BranchInfoCards.tsx +179 -0
  304. package/src/web/client/src/components/branch-detail/SessionHistoryTable.tsx +181 -0
  305. package/src/web/client/src/components/branch-detail/TerminalPanel.tsx +92 -0
  306. package/src/web/client/src/components/branch-detail/ToolLauncher.tsx +327 -0
  307. package/src/web/client/src/components/branch-detail/index.ts +4 -0
  308. package/src/web/client/src/components/common/BranchCard.tsx +117 -0
  309. package/src/web/client/src/components/common/MetricCard.tsx +22 -0
  310. package/src/web/client/src/components/common/PageHeader.tsx +44 -0
  311. package/src/web/client/src/components/common/SearchInput.tsx +40 -0
  312. package/src/web/client/src/components/common/StatusBadge.tsx +37 -0
  313. package/src/web/client/src/components/common/index.ts +5 -0
  314. package/src/web/client/src/components/ui/alert.tsx +63 -0
  315. package/src/web/client/src/components/ui/badge.tsx +44 -0
  316. package/src/web/client/src/components/ui/button.tsx +57 -0
  317. package/src/web/client/src/components/ui/card.tsx +82 -0
  318. package/src/web/client/src/components/ui/index.ts +32 -0
  319. package/src/web/client/src/components/ui/input.tsx +21 -0
  320. package/src/web/client/src/components/ui/select.tsx +156 -0
  321. package/src/web/client/src/components/ui/table.tsx +119 -0
  322. package/src/web/client/src/hooks/useSessions.ts +10 -1
  323. package/src/web/client/src/index.css +46 -816
  324. package/src/web/client/src/lib/utils.ts +10 -0
  325. package/src/web/client/src/lib/websocket.ts +48 -1
  326. package/src/web/client/src/pages/BranchDetailPage.tsx +222 -694
  327. package/src/web/client/src/pages/BranchListPage.tsx +190 -236
  328. package/src/web/client/src/pages/ConfigManagementPage.tsx +94 -76
  329. package/src/web/client/src/pages/ConfigPage.tsx +362 -0
  330. package/src/web/client/vite.config.ts +8 -1
  331. package/src/web/server/index.ts +78 -19
  332. package/src/web/server/pty/manager.ts +128 -55
  333. package/src/web/server/routes/branches.ts +2 -2
  334. package/src/web/server/routes/config.ts +2 -2
  335. package/src/web/server/routes/index.ts +2 -2
  336. package/src/web/server/routes/sessions.ts +61 -9
  337. package/src/web/server/routes/worktrees.ts +5 -5
  338. package/src/web/server/services/worktrees.ts +12 -4
  339. package/src/web/server/tray.ts +93 -0
  340. package/src/web/server/types.ts +14 -0
  341. package/src/web/server/websocket/handler.ts +119 -13
  342. package/src/worktree.ts +1 -0
  343. package/dist/client/assets/index-DeNwPosA.css +0 -1
  344. package/dist/client/assets/index-Dl798X5w.js +0 -32
@@ -14,23 +14,53 @@ import { PTYManager } from "./pty/manager.js";
14
14
  import { WebSocketHandler } from "./websocket/handler.js";
15
15
  import { registerRoutes } from "./routes/index.js";
16
16
  import { importOsEnvIntoSharedConfig } from "./env/importer.js";
17
+ import { createLogger } from "../../logging/logger.js";
18
+ import type { WebFastifyInstance } from "./types.js";
19
+ import { disposeSystemTray, startSystemTray } from "./tray.js";
20
+ import { resolveWebUiPort } from "../../utils/webui.js";
17
21
 
18
22
  const __filename = fileURLToPath(import.meta.url);
19
23
  const __dirname = dirname(__filename);
20
24
 
21
25
  /**
22
- * Webサーバーを起動
26
+ * Web UI サーバーのライフサイクル操作ハンドル。
27
+ *
28
+ * `close()` は Web UI サーバーを停止し、関連リソース(PTY/トレイ等)を解放します。
23
29
  */
24
- export async function startWebServer(): Promise<void> {
25
- const fastify = Fastify({
26
- logger: {
27
- level: process.env.LOG_LEVEL || "info",
28
- },
30
+ export interface WebServerHandle {
31
+ close: () => Promise<void>;
32
+ }
33
+
34
+ /**
35
+ * `startWebServer` の起動オプション。
36
+ */
37
+ export interface StartWebServerOptions {
38
+ /**
39
+ * true の場合、Web UI サーバーが CLI 本体の終了をブロックしないようにします。
40
+ * (内部で `server.unref()` を呼び、サーバーの存在がプロセス生存を維持しないようにします)
41
+ */
42
+ background?: boolean;
43
+ }
44
+
45
+ /**
46
+ * Web UI サーバーを起動します。
47
+ *
48
+ * @param options - 起動オプション
49
+ * @returns Web UI サーバー停止用のハンドル
50
+ * @throws サーバー起動(listen/初期化)に失敗した場合
51
+ */
52
+ export async function startWebServer(
53
+ options: StartWebServerOptions = {},
54
+ ): Promise<WebServerHandle> {
55
+ const serverLogger = createLogger({ category: "server" });
56
+
57
+ const fastify: WebFastifyInstance = Fastify({
58
+ loggerInstance: serverLogger,
29
59
  });
30
60
 
31
61
  // PTYマネージャーとWebSocketハンドラーを初期化
32
62
  const ptyManager = new PTYManager();
33
- const wsHandler = new WebSocketHandler(ptyManager);
63
+ const wsHandler = new WebSocketHandler(ptyManager, fastify.log);
34
64
 
35
65
  // WebSocketサポートを追加
36
66
  await fastify.register(fastifyWebsocket);
@@ -58,17 +88,46 @@ export async function startWebServer(): Promise<void> {
58
88
  });
59
89
 
60
90
  // サーバー起動
61
- try {
62
- const port = process.env.PORT ? parseInt(process.env.PORT, 10) : 3000;
63
- // Docker環境からホストOSでアクセスできるよう、0.0.0.0でリッスン
64
- // IPv4/IPv6両方対応のため、listenOnStart: false も検討可能
65
- const host = process.env.HOST || "0.0.0.0";
66
-
67
- await fastify.listen({ port, host });
68
- console.log(`Web UI server running at http://${host}:${port}`);
69
- console.log(`Access from host: http://localhost:${port}`);
70
- } catch (err) {
71
- fastify.log.error(err);
72
- process.exit(1);
91
+ const port = resolveWebUiPort();
92
+ // Docker環境からホストOSでアクセスできるよう、0.0.0.0でリッスン
93
+ // IPv4/IPv6両方対応のため、listenOnStart: false も検討可能
94
+ const host = process.env.HOST || "0.0.0.0";
95
+
96
+ await fastify.listen({ port, host });
97
+ const accessUrl = `http://localhost:${port}`;
98
+ serverLogger.info({ host, port, accessUrl }, "Web UI server started");
99
+ await startSystemTray(accessUrl);
100
+
101
+ if (options.background) {
102
+ fastify.server?.unref?.();
73
103
  }
104
+
105
+ let closed = false;
106
+ return {
107
+ close: async () => {
108
+ if (closed) return;
109
+ closed = true;
110
+
111
+ try {
112
+ try {
113
+ disposeSystemTray();
114
+ } catch (err) {
115
+ serverLogger.warn({ err }, "System tray cleanup failed");
116
+ }
117
+
118
+ for (const session of ptyManager.list()) {
119
+ try {
120
+ ptyManager.delete(session.sessionId);
121
+ } catch (err) {
122
+ serverLogger.warn(
123
+ { err, sessionId: session.sessionId },
124
+ "Failed to delete PTY session",
125
+ );
126
+ }
127
+ }
128
+ } finally {
129
+ await fastify.close();
130
+ }
131
+ },
132
+ };
74
133
  }
@@ -9,6 +9,14 @@ import * as pty from "node-pty";
9
9
  import type { IPty } from "node-pty";
10
10
  import { randomUUID } from "node:crypto";
11
11
  import type { AIToolSession } from "../../../types/api.js";
12
+ import {
13
+ resolveClaudeCommand,
14
+ resolveCodexCommand,
15
+ resolveCustomToolCommand,
16
+ AIToolResolutionError,
17
+ type ResolvedCommand,
18
+ } from "../../../services/aiToolResolver.js";
19
+ import { loadToolsConfig } from "../../../config/tools.js";
12
20
 
13
21
  export interface PTYInstance {
14
22
  ptyProcess: IPty;
@@ -24,37 +32,80 @@ export class PTYManager {
24
32
  /**
25
33
  * 新しいPTYセッションを作成
26
34
  */
27
- public spawn(
35
+ public async spawn(
28
36
  toolType: "claude-code" | "codex-cli" | "custom",
29
37
  worktreePath: string,
30
38
  mode: "normal" | "continue" | "resume",
31
- toolName?: string | null,
32
- cols = 80,
33
- rows = 24,
34
- ): { sessionId: string; session: AIToolSession } {
39
+ options: {
40
+ toolName?: string | null;
41
+ cols?: number;
42
+ rows?: number;
43
+ skipPermissions?: boolean;
44
+ bypassApprovals?: boolean;
45
+ extraArgs?: string[];
46
+ customToolId?: string | null;
47
+ } = {},
48
+ ): Promise<{ sessionId: string; session: AIToolSession }> {
49
+ const cols = options.cols ?? 80;
50
+ const rows = options.rows ?? 24;
51
+ const toolName = options.toolName ?? null;
35
52
  const sessionId = randomUUID();
36
53
 
37
- // AI Toolコマンドを構築
38
- const command = this.buildCommand(toolType, mode, toolName);
39
- const args = this.buildArgs(toolType, mode);
54
+ const resolverOptions: {
55
+ toolName?: string | null;
56
+ skipPermissions?: boolean;
57
+ bypassApprovals?: boolean;
58
+ extraArgs?: string[];
59
+ customToolId?: string | null;
60
+ } = {};
61
+
62
+ if (toolName !== null) {
63
+ resolverOptions.toolName = toolName;
64
+ }
65
+ if (options.skipPermissions !== undefined) {
66
+ resolverOptions.skipPermissions = options.skipPermissions;
67
+ }
68
+ if (options.bypassApprovals !== undefined) {
69
+ resolverOptions.bypassApprovals = options.bypassApprovals;
70
+ }
71
+ if (options.extraArgs && options.extraArgs.length > 0) {
72
+ resolverOptions.extraArgs = options.extraArgs;
73
+ }
74
+ if (options.customToolId !== undefined) {
75
+ resolverOptions.customToolId = options.customToolId;
76
+ }
77
+
78
+ const resolved = await this.resolveCommand(toolType, mode, resolverOptions);
79
+ const sharedEnv = await this.loadSharedEnv();
80
+
81
+ const env: NodeJS.ProcessEnv = {
82
+ ...process.env,
83
+ ...sharedEnv,
84
+ TERM: "xterm-256color",
85
+ COLORTERM: "truecolor",
86
+ };
87
+
88
+ if (resolved.env) {
89
+ Object.assign(env, resolved.env);
90
+ }
91
+
92
+ if (toolType === "claude-code" && options.skipPermissions && isRootUser()) {
93
+ env.IS_SANDBOX = "1";
94
+ }
40
95
 
41
96
  // PTYプロセスをスポーン
42
- const ptyProcess = pty.spawn(command, args, {
97
+ const ptyProcess = pty.spawn(resolved.command, resolved.args, {
43
98
  name: "xterm-256color",
44
99
  cols,
45
100
  rows,
46
101
  cwd: worktreePath,
47
- env: {
48
- ...process.env,
49
- TERM: "xterm-256color",
50
- COLORTERM: "truecolor",
51
- },
102
+ env,
52
103
  });
53
104
 
54
105
  const session: AIToolSession = {
55
106
  sessionId,
56
107
  toolType,
57
- toolName: toolName || null,
108
+ toolName: options.customToolId ?? toolName ?? null,
58
109
  mode,
59
110
  worktreePath,
60
111
  ptyPid: ptyProcess.pid,
@@ -133,57 +184,79 @@ export class PTYManager {
133
184
  return Array.from(this.instances.values()).map((inst) => inst.session);
134
185
  }
135
186
 
136
- /**
137
- * AI Toolのコマンドを構築
138
- */
139
- private buildCommand(
187
+ private async resolveCommand(
140
188
  toolType: "claude-code" | "codex-cli" | "custom",
141
189
  mode: "normal" | "continue" | "resume",
142
- toolName?: string | null,
143
- ): string {
144
- if (toolType === "custom" && toolName) {
145
- // カスタムツールは別途config.jsonから取得する必要があるが、
146
- // ここでは簡易実装としてtoolNameをそのままコマンドとして使用
147
- return toolName;
148
- }
149
-
150
- if (toolType === "codex-cli") {
151
- return "codex";
152
- }
153
-
154
- // claude-code
155
- return "claude";
156
- }
157
-
158
- /**
159
- * AI Toolの引数を構築
160
- */
161
- private buildArgs(
162
- toolType: "claude-code" | "codex-cli" | "custom",
163
- mode: "normal" | "continue" | "resume",
164
- ): string[] {
190
+ options: {
191
+ toolName?: string | null;
192
+ skipPermissions?: boolean;
193
+ bypassApprovals?: boolean;
194
+ extraArgs?: string[];
195
+ customToolId?: string | null;
196
+ },
197
+ ): Promise<ResolvedCommand> {
165
198
  if (toolType === "custom") {
166
- // カスタムツールの引数は別途config.jsonから取得
167
- return [];
199
+ const toolId = options.customToolId ?? options.toolName;
200
+ if (!toolId) {
201
+ throw new AIToolResolutionError(
202
+ "COMMAND_NOT_FOUND",
203
+ "Custom tool identifier is required to start a session.",
204
+ );
205
+ }
206
+
207
+ return resolveCustomToolCommand({
208
+ toolId,
209
+ mode,
210
+ ...(options.skipPermissions !== undefined
211
+ ? { skipPermissions: options.skipPermissions }
212
+ : {}),
213
+ ...(options.extraArgs ? { extraArgs: options.extraArgs } : {}),
214
+ });
168
215
  }
169
216
 
170
217
  if (toolType === "codex-cli") {
171
- if (mode === "continue") {
172
- return ["--continue"];
218
+ const codexOptions: {
219
+ mode: "normal" | "continue" | "resume";
220
+ bypassApprovals?: boolean;
221
+ extraArgs?: string[];
222
+ } = { mode };
223
+
224
+ if (options.bypassApprovals !== undefined) {
225
+ codexOptions.bypassApprovals = options.bypassApprovals;
173
226
  }
174
- if (mode === "resume") {
175
- return ["--resume"];
227
+ if (options.extraArgs && options.extraArgs.length > 0) {
228
+ codexOptions.extraArgs = options.extraArgs;
176
229
  }
177
- return [];
230
+
231
+ return resolveCodexCommand(codexOptions);
178
232
  }
179
233
 
180
- // claude-code
181
- if (mode === "continue") {
182
- return ["--continue"];
234
+ const claudeOptions: {
235
+ mode: "normal" | "continue" | "resume";
236
+ skipPermissions?: boolean;
237
+ extraArgs?: string[];
238
+ } = { mode };
239
+
240
+ if (options.skipPermissions !== undefined) {
241
+ claudeOptions.skipPermissions = options.skipPermissions;
183
242
  }
184
- if (mode === "resume") {
185
- return ["--resume"];
243
+ if (options.extraArgs && options.extraArgs.length > 0) {
244
+ claudeOptions.extraArgs = options.extraArgs;
186
245
  }
187
- return [];
246
+
247
+ return resolveClaudeCommand(claudeOptions);
248
+ }
249
+
250
+ private async loadSharedEnv(): Promise<Record<string, string>> {
251
+ const config = await loadToolsConfig();
252
+ return { ...(config.env ?? {}) };
253
+ }
254
+ }
255
+
256
+ function isRootUser(): boolean {
257
+ try {
258
+ return typeof process.getuid === "function" && process.getuid() === 0;
259
+ } catch {
260
+ return false;
188
261
  }
189
262
  }
@@ -4,7 +4,6 @@
4
4
  * ブランチ関連のREST APIエンドポイント。
5
5
  */
6
6
 
7
- import type { FastifyInstance } from "fastify";
8
7
  import {
9
8
  listBranches,
10
9
  getBranchByName,
@@ -16,12 +15,13 @@ import type {
16
15
  BranchSyncRequest,
17
16
  BranchSyncResult,
18
17
  } from "../../../types/api.js";
18
+ import type { WebFastifyInstance } from "../types.js";
19
19
 
20
20
  /**
21
21
  * ブランチ関連のルートを登録
22
22
  */
23
23
  export async function registerBranchRoutes(
24
- fastify: FastifyInstance,
24
+ fastify: WebFastifyInstance,
25
25
  ): Promise<void> {
26
26
  // GET /api/branches - すべてのブランチ一覧を取得
27
27
  fastify.get<{ Reply: ApiResponse<Branch[]> }>(
@@ -2,7 +2,6 @@
2
2
  * Config Routes
3
3
  */
4
4
 
5
- import type { FastifyInstance } from "fastify";
6
5
  import { loadToolsConfig, saveToolsConfig } from "../../../config/tools.js";
7
6
  import {
8
7
  loadEnvHistory,
@@ -17,6 +16,7 @@ import type {
17
16
  } from "../../../types/api.js";
18
17
  import type { CustomAITool as FileCustomAITool } from "../../../types/tools.js";
19
18
  import { getImportedEnvKeys } from "../env/importer.js";
19
+ import type { WebFastifyInstance } from "../types.js";
20
20
 
21
21
  function normalizeEnv(
22
22
  env: Record<string, string> | undefined,
@@ -135,7 +135,7 @@ function diffEnvHistory(
135
135
  }
136
136
 
137
137
  export async function registerConfigRoutes(
138
- fastify: FastifyInstance,
138
+ fastify: WebFastifyInstance,
139
139
  ): Promise<void> {
140
140
  fastify.get<{ Reply: ApiResponse<ConfigPayload> }>(
141
141
  "/api/config",
@@ -5,19 +5,19 @@
5
5
  * 仕様: specs/SPEC-d5e56259/contracts/rest-api.yaml
6
6
  */
7
7
 
8
- import type { FastifyInstance } from "fastify";
9
8
  import type { PTYManager } from "../pty/manager.js";
10
9
  import { registerBranchRoutes } from "./branches.js";
11
10
  import { registerWorktreeRoutes } from "./worktrees.js";
12
11
  import { registerSessionRoutes } from "./sessions.js";
13
12
  import { registerConfigRoutes } from "./config.js";
14
13
  import type { HealthResponse } from "../../../types/api.js";
14
+ import type { WebFastifyInstance } from "../types.js";
15
15
 
16
16
  /**
17
17
  * すべてのルートを登録
18
18
  */
19
19
  export async function registerRoutes(
20
- fastify: FastifyInstance,
20
+ fastify: WebFastifyInstance,
21
21
  ptyManager: PTYManager,
22
22
  ): Promise<void> {
23
23
  // ヘルスチェック
@@ -4,8 +4,8 @@
4
4
  * AI Toolセッション関連のREST APIエンドポイント。
5
5
  */
6
6
 
7
- import type { FastifyInstance } from "fastify";
8
7
  import type { PTYManager } from "../pty/manager.js";
8
+ import { AIToolResolutionError } from "../../../services/aiToolResolver.js";
9
9
  import type {
10
10
  ApiResponse,
11
11
  AIToolSession,
@@ -13,12 +13,13 @@ import type {
13
13
  } from "../../../types/api.js";
14
14
  import { saveSession } from "../../../config/index.js";
15
15
  import { execa } from "execa";
16
+ import type { WebFastifyInstance } from "../types.js";
16
17
 
17
18
  /**
18
19
  * セッション関連のルートを登録
19
20
  */
20
21
  export async function registerSessionRoutes(
21
- fastify: FastifyInstance,
22
+ fastify: WebFastifyInstance,
22
23
  ptyManager: PTYManager,
23
24
  ): Promise<void> {
24
25
  // GET /api/sessions - すべてのセッション一覧を取得
@@ -28,7 +29,7 @@ export async function registerSessionRoutes(
28
29
  try {
29
30
  const sessions = ptyManager.list();
30
31
  return { success: true, data: sessions };
31
- } catch (error) {
32
+ } catch (error: unknown) {
32
33
  const errorMsg = error instanceof Error ? error.message : String(error);
33
34
  reply.code(500);
34
35
  return {
@@ -46,13 +47,55 @@ export async function registerSessionRoutes(
46
47
  Reply: ApiResponse<AIToolSession>;
47
48
  }>("/api/sessions", async (request, reply) => {
48
49
  try {
49
- const { toolType, toolName, mode, worktreePath } = request.body;
50
+ const {
51
+ toolType,
52
+ toolName,
53
+ mode,
54
+ worktreePath,
55
+ skipPermissions,
56
+ bypassApprovals,
57
+ extraArgs,
58
+ customToolId,
59
+ } = request.body;
60
+
61
+ const spawnOptions: {
62
+ toolName?: string | null;
63
+ skipPermissions?: boolean;
64
+ bypassApprovals?: boolean;
65
+ extraArgs?: string[];
66
+ customToolId?: string | null;
67
+ } = {};
68
+
69
+ if (typeof toolName !== "undefined") {
70
+ spawnOptions.toolName = toolName;
71
+ }
72
+ if (typeof skipPermissions !== "undefined") {
73
+ spawnOptions.skipPermissions = skipPermissions;
74
+ }
75
+ if (typeof bypassApprovals !== "undefined") {
76
+ spawnOptions.bypassApprovals = bypassApprovals;
77
+ }
78
+ if (Array.isArray(extraArgs) && extraArgs.length > 0) {
79
+ spawnOptions.extraArgs = extraArgs;
80
+ }
81
+ if (typeof customToolId !== "undefined") {
82
+ spawnOptions.customToolId = customToolId;
83
+ }
50
84
 
51
- const { session } = ptyManager.spawn(
85
+ if (toolType === "custom" && !toolName && !customToolId) {
86
+ reply.code(400);
87
+ return {
88
+ success: false,
89
+ error: "Custom tool requires toolName or customToolId",
90
+ details: null,
91
+ };
92
+ }
93
+
94
+ const { session } = await ptyManager.spawn(
52
95
  toolType,
53
96
  worktreePath,
54
97
  mode,
55
- toolName,
98
+ spawnOptions,
56
99
  );
57
100
 
58
101
  // 履歴を永続化(best-effort)
@@ -95,7 +138,16 @@ export async function registerSessionRoutes(
95
138
 
96
139
  reply.code(201);
97
140
  return { success: true, data: session };
98
- } catch (error) {
141
+ } catch (error: unknown) {
142
+ if (error instanceof AIToolResolutionError) {
143
+ reply.code(400);
144
+ return {
145
+ success: false,
146
+ error: error.message,
147
+ details: error.hints?.join("\n") ?? null,
148
+ };
149
+ }
150
+
99
151
  const errorMsg = error instanceof Error ? error.message : String(error);
100
152
  reply.code(500);
101
153
  return {
@@ -125,7 +177,7 @@ export async function registerSessionRoutes(
125
177
  }
126
178
 
127
179
  return { success: true, data: instance.session };
128
- } catch (error) {
180
+ } catch (error: unknown) {
129
181
  const errorMsg = error instanceof Error ? error.message : String(error);
130
182
  reply.code(500);
131
183
  return {
@@ -157,7 +209,7 @@ export async function registerSessionRoutes(
157
209
  }
158
210
 
159
211
  return { success: true };
160
- } catch (error) {
212
+ } catch (error: unknown) {
161
213
  const errorMsg = error instanceof Error ? error.message : String(error);
162
214
  reply.code(500);
163
215
  return {
@@ -4,7 +4,6 @@
4
4
  * Worktree関連のREST APIエンドポイント。
5
5
  */
6
6
 
7
- import type { FastifyInstance } from "fastify";
8
7
  import {
9
8
  listWorktrees,
10
9
  getWorktreeByPath,
@@ -16,12 +15,13 @@ import type {
16
15
  Worktree,
17
16
  CreateWorktreeRequest,
18
17
  } from "../../../types/api.js";
18
+ import type { WebFastifyInstance } from "../types.js";
19
19
 
20
20
  /**
21
21
  * Worktree関連のルートを登録
22
22
  */
23
23
  export async function registerWorktreeRoutes(
24
- fastify: FastifyInstance,
24
+ fastify: WebFastifyInstance,
25
25
  ): Promise<void> {
26
26
  // GET /api/worktrees - すべてのWorktree一覧を取得
27
27
  fastify.get<{ Reply: ApiResponse<Worktree[]> }>(
@@ -64,13 +64,13 @@ export async function registerWorktreeRoutes(
64
64
  }
65
65
  });
66
66
 
67
- // DELETE /api/worktrees - Worktreeを削除
67
+ // DELETE /api/worktrees/delete - Worktreeを削除
68
68
  fastify.delete<{
69
- Querystring: { path: string };
69
+ Querystring: { path: string; force?: boolean };
70
70
  Reply:
71
71
  | { success: true }
72
72
  | { success: false; error: string; details?: string | null };
73
- }>("/api/worktrees", async (request, reply) => {
73
+ }>("/api/worktrees/delete", async (request, reply) => {
74
74
  try {
75
75
  const { path } = request.query;
76
76
 
@@ -30,6 +30,8 @@ export async function listWorktrees(): Promise<Worktree[]> {
30
30
  isProtected: isProtectedBranchName(wt.branch),
31
31
  createdAt: null, // git worktreeからは取得不可
32
32
  lastAccessedAt: null, // git worktreeからは取得不可
33
+ divergence: null,
34
+ prInfo: null,
33
35
  }));
34
36
  }
35
37
 
@@ -50,16 +52,22 @@ export async function createNewWorktree(
50
52
  branchName: string,
51
53
  createBranch: boolean,
52
54
  ): Promise<Worktree> {
53
- const { getRepositoryRoot, getCurrentBranch } = await import(
54
- "../../../git.js"
55
- );
55
+ // 保護ブランチのチェック
56
+ if (isProtectedBranchName(branchName)) {
57
+ throw new Error(
58
+ `Cannot create worktree for protected branch: ${branchName}. Protected branches (main, develop, master) must remain in the main repository.`,
59
+ );
60
+ }
61
+
62
+ const { getRepositoryRoot, getCurrentBranch } =
63
+ await import("../../../git.js");
56
64
 
57
65
  const [repoRoot, currentBranch] = await Promise.all([
58
66
  getRepositoryRoot(),
59
67
  getCurrentBranch(),
60
68
  ]);
61
69
 
62
- const worktreePath = await generateWorktreePath(branchName, repoRoot);
70
+ const worktreePath = await generateWorktreePath(repoRoot, branchName);
63
71
 
64
72
  await createWorktreeCore({
65
73
  branchName,