@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.
- package/README.ja.md +58 -34
- package/README.md +18 -34
- package/dist/cli/ui/components/App.d.ts +2 -2
- package/dist/cli/ui/components/App.d.ts.map +1 -1
- package/dist/cli/ui/components/App.js +8 -8
- package/dist/cli/ui/components/App.js.map +1 -1
- package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.d.ts +27 -0
- package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.d.ts.map +1 -0
- package/dist/cli/ui/components/screens/{AIToolSelectorScreen.js → CodingAgentSelectorScreen.js} +35 -35
- package/dist/cli/ui/components/screens/CodingAgentSelectorScreen.js.map +1 -0
- package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts +2 -2
- package/dist/cli/ui/components/screens/ModelSelectorScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/ModelSelectorScreen.js.map +1 -1
- package/dist/cli/ui/types.d.ts +2 -2
- package/dist/cli/ui/types.d.ts.map +1 -1
- package/dist/cli/ui/utils/modelOptions.d.ts +4 -4
- package/dist/cli/ui/utils/modelOptions.d.ts.map +1 -1
- package/dist/cli/ui/utils/modelOptions.js.map +1 -1
- package/dist/client/assets/{index-PqK9jkug.js → index-LNPtOrn3.js} +17 -17
- package/dist/client/index.html +1 -1
- package/dist/config/builtin-coding-agents.d.ts +23 -0
- package/dist/config/builtin-coding-agents.d.ts.map +1 -0
- package/dist/config/{builtin-tools.js → builtin-coding-agents.js} +6 -6
- package/dist/config/builtin-coding-agents.js.map +1 -0
- package/dist/config/tools.d.ts +16 -16
- package/dist/config/tools.d.ts.map +1 -1
- package/dist/config/tools.js +81 -78
- package/dist/config/tools.js.map +1 -1
- package/dist/index.js +19 -19
- package/dist/index.js.map +1 -1
- package/dist/launcher.d.ts +8 -8
- package/dist/launcher.d.ts.map +1 -1
- package/dist/launcher.js +32 -28
- package/dist/launcher.js.map +1 -1
- package/dist/services/codingAgentCommandResolver.d.ts +10 -0
- package/dist/services/codingAgentCommandResolver.d.ts.map +1 -0
- package/dist/services/{customToolResolver.js → codingAgentCommandResolver.js} +25 -20
- package/dist/services/codingAgentCommandResolver.js.map +1 -0
- package/dist/services/{aiToolResolver.d.ts → codingAgentResolver.d.ts} +6 -6
- package/dist/services/codingAgentResolver.d.ts.map +1 -0
- package/dist/services/{aiToolResolver.js → codingAgentResolver.js} +23 -23
- package/dist/services/codingAgentResolver.js.map +1 -0
- package/dist/shared/{aiToolConstants.d.ts → codingAgentConstants.d.ts} +2 -2
- package/dist/shared/codingAgentConstants.d.ts.map +1 -0
- package/dist/shared/{aiToolConstants.js → codingAgentConstants.js} +2 -2
- package/dist/shared/codingAgentConstants.js.map +1 -0
- package/dist/types/api.d.ts +12 -12
- package/dist/types/api.d.ts.map +1 -1
- package/dist/types/tools.d.ts +30 -30
- package/dist/types/tools.d.ts.map +1 -1
- package/dist/types/tools.js +1 -1
- package/dist/web/client/src/components/CodingAgentLaunchModal.d.ts +9 -0
- package/dist/web/client/src/components/CodingAgentLaunchModal.d.ts.map +1 -0
- package/dist/web/client/src/components/{AIToolLaunchModal.js → CodingAgentLaunchModal.js} +58 -58
- package/dist/web/client/src/components/CodingAgentLaunchModal.js.map +1 -0
- package/dist/web/client/src/components/CustomCodingAgentForm.d.ts +23 -0
- package/dist/web/client/src/components/CustomCodingAgentForm.d.ts.map +1 -0
- package/dist/web/client/src/components/{CustomToolForm.js → CustomCodingAgentForm.js} +5 -5
- package/dist/web/client/src/components/CustomCodingAgentForm.js.map +1 -0
- package/dist/web/client/src/components/CustomCodingAgentList.d.ts +10 -0
- package/dist/web/client/src/components/CustomCodingAgentList.d.ts.map +1 -0
- package/dist/web/client/src/components/{CustomToolList.js → CustomCodingAgentList.js} +17 -17
- package/dist/web/client/src/components/CustomCodingAgentList.js.map +1 -0
- package/dist/web/client/src/components/branch-detail/SessionHistoryTable.d.ts +2 -2
- package/dist/web/client/src/components/branch-detail/SessionHistoryTable.d.ts.map +1 -1
- package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js +6 -6
- package/dist/web/client/src/components/branch-detail/SessionHistoryTable.js.map +1 -1
- package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts +2 -2
- package/dist/web/client/src/components/branch-detail/ToolLauncher.d.ts.map +1 -1
- package/dist/web/client/src/components/branch-detail/ToolLauncher.js +5 -5
- package/dist/web/client/src/components/branch-detail/ToolLauncher.js.map +1 -1
- package/dist/web/client/src/hooks/useSessions.d.ts +4 -4
- package/dist/web/client/src/hooks/useSessions.d.ts.map +1 -1
- package/dist/web/client/src/hooks/useSessions.js.map +1 -1
- package/dist/web/client/src/lib/api.d.ts +5 -5
- package/dist/web/client/src/lib/api.d.ts.map +1 -1
- package/dist/web/client/src/lib/api.js +1 -1
- package/dist/web/client/src/lib/api.js.map +1 -1
- package/dist/web/client/src/pages/BranchDetailPage.js +24 -24
- package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
- package/dist/web/client/src/pages/ConfigManagementPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/ConfigManagementPage.js +15 -15
- package/dist/web/client/src/pages/ConfigManagementPage.js.map +1 -1
- package/dist/web/client/src/pages/ConfigPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/ConfigPage.js +43 -39
- package/dist/web/client/src/pages/ConfigPage.js.map +1 -1
- package/dist/web/server/env/importer.d.ts.map +1 -1
- package/dist/web/server/env/importer.js +3 -3
- package/dist/web/server/env/importer.js.map +1 -1
- package/dist/web/server/pty/manager.d.ts +6 -6
- package/dist/web/server/pty/manager.d.ts.map +1 -1
- package/dist/web/server/pty/manager.js +11 -11
- package/dist/web/server/pty/manager.js.map +1 -1
- package/dist/web/server/routes/config.d.ts.map +1 -1
- package/dist/web/server/routes/config.js +34 -34
- package/dist/web/server/routes/config.js.map +1 -1
- package/dist/web/server/routes/sessions.d.ts +1 -1
- package/dist/web/server/routes/sessions.d.ts.map +1 -1
- package/dist/web/server/routes/sessions.js +20 -20
- package/dist/web/server/routes/sessions.js.map +1 -1
- package/package.json +2 -2
- package/src/cli/ui/__tests__/components/screens/{AIToolSelectorScreen.test.tsx → CodingAgentSelectorScreen.test.tsx} +38 -38
- package/src/cli/ui/components/App.tsx +22 -20
- package/src/cli/ui/components/screens/CodingAgentSelectorScreen.tsx +159 -0
- package/src/cli/ui/components/screens/ModelSelectorScreen.tsx +6 -2
- package/src/cli/ui/types.ts +2 -2
- package/src/cli/ui/utils/modelOptions.ts +6 -4
- package/src/config/{builtin-tools.ts → builtin-coding-agents.ts} +9 -9
- package/src/config/tools.ts +104 -92
- package/src/index.ts +19 -19
- package/src/launcher.ts +38 -31
- package/src/services/{customToolResolver.ts → codingAgentCommandResolver.ts} +33 -28
- package/src/services/{aiToolResolver.ts → codingAgentResolver.ts} +28 -28
- package/src/shared/{aiToolConstants.ts → codingAgentConstants.ts} +1 -1
- package/src/types/api.ts +12 -12
- package/src/types/tools.ts +30 -30
- package/src/web/client/src/components/{AIToolLaunchModal.tsx → CodingAgentLaunchModal.tsx} +74 -70
- package/src/web/client/src/components/{CustomToolForm.tsx → CustomCodingAgentForm.tsx} +14 -14
- package/src/web/client/src/components/{CustomToolList.tsx → CustomCodingAgentList.tsx} +26 -26
- package/src/web/client/src/components/branch-detail/SessionHistoryTable.tsx +7 -7
- package/src/web/client/src/components/branch-detail/ToolLauncher.tsx +9 -9
- package/src/web/client/src/hooks/useSessions.ts +5 -5
- package/src/web/client/src/lib/api.ts +8 -8
- package/src/web/client/src/pages/BranchDetailPage.tsx +26 -26
- package/src/web/client/src/pages/ConfigManagementPage.tsx +32 -24
- package/src/web/client/src/pages/ConfigPage.tsx +55 -49
- package/src/web/server/env/importer.ts +6 -3
- package/src/web/server/pty/manager.ts +20 -20
- package/src/web/server/routes/config.ts +45 -39
- package/src/web/server/routes/sessions.ts +29 -26
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts +0 -27
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts.map +0 -1
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.js.map +0 -1
- package/dist/config/builtin-tools.d.ts +0 -23
- package/dist/config/builtin-tools.d.ts.map +0 -1
- package/dist/config/builtin-tools.js.map +0 -1
- package/dist/services/aiToolResolver.d.ts.map +0 -1
- package/dist/services/aiToolResolver.js.map +0 -1
- package/dist/services/customToolResolver.d.ts +0 -10
- package/dist/services/customToolResolver.d.ts.map +0 -1
- package/dist/services/customToolResolver.js.map +0 -1
- package/dist/shared/aiToolConstants.d.ts.map +0 -1
- package/dist/shared/aiToolConstants.js.map +0 -1
- package/dist/web/client/src/components/AIToolLaunchModal.d.ts +0 -9
- package/dist/web/client/src/components/AIToolLaunchModal.d.ts.map +0 -1
- package/dist/web/client/src/components/AIToolLaunchModal.js.map +0 -1
- package/dist/web/client/src/components/CustomToolForm.d.ts +0 -23
- package/dist/web/client/src/components/CustomToolForm.d.ts.map +0 -1
- package/dist/web/client/src/components/CustomToolForm.js.map +0 -1
- package/dist/web/client/src/components/CustomToolList.d.ts +0 -10
- package/dist/web/client/src/components/CustomToolList.d.ts.map +0 -1
- package/dist/web/client/src/components/CustomToolList.js.map +0 -1
- 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 {
|
|
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:
|
|
40
|
+
tool: CodingAgentId;
|
|
37
41
|
onBack: () => void;
|
|
38
42
|
onSelect: (selection: ModelSelectionResult) => void;
|
|
39
43
|
version?: string | null;
|
package/src/cli/ui/types.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface WorktreeInfo {
|
|
|
9
9
|
hasUncommittedChanges?: boolean;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export type
|
|
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
|
-
| "
|
|
197
|
+
| "coding-agent-selector"
|
|
198
198
|
| "model-selector"
|
|
199
199
|
| "session-selector"
|
|
200
200
|
| "execution-mode-selector"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
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:
|
|
108
|
+
export function getModelOptions(tool: CodingAgentId): ModelOption[] {
|
|
109
109
|
return MODEL_OPTIONS[tool] ?? [];
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
export function getDefaultModelOption(
|
|
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:
|
|
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
|
-
*
|
|
2
|
+
* ビルトインコーディングエージェント定義
|
|
3
3
|
*
|
|
4
|
-
* Claude Code、Codex、Gemini の
|
|
4
|
+
* Claude Code、Codex、Gemini の CodingAgent 形式定義
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type {
|
|
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/
|
|
11
|
+
} from "../shared/codingAgentConstants.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Claude Code のビルトイン定義
|
|
15
15
|
*/
|
|
16
|
-
export const CLAUDE_CODE_TOOL:
|
|
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:
|
|
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:
|
|
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
|
|
67
|
+
export const BUILTIN_CODING_AGENTS: CodingAgent[] = [
|
|
68
68
|
CLAUDE_CODE_TOOL,
|
|
69
69
|
CODEX_CLI_TOOL,
|
|
70
70
|
GEMINI_CLI_TOOL,
|
package/src/config/tools.ts
CHANGED
|
@@ -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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
CodingAgentsConfig,
|
|
13
|
+
CodingAgent,
|
|
14
|
+
CodingAgentConfig,
|
|
15
15
|
} from "../types/tools.js";
|
|
16
|
-
import {
|
|
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:
|
|
35
|
+
const DEFAULT_CONFIG: CodingAgentsConfig = {
|
|
36
36
|
version: "1.0.0",
|
|
37
37
|
env: {},
|
|
38
|
-
|
|
38
|
+
customCodingAgents: [],
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
42
|
+
* コーディングエージェント設定を読み込む
|
|
43
43
|
*
|
|
44
44
|
* ~/.gwt/tools.jsonから設定を読み込みます。
|
|
45
45
|
* ファイルが存在しない場合は空配列を返します。
|
|
46
46
|
*
|
|
47
|
-
* @returns
|
|
47
|
+
* @returns CodingAgentsConfig
|
|
48
48
|
* @throws JSON構文エラー時
|
|
49
49
|
*/
|
|
50
|
-
export async function
|
|
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
|
|
53
|
+
const config = JSON.parse(content) as CodingAgentsConfig;
|
|
54
54
|
|
|
55
55
|
// 検証
|
|
56
|
-
|
|
56
|
+
validateCodingAgentsConfig(config);
|
|
57
57
|
|
|
58
58
|
logger.debug(
|
|
59
|
-
{
|
|
60
|
-
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
*
|
|
98
|
+
* CodingAgentsConfig全体を検証
|
|
96
99
|
*
|
|
97
100
|
* @param config - 検証対象の設定
|
|
98
101
|
* @throws 検証エラー時
|
|
99
102
|
*/
|
|
100
|
-
function
|
|
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
|
-
//
|
|
107
|
-
if (!Array.isArray(config.
|
|
108
|
-
throw new Error("
|
|
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
|
|
129
|
-
|
|
131
|
+
for (const agent of config.customCodingAgents) {
|
|
132
|
+
validateCodingAgent(agent);
|
|
130
133
|
|
|
131
134
|
// ID重複チェック
|
|
132
|
-
if (seenIds.has(
|
|
135
|
+
if (seenIds.has(agent.id)) {
|
|
133
136
|
throw new Error(
|
|
134
|
-
`Duplicate
|
|
135
|
-
`Each
|
|
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(
|
|
141
|
+
seenIds.add(agent.id);
|
|
139
142
|
|
|
140
|
-
//
|
|
141
|
-
const builtinIds =
|
|
142
|
-
if (builtinIds.includes(
|
|
143
|
+
// ビルトインエージェントとのID重複チェック
|
|
144
|
+
const builtinIds = BUILTIN_CODING_AGENTS.map((t) => t.id);
|
|
145
|
+
if (builtinIds.includes(agent.id)) {
|
|
143
146
|
throw new Error(
|
|
144
|
-
`
|
|
145
|
-
`Builtin
|
|
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
|
|
152
|
-
|
|
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
|
-
|
|
161
|
+
customCodingAgents: config.customCodingAgents,
|
|
157
162
|
};
|
|
158
163
|
|
|
159
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
195
|
+
* CodingAgent単体を検証
|
|
191
196
|
*
|
|
192
|
-
* @param
|
|
197
|
+
* @param agent - 検証対象のエージェント
|
|
193
198
|
* @throws 検証エラー時
|
|
194
199
|
*/
|
|
195
|
-
function
|
|
200
|
+
function validateCodingAgent(agent: unknown): asserts agent is CodingAgent {
|
|
196
201
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
197
|
-
const
|
|
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 (!
|
|
207
|
+
if (!a[field]) {
|
|
203
208
|
throw new Error(
|
|
204
|
-
`Required field "${field}" is missing in
|
|
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(
|
|
215
|
+
if (!/^[a-z0-9-]+$/.test(a.id)) {
|
|
211
216
|
throw new Error(
|
|
212
|
-
`Invalid
|
|
213
|
-
`
|
|
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(
|
|
224
|
+
if (!validTypes.includes(a.type)) {
|
|
220
225
|
throw new Error(
|
|
221
|
-
`Invalid type: "${
|
|
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 (
|
|
232
|
+
if (a.type === "path" && !path.isAbsolute(a.command)) {
|
|
228
233
|
throw new Error(
|
|
229
|
-
`For type="path", command must be an absolute path: "${
|
|
234
|
+
`For type="path", command must be an absolute path: "${a.command}"`,
|
|
230
235
|
);
|
|
231
236
|
}
|
|
232
237
|
|
|
233
238
|
// modeArgsの検証(少なくとも1つのモードが定義されている)
|
|
234
|
-
if (!
|
|
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
|
|
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 -
|
|
245
|
-
* @returns
|
|
249
|
+
* @param id - エージェントID
|
|
250
|
+
* @returns エージェント設定(見つからない場合はundefined)
|
|
246
251
|
*/
|
|
247
|
-
export async function
|
|
252
|
+
export async function getCodingAgentById(
|
|
248
253
|
id: string,
|
|
249
|
-
): Promise<
|
|
250
|
-
//
|
|
251
|
-
const
|
|
252
|
-
if (
|
|
253
|
-
logger.debug({ id, found: true, isBuiltin: true }, "
|
|
254
|
-
return
|
|
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
|
|
259
|
-
const
|
|
260
|
-
logger.debug(
|
|
261
|
-
|
|
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
|
|
275
|
+
* @returns CodingAgentConfigの配列
|
|
268
276
|
*/
|
|
269
|
-
export async function
|
|
270
|
-
const config = await
|
|
271
|
-
|
|
272
|
-
//
|
|
273
|
-
const builtinConfigs:
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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];
|