@akiojin/gwt 2.13.0 → 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 (295) 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 +27 -88
  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.map +1 -1
  13. package/dist/cli/ui/components/screens/BranchListScreen.js +14 -2
  14. package/dist/cli/ui/components/screens/BranchListScreen.js.map +1 -1
  15. package/dist/cli/ui/components/screens/BranchQuickStartScreen.d.ts.map +1 -1
  16. package/dist/cli/ui/components/screens/BranchQuickStartScreen.js +3 -3
  17. package/dist/cli/ui/components/screens/BranchQuickStartScreen.js.map +1 -1
  18. package/dist/cli/ui/utils/continueSession.d.ts.map +1 -1
  19. package/dist/cli/ui/utils/continueSession.js +1 -1
  20. package/dist/cli/ui/utils/continueSession.js.map +1 -1
  21. package/dist/client/assets/index-DPWWHorC.js +72 -0
  22. package/dist/client/assets/index-DsDNCy5f.css +1 -0
  23. package/dist/client/index.html +2 -2
  24. package/dist/codex.d.ts.map +1 -1
  25. package/dist/codex.js +21 -11
  26. package/dist/codex.js.map +1 -1
  27. package/dist/config/builtin-tools.d.ts.map +1 -1
  28. package/dist/config/builtin-tools.js +3 -2
  29. package/dist/config/builtin-tools.js.map +1 -1
  30. package/dist/config/shared-env.d.ts +41 -0
  31. package/dist/config/shared-env.d.ts.map +1 -0
  32. package/dist/config/shared-env.js +114 -0
  33. package/dist/config/shared-env.js.map +1 -0
  34. package/dist/gemini.d.ts.map +1 -1
  35. package/dist/gemini.js +20 -17
  36. package/dist/gemini.js.map +1 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +49 -7
  39. package/dist/index.js.map +1 -1
  40. package/dist/logging/logger.d.ts.map +1 -1
  41. package/dist/logging/logger.js +4 -1
  42. package/dist/logging/logger.js.map +1 -1
  43. package/dist/qwen.d.ts.map +1 -1
  44. package/dist/qwen.js +15 -11
  45. package/dist/qwen.js.map +1 -1
  46. package/dist/services/aiToolResolver.d.ts +41 -0
  47. package/dist/services/aiToolResolver.d.ts.map +1 -0
  48. package/dist/services/aiToolResolver.js +194 -0
  49. package/dist/services/aiToolResolver.js.map +1 -0
  50. package/dist/services/customToolResolver.d.ts +10 -0
  51. package/dist/services/customToolResolver.d.ts.map +1 -0
  52. package/dist/services/customToolResolver.js +71 -0
  53. package/dist/services/customToolResolver.js.map +1 -0
  54. package/dist/shared/aiToolConstants.d.ts +9 -0
  55. package/dist/shared/aiToolConstants.d.ts.map +1 -0
  56. package/dist/shared/aiToolConstants.js +29 -0
  57. package/dist/shared/aiToolConstants.js.map +1 -0
  58. package/dist/types/tools.d.ts +12 -0
  59. package/dist/types/tools.d.ts.map +1 -1
  60. package/dist/utils/prompt.d.ts.map +1 -1
  61. package/dist/utils/prompt.js.map +1 -1
  62. package/dist/utils/session.d.ts.map +1 -1
  63. package/dist/utils/session.js +15 -6
  64. package/dist/utils/session.js.map +1 -1
  65. package/dist/utils/terminal.d.ts +12 -3
  66. package/dist/utils/terminal.d.ts.map +1 -1
  67. package/dist/utils/terminal.js +5 -34
  68. package/dist/utils/terminal.js.map +1 -1
  69. package/dist/utils/webui.d.ts +8 -0
  70. package/dist/utils/webui.d.ts.map +1 -0
  71. package/dist/utils/webui.js +35 -0
  72. package/dist/utils/webui.js.map +1 -0
  73. package/dist/web/client/src/components/AIToolLaunchModal.d.ts +9 -0
  74. package/dist/web/client/src/components/AIToolLaunchModal.d.ts.map +1 -0
  75. package/dist/web/client/src/components/AIToolLaunchModal.js +363 -0
  76. package/dist/web/client/src/components/AIToolLaunchModal.js.map +1 -0
  77. package/dist/web/client/src/components/BranchGraph.d.ts.map +1 -1
  78. package/dist/web/client/src/components/BranchGraph.js +46 -49
  79. package/dist/web/client/src/components/BranchGraph.js.map +1 -1
  80. package/dist/web/client/src/components/CustomToolForm.d.ts +23 -0
  81. package/dist/web/client/src/components/CustomToolForm.d.ts.map +1 -0
  82. package/dist/web/client/src/components/CustomToolForm.js +209 -0
  83. package/dist/web/client/src/components/CustomToolForm.js.map +1 -0
  84. package/dist/web/client/src/components/CustomToolList.d.ts +10 -0
  85. package/dist/web/client/src/components/CustomToolList.d.ts.map +1 -0
  86. package/dist/web/client/src/components/CustomToolList.js +57 -0
  87. package/dist/web/client/src/components/CustomToolList.js.map +1 -0
  88. package/dist/web/client/src/components/EnvEditor.d.ts.map +1 -1
  89. package/dist/web/client/src/components/EnvEditor.js +33 -26
  90. package/dist/web/client/src/components/EnvEditor.js.map +1 -1
  91. package/dist/web/client/src/components/EnvironmentEditor.d.ts +17 -0
  92. package/dist/web/client/src/components/EnvironmentEditor.d.ts.map +1 -0
  93. package/dist/web/client/src/components/EnvironmentEditor.js +22 -0
  94. package/dist/web/client/src/components/EnvironmentEditor.js.map +1 -0
  95. package/dist/web/client/src/components/Terminal.d.ts.map +1 -1
  96. package/dist/web/client/src/components/Terminal.js +10 -3
  97. package/dist/web/client/src/components/Terminal.js.map +1 -1
  98. package/dist/web/client/src/components/branch-detail/BranchInfoCards.d.ts +10 -0
  99. package/dist/web/client/src/components/branch-detail/BranchInfoCards.d.ts.map +1 -0
  100. package/dist/web/client/src/components/branch-detail/BranchInfoCards.js +104 -0
  101. package/dist/web/client/src/components/branch-detail/BranchInfoCards.js.map +1 -0
  102. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.d.ts +22 -0
  103. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.d.ts.map +1 -0
  104. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js +79 -0
  105. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js.map +1 -0
  106. package/dist/web/client/src/components/branch-detail/TerminalPanel.d.ts +11 -0
  107. package/dist/web/client/src/components/branch-detail/TerminalPanel.d.ts.map +1 -0
  108. package/dist/web/client/src/components/branch-detail/TerminalPanel.js +32 -0
  109. package/dist/web/client/src/components/branch-detail/TerminalPanel.js.map +1 -0
  110. package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts +40 -0
  111. package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts.map +1 -0
  112. package/dist/web/client/src/components/branch-detail/ToolLauncher.js +147 -0
  113. package/dist/web/client/src/components/branch-detail/ToolLauncher.js.map +1 -0
  114. package/dist/web/client/src/components/branch-detail/index.d.ts +5 -0
  115. package/dist/web/client/src/components/branch-detail/index.d.ts.map +1 -0
  116. package/dist/web/client/src/components/branch-detail/index.js +5 -0
  117. package/dist/web/client/src/components/branch-detail/index.js.map +1 -0
  118. package/dist/web/client/src/components/common/BranchCard.d.ts +17 -0
  119. package/dist/web/client/src/components/common/BranchCard.d.ts.map +1 -0
  120. package/dist/web/client/src/components/common/BranchCard.js +36 -0
  121. package/dist/web/client/src/components/common/BranchCard.js.map +1 -0
  122. package/dist/web/client/src/components/common/MetricCard.d.ts +10 -0
  123. package/dist/web/client/src/components/common/MetricCard.d.ts.map +1 -0
  124. package/dist/web/client/src/components/common/MetricCard.js +10 -0
  125. package/dist/web/client/src/components/common/MetricCard.js.map +1 -0
  126. package/dist/web/client/src/components/common/PageHeader.d.ts +12 -0
  127. package/dist/web/client/src/components/common/PageHeader.d.ts.map +1 -0
  128. package/dist/web/client/src/components/common/PageHeader.js +14 -0
  129. package/dist/web/client/src/components/common/PageHeader.js.map +1 -0
  130. package/dist/web/client/src/components/common/SearchInput.d.ts +14 -0
  131. package/dist/web/client/src/components/common/SearchInput.d.ts.map +1 -0
  132. package/dist/web/client/src/components/common/SearchInput.js +15 -0
  133. package/dist/web/client/src/components/common/SearchInput.js.map +1 -0
  134. package/dist/web/client/src/components/common/StatusBadge.d.ts +10 -0
  135. package/dist/web/client/src/components/common/StatusBadge.d.ts.map +1 -0
  136. package/dist/web/client/src/components/common/StatusBadge.js +15 -0
  137. package/dist/web/client/src/components/common/StatusBadge.js.map +1 -0
  138. package/dist/web/client/src/components/common/index.d.ts +6 -0
  139. package/dist/web/client/src/components/common/index.d.ts.map +1 -0
  140. package/dist/web/client/src/components/common/index.js +6 -0
  141. package/dist/web/client/src/components/common/index.js.map +1 -0
  142. package/dist/web/client/src/components/ui/alert.d.ts +9 -0
  143. package/dist/web/client/src/components/ui/alert.d.ts.map +1 -0
  144. package/dist/web/client/src/components/ui/alert.js +25 -0
  145. package/dist/web/client/src/components/ui/alert.js.map +1 -0
  146. package/dist/web/client/src/components/ui/badge.d.ts +10 -0
  147. package/dist/web/client/src/components/ui/badge.d.ts.map +1 -0
  148. package/dist/web/client/src/components/ui/badge.js +25 -0
  149. package/dist/web/client/src/components/ui/badge.js.map +1 -0
  150. package/dist/web/client/src/components/ui/button.d.ts +12 -0
  151. package/dist/web/client/src/components/ui/button.d.ts.map +1 -0
  152. package/dist/web/client/src/components/ui/button.js +33 -0
  153. package/dist/web/client/src/components/ui/button.js.map +1 -0
  154. package/dist/web/client/src/components/ui/card.d.ts +9 -0
  155. package/dist/web/client/src/components/ui/card.d.ts.map +1 -0
  156. package/dist/web/client/src/components/ui/card.js +16 -0
  157. package/dist/web/client/src/components/ui/card.js.map +1 -0
  158. package/dist/web/client/src/components/ui/index.d.ts +8 -0
  159. package/dist/web/client/src/components/ui/index.d.ts.map +1 -0
  160. package/dist/web/client/src/components/ui/index.js +8 -0
  161. package/dist/web/client/src/components/ui/index.js.map +1 -0
  162. package/dist/web/client/src/components/ui/input.d.ts +4 -0
  163. package/dist/web/client/src/components/ui/input.d.ts.map +1 -0
  164. package/dist/web/client/src/components/ui/input.js +8 -0
  165. package/dist/web/client/src/components/ui/input.js.map +1 -0
  166. package/dist/web/client/src/components/ui/select.d.ts +14 -0
  167. package/dist/web/client/src/components/ui/select.d.ts.map +1 -0
  168. package/dist/web/client/src/components/ui/select.js +39 -0
  169. package/dist/web/client/src/components/ui/select.js.map +1 -0
  170. package/dist/web/client/src/components/ui/table.d.ts +11 -0
  171. package/dist/web/client/src/components/ui/table.d.ts.map +1 -0
  172. package/dist/web/client/src/components/ui/table.js +21 -0
  173. package/dist/web/client/src/components/ui/table.js.map +1 -0
  174. package/dist/web/client/src/hooks/useSessions.d.ts.map +1 -1
  175. package/dist/web/client/src/hooks/useSessions.js +6 -1
  176. package/dist/web/client/src/hooks/useSessions.js.map +1 -1
  177. package/dist/web/client/src/lib/utils.d.ts +7 -0
  178. package/dist/web/client/src/lib/utils.d.ts.map +1 -0
  179. package/dist/web/client/src/lib/utils.js +10 -0
  180. package/dist/web/client/src/lib/utils.js.map +1 -0
  181. package/dist/web/client/src/lib/websocket.d.ts +7 -0
  182. package/dist/web/client/src/lib/websocket.d.ts.map +1 -1
  183. package/dist/web/client/src/lib/websocket.js +44 -0
  184. package/dist/web/client/src/lib/websocket.js.map +1 -1
  185. package/dist/web/client/src/pages/BranchDetailPage.d.ts.map +1 -1
  186. package/dist/web/client/src/pages/BranchDetailPage.js +113 -361
  187. package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
  188. package/dist/web/client/src/pages/BranchListPage.d.ts.map +1 -1
  189. package/dist/web/client/src/pages/BranchListPage.js +89 -127
  190. package/dist/web/client/src/pages/BranchListPage.js.map +1 -1
  191. package/dist/web/client/src/pages/ConfigManagementPage.d.ts.map +1 -1
  192. package/dist/web/client/src/pages/ConfigManagementPage.js +46 -41
  193. package/dist/web/client/src/pages/ConfigManagementPage.js.map +1 -1
  194. package/dist/web/client/src/pages/ConfigPage.d.ts +3 -0
  195. package/dist/web/client/src/pages/ConfigPage.d.ts.map +1 -0
  196. package/dist/web/client/src/pages/ConfigPage.js +216 -0
  197. package/dist/web/client/src/pages/ConfigPage.js.map +1 -0
  198. package/dist/web/client/vite.config.d.ts.map +1 -1
  199. package/dist/web/client/vite.config.js +8 -1
  200. package/dist/web/client/vite.config.js.map +1 -1
  201. package/dist/web/server/index.d.ts +24 -2
  202. package/dist/web/server/index.d.ts.map +1 -1
  203. package/dist/web/server/index.js +46 -15
  204. package/dist/web/server/index.js.map +1 -1
  205. package/dist/web/server/pty/manager.d.ts +12 -10
  206. package/dist/web/server/pty/manager.d.ts.map +1 -1
  207. package/dist/web/server/pty/manager.js +76 -43
  208. package/dist/web/server/pty/manager.js.map +1 -1
  209. package/dist/web/server/routes/sessions.d.ts.map +1 -1
  210. package/dist/web/server/routes/sessions.js +35 -2
  211. package/dist/web/server/routes/sessions.js.map +1 -1
  212. package/dist/web/server/routes/worktrees.js +2 -2
  213. package/dist/web/server/routes/worktrees.js.map +1 -1
  214. package/dist/web/server/services/worktrees.d.ts.map +1 -1
  215. package/dist/web/server/services/worktrees.js +7 -1
  216. package/dist/web/server/services/worktrees.js.map +1 -1
  217. package/dist/web/server/tray.d.ts +24 -0
  218. package/dist/web/server/tray.d.ts.map +1 -0
  219. package/dist/web/server/tray.js +79 -0
  220. package/dist/web/server/tray.js.map +1 -0
  221. package/dist/web/server/websocket/handler.d.ts +18 -2
  222. package/dist/web/server/websocket/handler.d.ts.map +1 -1
  223. package/dist/web/server/websocket/handler.js +82 -9
  224. package/dist/web/server/websocket/handler.js.map +1 -1
  225. package/package.json +15 -2
  226. package/src/claude.ts +26 -15
  227. package/src/cli/ui/__tests__/components/common/Select.test.tsx +11 -0
  228. package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +17 -1
  229. package/src/cli/ui/__tests__/components/screens/BranchQuickStartScreen.test.tsx +4 -4
  230. package/src/cli/ui/components/App.tsx +33 -133
  231. package/src/cli/ui/components/common/Select.tsx +2 -2
  232. package/src/cli/ui/components/screens/BranchListScreen.tsx +43 -23
  233. package/src/cli/ui/components/screens/BranchQuickStartScreen.tsx +41 -46
  234. package/src/cli/ui/utils/continueSession.ts +1 -7
  235. package/src/codex.ts +31 -22
  236. package/src/config/builtin-tools.ts +6 -2
  237. package/src/config/shared-env.ts +139 -0
  238. package/src/gemini.ts +35 -22
  239. package/src/index.ts +54 -7
  240. package/src/logging/logger.ts +5 -2
  241. package/src/qwen.ts +28 -19
  242. package/src/services/aiToolResolver.ts +276 -0
  243. package/src/services/customToolResolver.ts +98 -0
  244. package/src/shared/aiToolConstants.ts +30 -0
  245. package/src/trayicon.d.ts +30 -0
  246. package/src/types/tools.ts +15 -0
  247. package/src/utils/prompt.ts +15 -9
  248. package/src/utils/session.ts +80 -26
  249. package/src/utils/terminal.ts +11 -41
  250. package/src/utils/webui.ts +43 -0
  251. package/src/web/client/components.json +21 -0
  252. package/src/web/client/src/components/AIToolLaunchModal.tsx +575 -0
  253. package/src/web/client/src/components/BranchGraph.tsx +95 -75
  254. package/src/web/client/src/components/CustomToolForm.tsx +386 -0
  255. package/src/web/client/src/components/CustomToolList.tsx +119 -0
  256. package/src/web/client/src/components/EnvEditor.tsx +91 -81
  257. package/src/web/client/src/components/EnvironmentEditor.tsx +97 -0
  258. package/src/web/client/src/components/Terminal.tsx +11 -3
  259. package/src/web/client/src/components/branch-detail/BranchInfoCards.tsx +179 -0
  260. package/src/web/client/src/components/branch-detail/SessionHistoryTable.tsx +181 -0
  261. package/src/web/client/src/components/branch-detail/TerminalPanel.tsx +92 -0
  262. package/src/web/client/src/components/branch-detail/ToolLauncher.tsx +327 -0
  263. package/src/web/client/src/components/branch-detail/index.ts +4 -0
  264. package/src/web/client/src/components/common/BranchCard.tsx +117 -0
  265. package/src/web/client/src/components/common/MetricCard.tsx +22 -0
  266. package/src/web/client/src/components/common/PageHeader.tsx +44 -0
  267. package/src/web/client/src/components/common/SearchInput.tsx +40 -0
  268. package/src/web/client/src/components/common/StatusBadge.tsx +37 -0
  269. package/src/web/client/src/components/common/index.ts +5 -0
  270. package/src/web/client/src/components/ui/alert.tsx +63 -0
  271. package/src/web/client/src/components/ui/badge.tsx +44 -0
  272. package/src/web/client/src/components/ui/button.tsx +57 -0
  273. package/src/web/client/src/components/ui/card.tsx +82 -0
  274. package/src/web/client/src/components/ui/index.ts +32 -0
  275. package/src/web/client/src/components/ui/input.tsx +21 -0
  276. package/src/web/client/src/components/ui/select.tsx +156 -0
  277. package/src/web/client/src/components/ui/table.tsx +119 -0
  278. package/src/web/client/src/hooks/useSessions.ts +10 -1
  279. package/src/web/client/src/index.css +46 -816
  280. package/src/web/client/src/lib/utils.ts +10 -0
  281. package/src/web/client/src/lib/websocket.ts +48 -1
  282. package/src/web/client/src/pages/BranchDetailPage.tsx +222 -694
  283. package/src/web/client/src/pages/BranchListPage.tsx +190 -236
  284. package/src/web/client/src/pages/ConfigManagementPage.tsx +94 -76
  285. package/src/web/client/src/pages/ConfigPage.tsx +362 -0
  286. package/src/web/client/vite.config.ts +8 -1
  287. package/src/web/server/index.ts +72 -15
  288. package/src/web/server/pty/manager.ts +128 -55
  289. package/src/web/server/routes/sessions.ts +59 -7
  290. package/src/web/server/routes/worktrees.ts +3 -3
  291. package/src/web/server/services/worktrees.ts +12 -4
  292. package/src/web/server/tray.ts +93 -0
  293. package/src/web/server/websocket/handler.ts +119 -13
  294. package/dist/client/assets/index-DeNwPosA.css +0 -1
  295. package/dist/client/assets/index-Dl798X5w.js +0 -32
@@ -17,7 +17,7 @@ export interface LoggerConfig {
17
17
  sync?: boolean;
18
18
  }
19
19
 
20
- /**
20
+ /**
21
21
  * Create a pino logger with unified structure and category field.
22
22
  * - Writes to a single file stream (no per-component files)
23
23
  * - Adds `category` to each log record
@@ -51,7 +51,10 @@ export function createLogger(config: LoggerConfig = {}): Logger {
51
51
  };
52
52
 
53
53
  if (config.sync) {
54
- const destinationStream = pino.destination({ dest: destination, sync: true });
54
+ const destinationStream = pino.destination({
55
+ dest: destination,
56
+ sync: true,
57
+ });
55
58
  return pino(options, destinationStream);
56
59
  }
57
60
 
package/src/qwen.ts CHANGED
@@ -52,6 +52,9 @@ export async function launchQwenCLI(
52
52
  options.sessionId && options.sessionId.trim().length > 0
53
53
  ? options.sessionId.trim()
54
54
  : null;
55
+ const usedExplicitSessionId =
56
+ Boolean(resumeSessionId) &&
57
+ (options.mode === "continue" || options.mode === "resume");
55
58
  switch (options.mode) {
56
59
  case "continue":
57
60
  console.log(
@@ -94,10 +97,14 @@ export async function launchQwenCLI(
94
97
 
95
98
  terminal.exitRawMode();
96
99
 
97
- const baseEnv = {
98
- ...process.env,
99
- ...(options.envOverrides ?? {}),
100
- };
100
+ const baseEnv = Object.fromEntries(
101
+ Object.entries({
102
+ ...process.env,
103
+ ...(options.envOverrides ?? {}),
104
+ }).filter(
105
+ (entry): entry is [string, string] => typeof entry[1] === "string",
106
+ ),
107
+ );
101
108
 
102
109
  const childStdio = createChildStdio();
103
110
 
@@ -105,12 +112,13 @@ export async function launchQwenCLI(
105
112
  const hasLocalQwen = await isQwenCommandAvailable();
106
113
 
107
114
  try {
108
- const execChild = async (child: any) => {
115
+ const execChild = async (child: Promise<unknown>) => {
109
116
  try {
110
117
  await child;
111
- } catch (execError: any) {
118
+ } catch (execError: unknown) {
112
119
  // Treat SIGINT/SIGTERM as normal exit (user pressed Ctrl+C)
113
- if (execError.signal === "SIGINT" || execError.signal === "SIGTERM") {
120
+ const signal = (execError as { signal?: unknown })?.signal;
121
+ if (signal === "SIGINT" || signal === "SIGTERM") {
114
122
  return;
115
123
  }
116
124
  throw execError;
@@ -127,7 +135,7 @@ export async function launchQwenCLI(
127
135
  stdout: childStdio.stdout,
128
136
  stderr: childStdio.stderr,
129
137
  env: baseEnv,
130
- } as any);
138
+ });
131
139
  await execChild(child);
132
140
  } else {
133
141
  // Fallback to bunx
@@ -150,7 +158,7 @@ export async function launchQwenCLI(
150
158
  stdout: childStdio.stdout,
151
159
  stderr: childStdio.stderr,
152
160
  env: baseEnv,
153
- } as any);
161
+ });
154
162
  await execChild(child);
155
163
  }
156
164
  } finally {
@@ -159,12 +167,10 @@ export async function launchQwenCLI(
159
167
 
160
168
  let capturedSessionId: string | null = null;
161
169
  try {
162
- capturedSessionId =
163
- (await findLatestQwenSessionId(worktreePath)) ??
164
- resumeSessionId ??
165
- null;
170
+ const detected = (await findLatestQwenSessionId(worktreePath)) ?? null;
171
+ capturedSessionId = usedExplicitSessionId ? resumeSessionId : detected;
166
172
  } catch {
167
- capturedSessionId = resumeSessionId ?? null;
173
+ capturedSessionId = usedExplicitSessionId ? resumeSessionId : null;
168
174
  }
169
175
 
170
176
  if (capturedSessionId) {
@@ -181,11 +187,12 @@ export async function launchQwenCLI(
181
187
  }
182
188
 
183
189
  return capturedSessionId ? { sessionId: capturedSessionId } : {};
184
- } catch (error: any) {
190
+ } catch (error: unknown) {
185
191
  const hasLocalQwen = await isQwenCommandAvailable();
186
192
  let errorMessage: string;
193
+ const err = error as NodeJS.ErrnoException;
187
194
 
188
- if (error.code === "ENOENT") {
195
+ if (err.code === "ENOENT") {
189
196
  if (hasLocalQwen) {
190
197
  errorMessage =
191
198
  "qwen command not found. Please ensure Qwen CLI is properly installed.";
@@ -194,7 +201,8 @@ export async function launchQwenCLI(
194
201
  "bunx command not found. Please ensure Bun is installed so Qwen CLI can run via bunx.";
195
202
  }
196
203
  } else {
197
- errorMessage = `Failed to launch Qwen CLI: ${error.message || "Unknown error"}`;
204
+ const details = error instanceof Error ? error.message : String(error);
205
+ errorMessage = `Failed to launch Qwen CLI: ${details || "Unknown error"}`;
198
206
  }
199
207
 
200
208
  if (process.platform === "win32") {
@@ -250,8 +258,9 @@ export async function isQwenCLIAvailable(): Promise<boolean> {
250
258
  try {
251
259
  await execa("bunx", [QWEN_CLI_PACKAGE, "--version"], { shell: true });
252
260
  return true;
253
- } catch (error: any) {
254
- if (error.code === "ENOENT") {
261
+ } catch (error: unknown) {
262
+ const err = error as NodeJS.ErrnoException;
263
+ if (err.code === "ENOENT") {
255
264
  console.error(chalk.yellow("\n⚠️ bunx command not found"));
256
265
  console.error(
257
266
  chalk.gray(
@@ -0,0 +1,276 @@
1
+ import { execa } from "execa";
2
+ import { platform } from "os";
3
+ import { getToolById } from "../config/tools.js";
4
+ import {
5
+ CODEX_DEFAULT_ARGS,
6
+ CLAUDE_PERMISSION_SKIP_ARGS,
7
+ } from "../shared/aiToolConstants.js";
8
+ import { prepareCustomToolExecution } from "./customToolResolver.js";
9
+ import type { LaunchOptions } from "../types/tools.js";
10
+
11
+ const DETECTION_COMMAND = platform() === "win32" ? "where" : "which";
12
+ const MIN_BUN_MAJOR = 1;
13
+
14
+ export const CLAUDE_CLI_PACKAGE = "@anthropic-ai/claude-code@latest";
15
+ export const CODEX_CLI_PACKAGE = "@openai/codex@latest";
16
+
17
+ export type ResolverErrorCode =
18
+ | "COMMAND_NOT_FOUND"
19
+ | "BUNX_NOT_FOUND"
20
+ | "BUN_TOO_OLD"
21
+ | "CUSTOM_TOOL_NOT_FOUND";
22
+
23
+ export interface ResolvedCommand {
24
+ command: string;
25
+ args: string[];
26
+ usesFallback: boolean;
27
+ env?: NodeJS.ProcessEnv;
28
+ }
29
+
30
+ export class AIToolResolutionError extends Error {
31
+ constructor(
32
+ public code: ResolverErrorCode,
33
+ message: string,
34
+ public hints?: string[],
35
+ ) {
36
+ super(message);
37
+ this.name = "AIToolResolutionError";
38
+ }
39
+ }
40
+
41
+ async function commandExists(command: string): Promise<boolean> {
42
+ try {
43
+ await execa(DETECTION_COMMAND, [command], { shell: true });
44
+ return true;
45
+ } catch {
46
+ return false;
47
+ }
48
+ }
49
+
50
+ let bunxCheckPromise: Promise<void> | null = null;
51
+
52
+ async function ensureBunxAvailable(): Promise<void> {
53
+ if (!bunxCheckPromise) {
54
+ bunxCheckPromise = (async () => {
55
+ const bunxExists = await commandExists("bunx");
56
+ if (!bunxExists) {
57
+ throw new AIToolResolutionError(
58
+ "BUNX_NOT_FOUND",
59
+ "bunx command not found. Install Bun 1.0+ so bunx is available on PATH.",
60
+ [
61
+ "Install Bun: https://bun.sh/docs/installation",
62
+ "After installation, restart your terminal so bunx is on PATH.",
63
+ ],
64
+ );
65
+ }
66
+
67
+ try {
68
+ const { stdout } = await execa("bun", ["--version"]);
69
+ const version = stdout.trim();
70
+ const major = parseInt(version.split(".")[0] ?? "0", 10);
71
+ if (!Number.isFinite(major) || major < MIN_BUN_MAJOR) {
72
+ throw new AIToolResolutionError(
73
+ "BUN_TOO_OLD",
74
+ `Detected Bun ${version}. Bun ${MIN_BUN_MAJOR}.0+ is required for bunx fallback execution.`,
75
+ [
76
+ "Upgrade Bun: curl -fsSL https://bun.sh/install | bash",
77
+ "Verify with 'bun --version' (needs >= 1.0)",
78
+ ],
79
+ );
80
+ }
81
+ } catch (error: unknown) {
82
+ if (error instanceof AIToolResolutionError) {
83
+ throw error;
84
+ }
85
+ const err = error as NodeJS.ErrnoException;
86
+ if (err?.code === "ENOENT") {
87
+ throw new AIToolResolutionError(
88
+ "BUNX_NOT_FOUND",
89
+ "bun command not found while verifying bunx. Install Bun 1.0+ and ensure it is on PATH.",
90
+ [
91
+ "Install Bun: https://bun.sh/docs/installation",
92
+ "After installation, run 'bun --version' to confirm.",
93
+ ],
94
+ );
95
+ }
96
+ throw new AIToolResolutionError(
97
+ "BUN_TOO_OLD",
98
+ `Failed to verify Bun version: ${err?.message ?? "unknown error"}`,
99
+ );
100
+ }
101
+ })();
102
+ }
103
+
104
+ try {
105
+ await bunxCheckPromise;
106
+ } catch (error) {
107
+ bunxCheckPromise = null;
108
+ throw error;
109
+ }
110
+ }
111
+
112
+ export interface ClaudeCommandOptions {
113
+ mode?: "normal" | "continue" | "resume";
114
+ skipPermissions?: boolean;
115
+ extraArgs?: string[];
116
+ }
117
+
118
+ export function buildClaudeArgs(options: ClaudeCommandOptions = {}): string[] {
119
+ const args: string[] = [];
120
+
121
+ switch (options.mode) {
122
+ case "continue":
123
+ args.push("-c");
124
+ break;
125
+ case "resume":
126
+ args.push("-r");
127
+ break;
128
+ default:
129
+ break;
130
+ }
131
+
132
+ if (options.skipPermissions) {
133
+ args.push(...CLAUDE_PERMISSION_SKIP_ARGS);
134
+ }
135
+
136
+ if (options.extraArgs?.length) {
137
+ args.push(...options.extraArgs);
138
+ }
139
+
140
+ return args;
141
+ }
142
+
143
+ export async function resolveClaudeCommand(
144
+ options: ClaudeCommandOptions = {},
145
+ ): Promise<ResolvedCommand> {
146
+ const args = buildClaudeArgs(options);
147
+
148
+ if (await commandExists("claude")) {
149
+ return {
150
+ command: "claude",
151
+ args,
152
+ usesFallback: false,
153
+ };
154
+ }
155
+
156
+ await ensureBunxAvailable();
157
+ return {
158
+ command: "bunx",
159
+ args: [CLAUDE_CLI_PACKAGE, ...args],
160
+ usesFallback: true,
161
+ };
162
+ }
163
+
164
+ export interface CodexCommandOptions {
165
+ mode?: "normal" | "continue" | "resume";
166
+ bypassApprovals?: boolean;
167
+ extraArgs?: string[];
168
+ }
169
+
170
+ export function buildCodexArgs(options: CodexCommandOptions = {}): string[] {
171
+ const args: string[] = [];
172
+
173
+ switch (options.mode) {
174
+ case "continue":
175
+ args.push("resume", "--last");
176
+ break;
177
+ case "resume":
178
+ args.push("resume");
179
+ break;
180
+ default:
181
+ break;
182
+ }
183
+
184
+ if (options.bypassApprovals) {
185
+ args.push("--yolo");
186
+ }
187
+
188
+ if (options.extraArgs?.length) {
189
+ args.push(...options.extraArgs);
190
+ }
191
+
192
+ args.push(...CODEX_DEFAULT_ARGS);
193
+ return args;
194
+ }
195
+
196
+ export async function resolveCodexCommand(
197
+ options: CodexCommandOptions = {},
198
+ ): Promise<ResolvedCommand> {
199
+ const args = buildCodexArgs(options);
200
+
201
+ if (await commandExists("codex")) {
202
+ return {
203
+ command: "codex",
204
+ args,
205
+ usesFallback: false,
206
+ };
207
+ }
208
+
209
+ await ensureBunxAvailable();
210
+ return {
211
+ command: "bunx",
212
+ args: [CODEX_CLI_PACKAGE, ...args],
213
+ usesFallback: true,
214
+ };
215
+ }
216
+
217
+ export interface CustomToolCommandOptions extends LaunchOptions {
218
+ toolId: string;
219
+ }
220
+
221
+ export async function resolveCustomToolCommand(
222
+ options: CustomToolCommandOptions,
223
+ ): Promise<ResolvedCommand> {
224
+ const tool = await getToolById(options.toolId);
225
+ if (!tool) {
226
+ throw new AIToolResolutionError(
227
+ "CUSTOM_TOOL_NOT_FOUND",
228
+ `Custom tool not found: ${options.toolId}`,
229
+ [
230
+ "Update ~/.gwt/tools.json to include this ID",
231
+ "Reload the Web UI after editing the tools list",
232
+ ],
233
+ );
234
+ }
235
+
236
+ const execution = await prepareCustomToolExecution(tool, options);
237
+
238
+ return {
239
+ command: execution.command,
240
+ args: execution.args,
241
+ usesFallback: tool.type === "bunx",
242
+ ...(execution.env ? { env: execution.env } : {}),
243
+ };
244
+ }
245
+
246
+ export async function isClaudeCodeAvailable(): Promise<boolean> {
247
+ try {
248
+ await resolveClaudeCommand();
249
+ return true;
250
+ } catch (error) {
251
+ if (error instanceof AIToolResolutionError) {
252
+ return false;
253
+ }
254
+ return false;
255
+ }
256
+ }
257
+
258
+ export async function isCodexAvailable(): Promise<boolean> {
259
+ try {
260
+ await resolveCodexCommand();
261
+ return true;
262
+ } catch (error) {
263
+ if (error instanceof AIToolResolutionError) {
264
+ return false;
265
+ }
266
+ return false;
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Test-helper: resets cached bunx availability check.
272
+ * Not exported in type definitions to avoid production usage.
273
+ */
274
+ export function __resetBunxCacheForTests(): void {
275
+ bunxCheckPromise = null;
276
+ }
@@ -0,0 +1,98 @@
1
+ import { execa } from "execa";
2
+ import type { CustomAITool, LaunchOptions } from "../types/tools.js";
3
+
4
+ export interface CustomToolExecutionPlan {
5
+ command: string;
6
+ args: string[];
7
+ env?: NodeJS.ProcessEnv;
8
+ }
9
+
10
+ const WHICH_COMMAND = process.platform === "win32" ? "where" : "which";
11
+
12
+ export async function resolveCommandPath(commandName: string): Promise<string> {
13
+ try {
14
+ const { stdout } = await execa(WHICH_COMMAND, [commandName]);
15
+ const resolvedPath = (stdout.split("\n")[0] ?? "").trim();
16
+
17
+ if (!resolvedPath) {
18
+ throw new Error(
19
+ `Command "${commandName}" not found in PATH.\n` +
20
+ "Please ensure it is installed and available in your PATH.",
21
+ );
22
+ }
23
+
24
+ return resolvedPath;
25
+ } catch (error) {
26
+ const reason = error instanceof Error ? error.message : String(error);
27
+ throw new Error(
28
+ `Failed to resolve command "${commandName}".\n${reason}\n` +
29
+ "Please ensure the command is installed and available in your PATH.",
30
+ );
31
+ }
32
+ }
33
+
34
+ export function buildCustomToolArgs(
35
+ tool: CustomAITool,
36
+ options: LaunchOptions = {},
37
+ ): string[] {
38
+ const args: string[] = [];
39
+
40
+ if (tool.defaultArgs?.length) {
41
+ args.push(...tool.defaultArgs);
42
+ }
43
+
44
+ const mode = options.mode ?? "normal";
45
+ const modeArgs = tool.modeArgs?.[mode];
46
+ if (modeArgs?.length) {
47
+ args.push(...modeArgs);
48
+ }
49
+
50
+ if (options.skipPermissions && tool.permissionSkipArgs?.length) {
51
+ args.push(...tool.permissionSkipArgs);
52
+ }
53
+
54
+ if (options.extraArgs?.length) {
55
+ args.push(...options.extraArgs);
56
+ }
57
+
58
+ return args;
59
+ }
60
+
61
+ export async function prepareCustomToolExecution(
62
+ tool: CustomAITool,
63
+ options: LaunchOptions = {},
64
+ ): Promise<CustomToolExecutionPlan> {
65
+ const args = buildCustomToolArgs(tool, options);
66
+ const envOverrides: NodeJS.ProcessEnv | undefined = tool.env
67
+ ? ({ ...tool.env } as NodeJS.ProcessEnv)
68
+ : undefined;
69
+
70
+ switch (tool.type) {
71
+ case "path": {
72
+ return {
73
+ command: tool.command,
74
+ args,
75
+ ...(envOverrides ? { env: envOverrides } : {}),
76
+ };
77
+ }
78
+ case "bunx": {
79
+ return {
80
+ command: "bunx",
81
+ args: [tool.command, ...args],
82
+ ...(envOverrides ? { env: envOverrides } : {}),
83
+ };
84
+ }
85
+ case "command": {
86
+ const resolved = await resolveCommandPath(tool.command);
87
+ return {
88
+ command: resolved,
89
+ args,
90
+ ...(envOverrides ? { env: envOverrides } : {}),
91
+ };
92
+ }
93
+ default: {
94
+ const exhaustive: never = tool.type;
95
+ throw new Error(`Unknown custom tool type: ${exhaustive as string}`);
96
+ }
97
+ }
98
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Shared constants for AI tool integrations.
3
+ *
4
+ * These values are consumed by both the CLI (Node) runtime and the Web UI so
5
+ * that command previews, permission flags, and default arguments stay in sync.
6
+ */
7
+
8
+ export const CLAUDE_PERMISSION_SKIP_ARGS = [
9
+ "--dangerously-skip-permissions",
10
+ ] as const;
11
+
12
+ export const CODEX_DEFAULT_ARGS = [
13
+ "--enable",
14
+ "web_search_request",
15
+ "--model=gpt-5-codex",
16
+ "--sandbox",
17
+ "workspace-write",
18
+ "-c",
19
+ "model_reasoning_effort=high",
20
+ "-c",
21
+ "model_reasoning_summaries=detailed",
22
+ "-c",
23
+ "sandbox_workspace_write.network_access=true",
24
+ "-c",
25
+ "shell_environment_policy.inherit=all",
26
+ "-c",
27
+ "shell_environment_policy.ignore_default_excludes=true",
28
+ "-c",
29
+ "shell_environment_policy.experimental_use_profile=true",
30
+ ] as const;
@@ -0,0 +1,30 @@
1
+ declare module "trayicon" {
2
+ export interface TrayIconMenuItem {
3
+ text: string;
4
+ action?: () => void | Promise<void>;
5
+ disabled?: boolean;
6
+ checked?: boolean;
7
+ }
8
+
9
+ export interface TrayIconOptions {
10
+ icon: Buffer;
11
+ title?: string;
12
+ tooltip?: string;
13
+ action?: () => void | Promise<void>;
14
+ menu?: TrayIconMenuItem[];
15
+ }
16
+
17
+ export interface TrayIconInstance {
18
+ setIcon?: (icon: Buffer) => void;
19
+ setTitle?: (title: string) => void;
20
+ dispose?: () => void;
21
+ }
22
+
23
+ export function create(options: TrayIconOptions): TrayIconInstance;
24
+
25
+ const trayicon: {
26
+ create: typeof create;
27
+ };
28
+
29
+ export default trayicon;
30
+ }
@@ -69,6 +69,11 @@ export interface CustomAITool {
69
69
  */
70
70
  icon?: string;
71
71
 
72
+ /**
73
+ * 説明文(オプション)
74
+ */
75
+ description?: string;
76
+
72
77
  /**
73
78
  * 実行方式
74
79
  *
@@ -118,6 +123,16 @@ export interface CustomAITool {
118
123
  * APIキーや設定ファイルパスなどを指定。
119
124
  */
120
125
  env?: Record<string, string>;
126
+
127
+ /**
128
+ * 作成日時(ISO8601)。tools.jsonのメタデータとして使用。
129
+ */
130
+ createdAt?: string;
131
+
132
+ /**
133
+ * 更新日時(ISO8601)。tools.jsonのメタデータとして使用。
134
+ */
135
+ updatedAt?: string;
121
136
  }
122
137
 
123
138
  /**
@@ -22,7 +22,9 @@ export async function waitForEnter(promptMessage: string): Promise<void> {
22
22
 
23
23
  if ((stdin as NodeJS.ReadStream & { isRaw?: boolean }).isRaw) {
24
24
  try {
25
- (stdin as NodeJS.ReadStream & { setRawMode?: (flag: boolean) => void }).setRawMode?.(false);
25
+ (
26
+ stdin as NodeJS.ReadStream & { setRawMode?: (flag: boolean) => void }
27
+ ).setRawMode?.(false);
26
28
  } catch {
27
29
  // Ignore raw mode errors
28
30
  }
@@ -35,17 +37,21 @@ export async function waitForEnter(promptMessage: string): Promise<void> {
35
37
  rl.removeAllListeners();
36
38
  rl.close();
37
39
  const remover = (method: "off" | "removeListener") =>
38
- (stdin as unknown as Record<string, (event: string, fn: () => void) => void>)[method]?.(
39
- "end",
40
- onEnd,
41
- );
40
+ (
41
+ stdin as unknown as Record<
42
+ string,
43
+ (event: string, fn: () => void) => void
44
+ >
45
+ )[method]?.("end", onEnd);
42
46
  remover("off");
43
47
  remover("removeListener");
44
48
  const removerErr = (method: "off" | "removeListener") =>
45
- (stdin as unknown as Record<string, (event: string, fn: () => void) => void>)[method]?.(
46
- "error",
47
- onEnd,
48
- );
49
+ (
50
+ stdin as unknown as Record<
51
+ string,
52
+ (event: string, fn: () => void) => void
53
+ >
54
+ )[method]?.("error", onEnd);
49
55
  removerErr("off");
50
56
  removerErr("removeListener");
51
57
  if (typeof stdin.pause === "function") {