@akiojin/gwt 4.9.0 → 4.10.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.
- 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 +27 -9
- package/dist/cli/ui/components/App.js.map +1 -1
- package/dist/cli/ui/components/screens/BranchQuickStartScreen.d.ts +1 -1
- package/dist/cli/ui/components/screens/BranchQuickStartScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/BranchQuickStartScreen.js +4 -1
- package/dist/cli/ui/components/screens/BranchQuickStartScreen.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 +27 -0
- package/dist/config/builtin-coding-agents.d.ts.map +1 -0
- package/dist/config/{builtin-tools.js → builtin-coding-agents.js} +21 -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 +92 -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/utils/command.d.ts.map +1 -1
- package/dist/utils/command.js +9 -0
- package/dist/utils/command.js.map +1 -1
- package/dist/utils/session/index.d.ts +5 -3
- package/dist/utils/session/index.d.ts.map +1 -1
- package/dist/utils/session/index.js +5 -2
- package/dist/utils/session/index.js.map +1 -1
- package/dist/utils/session/parsers/index.d.ts +1 -0
- package/dist/utils/session/parsers/index.d.ts.map +1 -1
- package/dist/utils/session/parsers/index.js +2 -0
- package/dist/utils/session/parsers/index.js.map +1 -1
- package/dist/utils/session/parsers/opencode.d.ts +23 -0
- package/dist/utils/session/parsers/opencode.d.ts.map +1 -0
- package/dist/utils/session/parsers/opencode.js +89 -0
- package/dist/utils/session/parsers/opencode.js.map +1 -0
- package/dist/utils/session/types.d.ts +4 -0
- package/dist/utils/session/types.d.ts.map +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 +44 -20
- package/src/cli/ui/components/screens/BranchQuickStartScreen.tsx +6 -3
- 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} +25 -9
- package/src/config/tools.ts +120 -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/utils/command.ts +9 -0
- package/src/utils/session/index.ts +10 -2
- package/src/utils/session/parsers/index.ts +6 -0
- package/src/utils/session/parsers/opencode.ts +110 -0
- package/src/utils/session/types.ts +5 -0
- 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,10 +62,26 @@ export const GEMINI_CLI_TOOL: CustomAITool = {
|
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
*
|
|
65
|
+
* OpenCode のビルトイン定義
|
|
66
66
|
*/
|
|
67
|
-
export const
|
|
67
|
+
export const OPENCODE_TOOL: CodingAgent = {
|
|
68
|
+
id: "opencode",
|
|
69
|
+
displayName: "OpenCode",
|
|
70
|
+
type: "bunx",
|
|
71
|
+
command: "opencode-ai@latest",
|
|
72
|
+
modeArgs: {
|
|
73
|
+
normal: [],
|
|
74
|
+
continue: ["-c"],
|
|
75
|
+
resume: ["-s"],
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* すべてのビルトインコーディングエージェント
|
|
81
|
+
*/
|
|
82
|
+
export const BUILTIN_CODING_AGENTS: CodingAgent[] = [
|
|
68
83
|
CLAUDE_CODE_TOOL,
|
|
69
84
|
CODEX_CLI_TOOL,
|
|
70
85
|
GEMINI_CLI_TOOL,
|
|
86
|
+
OPENCODE_TOOL,
|
|
71
87
|
];
|
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,51 @@ 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
|
+
|
|
55
|
+
// マイグレーション: customTools → customCodingAgents (後方互換性)
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
|
+
const legacyConfig = config as any;
|
|
58
|
+
if (!config.customCodingAgents && legacyConfig.customTools) {
|
|
59
|
+
config.customCodingAgents = legacyConfig.customTools;
|
|
60
|
+
logger.warn(
|
|
61
|
+
{ path: TOOLS_CONFIG_PATH },
|
|
62
|
+
"Migrating deprecated 'customTools' to 'customCodingAgents'",
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// フォールバック: undefined/null → 空配列
|
|
67
|
+
if (!config.customCodingAgents) {
|
|
68
|
+
config.customCodingAgents = [];
|
|
69
|
+
}
|
|
54
70
|
|
|
55
71
|
// 検証
|
|
56
|
-
|
|
72
|
+
validateCodingAgentsConfig(config);
|
|
57
73
|
|
|
58
74
|
logger.debug(
|
|
59
|
-
{
|
|
60
|
-
|
|
75
|
+
{
|
|
76
|
+
path: TOOLS_CONFIG_PATH,
|
|
77
|
+
agentCount: config.customCodingAgents.length,
|
|
78
|
+
},
|
|
79
|
+
"Coding agents config loaded",
|
|
61
80
|
);
|
|
62
81
|
|
|
63
82
|
return {
|
|
@@ -69,7 +88,7 @@ export async function loadToolsConfig(): Promise<ToolsConfig> {
|
|
|
69
88
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
70
89
|
logger.debug(
|
|
71
90
|
{ path: TOOLS_CONFIG_PATH },
|
|
72
|
-
"
|
|
91
|
+
"Coding agents config not found, using defaults",
|
|
73
92
|
);
|
|
74
93
|
return { ...DEFAULT_CONFIG };
|
|
75
94
|
}
|
|
@@ -78,7 +97,7 @@ export async function loadToolsConfig(): Promise<ToolsConfig> {
|
|
|
78
97
|
if (error instanceof SyntaxError) {
|
|
79
98
|
logger.error(
|
|
80
99
|
{ path: TOOLS_CONFIG_PATH, error: error.message },
|
|
81
|
-
"
|
|
100
|
+
"Coding agents config parse error",
|
|
82
101
|
);
|
|
83
102
|
throw new Error(
|
|
84
103
|
`Failed to parse tools.json: ${error.message}\n` +
|
|
@@ -92,20 +111,20 @@ export async function loadToolsConfig(): Promise<ToolsConfig> {
|
|
|
92
111
|
}
|
|
93
112
|
|
|
94
113
|
/**
|
|
95
|
-
*
|
|
114
|
+
* CodingAgentsConfig全体を検証
|
|
96
115
|
*
|
|
97
116
|
* @param config - 検証対象の設定
|
|
98
117
|
* @throws 検証エラー時
|
|
99
118
|
*/
|
|
100
|
-
function
|
|
119
|
+
function validateCodingAgentsConfig(config: CodingAgentsConfig): void {
|
|
101
120
|
// versionフィールドの検証
|
|
102
121
|
if (!config.version || typeof config.version !== "string") {
|
|
103
122
|
throw new Error("version field is required and must be a string");
|
|
104
123
|
}
|
|
105
124
|
|
|
106
|
-
//
|
|
107
|
-
if (!Array.isArray(config.
|
|
108
|
-
throw new Error("
|
|
125
|
+
// customCodingAgentsフィールドの検証
|
|
126
|
+
if (!Array.isArray(config.customCodingAgents)) {
|
|
127
|
+
throw new Error("customCodingAgents field must be an array");
|
|
109
128
|
}
|
|
110
129
|
|
|
111
130
|
if (config.env && typeof config.env !== "object") {
|
|
@@ -123,40 +142,42 @@ function validateToolsConfig(config: ToolsConfig): void {
|
|
|
123
142
|
}
|
|
124
143
|
}
|
|
125
144
|
|
|
126
|
-
//
|
|
145
|
+
// 各エージェントの検証
|
|
127
146
|
const seenIds = new Set<string>();
|
|
128
|
-
for (const
|
|
129
|
-
|
|
147
|
+
for (const agent of config.customCodingAgents) {
|
|
148
|
+
validateCodingAgent(agent);
|
|
130
149
|
|
|
131
150
|
// ID重複チェック
|
|
132
|
-
if (seenIds.has(
|
|
151
|
+
if (seenIds.has(agent.id)) {
|
|
133
152
|
throw new Error(
|
|
134
|
-
`Duplicate
|
|
135
|
-
`Each
|
|
153
|
+
`Duplicate agent ID found: "${agent.id}"\n` +
|
|
154
|
+
`Each agent must have a unique ID in ${TOOLS_CONFIG_PATH}`,
|
|
136
155
|
);
|
|
137
156
|
}
|
|
138
|
-
seenIds.add(
|
|
157
|
+
seenIds.add(agent.id);
|
|
139
158
|
|
|
140
|
-
//
|
|
141
|
-
const builtinIds =
|
|
142
|
-
if (builtinIds.includes(
|
|
159
|
+
// ビルトインエージェントとのID重複チェック
|
|
160
|
+
const builtinIds = BUILTIN_CODING_AGENTS.map((t) => t.id);
|
|
161
|
+
if (builtinIds.includes(agent.id)) {
|
|
143
162
|
throw new Error(
|
|
144
|
-
`
|
|
145
|
-
`Builtin
|
|
163
|
+
`Agent ID "${agent.id}" conflicts with builtin agent\n` +
|
|
164
|
+
`Builtin agent IDs: ${builtinIds.join(", ")}`,
|
|
146
165
|
);
|
|
147
166
|
}
|
|
148
167
|
}
|
|
149
168
|
}
|
|
150
169
|
|
|
151
|
-
export async function
|
|
152
|
-
|
|
170
|
+
export async function saveCodingAgentsConfig(
|
|
171
|
+
config: CodingAgentsConfig,
|
|
172
|
+
): Promise<void> {
|
|
173
|
+
const normalized: CodingAgentsConfig = {
|
|
153
174
|
version: config.version,
|
|
154
175
|
updatedAt: config.updatedAt ?? new Date().toISOString(),
|
|
155
176
|
env: config.env ?? {},
|
|
156
|
-
|
|
177
|
+
customCodingAgents: config.customCodingAgents,
|
|
157
178
|
};
|
|
158
179
|
|
|
159
|
-
|
|
180
|
+
validateCodingAgentsConfig(normalized);
|
|
160
181
|
|
|
161
182
|
await mkdir(CONFIG_DIR, { recursive: true });
|
|
162
183
|
const payload = JSON.stringify(normalized, null, 2);
|
|
@@ -167,7 +188,7 @@ export async function saveToolsConfig(config: ToolsConfig): Promise<void> {
|
|
|
167
188
|
/**
|
|
168
189
|
* 共有環境変数を取得
|
|
169
190
|
*
|
|
170
|
-
*
|
|
191
|
+
* コーディングエージェント起動時に適用される環境変数を返します。
|
|
171
192
|
* マージ優先順位(後勝ち):
|
|
172
193
|
* 1. tools.json の env フィールド
|
|
173
194
|
* 2. profiles.yaml のアクティブプロファイル
|
|
@@ -176,7 +197,7 @@ export async function saveToolsConfig(config: ToolsConfig): Promise<void> {
|
|
|
176
197
|
*/
|
|
177
198
|
export async function getSharedEnvironment(): Promise<Record<string, string>> {
|
|
178
199
|
const [config, profileEnv] = await Promise.all([
|
|
179
|
-
|
|
200
|
+
loadCodingAgentsConfig(),
|
|
180
201
|
resolveProfileEnv(),
|
|
181
202
|
]);
|
|
182
203
|
|
|
@@ -187,104 +208,111 @@ export async function getSharedEnvironment(): Promise<Record<string, string>> {
|
|
|
187
208
|
}
|
|
188
209
|
|
|
189
210
|
/**
|
|
190
|
-
*
|
|
211
|
+
* CodingAgent単体を検証
|
|
191
212
|
*
|
|
192
|
-
* @param
|
|
213
|
+
* @param agent - 検証対象のエージェント
|
|
193
214
|
* @throws 検証エラー時
|
|
194
215
|
*/
|
|
195
|
-
function
|
|
216
|
+
function validateCodingAgent(agent: unknown): asserts agent is CodingAgent {
|
|
196
217
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
197
|
-
const
|
|
218
|
+
const a = agent as any;
|
|
198
219
|
|
|
199
220
|
// 必須フィールドの存在チェック
|
|
200
221
|
const requiredFields = ["id", "displayName", "type", "command", "modeArgs"];
|
|
201
222
|
for (const field of requiredFields) {
|
|
202
|
-
if (!
|
|
223
|
+
if (!a[field]) {
|
|
203
224
|
throw new Error(
|
|
204
|
-
`Required field "${field}" is missing in
|
|
225
|
+
`Required field "${field}" is missing in agent configuration`,
|
|
205
226
|
);
|
|
206
227
|
}
|
|
207
228
|
}
|
|
208
229
|
|
|
209
230
|
// id形式の検証(小文字英数字とハイフンのみ)
|
|
210
|
-
if (!/^[a-z0-9-]+$/.test(
|
|
231
|
+
if (!/^[a-z0-9-]+$/.test(a.id)) {
|
|
211
232
|
throw new Error(
|
|
212
|
-
`Invalid
|
|
213
|
-
`
|
|
233
|
+
`Invalid agent ID format: "${a.id}"\n` +
|
|
234
|
+
`Agent ID must contain only lowercase letters, numbers, and hyphens (pattern: ^[a-z0-9-]+$)`,
|
|
214
235
|
);
|
|
215
236
|
}
|
|
216
237
|
|
|
217
238
|
// typeフィールドの値検証
|
|
218
239
|
const validTypes = ["path", "bunx", "command"];
|
|
219
|
-
if (!validTypes.includes(
|
|
240
|
+
if (!validTypes.includes(a.type)) {
|
|
220
241
|
throw new Error(
|
|
221
|
-
`Invalid type: "${
|
|
242
|
+
`Invalid type: "${a.type}"\n` +
|
|
222
243
|
`Type must be one of: ${validTypes.join(", ")}`,
|
|
223
244
|
);
|
|
224
245
|
}
|
|
225
246
|
|
|
226
247
|
// type='path'の場合、commandが絶対パスであることを確認
|
|
227
|
-
if (
|
|
248
|
+
if (a.type === "path" && !path.isAbsolute(a.command)) {
|
|
228
249
|
throw new Error(
|
|
229
|
-
`For type="path", command must be an absolute path: "${
|
|
250
|
+
`For type="path", command must be an absolute path: "${a.command}"`,
|
|
230
251
|
);
|
|
231
252
|
}
|
|
232
253
|
|
|
233
254
|
// modeArgsの検証(少なくとも1つのモードが定義されている)
|
|
234
|
-
if (!
|
|
255
|
+
if (!a.modeArgs.normal && !a.modeArgs.continue && !a.modeArgs.resume) {
|
|
235
256
|
throw new Error(
|
|
236
|
-
`modeArgs must define at least one mode (normal, continue, or resume) for
|
|
257
|
+
`modeArgs must define at least one mode (normal, continue, or resume) for agent "${a.id}"`,
|
|
237
258
|
);
|
|
238
259
|
}
|
|
239
260
|
}
|
|
240
261
|
|
|
241
262
|
/**
|
|
242
|
-
* ID
|
|
263
|
+
* IDでコーディングエージェントを検索
|
|
243
264
|
*
|
|
244
|
-
* @param id -
|
|
245
|
-
* @returns
|
|
265
|
+
* @param id - エージェントID
|
|
266
|
+
* @returns エージェント設定(見つからない場合はundefined)
|
|
246
267
|
*/
|
|
247
|
-
export async function
|
|
268
|
+
export async function getCodingAgentById(
|
|
248
269
|
id: string,
|
|
249
|
-
): Promise<
|
|
250
|
-
//
|
|
251
|
-
const
|
|
252
|
-
if (
|
|
253
|
-
logger.debug({ id, found: true, isBuiltin: true }, "
|
|
254
|
-
return
|
|
270
|
+
): Promise<CodingAgent | undefined> {
|
|
271
|
+
// ビルトインエージェントから検索
|
|
272
|
+
const builtinAgent = BUILTIN_CODING_AGENTS.find((a) => a.id === id);
|
|
273
|
+
if (builtinAgent) {
|
|
274
|
+
logger.debug({ id, found: true, isBuiltin: true }, "Coding agent lookup");
|
|
275
|
+
return builtinAgent;
|
|
255
276
|
}
|
|
256
277
|
|
|
257
|
-
//
|
|
258
|
-
const config = await
|
|
259
|
-
const
|
|
260
|
-
logger.debug(
|
|
261
|
-
|
|
278
|
+
// カスタムエージェントから検索
|
|
279
|
+
const config = await loadCodingAgentsConfig();
|
|
280
|
+
const customAgent = config.customCodingAgents.find((a) => a.id === id);
|
|
281
|
+
logger.debug(
|
|
282
|
+
{ id, found: !!customAgent, isBuiltin: false },
|
|
283
|
+
"Coding agent lookup",
|
|
284
|
+
);
|
|
285
|
+
return customAgent;
|
|
262
286
|
}
|
|
263
287
|
|
|
264
288
|
/**
|
|
265
|
-
*
|
|
289
|
+
* すべてのコーディングエージェント(ビルトイン+カスタム)を取得
|
|
266
290
|
*
|
|
267
|
-
* @returns
|
|
291
|
+
* @returns CodingAgentConfigの配列
|
|
268
292
|
*/
|
|
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
|
-
|
|
293
|
+
export async function getAllCodingAgents(): Promise<CodingAgentConfig[]> {
|
|
294
|
+
const config = await loadCodingAgentsConfig();
|
|
295
|
+
|
|
296
|
+
// ビルトインエージェントをCodingAgentConfig形式に変換
|
|
297
|
+
const builtinConfigs: CodingAgentConfig[] = BUILTIN_CODING_AGENTS.map(
|
|
298
|
+
(agent) => ({
|
|
299
|
+
id: agent.id,
|
|
300
|
+
displayName: agent.displayName,
|
|
301
|
+
...(agent.icon ? { icon: agent.icon } : {}),
|
|
302
|
+
isBuiltin: true,
|
|
303
|
+
}),
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
// カスタムエージェントをCodingAgentConfig形式に変換
|
|
307
|
+
const customConfigs: CodingAgentConfig[] = config.customCodingAgents.map(
|
|
308
|
+
(agent) => ({
|
|
309
|
+
id: agent.id,
|
|
310
|
+
displayName: agent.displayName,
|
|
311
|
+
...(agent.icon ? { icon: agent.icon } : {}),
|
|
312
|
+
isBuiltin: false,
|
|
313
|
+
customConfig: agent,
|
|
314
|
+
}),
|
|
315
|
+
);
|
|
288
316
|
|
|
289
317
|
// ビルトイン + カスタム の順で統合
|
|
290
318
|
return [...builtinConfigs, ...customConfigs];
|