gsd-opencode 1.10.1 → 1.10.2
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/agents/gsd-settings.md +476 -30
- package/lib/constants.js +7 -1
- package/package.json +1 -1
- package/src/services/file-ops.js +27 -2
package/agents/gsd-settings.md
CHANGED
|
@@ -27,6 +27,12 @@ Do NOT modify agent .md files.
|
|
|
27
27
|
- **Verification:** gsd-verifier, gsd-integration-checker, gsd-set-profile, gsd-settings, gsd-set-model
|
|
28
28
|
|
|
29
29
|
**Model discovery:** Presets are user-defined, not hardcoded. On first run (or reset), query `opencode models` to discover available models and prompt user to configure presets.
|
|
30
|
+
|
|
31
|
+
**Model ID structure:** Models use 2-level (provider/model) or 3-level (provider/subprovider/model) format:
|
|
32
|
+
- 2-level: `opencode/glm-4.7-free`, `xai/grok-3`
|
|
33
|
+
- 3-level: `openrouter/anthropic/claude-3.5-haiku`, `synthetic/hf:deepseek-ai/DeepSeek-R1`
|
|
34
|
+
|
|
35
|
+
**Provider hierarchy:** Some providers (openrouter, synthetic) have subproviders; others (opencode, xai) are flat. Always use hierarchical selection: provider → subprovider (if applicable) → model.
|
|
30
36
|
</context>
|
|
31
37
|
|
|
32
38
|
<rules>
|
|
@@ -42,10 +48,43 @@ Do NOT modify agent .md files.
|
|
|
42
48
|
- Never overwrite existing presets — only create defaults for new/migrated projects
|
|
43
49
|
- Keep `model_profile` in sync with `profiles.active_profile`
|
|
44
50
|
- Merge into existing `opencode.json` (preserve non-agent keys)
|
|
45
|
-
</rules>
|
|
51
|
+
</rules>
|
|
46
52
|
|
|
47
53
|
<behavior>
|
|
48
54
|
|
|
55
|
+
## Helper Discovery Functions
|
|
56
|
+
|
|
57
|
+
These bash commands use the cached MODELS_DATA for hierarchical model discovery:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Initialize cache at wizard start (run once)
|
|
61
|
+
MODELS_DATA=$(opencode models 2>/dev/null)
|
|
62
|
+
|
|
63
|
+
# Get all unique providers (from cache)
|
|
64
|
+
echo "$MODELS_DATA" | cut -d'/' -f1 | sort -u
|
|
65
|
+
|
|
66
|
+
# Get model count for a provider (from cache)
|
|
67
|
+
echo "$MODELS_DATA" | grep "^${provider}/" | wc -l
|
|
68
|
+
|
|
69
|
+
# Check if provider has subproviders (returns "true" or "false", from cache)
|
|
70
|
+
echo "$MODELS_DATA" | grep "^${provider}/" | awk -F'/' '{print NF}' | head -1 | grep -q '^3$' && echo "true" || echo "false"
|
|
71
|
+
|
|
72
|
+
# Get unique subproviders for a provider (from cache)
|
|
73
|
+
echo "$MODELS_DATA" | grep "^${provider}/" | cut -d'/' -f2 | sort -u
|
|
74
|
+
|
|
75
|
+
# Get model count for a subprovider (from cache)
|
|
76
|
+
echo "$MODELS_DATA" | grep "^${provider}/${subprovider}/" | wc -l
|
|
77
|
+
|
|
78
|
+
# Get models for provider/subprovider (3-level, from cache)
|
|
79
|
+
echo "$MODELS_DATA" | grep "^${provider}/${subprovider}/" | cut -d'/' -f3- | sort
|
|
80
|
+
|
|
81
|
+
# Get models for 2-level provider (from cache)
|
|
82
|
+
echo "$MODELS_DATA" | grep "^${provider}/" | cut -d'/' -f2- | sort
|
|
83
|
+
|
|
84
|
+
# Verify a model ID exists (from cache)
|
|
85
|
+
echo "$MODELS_DATA" | grep -q "^${model_id}$" && echo "valid" || echo "invalid"
|
|
86
|
+
```
|
|
87
|
+
|
|
49
88
|
## Step 1: Load Config
|
|
50
89
|
|
|
51
90
|
```bash
|
|
@@ -68,29 +107,286 @@ Ensure `workflow` section exists (defaults: `research: true`, `plan_check: true`
|
|
|
68
107
|
|
|
69
108
|
### Preset Setup Wizard
|
|
70
109
|
|
|
71
|
-
This wizard runs on first use or when "Reset presets" is selected. It queries available models and lets the user configure all three profiles.
|
|
110
|
+
This wizard runs on first use or when "Reset presets" is selected. It queries available models and lets the user configure all three profiles using hierarchical selection (provider → subprovider → model).
|
|
72
111
|
|
|
73
|
-
**Step W1: Discover models**
|
|
112
|
+
**Step W1: Discover models and initialize cache**
|
|
74
113
|
|
|
75
114
|
```bash
|
|
76
|
-
opencode models 2>/dev/null
|
|
115
|
+
MODELS_DATA=$(opencode models 2>/dev/null)
|
|
77
116
|
```
|
|
78
117
|
|
|
79
|
-
|
|
118
|
+
Cache the models output in `MODELS_DATA` variable. All subsequent operations use this cache instead of calling `opencode models` repeatedly.
|
|
80
119
|
|
|
81
|
-
|
|
120
|
+
If command fails or returns no models, print `Error: Could not fetch available models. Check your OpenCode installation.` and stop.
|
|
82
121
|
|
|
83
|
-
|
|
122
|
+
**Cache Statistics (for internal use):**
|
|
123
|
+
```bash
|
|
124
|
+
# Pre-compute provider counts for all menus
|
|
125
|
+
PROVIDER_COUNTS=$(echo "$MODELS_DATA" | awk -F'/' '{count[$1]++} END {for(p in count) print p ":" count[p]}')
|
|
126
|
+
|
|
127
|
+
# Pre-compute subprovider structure for 3-level providers
|
|
128
|
+
SUBPROVIDER_MAP=$(echo "$MODELS_DATA" | awk -F'/' 'NF==3 {print $1 "/" $2}' | sort -u)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Step W2: Configure Quality Profile**
|
|
132
|
+
|
|
133
|
+
Configure all 3 stages for the quality profile with full hierarchical selection.
|
|
134
|
+
|
|
135
|
+
**W2.1: Quality Profile - Planning Stage**
|
|
136
|
+
|
|
137
|
+
1. **Build Provider Menu (using cached data)**
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# Get providers with counts from cache
|
|
141
|
+
echo "$PROVIDER_COUNTS" | while IFS=':' read -r provider count; do
|
|
142
|
+
echo "- label: \"$provider\""
|
|
143
|
+
echo " description: \"$count models\""
|
|
144
|
+
done
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Use Question tool:
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
header: "Quality Profile - Planning"
|
|
151
|
+
question: "Which provider for planning agents (Quality profile)?"
|
|
152
|
+
options:
|
|
153
|
+
[providers from above with counts]
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Store selected provider as `quality_planning_provider`.
|
|
157
|
+
|
|
158
|
+
2. **Check for Subproviders (using cache)**
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Check if provider has subproviders using cached data
|
|
162
|
+
HAS_SUBPROVIDERS=$(echo "$MODELS_DATA" | grep "^${quality_planning_provider}/" | awk -F'/' '{print NF}' | head -1 | grep -q '^3$' && echo "true" || echo "false")
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
If result is "true" (provider has subproviders):
|
|
166
|
+
|
|
167
|
+
**Build Subprovider Menu (lazy-load examples only when selected):**
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Get subproviders with counts from cache
|
|
171
|
+
echo "$MODELS_DATA" | grep "^${quality_planning_provider}/" | awk -F'/' '{print $2}' | sort | uniq -c | while read count subprovider; do
|
|
172
|
+
echo "- label: \"$subprovider\""
|
|
173
|
+
echo " description: \"$count models\""
|
|
174
|
+
done
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Use Question tool:
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
header: "Quality Profile - {quality_planning_provider} Subprovider (Planning Stage)"
|
|
181
|
+
question: "Which subprovider for planning agents?"
|
|
182
|
+
options:
|
|
183
|
+
- label: "{subprovider1}"
|
|
184
|
+
description: "{model_count} models (e.g., {model1}, {model2}, {model3}, ...)"
|
|
185
|
+
- label: "{subprovider2}"
|
|
186
|
+
description: "{model_count} models (e.g., {model1}, {model2}, {model3}, ...)"
|
|
187
|
+
[all unique subproviders for this provider with 3 example models each]
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Store selected subprovider as `quality_planning_subprovider`.
|
|
191
|
+
|
|
192
|
+
3. **Choose Model (using cache)**
|
|
193
|
+
|
|
194
|
+
For 3-level structure (provider/subprovider/model):
|
|
195
|
+
```bash
|
|
196
|
+
MODELS=$(echo "$MODELS_DATA" | grep "^${quality_planning_provider}/${quality_planning_subprovider}/" | cut -d'/' -f3- | sort)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
For 2-level structure (provider/model):
|
|
200
|
+
```bash
|
|
201
|
+
MODELS=$(echo "$MODELS_DATA" | grep "^${quality_planning_provider}/" | cut -d'/' -f2- | sort)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Use Question tool:
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
header: "{quality_planning_provider} {quality_planning_subprovider} Models"
|
|
208
|
+
question: "Which model for planning?"
|
|
209
|
+
options:
|
|
210
|
+
[models from filtered list]
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Store full model ID as `quality_planning_model`.
|
|
214
|
+
|
|
215
|
+
**W2.2: Quality Profile - Execution Stage**
|
|
216
|
+
|
|
217
|
+
1. **Choose Provider (using cached data)**
|
|
218
|
+
|
|
219
|
+
Use Question tool with smart proposal:
|
|
220
|
+
|
|
221
|
+
```
|
|
222
|
+
header: "Quality Profile - Execution"
|
|
223
|
+
question: "Which provider for execution agents (Quality profile)?"
|
|
224
|
+
options:
|
|
225
|
+
- label: "Same as planning"
|
|
226
|
+
description: "Use {quality_planning_model}"
|
|
227
|
+
[providers from cache with counts]
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
If "Same as planning" selected: Set `quality_execution_model = quality_planning_model`, skip to W2.3.
|
|
231
|
+
|
|
232
|
+
Otherwise: Repeat W2.1 steps 2-3 (subprovider → model) for execution, store as `quality_execution_model`.
|
|
233
|
+
|
|
234
|
+
**W2.3: Quality Profile - Verification Stage**
|
|
235
|
+
|
|
236
|
+
Use Question tool with smart proposals (using cached data):
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
header: "Quality Profile - Verification"
|
|
240
|
+
question: "Which provider for verification agents (Quality profile)?"
|
|
241
|
+
options:
|
|
242
|
+
- label: "Same as planning"
|
|
243
|
+
description: "Use {quality_planning_model}"
|
|
244
|
+
- label: "Same as execution"
|
|
245
|
+
description: "Use {quality_execution_model}"
|
|
246
|
+
[providers from cache with counts]
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
If "Same as planning" selected: Set `quality_verification_model = quality_planning_model`, skip to W2.4.
|
|
250
|
+
|
|
251
|
+
If "Same as execution" selected: Set `quality_verification_model = quality_execution_model`, skip to W2.4.
|
|
252
|
+
|
|
253
|
+
Otherwise: Repeat W2.1 steps 2-3 (subprovider → model) for verification, store as `quality_verification_model`.
|
|
254
|
+
|
|
255
|
+
**Step W3: Configure Balanced Profile**
|
|
256
|
+
|
|
257
|
+
Configure all 3 stages for balanced profile with smart proposals from quality profile.
|
|
258
|
+
|
|
259
|
+
**W3.1: Balanced Profile - Planning**
|
|
260
|
+
|
|
261
|
+
Use Question tool (using cached data):
|
|
262
|
+
|
|
263
|
+
```
|
|
264
|
+
header: "Balanced Profile - Planning"
|
|
265
|
+
question: "Which provider for planning agents (Balanced profile)?"
|
|
266
|
+
options:
|
|
267
|
+
- label: "Same as quality profile"
|
|
268
|
+
description: "Use {quality_planning_model}"
|
|
269
|
+
[providers from cache with counts]
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
If "Same as quality profile" selected: Set `balanced_planning_model = quality_planning_model`, skip to W3.2.
|
|
273
|
+
|
|
274
|
+
Otherwise: Repeat hierarchical selection (provider → subprovider → model), store as `balanced_planning_model`.
|
|
275
|
+
|
|
276
|
+
**W3.2: Balanced Profile - Execution**
|
|
277
|
+
|
|
278
|
+
Use Question tool (using cached data):
|
|
279
|
+
|
|
280
|
+
```
|
|
281
|
+
header: "Balanced Profile - Execution"
|
|
282
|
+
question: "Which provider for execution agents (Balanced profile)?"
|
|
283
|
+
options:
|
|
284
|
+
- label: "Same as planning"
|
|
285
|
+
description: "Use {balanced_planning_model}"
|
|
286
|
+
- label: "Same as quality execution"
|
|
287
|
+
description: "Use {quality_execution_model}"
|
|
288
|
+
[providers from cache with counts]
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
If "Same as planning" selected: Set `balanced_execution_model = balanced_planning_model`, skip to W3.3.
|
|
292
|
+
|
|
293
|
+
If "Same as quality execution" selected: Set `balanced_execution_model = quality_execution_model`, skip to W3.3.
|
|
294
|
+
|
|
295
|
+
Otherwise: Repeat hierarchical selection, store as `balanced_execution_model`.
|
|
296
|
+
|
|
297
|
+
**W3.3: Balanced Profile - Verification**
|
|
298
|
+
|
|
299
|
+
Use Question tool (using cached data):
|
|
84
300
|
|
|
85
|
-
```json
|
|
86
|
-
[
|
|
87
|
-
{ "header": "{Profile} Profile - Planning", "question": "Which model for planning agents?", "options": ["{model1}", "{model2}", ...] },
|
|
88
|
-
{ "header": "{Profile} Profile - Execution", "question": "Which model for execution agents?", "options": ["{model1}", "{model2}", ...] },
|
|
89
|
-
{ "header": "{Profile} Profile - Verification", "question": "Which model for verification agents?", "options": ["{model1}", "{model2}", ...] }
|
|
90
|
-
]
|
|
91
301
|
```
|
|
302
|
+
header: "Balanced Profile - Verification"
|
|
303
|
+
question: "Which provider for verification agents (Balanced profile)?"
|
|
304
|
+
options:
|
|
305
|
+
- label: "Same as planning"
|
|
306
|
+
description: "Use {balanced_planning_model}"
|
|
307
|
+
- label: "Same as quality verification"
|
|
308
|
+
description: "Use {quality_verification_model}"
|
|
309
|
+
[providers from cache with counts]
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
If "Same as planning" selected: Set `balanced_verification_model = balanced_planning_model`, skip to W4.
|
|
313
|
+
|
|
314
|
+
If "Same as quality verification" selected: Set `balanced_verification_model = quality_verification_model`, skip to W4.
|
|
315
|
+
|
|
316
|
+
Otherwise: Repeat hierarchical selection, store as `balanced_verification_model`.
|
|
317
|
+
|
|
318
|
+
**Step W4: Configure Budget Profile**
|
|
319
|
+
|
|
320
|
+
Configure all 3 stages for budget profile with smart proposals from balanced and quality profiles.
|
|
321
|
+
|
|
322
|
+
**W4.1: Budget Profile - Planning**
|
|
323
|
+
|
|
324
|
+
Use Question tool (using cached data):
|
|
92
325
|
|
|
93
|
-
|
|
326
|
+
```
|
|
327
|
+
header: "Budget Profile - Planning"
|
|
328
|
+
question: "Which provider for planning agents (Budget profile)?"
|
|
329
|
+
options:
|
|
330
|
+
- label: "Same as balanced profile"
|
|
331
|
+
description: "Use {balanced_planning_model}"
|
|
332
|
+
- label: "Same as quality profile"
|
|
333
|
+
description: "Use {quality_planning_model}"
|
|
334
|
+
[providers from cache with counts]
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
If "Same as balanced profile" selected: Set `budget_planning_model = balanced_planning_model`, skip to W4.2.
|
|
338
|
+
|
|
339
|
+
If "Same as quality profile" selected: Set `budget_planning_model = quality_planning_model`, skip to W4.2.
|
|
340
|
+
|
|
341
|
+
Otherwise: Repeat hierarchical selection, store as `budget_planning_model`.
|
|
342
|
+
|
|
343
|
+
**W4.2: Budget Profile - Execution**
|
|
344
|
+
|
|
345
|
+
Use Question tool (using cached data):
|
|
346
|
+
|
|
347
|
+
```
|
|
348
|
+
header: "Budget Profile - Execution"
|
|
349
|
+
question: "Which provider for execution agents (Budget profile)?"
|
|
350
|
+
options:
|
|
351
|
+
- label: "Same as planning"
|
|
352
|
+
description: "Use {budget_planning_model}"
|
|
353
|
+
- label: "Same as balanced execution"
|
|
354
|
+
description: "Use {balanced_execution_model}"
|
|
355
|
+
- label: "Same as quality execution"
|
|
356
|
+
description: "Use {quality_execution_model}"
|
|
357
|
+
[providers from cache with counts]
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
If "Same as planning" selected: Set `budget_execution_model = budget_planning_model`, skip to W4.3.
|
|
361
|
+
|
|
362
|
+
Otherwise if other "Same as" option selected: Set accordingly and skip to W4.3.
|
|
363
|
+
|
|
364
|
+
Otherwise: Repeat hierarchical selection, store as `budget_execution_model`.
|
|
365
|
+
|
|
366
|
+
**W4.3: Budget Profile - Verification**
|
|
367
|
+
|
|
368
|
+
Use Question tool (using cached data):
|
|
369
|
+
|
|
370
|
+
```
|
|
371
|
+
header: "Budget Profile - Verification"
|
|
372
|
+
question: "Which provider for verification agents (Budget profile)?"
|
|
373
|
+
options:
|
|
374
|
+
- label: "Same as planning"
|
|
375
|
+
description: "Use {budget_planning_model}"
|
|
376
|
+
- label: "Same as balanced verification"
|
|
377
|
+
description: "Use {balanced_verification_model}"
|
|
378
|
+
- label: "Same as quality verification"
|
|
379
|
+
description: "Use {quality_verification_model}"
|
|
380
|
+
[providers from cache with counts]
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
If "Same as planning" selected: Set `budget_verification_model = budget_planning_model`, skip to W5.
|
|
384
|
+
|
|
385
|
+
Otherwise if other "Same as" option selected: Set accordingly and skip to W5.
|
|
386
|
+
|
|
387
|
+
Otherwise: Repeat hierarchical selection, store as `budget_verification_model`.
|
|
388
|
+
|
|
389
|
+
**Step W5: Save config**
|
|
94
390
|
|
|
95
391
|
Create config with user selections:
|
|
96
392
|
|
|
@@ -99,9 +395,21 @@ Create config with user selections:
|
|
|
99
395
|
"profiles": {
|
|
100
396
|
"active_profile": "balanced",
|
|
101
397
|
"presets": {
|
|
102
|
-
"quality": {
|
|
103
|
-
|
|
104
|
-
|
|
398
|
+
"quality": {
|
|
399
|
+
"planning": "{user_selection}",
|
|
400
|
+
"execution": "{user_selection}",
|
|
401
|
+
"verification": "{user_selection}"
|
|
402
|
+
},
|
|
403
|
+
"balanced": {
|
|
404
|
+
"planning": "{user_selection}",
|
|
405
|
+
"execution": "{user_selection}",
|
|
406
|
+
"verification": "{user_selection}"
|
|
407
|
+
},
|
|
408
|
+
"budget": {
|
|
409
|
+
"planning": "{user_selection}",
|
|
410
|
+
"execution": "{user_selection}",
|
|
411
|
+
"verification": "{user_selection}"
|
|
412
|
+
}
|
|
105
413
|
},
|
|
106
414
|
"custom_overrides": { "quality": {}, "balanced": {}, "budget": {} }
|
|
107
415
|
},
|
|
@@ -116,7 +424,7 @@ Print:
|
|
|
116
424
|
GSD ► PRESETS CONFIGURED
|
|
117
425
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
118
426
|
|
|
119
|
-
Your model presets have been saved. Use "Reset presets"
|
|
427
|
+
Your model presets have been saved. Use "Reset presets"
|
|
120
428
|
from the settings menu if available models change.
|
|
121
429
|
|
|
122
430
|
Note: Quit and relaunch OpenCode to apply model changes.
|
|
@@ -187,10 +495,26 @@ Use multi-question call with pre-selected current values:
|
|
|
187
495
|
|
|
188
496
|
```json
|
|
189
497
|
[
|
|
190
|
-
{
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
498
|
+
{
|
|
499
|
+
"header": "Model",
|
|
500
|
+
"question": "Which model profile?",
|
|
501
|
+
"options": ["Quality", "Balanced", "Budget"]
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
"header": "Research",
|
|
505
|
+
"question": "Spawn Plan Researcher?",
|
|
506
|
+
"options": ["Yes", "No"]
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
"header": "Plan Check",
|
|
510
|
+
"question": "Spawn Plan Checker?",
|
|
511
|
+
"options": ["Yes", "No"]
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
"header": "Verifier",
|
|
515
|
+
"question": "Spawn Execution Verifier?",
|
|
516
|
+
"options": ["Yes", "No"]
|
|
517
|
+
}
|
|
194
518
|
]
|
|
195
519
|
```
|
|
196
520
|
|
|
@@ -223,13 +547,128 @@ Quick commands:
|
|
|
223
547
|
|
|
224
548
|
### Set stage override
|
|
225
549
|
|
|
226
|
-
1. Pick stage
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
550
|
+
1. **Pick stage**
|
|
551
|
+
|
|
552
|
+
Use Question tool:
|
|
553
|
+
|
|
554
|
+
```
|
|
555
|
+
header: "Select Stage"
|
|
556
|
+
question: "Which stage to override?"
|
|
557
|
+
options:
|
|
558
|
+
- label: "Planning"
|
|
559
|
+
description: "Override planning model"
|
|
560
|
+
- label: "Execution"
|
|
561
|
+
description: "Override execution model"
|
|
562
|
+
- label: "Verification"
|
|
563
|
+
description: "Override verification model"
|
|
564
|
+
- label: "Cancel"
|
|
565
|
+
description: "Return to menu"
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
If Cancel selected, return to menu.
|
|
569
|
+
|
|
570
|
+
Store selected stage as `targetStage`.
|
|
571
|
+
|
|
572
|
+
2. **Choose Provider (using cache)**
|
|
573
|
+
|
|
574
|
+
Initialize cache if not already available:
|
|
575
|
+
```bash
|
|
576
|
+
[ -z "$MODELS_DATA" ] && MODELS_DATA=$(opencode models 2>/dev/null)
|
|
577
|
+
PROVIDER_COUNTS=$(echo "$MODELS_DATA" | awk -F'/' '{count[$1]++} END {for(p in count) print p ":" count[p]}')
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
Build provider menu from cache:
|
|
581
|
+
```bash
|
|
582
|
+
echo "$PROVIDER_COUNTS" | while IFS=':' read -r provider count; do
|
|
583
|
+
echo "- label: \"$provider\""
|
|
584
|
+
echo " description: \"$count models\""
|
|
585
|
+
done
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
Use Question tool:
|
|
589
|
+
|
|
590
|
+
```
|
|
591
|
+
header: "Choose LLM Provider ({activeProfile} profile)"
|
|
592
|
+
question: "Which provider for {targetStage} stage?"
|
|
593
|
+
options:
|
|
594
|
+
[providers from cache with counts]
|
|
595
|
+
- label: "Cancel"
|
|
596
|
+
description: "Return to menu"
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
If Cancel selected, return to menu.
|
|
600
|
+
|
|
601
|
+
Store selected provider as `overrideProvider`.
|
|
602
|
+
|
|
603
|
+
3. **Check for Subproviders (using cache)**
|
|
604
|
+
|
|
605
|
+
```bash
|
|
606
|
+
HAS_SUBPROVIDERS=$(echo "$MODELS_DATA" | grep "^${overrideProvider}/" | awk -F'/' '{print NF}' | head -1 | grep -q '^3$' && echo "true" || echo "false")
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
If result is "true" (provider has subproviders):
|
|
610
|
+
|
|
611
|
+
Build subprovider menu from cache:
|
|
612
|
+
```bash
|
|
613
|
+
echo "$MODELS_DATA" | grep "^${overrideProvider}/" | awk -F'/' '{print $2}' | sort | uniq -c | while read count subprovider; do
|
|
614
|
+
echo "- label: \"$subprovider\""
|
|
615
|
+
echo " description: \"$count models\""
|
|
616
|
+
done
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
Use Question tool:
|
|
620
|
+
|
|
621
|
+
```
|
|
622
|
+
header: "{activeProfile} Profile - {overrideProvider} Subprovider ({targetStage} Stage)"
|
|
623
|
+
question: "Which subprovider for {targetStage}?"
|
|
624
|
+
options:
|
|
625
|
+
[subproviders from cache with counts]
|
|
626
|
+
- label: "Cancel"
|
|
627
|
+
description: "Back to provider selection"
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
If Cancel selected, return to step 2.
|
|
631
|
+
|
|
632
|
+
Store selected subprovider as `overrideSubprovider`.
|
|
633
|
+
|
|
634
|
+
4. **Choose Model**
|
|
635
|
+
|
|
636
|
+
For 3-level structure (provider/subprovider/model):
|
|
637
|
+
```bash
|
|
638
|
+
MODELS=$(echo "$MODELS_DATA" | grep "^${overrideProvider}/${overrideSubprovider}/" | cut -d'/' -f3- | sort)
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
For 2-level structure (provider/model):
|
|
642
|
+
```bash
|
|
643
|
+
MODELS=$(echo "$MODELS_DATA" | grep "^${overrideProvider}/" | cut -d'/' -f2- | sort)
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
Use Question tool:
|
|
647
|
+
|
|
648
|
+
```
|
|
649
|
+
header: "{overrideProvider} {overrideSubprovider} Models"
|
|
650
|
+
question: "Which model for {targetStage} stage?"
|
|
651
|
+
options:
|
|
652
|
+
[models from cache]
|
|
653
|
+
- label: "Cancel"
|
|
654
|
+
description: "Back to provider selection"
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
If Cancel selected, return to step 2.
|
|
658
|
+
|
|
659
|
+
Store selected model and construct full model ID:
|
|
660
|
+
- 3-level: `{overrideProvider}/{overrideSubprovider}/{model}`
|
|
661
|
+
- 2-level: `{overrideProvider}/{model}`
|
|
662
|
+
|
|
663
|
+
5. **Save Override**
|
|
664
|
+
|
|
665
|
+
Set `config.profiles.custom_overrides[activeProfile][targetStage] = model_id`
|
|
666
|
+
|
|
667
|
+
6. **Save and Return**
|
|
668
|
+
|
|
669
|
+
Save both files and print: `Saved {targetStage} override: {model_id}`
|
|
670
|
+
|
|
671
|
+
Return to main menu (Step 4).
|
|
233
672
|
|
|
234
673
|
### Clear stage override
|
|
235
674
|
|
|
@@ -253,7 +692,7 @@ Current overrides for {activeProfile} profile:
|
|
|
253
692
|
|
|
254
693
|
### Reset presets
|
|
255
694
|
|
|
256
|
-
Run the **Preset Setup Wizard** (see Step 1). This re-queries available models and lets the user reconfigure all three profiles from scratch. Existing `custom_overrides` are cleared. After completion, return to menu.
|
|
695
|
+
Run the **Preset Setup Wizard** (see Step 1, W1-W5). This re-queries available models and lets the user reconfigure all three profiles from scratch using hierarchical selection. Existing `custom_overrides` are cleared. After completion, return to menu.
|
|
257
696
|
|
|
258
697
|
### Exit
|
|
259
698
|
|
|
@@ -299,5 +738,12 @@ Preserve existing non-agent keys in `opencode.json`.
|
|
|
299
738
|
- Overrides are profile-scoped: `custom_overrides.{profile}.{stage}`
|
|
300
739
|
- Source of truth: `config.json`; `opencode.json` is derived
|
|
301
740
|
- OpenCode does not hot-reload model assignments; user must quit and relaunch to apply changes
|
|
741
|
+
- Model IDs support 2-level (provider/model) and 3-level (provider/subprovider/model) structures
|
|
742
|
+
- Hierarchical selection is used by default: provider → subprovider (if applicable) → model
|
|
743
|
+
- Providers with subproviders: openrouter (anthropic, meta-llama, google, etc.), synthetic (hf:deepseek-ai, hf:meta-llama, etc.)
|
|
744
|
+
- Providers without subproviders: opencode, xai, back, ollama, kimi-for-coding, zai-coding-plan
|
|
745
|
+
- Smart proposals allow reusing previous selections across profiles and stages to reduce user input
|
|
746
|
+
- All model selections are validated against `opencode models` output
|
|
747
|
+
- **Performance Optimization:** All model discovery uses a single cached `MODELS_DATA` variable instead of repeated `opencode models` calls. Provider counts are pre-computed with awk for O(n) efficiency. Lazy loading: model examples are not fetched until user selects a subprovider.
|
|
302
748
|
|
|
303
749
|
</notes>
|
package/lib/constants.js
CHANGED
|
@@ -46,7 +46,13 @@ export const PATH_PATTERNS = {
|
|
|
46
46
|
* Pattern to match @gsd-opencode/ references in markdown files.
|
|
47
47
|
* Used for replacing package references with actual paths.
|
|
48
48
|
*/
|
|
49
|
-
gsdReference: /@gsd-opencode\//g
|
|
49
|
+
gsdReference: /@gsd-opencode\//g,
|
|
50
|
+
/**
|
|
51
|
+
* Pattern to match @~/.config/opencode/ references in markdown files.
|
|
52
|
+
* These are absolute references to the global config that need to be
|
|
53
|
+
* replaced for local installs.
|
|
54
|
+
*/
|
|
55
|
+
absoluteReference: /@~\/\.config\/opencode\//g
|
|
50
56
|
};
|
|
51
57
|
|
|
52
58
|
/**
|
package/package.json
CHANGED
package/src/services/file-ops.js
CHANGED
|
@@ -474,13 +474,38 @@ export class FileOperations {
|
|
|
474
474
|
// Read, replace, and write markdown content
|
|
475
475
|
let content = await fs.readFile(sourcePath, 'utf-8');
|
|
476
476
|
|
|
477
|
+
// Optimization: Skip files that don't contain any patterns needing replacement
|
|
478
|
+
const hasGsdRef = PATH_PATTERNS.gsdReference.test(content);
|
|
479
|
+
PATH_PATTERNS.gsdReference.lastIndex = 0; // Reset regex
|
|
480
|
+
const hasAbsRef = PATH_PATTERNS.absoluteReference && PATH_PATTERNS.absoluteReference.test(content);
|
|
481
|
+
if (PATH_PATTERNS.absoluteReference) {
|
|
482
|
+
PATH_PATTERNS.absoluteReference.lastIndex = 0; // Reset regex
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (!hasGsdRef && !hasAbsRef) {
|
|
486
|
+
await fs.copyFile(sourcePath, targetPath, fsConstants.COPYFILE_FICLONE);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
|
|
477
490
|
// Replace @gsd-opencode/ references with actual path
|
|
478
|
-
|
|
491
|
+
// Use function-based replacement to avoid issues with special characters
|
|
492
|
+
// like '$' in the target directory path
|
|
493
|
+
// Use getPathPrefix() to get the correct prefix (./.opencode for local, ~/.config/opencode for global)
|
|
494
|
+
const targetDir = this.scopeManager.getPathPrefix();
|
|
479
495
|
content = content.replace(
|
|
480
496
|
PATH_PATTERNS.gsdReference,
|
|
481
|
-
targetDir + '/'
|
|
497
|
+
() => targetDir + '/'
|
|
482
498
|
);
|
|
483
499
|
|
|
500
|
+
// For local installs, also replace @~/.config/opencode/ with local path
|
|
501
|
+
// This handles files that have hardcoded global references
|
|
502
|
+
if (this.scopeManager.scope === 'local' && PATH_PATTERNS.absoluteReference) {
|
|
503
|
+
content = content.replace(
|
|
504
|
+
PATH_PATTERNS.absoluteReference,
|
|
505
|
+
() => targetDir + '/'
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
|
|
484
509
|
await fs.writeFile(targetPath, content, 'utf-8');
|
|
485
510
|
} else {
|
|
486
511
|
// Copy binary or other files directly
|