@akiojin/gwt 4.9.0 → 4.9.1

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 (153) hide show
  1. package/README.ja.md +58 -34
  2. package/README.md +18 -34
  3. package/dist/cli/ui/components/App.d.ts +2 -2
  4. package/dist/cli/ui/components/App.d.ts.map +1 -1
  5. package/dist/cli/ui/components/App.js +8 -8
  6. package/dist/cli/ui/components/App.js.map +1 -1
  7. package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.d.ts +27 -0
  8. package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.d.ts.map +1 -0
  9. package/dist/cli/ui/components/screens/{AIToolSelectorScreen.js → CodingAgentSelectorScreen.js} +35 -35
  10. package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.js.map +1 -0
  11. package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts +2 -2
  12. package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts.map +1 -1
  13. package/dist/cli/ui/components/screens/ModelSelectorScreen.js.map +1 -1
  14. package/dist/cli/ui/types.d.ts +2 -2
  15. package/dist/cli/ui/types.d.ts.map +1 -1
  16. package/dist/cli/ui/utils/modelOptions.d.ts +4 -4
  17. package/dist/cli/ui/utils/modelOptions.d.ts.map +1 -1
  18. package/dist/cli/ui/utils/modelOptions.js.map +1 -1
  19. package/dist/client/assets/{index-PqK9jkug.js → index-LNPtOrn3.js} +17 -17
  20. package/dist/client/index.html +1 -1
  21. package/dist/config/builtin-coding-agents.d.ts +23 -0
  22. package/dist/config/builtin-coding-agents.d.ts.map +1 -0
  23. package/dist/config/{builtin-tools.js → builtin-coding-agents.js} +6 -6
  24. package/dist/config/builtin-coding-agents.js.map +1 -0
  25. package/dist/config/tools.d.ts +16 -16
  26. package/dist/config/tools.d.ts.map +1 -1
  27. package/dist/config/tools.js +81 -78
  28. package/dist/config/tools.js.map +1 -1
  29. package/dist/index.js +19 -19
  30. package/dist/index.js.map +1 -1
  31. package/dist/launcher.d.ts +8 -8
  32. package/dist/launcher.d.ts.map +1 -1
  33. package/dist/launcher.js +32 -28
  34. package/dist/launcher.js.map +1 -1
  35. package/dist/services/codingAgentCommandResolver.d.ts +10 -0
  36. package/dist/services/codingAgentCommandResolver.d.ts.map +1 -0
  37. package/dist/services/{customToolResolver.js → codingAgentCommandResolver.js} +25 -20
  38. package/dist/services/codingAgentCommandResolver.js.map +1 -0
  39. package/dist/services/{aiToolResolver.d.ts → codingAgentResolver.d.ts} +6 -6
  40. package/dist/services/codingAgentResolver.d.ts.map +1 -0
  41. package/dist/services/{aiToolResolver.js → codingAgentResolver.js} +23 -23
  42. package/dist/services/codingAgentResolver.js.map +1 -0
  43. package/dist/shared/{aiToolConstants.d.ts → codingAgentConstants.d.ts} +2 -2
  44. package/dist/shared/codingAgentConstants.d.ts.map +1 -0
  45. package/dist/shared/{aiToolConstants.js → codingAgentConstants.js} +2 -2
  46. package/dist/shared/codingAgentConstants.js.map +1 -0
  47. package/dist/types/api.d.ts +12 -12
  48. package/dist/types/api.d.ts.map +1 -1
  49. package/dist/types/tools.d.ts +30 -30
  50. package/dist/types/tools.d.ts.map +1 -1
  51. package/dist/types/tools.js +1 -1
  52. package/dist/web/client/src/components/CodingAgentLaunchModal.d.ts +9 -0
  53. package/dist/web/client/src/components/CodingAgentLaunchModal.d.ts.map +1 -0
  54. package/dist/web/client/src/components/{AIToolLaunchModal.js → CodingAgentLaunchModal.js} +58 -58
  55. package/dist/web/client/src/components/CodingAgentLaunchModal.js.map +1 -0
  56. package/dist/web/client/src/components/CustomCodingAgentForm.d.ts +23 -0
  57. package/dist/web/client/src/components/CustomCodingAgentForm.d.ts.map +1 -0
  58. package/dist/web/client/src/components/{CustomToolForm.js → CustomCodingAgentForm.js} +5 -5
  59. package/dist/web/client/src/components/CustomCodingAgentForm.js.map +1 -0
  60. package/dist/web/client/src/components/CustomCodingAgentList.d.ts +10 -0
  61. package/dist/web/client/src/components/CustomCodingAgentList.d.ts.map +1 -0
  62. package/dist/web/client/src/components/{CustomToolList.js → CustomCodingAgentList.js} +17 -17
  63. package/dist/web/client/src/components/CustomCodingAgentList.js.map +1 -0
  64. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.d.ts +2 -2
  65. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.d.ts.map +1 -1
  66. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js +6 -6
  67. package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js.map +1 -1
  68. package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts +2 -2
  69. package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts.map +1 -1
  70. package/dist/web/client/src/components/branch-detail/ToolLauncher.js +5 -5
  71. package/dist/web/client/src/components/branch-detail/ToolLauncher.js.map +1 -1
  72. package/dist/web/client/src/hooks/useSessions.d.ts +4 -4
  73. package/dist/web/client/src/hooks/useSessions.d.ts.map +1 -1
  74. package/dist/web/client/src/hooks/useSessions.js.map +1 -1
  75. package/dist/web/client/src/lib/api.d.ts +5 -5
  76. package/dist/web/client/src/lib/api.d.ts.map +1 -1
  77. package/dist/web/client/src/lib/api.js +1 -1
  78. package/dist/web/client/src/lib/api.js.map +1 -1
  79. package/dist/web/client/src/pages/BranchDetailPage.js +24 -24
  80. package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
  81. package/dist/web/client/src/pages/ConfigManagementPage.d.ts.map +1 -1
  82. package/dist/web/client/src/pages/ConfigManagementPage.js +15 -15
  83. package/dist/web/client/src/pages/ConfigManagementPage.js.map +1 -1
  84. package/dist/web/client/src/pages/ConfigPage.d.ts.map +1 -1
  85. package/dist/web/client/src/pages/ConfigPage.js +43 -39
  86. package/dist/web/client/src/pages/ConfigPage.js.map +1 -1
  87. package/dist/web/server/env/importer.d.ts.map +1 -1
  88. package/dist/web/server/env/importer.js +3 -3
  89. package/dist/web/server/env/importer.js.map +1 -1
  90. package/dist/web/server/pty/manager.d.ts +6 -6
  91. package/dist/web/server/pty/manager.d.ts.map +1 -1
  92. package/dist/web/server/pty/manager.js +11 -11
  93. package/dist/web/server/pty/manager.js.map +1 -1
  94. package/dist/web/server/routes/config.d.ts.map +1 -1
  95. package/dist/web/server/routes/config.js +34 -34
  96. package/dist/web/server/routes/config.js.map +1 -1
  97. package/dist/web/server/routes/sessions.d.ts +1 -1
  98. package/dist/web/server/routes/sessions.d.ts.map +1 -1
  99. package/dist/web/server/routes/sessions.js +20 -20
  100. package/dist/web/server/routes/sessions.js.map +1 -1
  101. package/package.json +2 -2
  102. package/src/cli/ui/__tests__/components/screens/{AIToolSelectorScreen.test.tsx → CodingAgentSelectorScreen.test.tsx} +38 -38
  103. package/src/cli/ui/components/App.tsx +22 -20
  104. package/src/cli/ui/components/screens/CodingAgentSelectorScreen.tsx +159 -0
  105. package/src/cli/ui/components/screens/ModelSelectorScreen.tsx +6 -2
  106. package/src/cli/ui/types.ts +2 -2
  107. package/src/cli/ui/utils/modelOptions.ts +6 -4
  108. package/src/config/{builtin-tools.ts → builtin-coding-agents.ts} +9 -9
  109. package/src/config/tools.ts +104 -92
  110. package/src/index.ts +19 -19
  111. package/src/launcher.ts +38 -31
  112. package/src/services/{customToolResolver.ts → codingAgentCommandResolver.ts} +33 -28
  113. package/src/services/{aiToolResolver.ts → codingAgentResolver.ts} +28 -28
  114. package/src/shared/{aiToolConstants.ts → codingAgentConstants.ts} +1 -1
  115. package/src/types/api.ts +12 -12
  116. package/src/types/tools.ts +30 -30
  117. package/src/web/client/src/components/{AIToolLaunchModal.tsx → CodingAgentLaunchModal.tsx} +74 -70
  118. package/src/web/client/src/components/{CustomToolForm.tsx → CustomCodingAgentForm.tsx} +14 -14
  119. package/src/web/client/src/components/{CustomToolList.tsx → CustomCodingAgentList.tsx} +26 -26
  120. package/src/web/client/src/components/branch-detail/SessionHistoryTable.tsx +7 -7
  121. package/src/web/client/src/components/branch-detail/ToolLauncher.tsx +9 -9
  122. package/src/web/client/src/hooks/useSessions.ts +5 -5
  123. package/src/web/client/src/lib/api.ts +8 -8
  124. package/src/web/client/src/pages/BranchDetailPage.tsx +26 -26
  125. package/src/web/client/src/pages/ConfigManagementPage.tsx +32 -24
  126. package/src/web/client/src/pages/ConfigPage.tsx +55 -49
  127. package/src/web/server/env/importer.ts +6 -3
  128. package/src/web/server/pty/manager.ts +20 -20
  129. package/src/web/server/routes/config.ts +45 -39
  130. package/src/web/server/routes/sessions.ts +29 -26
  131. package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts +0 -27
  132. package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts.map +0 -1
  133. package/dist/cli/ui/components/screens/AIToolSelectorScreen.js.map +0 -1
  134. package/dist/config/builtin-tools.d.ts +0 -23
  135. package/dist/config/builtin-tools.d.ts.map +0 -1
  136. package/dist/config/builtin-tools.js.map +0 -1
  137. package/dist/services/aiToolResolver.d.ts.map +0 -1
  138. package/dist/services/aiToolResolver.js.map +0 -1
  139. package/dist/services/customToolResolver.d.ts +0 -10
  140. package/dist/services/customToolResolver.d.ts.map +0 -1
  141. package/dist/services/customToolResolver.js.map +0 -1
  142. package/dist/shared/aiToolConstants.d.ts.map +0 -1
  143. package/dist/shared/aiToolConstants.js.map +0 -1
  144. package/dist/web/client/src/components/AIToolLaunchModal.d.ts +0 -9
  145. package/dist/web/client/src/components/AIToolLaunchModal.d.ts.map +0 -1
  146. package/dist/web/client/src/components/AIToolLaunchModal.js.map +0 -1
  147. package/dist/web/client/src/components/CustomToolForm.d.ts +0 -23
  148. package/dist/web/client/src/components/CustomToolForm.d.ts.map +0 -1
  149. package/dist/web/client/src/components/CustomToolForm.js.map +0 -1
  150. package/dist/web/client/src/components/CustomToolList.d.ts +0 -10
  151. package/dist/web/client/src/components/CustomToolList.d.ts.map +0 -1
  152. package/dist/web/client/src/components/CustomToolList.js.map +0 -1
  153. package/src/cli/ui/components/screens/AIToolSelectorScreen.tsx +0 -153
@@ -0,0 +1,159 @@
1
+ import React, { useState, useEffect } from "react";
2
+ import { Box, Text } from "ink";
3
+ import { Header } from "../parts/Header.js";
4
+ import { Footer } from "../parts/Footer.js";
5
+ import { Select } from "../common/Select.js";
6
+ import { useAppInput } from "../../hooks/useAppInput.js";
7
+ import { useTerminalSize } from "../../hooks/useTerminalSize.js";
8
+ import { getAllCodingAgents } from "../../../../config/tools.js";
9
+ import type { CodingAgentConfig } from "../../../../types/tools.js";
10
+ import type { CodingAgentId } from "../../types.js";
11
+
12
+ /**
13
+ * Renderable item for the coding agent selector list.
14
+ */
15
+ export interface CodingAgentItem {
16
+ label: string;
17
+ value: CodingAgentId;
18
+ description: string;
19
+ }
20
+
21
+ /**
22
+ * Props for `CodingAgentSelectorScreen`.
23
+ */
24
+ export interface CodingAgentSelectorScreenProps {
25
+ onBack: () => void;
26
+ onSelect: (agentId: CodingAgentId) => void;
27
+ version?: string | null;
28
+ initialAgentId?: CodingAgentId | null;
29
+ }
30
+
31
+ /**
32
+ * CodingAgentSelectorScreen - Screen for selecting coding agent (Claude Code, Codex CLI, or custom agents)
33
+ * Layout: Header + Agent Selection + Footer
34
+ *
35
+ * This screen dynamically loads available agents from the configuration (builtin + custom).
36
+ */
37
+ export function CodingAgentSelectorScreen({
38
+ onBack,
39
+ onSelect,
40
+ version,
41
+ initialAgentId,
42
+ }: CodingAgentSelectorScreenProps) {
43
+ const { rows } = useTerminalSize();
44
+ const [agentItems, setAgentItems] = useState<CodingAgentItem[]>([]);
45
+ const [isLoading, setIsLoading] = useState(true);
46
+ const [selectedIndex, setSelectedIndex] = useState<number>(0);
47
+
48
+ // Load agents from getAllCodingAgents()
49
+ useEffect(() => {
50
+ const loadAgents = async () => {
51
+ try {
52
+ const agents = await getAllCodingAgents();
53
+
54
+ // Convert CodingAgentConfig[] to CodingAgentItem[]
55
+ const items: CodingAgentItem[] = agents.map(
56
+ (agent: CodingAgentConfig) => {
57
+ // Generate description based on whether it's builtin or custom
58
+ const description = agent.isBuiltin
59
+ ? `Official ${agent.displayName} agent`
60
+ : `Custom coding agent`;
61
+
62
+ // Add icon to label if present
63
+ const label = agent.icon
64
+ ? `${agent.icon} ${agent.displayName}`
65
+ : agent.displayName;
66
+
67
+ return {
68
+ label,
69
+ value: agent.id,
70
+ description,
71
+ };
72
+ },
73
+ );
74
+
75
+ setAgentItems(items);
76
+
77
+ // Decide initial cursor position based on last used agent
78
+ const idx =
79
+ initialAgentId && items.length > 0
80
+ ? items.findIndex((item) => item.value === initialAgentId)
81
+ : 0;
82
+ setSelectedIndex(idx >= 0 ? idx : 0);
83
+ } catch (error) {
84
+ // If loading fails, show error in console but don't crash
85
+ console.error("Failed to load coding agents:", error);
86
+ // Fall back to empty array
87
+ setAgentItems([]);
88
+ } finally {
89
+ setIsLoading(false);
90
+ }
91
+ };
92
+
93
+ loadAgents();
94
+ }, [initialAgentId]);
95
+
96
+ // Update selection when props or items change
97
+ useEffect(() => {
98
+ if (isLoading || agentItems.length === 0) return;
99
+ const idx =
100
+ initialAgentId && agentItems.length > 0
101
+ ? agentItems.findIndex((item) => item.value === initialAgentId)
102
+ : 0;
103
+ setSelectedIndex(idx >= 0 ? idx : 0);
104
+ }, [initialAgentId, agentItems, isLoading]);
105
+
106
+ // Handle keyboard input
107
+ // Note: Select component handles Enter and arrow keys
108
+ useAppInput((input, key) => {
109
+ if (key.escape) {
110
+ onBack();
111
+ }
112
+ });
113
+
114
+ // Handle agent selection
115
+ const handleSelect = (item: CodingAgentItem) => {
116
+ onSelect(item.value);
117
+ };
118
+
119
+ // Footer actions
120
+ const footerActions = [
121
+ { key: "enter", description: "Select" },
122
+ { key: "esc", description: "Back" },
123
+ ];
124
+
125
+ return (
126
+ <Box flexDirection="column" height={rows}>
127
+ {/* Header */}
128
+ <Header
129
+ title="Coding Agent Selection"
130
+ titleColor="blue"
131
+ version={version}
132
+ />
133
+
134
+ {/* Content */}
135
+ <Box flexDirection="column" flexGrow={1} marginTop={1}>
136
+ <Box marginBottom={1}>
137
+ <Text>Select coding agent to use:</Text>
138
+ </Box>
139
+ {isLoading ? (
140
+ <Text>Loading coding agents...</Text>
141
+ ) : agentItems.length === 0 ? (
142
+ <Text color="yellow">
143
+ No coding agents available. Please check your configuration.
144
+ </Text>
145
+ ) : (
146
+ <Select
147
+ items={agentItems}
148
+ onSelect={handleSelect}
149
+ selectedIndex={selectedIndex}
150
+ onSelectedIndexChange={setSelectedIndex}
151
+ />
152
+ )}
153
+ </Box>
154
+
155
+ {/* Footer */}
156
+ <Footer actions={footerActions} />
157
+ </Box>
158
+ );
159
+ }
@@ -5,7 +5,11 @@ import { Footer } from "../parts/Footer.js";
5
5
  import { Select, type SelectItem } from "../common/Select.js";
6
6
  import { useAppInput } from "../../hooks/useAppInput.js";
7
7
  import { useTerminalSize } from "../../hooks/useTerminalSize.js";
8
- import type { AITool, InferenceLevel, ModelOption } from "../../types.js";
8
+ import type {
9
+ CodingAgentId,
10
+ InferenceLevel,
11
+ ModelOption,
12
+ } from "../../types.js";
9
13
  import {
10
14
  getDefaultInferenceForModel,
11
15
  getDefaultModelOption,
@@ -33,7 +37,7 @@ interface InferenceSelectItem extends SelectItem {
33
37
  * Props for `ModelSelectorScreen`.
34
38
  */
35
39
  export interface ModelSelectorScreenProps {
36
- tool: AITool;
40
+ tool: CodingAgentId;
37
41
  onBack: () => void;
38
42
  onSelect: (selection: ModelSelectionResult) => void;
39
43
  version?: string | null;
@@ -9,7 +9,7 @@ export interface WorktreeInfo {
9
9
  hasUncommittedChanges?: boolean;
10
10
  }
11
11
 
12
- export type AITool = string;
12
+ export type CodingAgentId = string;
13
13
  export type InferenceLevel = "low" | "medium" | "high" | "xhigh";
14
14
 
15
15
  /**
@@ -194,7 +194,7 @@ export type ScreenType =
194
194
  | "branch-creator"
195
195
  | "branch-action-selector"
196
196
  | "branch-quick-start"
197
- | "ai-tool-selector"
197
+ | "coding-agent-selector"
198
198
  | "model-selector"
199
199
  | "session-selector"
200
200
  | "execution-mode-selector"
@@ -1,4 +1,4 @@
1
- import type { AITool, InferenceLevel, ModelOption } from "../types.js";
1
+ import type { CodingAgentId, InferenceLevel, ModelOption } from "../types.js";
2
2
 
3
3
  const CODEX_BASE_LEVELS: InferenceLevel[] = ["high", "medium", "low"];
4
4
  const CODEX_MAX_LEVELS: InferenceLevel[] = ["xhigh", "high", "medium", "low"];
@@ -105,11 +105,13 @@ const MODEL_OPTIONS: Record<string, ModelOption[]> = {
105
105
  ],
106
106
  };
107
107
 
108
- export function getModelOptions(tool: AITool): ModelOption[] {
108
+ export function getModelOptions(tool: CodingAgentId): ModelOption[] {
109
109
  return MODEL_OPTIONS[tool] ?? [];
110
110
  }
111
111
 
112
- export function getDefaultModelOption(tool: AITool): ModelOption | undefined {
112
+ export function getDefaultModelOption(
113
+ tool: CodingAgentId,
114
+ ): ModelOption | undefined {
113
115
  const options = getModelOptions(tool);
114
116
  return options.find((opt) => opt.isDefault) ?? options[0];
115
117
  }
@@ -136,7 +138,7 @@ export function getDefaultInferenceForModel(
136
138
  * Normalize a model identifier for consistent display and persistence.
137
139
  */
138
140
  export function normalizeModelId(
139
- tool: AITool,
141
+ tool: CodingAgentId,
140
142
  model?: string | null,
141
143
  ): string | null {
142
144
  if (model === null || model === undefined) return model ?? null;
@@ -1,19 +1,19 @@
1
1
  /**
2
- * ビルトインAIツール定義
2
+ * ビルトインコーディングエージェント定義
3
3
  *
4
- * Claude Code、Codex、Gemini の CustomAITool 形式定義
4
+ * Claude Code、Codex、Gemini の CodingAgent 形式定義
5
5
  */
6
6
 
7
- import type { CustomAITool } from "../types/tools.js";
7
+ import type { CodingAgent } from "../types/tools.js";
8
8
  import {
9
9
  CLAUDE_PERMISSION_SKIP_ARGS,
10
10
  CODEX_DEFAULT_ARGS,
11
- } from "../shared/aiToolConstants.js";
11
+ } from "../shared/codingAgentConstants.js";
12
12
 
13
13
  /**
14
14
  * Claude Code のビルトイン定義
15
15
  */
16
- export const CLAUDE_CODE_TOOL: CustomAITool = {
16
+ export const CLAUDE_CODE_TOOL: CodingAgent = {
17
17
  id: "claude-code",
18
18
  displayName: "Claude Code",
19
19
  type: "bunx",
@@ -32,7 +32,7 @@ export const CLAUDE_CODE_TOOL: CustomAITool = {
32
32
  /**
33
33
  * Codex のビルトイン定義
34
34
  */
35
- export const CODEX_CLI_TOOL: CustomAITool = {
35
+ export const CODEX_CLI_TOOL: CodingAgent = {
36
36
  id: "codex-cli",
37
37
  displayName: "Codex",
38
38
  type: "bunx",
@@ -48,7 +48,7 @@ export const CODEX_CLI_TOOL: CustomAITool = {
48
48
  /**
49
49
  * Gemini のビルトイン定義
50
50
  */
51
- export const GEMINI_CLI_TOOL: CustomAITool = {
51
+ export const GEMINI_CLI_TOOL: CodingAgent = {
52
52
  id: "gemini-cli",
53
53
  displayName: "Gemini",
54
54
  type: "bunx",
@@ -62,9 +62,9 @@ export const GEMINI_CLI_TOOL: CustomAITool = {
62
62
  };
63
63
 
64
64
  /**
65
- * すべてのビルトインツール
65
+ * すべてのビルトインコーディングエージェント
66
66
  */
67
- export const BUILTIN_TOOLS: CustomAITool[] = [
67
+ export const BUILTIN_CODING_AGENTS: CodingAgent[] = [
68
68
  CLAUDE_CODE_TOOL,
69
69
  CODEX_CLI_TOOL,
70
70
  GEMINI_CLI_TOOL,
@@ -1,26 +1,26 @@
1
1
  /**
2
- * カスタムツール設定管理
2
+ * コーディングエージェント設定管理
3
3
  *
4
4
  * ~/.gwt/tools.jsonから設定を読み込み、
5
- * ビルトインツールと統合して管理します。
5
+ * ビルトインエージェントと統合して管理します。
6
6
  */
7
7
 
8
8
  import { homedir } from "node:os";
9
9
  import path from "node:path";
10
10
  import { readFile, writeFile, mkdir, rename } from "node:fs/promises";
11
11
  import type {
12
- ToolsConfig,
13
- CustomAITool,
14
- AIToolConfig,
12
+ CodingAgentsConfig,
13
+ CodingAgent,
14
+ CodingAgentConfig,
15
15
  } from "../types/tools.js";
16
- import { BUILTIN_TOOLS } from "./builtin-tools.js";
16
+ import { BUILTIN_CODING_AGENTS } from "./builtin-coding-agents.js";
17
17
  import { createLogger } from "../logging/logger.js";
18
18
  import { resolveProfileEnv } from "./profiles.js";
19
19
 
20
20
  const logger = createLogger({ category: "config" });
21
21
 
22
22
  /**
23
- * ツール設定ファイルのパス
23
+ * コーディングエージェント設定ファイルのパス
24
24
  * 環境変数 GWT_HOME が設定されている場合はそれを使用、それ以外はホームディレクトリ
25
25
  */
26
26
  export const WORKTREE_HOME =
@@ -32,32 +32,35 @@ export const CONFIG_DIR = path.join(WORKTREE_HOME, ".gwt");
32
32
  export const TOOLS_CONFIG_PATH = path.join(CONFIG_DIR, "tools.json");
33
33
  const TEMP_CONFIG_PATH = `${TOOLS_CONFIG_PATH}.tmp`;
34
34
 
35
- const DEFAULT_CONFIG: ToolsConfig = {
35
+ const DEFAULT_CONFIG: CodingAgentsConfig = {
36
36
  version: "1.0.0",
37
37
  env: {},
38
- customTools: [],
38
+ customCodingAgents: [],
39
39
  };
40
40
 
41
41
  /**
42
- * ツール設定を読み込む
42
+ * コーディングエージェント設定を読み込む
43
43
  *
44
44
  * ~/.gwt/tools.jsonから設定を読み込みます。
45
45
  * ファイルが存在しない場合は空配列を返します。
46
46
  *
47
- * @returns ToolsConfig
47
+ * @returns CodingAgentsConfig
48
48
  * @throws JSON構文エラー時
49
49
  */
50
- export async function loadToolsConfig(): Promise<ToolsConfig> {
50
+ export async function loadCodingAgentsConfig(): Promise<CodingAgentsConfig> {
51
51
  try {
52
52
  const content = await readFile(TOOLS_CONFIG_PATH, "utf-8");
53
- const config = JSON.parse(content) as ToolsConfig;
53
+ const config = JSON.parse(content) as CodingAgentsConfig;
54
54
 
55
55
  // 検証
56
- validateToolsConfig(config);
56
+ validateCodingAgentsConfig(config);
57
57
 
58
58
  logger.debug(
59
- { path: TOOLS_CONFIG_PATH, toolCount: config.customTools.length },
60
- "Tools config loaded",
59
+ {
60
+ path: TOOLS_CONFIG_PATH,
61
+ agentCount: config.customCodingAgents.length,
62
+ },
63
+ "Coding agents config loaded",
61
64
  );
62
65
 
63
66
  return {
@@ -69,7 +72,7 @@ export async function loadToolsConfig(): Promise<ToolsConfig> {
69
72
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
70
73
  logger.debug(
71
74
  { path: TOOLS_CONFIG_PATH },
72
- "Tools config not found, using defaults",
75
+ "Coding agents config not found, using defaults",
73
76
  );
74
77
  return { ...DEFAULT_CONFIG };
75
78
  }
@@ -78,7 +81,7 @@ export async function loadToolsConfig(): Promise<ToolsConfig> {
78
81
  if (error instanceof SyntaxError) {
79
82
  logger.error(
80
83
  { path: TOOLS_CONFIG_PATH, error: error.message },
81
- "Tools config parse error",
84
+ "Coding agents config parse error",
82
85
  );
83
86
  throw new Error(
84
87
  `Failed to parse tools.json: ${error.message}\n` +
@@ -92,20 +95,20 @@ export async function loadToolsConfig(): Promise<ToolsConfig> {
92
95
  }
93
96
 
94
97
  /**
95
- * ToolsConfig全体を検証
98
+ * CodingAgentsConfig全体を検証
96
99
  *
97
100
  * @param config - 検証対象の設定
98
101
  * @throws 検証エラー時
99
102
  */
100
- function validateToolsConfig(config: ToolsConfig): void {
103
+ function validateCodingAgentsConfig(config: CodingAgentsConfig): void {
101
104
  // versionフィールドの検証
102
105
  if (!config.version || typeof config.version !== "string") {
103
106
  throw new Error("version field is required and must be a string");
104
107
  }
105
108
 
106
- // customToolsフィールドの検証
107
- if (!Array.isArray(config.customTools)) {
108
- throw new Error("customTools field must be an array");
109
+ // customCodingAgentsフィールドの検証
110
+ if (!Array.isArray(config.customCodingAgents)) {
111
+ throw new Error("customCodingAgents field must be an array");
109
112
  }
110
113
 
111
114
  if (config.env && typeof config.env !== "object") {
@@ -123,40 +126,42 @@ function validateToolsConfig(config: ToolsConfig): void {
123
126
  }
124
127
  }
125
128
 
126
- // 各ツールの検証
129
+ // 各エージェントの検証
127
130
  const seenIds = new Set<string>();
128
- for (const tool of config.customTools) {
129
- validateCustomAITool(tool);
131
+ for (const agent of config.customCodingAgents) {
132
+ validateCodingAgent(agent);
130
133
 
131
134
  // ID重複チェック
132
- if (seenIds.has(tool.id)) {
135
+ if (seenIds.has(agent.id)) {
133
136
  throw new Error(
134
- `Duplicate tool ID found: "${tool.id}"\n` +
135
- `Each tool must have a unique ID in ${TOOLS_CONFIG_PATH}`,
137
+ `Duplicate agent ID found: "${agent.id}"\n` +
138
+ `Each agent must have a unique ID in ${TOOLS_CONFIG_PATH}`,
136
139
  );
137
140
  }
138
- seenIds.add(tool.id);
141
+ seenIds.add(agent.id);
139
142
 
140
- // ビルトインツールとのID重複チェック
141
- const builtinIds = BUILTIN_TOOLS.map((t) => t.id);
142
- if (builtinIds.includes(tool.id)) {
143
+ // ビルトインエージェントとのID重複チェック
144
+ const builtinIds = BUILTIN_CODING_AGENTS.map((t) => t.id);
145
+ if (builtinIds.includes(agent.id)) {
143
146
  throw new Error(
144
- `Tool ID "${tool.id}" conflicts with builtin tool\n` +
145
- `Builtin tool IDs: ${builtinIds.join(", ")}`,
147
+ `Agent ID "${agent.id}" conflicts with builtin agent\n` +
148
+ `Builtin agent IDs: ${builtinIds.join(", ")}`,
146
149
  );
147
150
  }
148
151
  }
149
152
  }
150
153
 
151
- export async function saveToolsConfig(config: ToolsConfig): Promise<void> {
152
- const normalized: ToolsConfig = {
154
+ export async function saveCodingAgentsConfig(
155
+ config: CodingAgentsConfig,
156
+ ): Promise<void> {
157
+ const normalized: CodingAgentsConfig = {
153
158
  version: config.version,
154
159
  updatedAt: config.updatedAt ?? new Date().toISOString(),
155
160
  env: config.env ?? {},
156
- customTools: config.customTools,
161
+ customCodingAgents: config.customCodingAgents,
157
162
  };
158
163
 
159
- validateToolsConfig(normalized);
164
+ validateCodingAgentsConfig(normalized);
160
165
 
161
166
  await mkdir(CONFIG_DIR, { recursive: true });
162
167
  const payload = JSON.stringify(normalized, null, 2);
@@ -167,7 +172,7 @@ export async function saveToolsConfig(config: ToolsConfig): Promise<void> {
167
172
  /**
168
173
  * 共有環境変数を取得
169
174
  *
170
- * AIツール起動時に適用される環境変数を返します。
175
+ * コーディングエージェント起動時に適用される環境変数を返します。
171
176
  * マージ優先順位(後勝ち):
172
177
  * 1. tools.json の env フィールド
173
178
  * 2. profiles.yaml のアクティブプロファイル
@@ -176,7 +181,7 @@ export async function saveToolsConfig(config: ToolsConfig): Promise<void> {
176
181
  */
177
182
  export async function getSharedEnvironment(): Promise<Record<string, string>> {
178
183
  const [config, profileEnv] = await Promise.all([
179
- loadToolsConfig(),
184
+ loadCodingAgentsConfig(),
180
185
  resolveProfileEnv(),
181
186
  ]);
182
187
 
@@ -187,104 +192,111 @@ export async function getSharedEnvironment(): Promise<Record<string, string>> {
187
192
  }
188
193
 
189
194
  /**
190
- * CustomAITool単体を検証
195
+ * CodingAgent単体を検証
191
196
  *
192
- * @param tool - 検証対象のツール
197
+ * @param agent - 検証対象のエージェント
193
198
  * @throws 検証エラー時
194
199
  */
195
- function validateCustomAITool(tool: unknown): asserts tool is CustomAITool {
200
+ function validateCodingAgent(agent: unknown): asserts agent is CodingAgent {
196
201
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
197
- const t = tool as any;
202
+ const a = agent as any;
198
203
 
199
204
  // 必須フィールドの存在チェック
200
205
  const requiredFields = ["id", "displayName", "type", "command", "modeArgs"];
201
206
  for (const field of requiredFields) {
202
- if (!t[field]) {
207
+ if (!a[field]) {
203
208
  throw new Error(
204
- `Required field "${field}" is missing in tool configuration`,
209
+ `Required field "${field}" is missing in agent configuration`,
205
210
  );
206
211
  }
207
212
  }
208
213
 
209
214
  // id形式の検証(小文字英数字とハイフンのみ)
210
- if (!/^[a-z0-9-]+$/.test(t.id)) {
215
+ if (!/^[a-z0-9-]+$/.test(a.id)) {
211
216
  throw new Error(
212
- `Invalid tool ID format: "${t.id}"\n` +
213
- `Tool ID must contain only lowercase letters, numbers, and hyphens (pattern: ^[a-z0-9-]+$)`,
217
+ `Invalid agent ID format: "${a.id}"\n` +
218
+ `Agent ID must contain only lowercase letters, numbers, and hyphens (pattern: ^[a-z0-9-]+$)`,
214
219
  );
215
220
  }
216
221
 
217
222
  // typeフィールドの値検証
218
223
  const validTypes = ["path", "bunx", "command"];
219
- if (!validTypes.includes(t.type)) {
224
+ if (!validTypes.includes(a.type)) {
220
225
  throw new Error(
221
- `Invalid type: "${t.type}"\n` +
226
+ `Invalid type: "${a.type}"\n` +
222
227
  `Type must be one of: ${validTypes.join(", ")}`,
223
228
  );
224
229
  }
225
230
 
226
231
  // type='path'の場合、commandが絶対パスであることを確認
227
- if (t.type === "path" && !path.isAbsolute(t.command)) {
232
+ if (a.type === "path" && !path.isAbsolute(a.command)) {
228
233
  throw new Error(
229
- `For type="path", command must be an absolute path: "${t.command}"`,
234
+ `For type="path", command must be an absolute path: "${a.command}"`,
230
235
  );
231
236
  }
232
237
 
233
238
  // modeArgsの検証(少なくとも1つのモードが定義されている)
234
- if (!t.modeArgs.normal && !t.modeArgs.continue && !t.modeArgs.resume) {
239
+ if (!a.modeArgs.normal && !a.modeArgs.continue && !a.modeArgs.resume) {
235
240
  throw new Error(
236
- `modeArgs must define at least one mode (normal, continue, or resume) for tool "${t.id}"`,
241
+ `modeArgs must define at least one mode (normal, continue, or resume) for agent "${a.id}"`,
237
242
  );
238
243
  }
239
244
  }
240
245
 
241
246
  /**
242
- * IDでツールを検索
247
+ * IDでコーディングエージェントを検索
243
248
  *
244
- * @param id - ツールID
245
- * @returns ツール設定(見つからない場合はundefined)
249
+ * @param id - エージェントID
250
+ * @returns エージェント設定(見つからない場合はundefined)
246
251
  */
247
- export async function getToolById(
252
+ export async function getCodingAgentById(
248
253
  id: string,
249
- ): Promise<CustomAITool | undefined> {
250
- // ビルトインツールから検索
251
- const builtinTool = BUILTIN_TOOLS.find((t) => t.id === id);
252
- if (builtinTool) {
253
- logger.debug({ id, found: true, isBuiltin: true }, "Tool lookup");
254
- return builtinTool;
254
+ ): Promise<CodingAgent | undefined> {
255
+ // ビルトインエージェントから検索
256
+ const builtinAgent = BUILTIN_CODING_AGENTS.find((a) => a.id === id);
257
+ if (builtinAgent) {
258
+ logger.debug({ id, found: true, isBuiltin: true }, "Coding agent lookup");
259
+ return builtinAgent;
255
260
  }
256
261
 
257
- // カスタムツールから検索
258
- const config = await loadToolsConfig();
259
- const customTool = config.customTools.find((t) => t.id === id);
260
- logger.debug({ id, found: !!customTool, isBuiltin: false }, "Tool lookup");
261
- return customTool;
262
+ // カスタムエージェントから検索
263
+ const config = await loadCodingAgentsConfig();
264
+ const customAgent = config.customCodingAgents.find((a) => a.id === id);
265
+ logger.debug(
266
+ { id, found: !!customAgent, isBuiltin: false },
267
+ "Coding agent lookup",
268
+ );
269
+ return customAgent;
262
270
  }
263
271
 
264
272
  /**
265
- * すべてのツール(ビルトイン+カスタム)を取得
273
+ * すべてのコーディングエージェント(ビルトイン+カスタム)を取得
266
274
  *
267
- * @returns AIToolConfigの配列
275
+ * @returns CodingAgentConfigの配列
268
276
  */
269
- export async function getAllTools(): Promise<AIToolConfig[]> {
270
- const config = await loadToolsConfig();
271
-
272
- // ビルトインツールをAIToolConfig形式に変換
273
- const builtinConfigs: AIToolConfig[] = BUILTIN_TOOLS.map((tool) => ({
274
- id: tool.id,
275
- displayName: tool.displayName,
276
- ...(tool.icon ? { icon: tool.icon } : {}),
277
- isBuiltin: true,
278
- }));
279
-
280
- // カスタムツールをAIToolConfig形式に変換
281
- const customConfigs: AIToolConfig[] = config.customTools.map((tool) => ({
282
- id: tool.id,
283
- displayName: tool.displayName,
284
- ...(tool.icon ? { icon: tool.icon } : {}),
285
- isBuiltin: false,
286
- customConfig: tool,
287
- }));
277
+ export async function getAllCodingAgents(): Promise<CodingAgentConfig[]> {
278
+ const config = await loadCodingAgentsConfig();
279
+
280
+ // ビルトインエージェントをCodingAgentConfig形式に変換
281
+ const builtinConfigs: CodingAgentConfig[] = BUILTIN_CODING_AGENTS.map(
282
+ (agent) => ({
283
+ id: agent.id,
284
+ displayName: agent.displayName,
285
+ ...(agent.icon ? { icon: agent.icon } : {}),
286
+ isBuiltin: true,
287
+ }),
288
+ );
289
+
290
+ // カスタムエージェントをCodingAgentConfig形式に変換
291
+ const customConfigs: CodingAgentConfig[] = config.customCodingAgents.map(
292
+ (agent) => ({
293
+ id: agent.id,
294
+ displayName: agent.displayName,
295
+ ...(agent.icon ? { icon: agent.icon } : {}),
296
+ isBuiltin: false,
297
+ customConfig: agent,
298
+ }),
299
+ );
288
300
 
289
301
  // ビルトイン + カスタム の順で統合
290
302
  return [...builtinConfigs, ...customConfigs];