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.
@@ -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
- Parse the output to extract model IDs. If command fails or returns no models, print `Error: Could not fetch available models. Check your OpenCode installation.` and stop.
118
+ Cache the models output in `MODELS_DATA` variable. All subsequent operations use this cache instead of calling `opencode models` repeatedly.
80
119
 
81
- **Step W2: Configure each profile**
120
+ If command fails or returns no models, print `Error: Could not fetch available models. Check your OpenCode installation.` and stop.
82
121
 
83
- For each profile (quality, balanced, budget), use a multi-question call:
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
- **Step W3: Save config**
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": { "planning": "{user_selection}", "execution": "{user_selection}", "verification": "{user_selection}" },
103
- "balanced": { "planning": "{user_selection}", "execution": "{user_selection}", "verification": "{user_selection}" },
104
- "budget": { "planning": "{user_selection}", "execution": "{user_selection}", "verification": "{user_selection}" }
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
- { "header": "Model", "question": "Which model profile?", "options": ["Quality", "Balanced", "Budget"] },
191
- { "header": "Research", "question": "Spawn Plan Researcher?", "options": ["Yes", "No"] },
192
- { "header": "Plan Check", "question": "Spawn Plan Checker?", "options": ["Yes", "No"] },
193
- { "header": "Verifier", "question": "Spawn Execution Verifier?", "options": ["Yes", "No"] }
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: Planning / Execution / Verification / Cancel
227
- 2. If Cancel, return to menu
228
- 3. Fetch models via `opencode models` command
229
- 4. If command fails: print error and stop
230
- 5. Pick model from list (include Cancel option)
231
- 6. Set `custom_overrides[activeProfile][stage]` = model
232
- 7. Save, print "Saved", return to menu
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gsd-opencode",
3
- "version": "1.10.1",
3
+ "version": "1.10.2",
4
4
  "description": "GSD-OpenCode distribution manager - install, verify, and maintain your GSD-OpenCode installation",
5
5
  "type": "module",
6
6
  "main": "bin/gsd.js",
@@ -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
- const targetDir = this.scopeManager.getTargetDir();
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