@workweave/router 0.2.4 → 0.2.6
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.md +15 -3
- package/cc-statusline.sh +62 -33
- package/commands/router-session.md +15 -0
- package/install.sh +133 -73
- package/opencode-weave/README.md +3 -3
- package/package.json +3 -2
- package/pi-router/README.md +2 -2
- package/uninstall.sh +39 -4
package/README.md
CHANGED
|
@@ -84,6 +84,18 @@ for the full reference.
|
|
|
84
84
|
|
|
85
85
|
## Why npx
|
|
86
86
|
|
|
87
|
-
`
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
`npx @workweave/router` gives Windows support via Git Bash, painless version
|
|
88
|
+
pinning, and discoverability via the npm registry.
|
|
89
|
+
|
|
90
|
+
## Older npm
|
|
91
|
+
|
|
92
|
+
On npm ≤ 6 the bundled `npx` treats an undeclared `-y` as consuming the next
|
|
93
|
+
token, so `npx -y @workweave/router --claude` silently drops the package name
|
|
94
|
+
and resolves the following argument as the command instead. Either upgrade
|
|
95
|
+
(`npm i -g npm@latest`) or name the binary explicitly:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
npx --package @workweave/router -y -- weave-router --claude
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
That form is correct on every npm version.
|
package/cc-statusline.sh
CHANGED
|
@@ -130,14 +130,19 @@ normalize_model() {
|
|
|
130
130
|
prices='{
|
|
131
131
|
"input": {
|
|
132
132
|
"claude-fable-5": 0.01,
|
|
133
|
-
"claude-haiku-4-5": 0.
|
|
133
|
+
"claude-haiku-4-5": 0.001,
|
|
134
|
+
"claude-opus-4-0": 0.015,
|
|
135
|
+
"claude-opus-4-1": 0.015,
|
|
136
|
+
"claude-opus-4-5": 0.005,
|
|
134
137
|
"claude-opus-4-6": 0.005,
|
|
135
138
|
"claude-opus-4-7": 0.005,
|
|
136
139
|
"claude-opus-4-8": 0.005,
|
|
140
|
+
"claude-opus-5": 0.005,
|
|
137
141
|
"claude-sonnet-4-5": 0.003,
|
|
138
142
|
"claude-sonnet-4-6": 0.003,
|
|
139
|
-
"
|
|
140
|
-
"deepseek/deepseek-v4-
|
|
143
|
+
"claude-sonnet-5": 0.003,
|
|
144
|
+
"deepseek/deepseek-v4-flash": 0.0001134,
|
|
145
|
+
"deepseek/deepseek-v4-pro": 0.001318,
|
|
141
146
|
"gemini-2.0-flash": 0.0001,
|
|
142
147
|
"gemini-2.0-flash-lite": 0.000075,
|
|
143
148
|
"gemini-2.5-flash": 0.0003,
|
|
@@ -148,6 +153,9 @@ prices='{
|
|
|
148
153
|
"gemini-3.1-flash-lite-preview": 0.0001,
|
|
149
154
|
"gemini-3.1-pro-preview": 0.002,
|
|
150
155
|
"gemini-3.5-flash": 0.0015,
|
|
156
|
+
"gemini-3.5-flash-lite": 0.0003,
|
|
157
|
+
"gemini-3.6-flash": 0.0015,
|
|
158
|
+
"google/gemma-4-26b-a4b-it": 0.00015,
|
|
151
159
|
"gpt-4.1": 0.002,
|
|
152
160
|
"gpt-4.1-mini": 0.0004,
|
|
153
161
|
"gpt-4.1-nano": 0.0001,
|
|
@@ -157,43 +165,53 @@ prices='{
|
|
|
157
165
|
"gpt-5-chat": 0.0025,
|
|
158
166
|
"gpt-5-mini": 0.0005,
|
|
159
167
|
"gpt-5-nano": 0.0001,
|
|
160
|
-
"gpt-5.4": 0.
|
|
161
|
-
"gpt-5.4-mini": 0.
|
|
162
|
-
"gpt-5.4-nano": 0.
|
|
163
|
-
"gpt-5.4-pro": 0.
|
|
168
|
+
"gpt-5.4": 0.0025,
|
|
169
|
+
"gpt-5.4-mini": 0.00075,
|
|
170
|
+
"gpt-5.4-nano": 0.0002,
|
|
171
|
+
"gpt-5.4-pro": 0.03,
|
|
164
172
|
"gpt-5.5": 0.005,
|
|
165
173
|
"gpt-5.5-mini": 0.0005,
|
|
166
174
|
"gpt-5.5-nano": 0.00015,
|
|
167
175
|
"gpt-5.5-pro": 0.03,
|
|
176
|
+
"gpt-5.6-luna": 0.001,
|
|
177
|
+
"gpt-5.6-sol": 0.005,
|
|
178
|
+
"gpt-5.6-terra": 0.0025,
|
|
179
|
+
"grok-4.5": 0.002,
|
|
168
180
|
"minimax/minimax-m2.7": 0.0003,
|
|
169
181
|
"minimax/minimax-m3": 0.0003,
|
|
170
182
|
"mistralai/mistral-small-2603": 0.0002,
|
|
171
183
|
"moonshotai/kimi-k2.5": 0.0006,
|
|
172
184
|
"moonshotai/kimi-k2.6": 0.00095,
|
|
173
185
|
"moonshotai/kimi-k2.7": 0.00095,
|
|
186
|
+
"moonshotai/kimi-k3": 0.003,
|
|
174
187
|
"qwen/qwen3-235b-a22b-2507": 0.0002266,
|
|
175
188
|
"qwen/qwen3-30b-a3b-instruct-2507": 0.00015,
|
|
176
189
|
"qwen/qwen3-coder": 0.0009,
|
|
177
190
|
"qwen/qwen3-coder-next": 0.0005,
|
|
178
191
|
"qwen/qwen3-next-80b-a3b-instruct": 0.00015,
|
|
179
192
|
"qwen/qwen3.5-flash-02-23": 0.00005,
|
|
180
|
-
"qwen/qwen3.6-35b-a3b": 0.
|
|
193
|
+
"qwen/qwen3.6-35b-a3b": 0.000172,
|
|
181
194
|
"qwen/qwen3.7-plus": 0.0004,
|
|
182
195
|
"xiaomi/mimo-v2.5-pro": 0.001,
|
|
183
|
-
"z-ai/glm-5": 0.
|
|
184
|
-
"z-ai/glm-5.1": 0.
|
|
196
|
+
"z-ai/glm-5": 0.001,
|
|
197
|
+
"z-ai/glm-5.1": 0.0014,
|
|
185
198
|
"z-ai/glm-5.2": 0.0014
|
|
186
199
|
},
|
|
187
200
|
"output": {
|
|
188
201
|
"claude-fable-5": 0.05,
|
|
189
|
-
"claude-haiku-4-5": 0.
|
|
202
|
+
"claude-haiku-4-5": 0.005,
|
|
203
|
+
"claude-opus-4-0": 0.075,
|
|
204
|
+
"claude-opus-4-1": 0.075,
|
|
205
|
+
"claude-opus-4-5": 0.025,
|
|
190
206
|
"claude-opus-4-6": 0.025,
|
|
191
207
|
"claude-opus-4-7": 0.025,
|
|
192
208
|
"claude-opus-4-8": 0.025,
|
|
209
|
+
"claude-opus-5": 0.025,
|
|
193
210
|
"claude-sonnet-4-5": 0.015,
|
|
194
211
|
"claude-sonnet-4-6": 0.015,
|
|
195
|
-
"
|
|
196
|
-
"deepseek/deepseek-v4-
|
|
212
|
+
"claude-sonnet-5": 0.015,
|
|
213
|
+
"deepseek/deepseek-v4-flash": 0.0002791,
|
|
214
|
+
"deepseek/deepseek-v4-pro": 0.0026361,
|
|
197
215
|
"gemini-2.0-flash": 0.0004,
|
|
198
216
|
"gemini-2.0-flash-lite": 0.0003,
|
|
199
217
|
"gemini-2.5-flash": 0.0012,
|
|
@@ -204,6 +222,9 @@ prices='{
|
|
|
204
222
|
"gemini-3.1-flash-lite-preview": 0.0004,
|
|
205
223
|
"gemini-3.1-pro-preview": 0.008,
|
|
206
224
|
"gemini-3.5-flash": 0.009,
|
|
225
|
+
"gemini-3.5-flash-lite": 0.0025,
|
|
226
|
+
"gemini-3.6-flash": 0.0075,
|
|
227
|
+
"google/gemma-4-26b-a4b-it": 0.0006,
|
|
207
228
|
"gpt-4.1": 0.008,
|
|
208
229
|
"gpt-4.1-mini": 0.0016,
|
|
209
230
|
"gpt-4.1-nano": 0.0004,
|
|
@@ -213,31 +234,36 @@ prices='{
|
|
|
213
234
|
"gpt-5-chat": 0.01,
|
|
214
235
|
"gpt-5-mini": 0.002,
|
|
215
236
|
"gpt-5-nano": 0.0004,
|
|
216
|
-
"gpt-5.4": 0.
|
|
217
|
-
"gpt-5.4-mini": 0.
|
|
218
|
-
"gpt-5.4-nano": 0.
|
|
219
|
-
"gpt-5.4-pro": 0.
|
|
220
|
-
"gpt-5.5": 0.
|
|
237
|
+
"gpt-5.4": 0.015,
|
|
238
|
+
"gpt-5.4-mini": 0.0045,
|
|
239
|
+
"gpt-5.4-nano": 0.00125,
|
|
240
|
+
"gpt-5.4-pro": 0.18,
|
|
241
|
+
"gpt-5.5": 0.03,
|
|
221
242
|
"gpt-5.5-mini": 0.0025,
|
|
222
243
|
"gpt-5.5-nano": 0.0006,
|
|
223
|
-
"gpt-5.5-pro": 0.
|
|
244
|
+
"gpt-5.5-pro": 0.18,
|
|
245
|
+
"gpt-5.6-luna": 0.006,
|
|
246
|
+
"gpt-5.6-sol": 0.03,
|
|
247
|
+
"gpt-5.6-terra": 0.015,
|
|
248
|
+
"grok-4.5": 0.006,
|
|
224
249
|
"minimax/minimax-m2.7": 0.0012,
|
|
225
250
|
"minimax/minimax-m3": 0.0012,
|
|
226
251
|
"mistralai/mistral-small-2603": 0.0006,
|
|
227
252
|
"moonshotai/kimi-k2.5": 0.003,
|
|
228
253
|
"moonshotai/kimi-k2.6": 0.004,
|
|
229
254
|
"moonshotai/kimi-k2.7": 0.004,
|
|
255
|
+
"moonshotai/kimi-k3": 0.015,
|
|
230
256
|
"qwen/qwen3-235b-a22b-2507": 0.0009064,
|
|
231
257
|
"qwen/qwen3-30b-a3b-instruct-2507": 0.0006,
|
|
232
258
|
"qwen/qwen3-coder": 0.0027,
|
|
233
259
|
"qwen/qwen3-coder-next": 0.0012,
|
|
234
260
|
"qwen/qwen3-next-80b-a3b-instruct": 0.0012,
|
|
235
261
|
"qwen/qwen3.5-flash-02-23": 0.00015,
|
|
236
|
-
"qwen/qwen3.6-35b-a3b": 0.
|
|
262
|
+
"qwen/qwen3.6-35b-a3b": 0.0012002,
|
|
237
263
|
"qwen/qwen3.7-plus": 0.0016,
|
|
238
264
|
"xiaomi/mimo-v2.5-pro": 0.003,
|
|
239
|
-
"z-ai/glm-5": 0.
|
|
240
|
-
"z-ai/glm-5.1": 0.
|
|
265
|
+
"z-ai/glm-5": 0.0032,
|
|
266
|
+
"z-ai/glm-5.1": 0.0044,
|
|
241
267
|
"z-ai/glm-5.2": 0.0044
|
|
242
268
|
}
|
|
243
269
|
}'
|
|
@@ -427,20 +453,23 @@ elif [[ "$routed" == "failure" ]]; then
|
|
|
427
453
|
# swap or compute savings against a non-model.
|
|
428
454
|
printf '%s — %s%s' "$brand" "$routed" "$tokens_clause"
|
|
429
455
|
elif [[ -n "$routed" ]]; then
|
|
430
|
-
#
|
|
456
|
+
# Always show the savings clause, flooring a non-positive total at $0.00.
|
|
431
457
|
# session_savings is "0.0000" on fresh sessions or sessions where every
|
|
432
|
-
# turn routed back to the selected model
|
|
433
|
-
#
|
|
434
|
-
#
|
|
435
|
-
#
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
458
|
+
# turn routed back to the selected model, and can go negative when routing
|
|
459
|
+
# upgrades a turn to a pricier model (e.g. a sticky/hard-pinned side-call,
|
|
460
|
+
# or a hard turn escalated to opus). "saved -$X" would mislead, so clamp
|
|
461
|
+
# the display to $0.00 rather than dropping the clause — a $0.00 readout
|
|
462
|
+
# tells the user the router ran and simply didn't beat their selection.
|
|
463
|
+
# When the CC selection is unknown ("?" or empty) there's nothing to
|
|
464
|
+
# compare against, so drop the "← selection" arrow and just show routed.
|
|
465
|
+
display_savings="$session_savings"
|
|
466
|
+
if [[ -z "$display_savings" ]] \
|
|
467
|
+
|| awk -v v="$display_savings" 'BEGIN{exit !(v+0 < 0)}'; then
|
|
468
|
+
display_savings="0"
|
|
440
469
|
fi
|
|
441
|
-
if [[ "$
|
|
470
|
+
if [[ -n "$selected_display" && "$selected_display" != "?" ]]; then
|
|
442
471
|
printf '%s — %s ← %s · saved %s%s' \
|
|
443
|
-
"$brand" "$routed" "$selected_display" "$(fmt_money "$
|
|
472
|
+
"$brand" "$routed" "$selected_display" "$(fmt_money "$display_savings")" "$tokens_clause"
|
|
444
473
|
else
|
|
445
474
|
printf '%s — %s%s' "$brand" "$routed" "$tokens_clause"
|
|
446
475
|
fi
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Print the session id that correlates this session in router telemetry and logs.
|
|
3
|
+
allowed-tools: Bash(echo:*)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Print the session id used by the Weave Router to correlate this session's
|
|
7
|
+
telemetry, logs, and feedback submissions. Also works as a transcript
|
|
8
|
+
filename key for manual lookups in the router dashboard.
|
|
9
|
+
|
|
10
|
+
The router carries this id as `X-Claude-Code-Session-Id` on every request and
|
|
11
|
+
stores it in `model_router_users.SessionID` for analytics joins.
|
|
12
|
+
|
|
13
|
+
Run `echo "$CLAUDE_CODE_SESSION_ID"`.
|
|
14
|
+
|
|
15
|
+
Then tell me the session id in one line, formatted as inline code so I can copy it.
|
package/install.sh
CHANGED
|
@@ -127,7 +127,10 @@ skip() { printf "%s⊙%s %s%s%s\n" "$C_DIM" "$C_RESET" "$C_DIM" "$*" "$C_RESET";
|
|
|
127
127
|
# print after a successful install is copy-paste-correct. Kept in sync with
|
|
128
128
|
# uninstall.sh's flag surface.
|
|
129
129
|
uninstall_cmd() {
|
|
130
|
-
|
|
130
|
+
# --package + `--` is load-bearing: npm <= 6's bundled npx treats an
|
|
131
|
+
# undeclared `-y` as consuming the NEXT token, so `npx -y @workweave/router`
|
|
132
|
+
# loses the package name and resolves whatever follows as the command.
|
|
133
|
+
local cmd="npx --package @workweave/router -y -- weave-router --uninstall"
|
|
131
134
|
case "$target" in
|
|
132
135
|
codex) cmd="$cmd --codex" ;;
|
|
133
136
|
opencode) cmd="$cmd --opencode" ;;
|
|
@@ -577,11 +580,10 @@ write_opencode_config() {
|
|
|
577
580
|
| (if $name != "" then . + {"X-Weave-User-Name": $name } else . end)
|
|
578
581
|
')"
|
|
579
582
|
|
|
580
|
-
#
|
|
581
|
-
#
|
|
582
|
-
#
|
|
583
|
-
#
|
|
584
|
-
# turn, its matching subscription (if connected) pays.
|
|
583
|
+
# Surface one Auto choice in opencode's picker. The router chooses the
|
|
584
|
+
# upstream model for every request, so presenting pinned model names would
|
|
585
|
+
# imply a choice that the router intentionally does not honor. Whichever
|
|
586
|
+
# model serves a turn uses its matching subscription when one is connected.
|
|
585
587
|
#
|
|
586
588
|
# npm is @ai-sdk/openai and baseURL KEEPS its /v1 here: opencode's
|
|
587
589
|
# @ai-sdk/openai provider appends /responses, yielding the router's
|
|
@@ -601,11 +603,7 @@ write_opencode_config() {
|
|
|
601
603
|
name: "Weave Router",
|
|
602
604
|
options: { apiKey: $key, baseURL: $url, headers: $headers },
|
|
603
605
|
models: {
|
|
604
|
-
|
|
605
|
-
"claude-opus-4-8": { name: "Claude Opus 4.8 (via Weave Router)" },
|
|
606
|
-
"claude-haiku-4-5": { name: "Claude Haiku 4.5 (via Weave Router)" },
|
|
607
|
-
"gpt-5.5": { name: "GPT-5.5 (via Weave Router)" },
|
|
608
|
-
"gpt-5.4": { name: "GPT-5.4 (via Weave Router)" }
|
|
606
|
+
auto: { name: "Auto" }
|
|
609
607
|
}
|
|
610
608
|
}
|
|
611
609
|
')"
|
|
@@ -655,8 +653,9 @@ write_opencode_config() {
|
|
|
655
653
|
|
|
656
654
|
# Merge into any existing opencode.json. We always overwrite provider.weave
|
|
657
655
|
# so re-install reflects the latest key/identity, but we leave the rest of the
|
|
658
|
-
# file (other providers, mcp, agent settings) untouched.
|
|
659
|
-
#
|
|
656
|
+
# file (other providers, mcp, agent settings) untouched. A previously
|
|
657
|
+
# installed `weave/*` model is migrated to `weave/auto`; unrelated provider
|
|
658
|
+
# choices stay untouched.
|
|
660
659
|
#
|
|
661
660
|
# The weave-claude login provider AND the plugin entry are written together
|
|
662
661
|
# only when the bundled plugin was present and copied ($plugin non-empty): the
|
|
@@ -684,12 +683,12 @@ write_opencode_config() {
|
|
|
684
683
|
then (.plugin -= [$pluginspec]) | (if (.plugin | length) == 0 then del(.plugin) else . end)
|
|
685
684
|
else . end)
|
|
686
685
|
end)
|
|
687
|
-
| (if (.model // "") == "" then .model = "weave/
|
|
688
|
-
#
|
|
689
|
-
#
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
686
|
+
| (if (.model // "") == "" then .model = "weave/auto" else . end)
|
|
687
|
+
# Replace any legacy Weave model choice with the single auto-routing
|
|
688
|
+
# choice. Models from unrelated providers remain unchanged.
|
|
689
|
+
| (if (.model // "" | tostring) as $model
|
|
690
|
+
| ($model | startswith("weave/") or startswith("weave-codex/") or startswith("weave-claude/"))
|
|
691
|
+
then .model = "weave/auto" else . end)
|
|
693
692
|
| (.["$schema"] //= "https://opencode.ai/config.json")
|
|
694
693
|
' "$config_file")"
|
|
695
694
|
else
|
|
@@ -699,7 +698,7 @@ write_opencode_config() {
|
|
|
699
698
|
--arg plugin "$plugin_arg" '
|
|
700
699
|
{
|
|
701
700
|
"$schema": "https://opencode.ai/config.json",
|
|
702
|
-
model: "weave/
|
|
701
|
+
model: "weave/auto",
|
|
703
702
|
provider: { weave: $block }
|
|
704
703
|
}
|
|
705
704
|
| (if $plugin != "" then .provider["weave-claude"] = $claude | .plugin = [$plugin] else . end)
|
|
@@ -770,10 +769,12 @@ write_pi_models_config() {
|
|
|
770
769
|
headers: $headers,
|
|
771
770
|
models: [
|
|
772
771
|
{ id: "claude-fable-5", name: "Claude Fable 5 (via Weave Router)", reasoning: true, input: ["text","image"], contextWindow: 1000000, maxTokens: 128000 },
|
|
773
|
-
{ id: "claude-opus-
|
|
772
|
+
{ id: "claude-opus-5", name: "Claude Opus 5 (via Weave Router)", reasoning: true, input: ["text","image"], contextWindow: 1000000, maxTokens: 128000 },
|
|
774
773
|
{ id: "claude-opus-4-7", name: "Claude Opus 4.7 (via Weave Router)", reasoning: true, input: ["text","image"], contextWindow: 200000, maxTokens: 64000 },
|
|
775
774
|
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6 (via Weave Router)", reasoning: true, input: ["text","image"], contextWindow: 200000, maxTokens: 64000 },
|
|
776
|
-
{ id: "claude-haiku-4-5", name: "Claude Haiku 4.5 (via Weave Router)", reasoning: true, input: ["text","image"], contextWindow: 200000, maxTokens: 32000 }
|
|
775
|
+
{ id: "claude-haiku-4-5", name: "Claude Haiku 4.5 (via Weave Router)", reasoning: true, input: ["text","image"], contextWindow: 200000, maxTokens: 32000 },
|
|
776
|
+
{ id: "gpt-5.6-sol", name: "GPT-5.6 Sol (via Weave Router)", reasoning: true, input: ["text","image"], contextWindow: 1050000, maxTokens: 128000 },
|
|
777
|
+
{ id: "grok-4.5", name: "Grok 4.5 (via Weave Router)", reasoning: true, input: ["text","image"], contextWindow: 500000, maxTokens: 131072 }
|
|
777
778
|
]
|
|
778
779
|
}
|
|
779
780
|
')"
|
|
@@ -1402,9 +1403,9 @@ toggle_claude() {
|
|
|
1402
1403
|
else
|
|
1403
1404
|
# Park just the router-owned env keys, then strip them so Claude Code
|
|
1404
1405
|
# falls back to its own Anthropic login.
|
|
1405
|
-
jq '{env: ((.env // {}) | {ANTHROPIC_BASE_URL, ANTHROPIC_CUSTOM_HEADERS} | with_entries(select(.value != null)))}' "$settings_file" >"$parked"
|
|
1406
|
+
jq '{env: ((.env // {}) | {ANTHROPIC_BASE_URL, ANTHROPIC_CUSTOM_HEADERS, ENABLE_TOOL_SEARCH} | with_entries(select(.value != null)))}' "$settings_file" >"$parked"
|
|
1406
1407
|
chmod 600 "$parked"
|
|
1407
|
-
merged="$(jq '(.env // {}) |= del(.ANTHROPIC_BASE_URL, .ANTHROPIC_CUSTOM_HEADERS)
|
|
1408
|
+
merged="$(jq '(.env // {}) |= del(.ANTHROPIC_BASE_URL, .ANTHROPIC_CUSTOM_HEADERS, .ENABLE_TOOL_SEARCH)
|
|
1408
1409
|
| (if (.env // {} | length) == 0 then del(.env) else . end)' "$settings_file")"
|
|
1409
1410
|
printf '%s\n' "$merged" >"$settings_file"
|
|
1410
1411
|
fi
|
|
@@ -1572,30 +1573,34 @@ toggle_opencode() {
|
|
|
1572
1573
|
;;
|
|
1573
1574
|
on)
|
|
1574
1575
|
if [ "$on" = "true" ]; then ok "opencode is already on — nothing to do."; return 0; fi
|
|
1575
|
-
restore_model="weave/
|
|
1576
|
+
restore_model="weave/auto"
|
|
1576
1577
|
if [ "$parked_present" = "true" ]; then
|
|
1577
|
-
restore_model="$(jq -r '.model // "weave/
|
|
1578
|
+
restore_model="$(jq -r '.model // "weave/auto"' "$parked")"
|
|
1578
1579
|
elif [ "$has_weave" != "true" ]; then
|
|
1579
1580
|
warn "opencode isn't configured for the router. Run the installer first."; return 0
|
|
1580
1581
|
else
|
|
1581
1582
|
# No parked model (sidecar deleted by hand). Derive the default from the
|
|
1582
1583
|
# installed provider.weave.models block rather than a hardcoded literal
|
|
1583
|
-
# that silently diverges when the installer's default changes — prefer
|
|
1584
|
-
#
|
|
1584
|
+
# that silently diverges when the installer's default changes — prefer
|
|
1585
|
+
# the auto-routing entry, else the first model the installer registered.
|
|
1585
1586
|
restore_model="$(jq -r '
|
|
1586
1587
|
(.provider.weave.models // {} | keys) as $k
|
|
1587
|
-
| (([$k[] | select(
|
|
1588
|
+
| (([$k[] | select(. == "auto")] | first) // $k[0] // "auto")
|
|
1588
1589
|
| "weave/" + .
|
|
1589
|
-
' "$f" 2>/dev/null || echo "weave/
|
|
1590
|
+
' "$f" 2>/dev/null || echo "weave/auto")"
|
|
1590
1591
|
fi
|
|
1591
|
-
#
|
|
1592
|
-
#
|
|
1593
|
-
# `weave` default so `on` can't leave opencode pointing at a missing
|
|
1594
|
-
# provider.
|
|
1592
|
+
# Restore only a registered `weave` model. Legacy installations may have
|
|
1593
|
+
# parked a pinned model, but a current install exposes only `weave/auto`.
|
|
1595
1594
|
case "$restore_model" in
|
|
1595
|
+
weave/*)
|
|
1596
|
+
local model_id="${restore_model#weave/}"
|
|
1597
|
+
if ! jq -e --arg id "$model_id" '(.provider.weave.models // {}) | has($id)' "$f" >/dev/null 2>&1; then
|
|
1598
|
+
restore_model="weave/auto"
|
|
1599
|
+
fi
|
|
1600
|
+
;;
|
|
1596
1601
|
weave-codex/*)
|
|
1597
1602
|
if [ "$(jq -r '((.provider // {}) | has("weave-codex"))' "$f" 2>/dev/null || true)" != "true" ]; then
|
|
1598
|
-
restore_model="weave/
|
|
1603
|
+
restore_model="weave/auto"
|
|
1599
1604
|
fi
|
|
1600
1605
|
;;
|
|
1601
1606
|
esac
|
|
@@ -1688,6 +1693,7 @@ fi
|
|
|
1688
1693
|
# Layout:
|
|
1689
1694
|
# Claude: <settings_dir>/commands/{force-model,unforce-model}.md → /force-model
|
|
1690
1695
|
# Codex: <codex_dir>/prompts/{force-model,unforce-model}.md → /prompts:force-model
|
|
1696
|
+
# opencode: <commands_dir>/{force-model,unforce-model}.md → /force-model
|
|
1691
1697
|
#
|
|
1692
1698
|
# Files come from install/commands/ in the repo (or the colocated commands/
|
|
1693
1699
|
# directory the npm package ships alongside install.sh).
|
|
@@ -1718,8 +1724,8 @@ install_slash_commands() {
|
|
|
1718
1724
|
installed="force-model, unforce-model, router-feedback, fm, ufm, rf"
|
|
1719
1725
|
cmds="force-model unforce-model router-feedback fm ufm rf"
|
|
1720
1726
|
if [ "$target" = "claude" ]; then
|
|
1721
|
-
cmds="$cmds router-off router-on router-status"
|
|
1722
|
-
installed="$installed, router-off, router-on, router-status"
|
|
1727
|
+
cmds="$cmds router-off router-on router-status router-session"
|
|
1728
|
+
installed="$installed, router-off, router-on, router-status, router-session"
|
|
1723
1729
|
fi
|
|
1724
1730
|
|
|
1725
1731
|
# Bake the same scope selector the toggle needs to find this install: --dir
|
|
@@ -1829,6 +1835,26 @@ if [ "$target" = "opencode" ]; then
|
|
|
1829
1835
|
ok "Updated $gitignore (ignored opencode.json, .weave/)"
|
|
1830
1836
|
fi
|
|
1831
1837
|
|
|
1838
|
+
# Slash command wrappers: opencode discovers commands in *.md files under
|
|
1839
|
+
# ~/.config/opencode/commands/ (user scope) and .opencode/commands/ (project
|
|
1840
|
+
# scope). Install command wrappers for /rf (±), /force-model, /unforce-model
|
|
1841
|
+
# so typing /rf + in the TUI expands to /router-feedback + and reaches the
|
|
1842
|
+
# router's server-side feedback interceptor, same as Claude Code + Codex.
|
|
1843
|
+
#
|
|
1844
|
+
# Router on/off/status are not installed — they run npx shell commands
|
|
1845
|
+
# specific to the Claude Code settings model and don't apply to opencode.
|
|
1846
|
+
if [ "$scope" = "project" ]; then
|
|
1847
|
+
opencode_commands_dir="$opencode_dir/.opencode/commands"
|
|
1848
|
+
else
|
|
1849
|
+
# User scope and --dir installs: use the global commands path that opencode
|
|
1850
|
+
# discovers regardless of working directory.
|
|
1851
|
+
opencode_commands_dir="${XDG_CONFIG_HOME:-$HOME/.config}/opencode/commands"
|
|
1852
|
+
fi
|
|
1853
|
+
install_slash_commands "$opencode_commands_dir"
|
|
1854
|
+
if [ "$scope" = "user" ] || [ -n "$install_dir" ]; then
|
|
1855
|
+
info "opencode restart required for commands to take effect."
|
|
1856
|
+
fi
|
|
1857
|
+
|
|
1832
1858
|
# Post-install verification: same probes the Claude/Codex paths run.
|
|
1833
1859
|
if [ "$quiet" != "true" ]; then
|
|
1834
1860
|
if ! spin "Pinging $base_url/health" curl -fsS --max-time 5 "$base_url/health"; then
|
|
@@ -2070,14 +2096,19 @@ normalize_model() {
|
|
|
2070
2096
|
prices='{
|
|
2071
2097
|
"input": {
|
|
2072
2098
|
"claude-fable-5": 0.01,
|
|
2073
|
-
"claude-haiku-4-5": 0.
|
|
2099
|
+
"claude-haiku-4-5": 0.001,
|
|
2100
|
+
"claude-opus-4-0": 0.015,
|
|
2101
|
+
"claude-opus-4-1": 0.015,
|
|
2102
|
+
"claude-opus-4-5": 0.005,
|
|
2074
2103
|
"claude-opus-4-6": 0.005,
|
|
2075
2104
|
"claude-opus-4-7": 0.005,
|
|
2076
2105
|
"claude-opus-4-8": 0.005,
|
|
2106
|
+
"claude-opus-5": 0.005,
|
|
2077
2107
|
"claude-sonnet-4-5": 0.003,
|
|
2078
2108
|
"claude-sonnet-4-6": 0.003,
|
|
2079
|
-
"
|
|
2080
|
-
"deepseek/deepseek-v4-
|
|
2109
|
+
"claude-sonnet-5": 0.003,
|
|
2110
|
+
"deepseek/deepseek-v4-flash": 0.0001134,
|
|
2111
|
+
"deepseek/deepseek-v4-pro": 0.001318,
|
|
2081
2112
|
"gemini-2.0-flash": 0.0001,
|
|
2082
2113
|
"gemini-2.0-flash-lite": 0.000075,
|
|
2083
2114
|
"gemini-2.5-flash": 0.0003,
|
|
@@ -2088,6 +2119,9 @@ prices='{
|
|
|
2088
2119
|
"gemini-3.1-flash-lite-preview": 0.0001,
|
|
2089
2120
|
"gemini-3.1-pro-preview": 0.002,
|
|
2090
2121
|
"gemini-3.5-flash": 0.0015,
|
|
2122
|
+
"gemini-3.5-flash-lite": 0.0003,
|
|
2123
|
+
"gemini-3.6-flash": 0.0015,
|
|
2124
|
+
"google/gemma-4-26b-a4b-it": 0.00015,
|
|
2091
2125
|
"gpt-4.1": 0.002,
|
|
2092
2126
|
"gpt-4.1-mini": 0.0004,
|
|
2093
2127
|
"gpt-4.1-nano": 0.0001,
|
|
@@ -2097,43 +2131,53 @@ prices='{
|
|
|
2097
2131
|
"gpt-5-chat": 0.0025,
|
|
2098
2132
|
"gpt-5-mini": 0.0005,
|
|
2099
2133
|
"gpt-5-nano": 0.0001,
|
|
2100
|
-
"gpt-5.4": 0.
|
|
2101
|
-
"gpt-5.4-mini": 0.
|
|
2102
|
-
"gpt-5.4-nano": 0.
|
|
2103
|
-
"gpt-5.4-pro": 0.
|
|
2134
|
+
"gpt-5.4": 0.0025,
|
|
2135
|
+
"gpt-5.4-mini": 0.00075,
|
|
2136
|
+
"gpt-5.4-nano": 0.0002,
|
|
2137
|
+
"gpt-5.4-pro": 0.03,
|
|
2104
2138
|
"gpt-5.5": 0.005,
|
|
2105
2139
|
"gpt-5.5-mini": 0.0005,
|
|
2106
2140
|
"gpt-5.5-nano": 0.00015,
|
|
2107
2141
|
"gpt-5.5-pro": 0.03,
|
|
2142
|
+
"gpt-5.6-luna": 0.001,
|
|
2143
|
+
"gpt-5.6-sol": 0.005,
|
|
2144
|
+
"gpt-5.6-terra": 0.0025,
|
|
2145
|
+
"grok-4.5": 0.002,
|
|
2108
2146
|
"minimax/minimax-m2.7": 0.0003,
|
|
2109
2147
|
"minimax/minimax-m3": 0.0003,
|
|
2110
2148
|
"mistralai/mistral-small-2603": 0.0002,
|
|
2111
2149
|
"moonshotai/kimi-k2.5": 0.0006,
|
|
2112
2150
|
"moonshotai/kimi-k2.6": 0.00095,
|
|
2113
2151
|
"moonshotai/kimi-k2.7": 0.00095,
|
|
2152
|
+
"moonshotai/kimi-k3": 0.003,
|
|
2114
2153
|
"qwen/qwen3-235b-a22b-2507": 0.0002266,
|
|
2115
2154
|
"qwen/qwen3-30b-a3b-instruct-2507": 0.00015,
|
|
2116
2155
|
"qwen/qwen3-coder": 0.0009,
|
|
2117
2156
|
"qwen/qwen3-coder-next": 0.0005,
|
|
2118
2157
|
"qwen/qwen3-next-80b-a3b-instruct": 0.00015,
|
|
2119
2158
|
"qwen/qwen3.5-flash-02-23": 0.00005,
|
|
2120
|
-
"qwen/qwen3.6-35b-a3b": 0.
|
|
2159
|
+
"qwen/qwen3.6-35b-a3b": 0.000172,
|
|
2121
2160
|
"qwen/qwen3.7-plus": 0.0004,
|
|
2122
2161
|
"xiaomi/mimo-v2.5-pro": 0.001,
|
|
2123
|
-
"z-ai/glm-5": 0.
|
|
2124
|
-
"z-ai/glm-5.1": 0.
|
|
2162
|
+
"z-ai/glm-5": 0.001,
|
|
2163
|
+
"z-ai/glm-5.1": 0.0014,
|
|
2125
2164
|
"z-ai/glm-5.2": 0.0014
|
|
2126
2165
|
},
|
|
2127
2166
|
"output": {
|
|
2128
2167
|
"claude-fable-5": 0.05,
|
|
2129
|
-
"claude-haiku-4-5": 0.
|
|
2168
|
+
"claude-haiku-4-5": 0.005,
|
|
2169
|
+
"claude-opus-4-0": 0.075,
|
|
2170
|
+
"claude-opus-4-1": 0.075,
|
|
2171
|
+
"claude-opus-4-5": 0.025,
|
|
2130
2172
|
"claude-opus-4-6": 0.025,
|
|
2131
2173
|
"claude-opus-4-7": 0.025,
|
|
2132
2174
|
"claude-opus-4-8": 0.025,
|
|
2175
|
+
"claude-opus-5": 0.025,
|
|
2133
2176
|
"claude-sonnet-4-5": 0.015,
|
|
2134
2177
|
"claude-sonnet-4-6": 0.015,
|
|
2135
|
-
"
|
|
2136
|
-
"deepseek/deepseek-v4-
|
|
2178
|
+
"claude-sonnet-5": 0.015,
|
|
2179
|
+
"deepseek/deepseek-v4-flash": 0.0002791,
|
|
2180
|
+
"deepseek/deepseek-v4-pro": 0.0026361,
|
|
2137
2181
|
"gemini-2.0-flash": 0.0004,
|
|
2138
2182
|
"gemini-2.0-flash-lite": 0.0003,
|
|
2139
2183
|
"gemini-2.5-flash": 0.0012,
|
|
@@ -2144,6 +2188,9 @@ prices='{
|
|
|
2144
2188
|
"gemini-3.1-flash-lite-preview": 0.0004,
|
|
2145
2189
|
"gemini-3.1-pro-preview": 0.008,
|
|
2146
2190
|
"gemini-3.5-flash": 0.009,
|
|
2191
|
+
"gemini-3.5-flash-lite": 0.0025,
|
|
2192
|
+
"gemini-3.6-flash": 0.0075,
|
|
2193
|
+
"google/gemma-4-26b-a4b-it": 0.0006,
|
|
2147
2194
|
"gpt-4.1": 0.008,
|
|
2148
2195
|
"gpt-4.1-mini": 0.0016,
|
|
2149
2196
|
"gpt-4.1-nano": 0.0004,
|
|
@@ -2153,31 +2200,36 @@ prices='{
|
|
|
2153
2200
|
"gpt-5-chat": 0.01,
|
|
2154
2201
|
"gpt-5-mini": 0.002,
|
|
2155
2202
|
"gpt-5-nano": 0.0004,
|
|
2156
|
-
"gpt-5.4": 0.
|
|
2157
|
-
"gpt-5.4-mini": 0.
|
|
2158
|
-
"gpt-5.4-nano": 0.
|
|
2159
|
-
"gpt-5.4-pro": 0.
|
|
2160
|
-
"gpt-5.5": 0.
|
|
2203
|
+
"gpt-5.4": 0.015,
|
|
2204
|
+
"gpt-5.4-mini": 0.0045,
|
|
2205
|
+
"gpt-5.4-nano": 0.00125,
|
|
2206
|
+
"gpt-5.4-pro": 0.18,
|
|
2207
|
+
"gpt-5.5": 0.03,
|
|
2161
2208
|
"gpt-5.5-mini": 0.0025,
|
|
2162
2209
|
"gpt-5.5-nano": 0.0006,
|
|
2163
|
-
"gpt-5.5-pro": 0.
|
|
2210
|
+
"gpt-5.5-pro": 0.18,
|
|
2211
|
+
"gpt-5.6-luna": 0.006,
|
|
2212
|
+
"gpt-5.6-sol": 0.03,
|
|
2213
|
+
"gpt-5.6-terra": 0.015,
|
|
2214
|
+
"grok-4.5": 0.006,
|
|
2164
2215
|
"minimax/minimax-m2.7": 0.0012,
|
|
2165
2216
|
"minimax/minimax-m3": 0.0012,
|
|
2166
2217
|
"mistralai/mistral-small-2603": 0.0006,
|
|
2167
2218
|
"moonshotai/kimi-k2.5": 0.003,
|
|
2168
2219
|
"moonshotai/kimi-k2.6": 0.004,
|
|
2169
2220
|
"moonshotai/kimi-k2.7": 0.004,
|
|
2221
|
+
"moonshotai/kimi-k3": 0.015,
|
|
2170
2222
|
"qwen/qwen3-235b-a22b-2507": 0.0009064,
|
|
2171
2223
|
"qwen/qwen3-30b-a3b-instruct-2507": 0.0006,
|
|
2172
2224
|
"qwen/qwen3-coder": 0.0027,
|
|
2173
2225
|
"qwen/qwen3-coder-next": 0.0012,
|
|
2174
2226
|
"qwen/qwen3-next-80b-a3b-instruct": 0.0012,
|
|
2175
2227
|
"qwen/qwen3.5-flash-02-23": 0.00015,
|
|
2176
|
-
"qwen/qwen3.6-35b-a3b": 0.
|
|
2228
|
+
"qwen/qwen3.6-35b-a3b": 0.0012002,
|
|
2177
2229
|
"qwen/qwen3.7-plus": 0.0016,
|
|
2178
2230
|
"xiaomi/mimo-v2.5-pro": 0.003,
|
|
2179
|
-
"z-ai/glm-5": 0.
|
|
2180
|
-
"z-ai/glm-5.1": 0.
|
|
2231
|
+
"z-ai/glm-5": 0.0032,
|
|
2232
|
+
"z-ai/glm-5.1": 0.0044,
|
|
2181
2233
|
"z-ai/glm-5.2": 0.0044
|
|
2182
2234
|
}
|
|
2183
2235
|
}'
|
|
@@ -2367,20 +2419,23 @@ elif [[ "$routed" == "failure" ]]; then
|
|
|
2367
2419
|
# swap or compute savings against a non-model.
|
|
2368
2420
|
printf '%s — %s%s' "$brand" "$routed" "$tokens_clause"
|
|
2369
2421
|
elif [[ -n "$routed" ]]; then
|
|
2370
|
-
#
|
|
2422
|
+
# Always show the savings clause, flooring a non-positive total at $0.00.
|
|
2371
2423
|
# session_savings is "0.0000" on fresh sessions or sessions where every
|
|
2372
|
-
# turn routed back to the selected model
|
|
2373
|
-
#
|
|
2374
|
-
#
|
|
2375
|
-
#
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2424
|
+
# turn routed back to the selected model, and can go negative when routing
|
|
2425
|
+
# upgrades a turn to a pricier model (e.g. a sticky/hard-pinned side-call,
|
|
2426
|
+
# or a hard turn escalated to opus). "saved -$X" would mislead, so clamp
|
|
2427
|
+
# the display to $0.00 rather than dropping the clause — a $0.00 readout
|
|
2428
|
+
# tells the user the router ran and simply didn't beat their selection.
|
|
2429
|
+
# When the CC selection is unknown ("?" or empty) there's nothing to
|
|
2430
|
+
# compare against, so drop the "← selection" arrow and just show routed.
|
|
2431
|
+
display_savings="$session_savings"
|
|
2432
|
+
if [[ -z "$display_savings" ]] \
|
|
2433
|
+
|| awk -v v="$display_savings" 'BEGIN{exit !(v+0 < 0)}'; then
|
|
2434
|
+
display_savings="0"
|
|
2435
|
+
fi
|
|
2436
|
+
if [[ -n "$selected_display" && "$selected_display" != "?" ]]; then
|
|
2382
2437
|
printf '%s — %s ← %s · saved %s%s' \
|
|
2383
|
-
"$brand" "$routed" "$selected_display" "$(fmt_money "$
|
|
2438
|
+
"$brand" "$routed" "$selected_display" "$(fmt_money "$display_savings")" "$tokens_clause"
|
|
2384
2439
|
else
|
|
2385
2440
|
printf '%s — %s%s' "$brand" "$routed" "$tokens_clause"
|
|
2386
2441
|
fi
|
|
@@ -2417,14 +2472,19 @@ if [ -n "$user_name" ]; then
|
|
|
2417
2472
|
fi
|
|
2418
2473
|
custom_headers="$custom_headers"$'\n'"X-App: claude-code"
|
|
2419
2474
|
|
|
2475
|
+
# Setting ANTHROPIC_BASE_URL makes Claude Code treat us as non-first-party and
|
|
2476
|
+
# disable MCP tool-search deferral, inlining every tool schema into every request
|
|
2477
|
+
# — a large uncompactable prefix that can push a session into an autocompact
|
|
2478
|
+
# thrash loop. ENABLE_TOOL_SEARCH=auto restores on-demand loading (Claude Code's
|
|
2479
|
+
# own first-party default).
|
|
2420
2480
|
if [ "$scope" = "project" ] && [ -z "$install_dir" ]; then
|
|
2421
2481
|
jq -n --arg url "$base_url" --arg sl "$statusline_path_for_settings" '{
|
|
2422
|
-
env: { ANTHROPIC_BASE_URL: $url },
|
|
2482
|
+
env: { ANTHROPIC_BASE_URL: $url, ENABLE_TOOL_SEARCH: "auto" },
|
|
2423
2483
|
statusLine: { type: "command", command: $sl }
|
|
2424
2484
|
}' >"$tmp_patch"
|
|
2425
2485
|
else
|
|
2426
2486
|
jq -n --arg url "$base_url" --arg header "$custom_headers" --arg sl "$statusline_path_for_settings" '{
|
|
2427
|
-
env: { ANTHROPIC_BASE_URL: $url, ANTHROPIC_CUSTOM_HEADERS: $header },
|
|
2487
|
+
env: { ANTHROPIC_BASE_URL: $url, ANTHROPIC_CUSTOM_HEADERS: $header, ENABLE_TOOL_SEARCH: "auto" },
|
|
2428
2488
|
statusLine: { type: "command", command: $sl }
|
|
2429
2489
|
}' >"$tmp_patch"
|
|
2430
2490
|
fi
|
package/opencode-weave/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Lets a caller's own **AI subscriptions** pay for their **opencode** turns, routed
|
|
4
4
|
through the Weave Router. A subscription is a **credential scoped to the model
|
|
5
5
|
family it can pay for**, not a provider you pick: you connect your ChatGPT
|
|
6
|
-
(Codex) and/or Claude (Pro/Max) plan once, the router routes every
|
|
6
|
+
(Codex) and/or Claude (Pro/Max) plan once, the router routes every request to the
|
|
7
7
|
best model, and bills the plan that matches the model it served — ChatGPT pays
|
|
8
8
|
for GPT/Codex turns, Claude pays for Claude turns, your Weave key pays for
|
|
9
9
|
everything else.
|
|
@@ -34,9 +34,9 @@ router's dedicated headers:
|
|
|
34
34
|
| `X-Weave-Anthropic-Subscription: <sk-ant-oat token>` | pays Claude turns, refreshed on expiry |
|
|
35
35
|
| `X-Weave-Router-Key: rk_…` | from `opencode.json` `options.headers` — the router authenticates off this |
|
|
36
36
|
|
|
37
|
-
The router routes
|
|
37
|
+
The router routes each request across every model the caller's subs + key can pay
|
|
38
38
|
for and resolves the subscription matching the chosen provider, so a sub is
|
|
39
|
-
never billed for a
|
|
39
|
+
never billed for a request outside its family.
|
|
40
40
|
|
|
41
41
|
## Two storage slots, one request provider
|
|
42
42
|
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workweave/router",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "One-command installer that points Claude Code, Codex, opencode, or pi at the Weave Router. For pi it also ships the routing extension, loaded via pi.extensions.",
|
|
5
5
|
"bin": {
|
|
6
|
-
"weave-router": "bin.js"
|
|
6
|
+
"weave-router": "bin.js",
|
|
7
|
+
"router": "bin.js"
|
|
7
8
|
},
|
|
8
9
|
"pi": {
|
|
9
10
|
"extensions": [
|
package/pi-router/README.md
CHANGED
|
@@ -9,8 +9,8 @@ LLM proxy that picks the most cost-efficient model that still solves each task.
|
|
|
9
9
|
Installed automatically by the Weave Router installer:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
WEAVE_ROUTER_KEY=rk_… npx
|
|
13
|
-
WEAVE_ROUTER_KEY=rk_… npx
|
|
12
|
+
WEAVE_ROUTER_KEY=rk_… npx --package @workweave/router -y -- weave-router --pi
|
|
13
|
+
WEAVE_ROUTER_KEY=rk_… npx --package @workweave/router -y -- weave-router --pi --local # local router
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
That writes `~/.pi/agent/models.json` (the `weave` provider), adds
|
package/uninstall.sh
CHANGED
|
@@ -213,6 +213,41 @@ if [ "$target" = "opencode" ]; then
|
|
|
213
213
|
ok "Removed $opencode_parked"
|
|
214
214
|
fi
|
|
215
215
|
|
|
216
|
+
# Remove slash command wrapper files this installer owns. Install mirrors
|
|
217
|
+
# this split: project scope uses <repo>/.opencode/commands/, while user
|
|
218
|
+
# scope—including a user-style --dir install—uses the global XDG commands
|
|
219
|
+
# directory so opencode discovers the wrappers from any working directory.
|
|
220
|
+
remove_opencode_command_dir() {
|
|
221
|
+
local opencode_cmds_dir="$1" cmd cmd_file
|
|
222
|
+
if [ -d "$opencode_cmds_dir" ]; then
|
|
223
|
+
refuse_if_symlink "$opencode_cmds_dir"
|
|
224
|
+
for cmd in force-model unforce-model router-feedback fm ufm rf; do
|
|
225
|
+
cmd_file="$opencode_cmds_dir/$cmd.md"
|
|
226
|
+
if [ -f "$cmd_file" ]; then
|
|
227
|
+
refuse_if_symlink "$cmd_file"
|
|
228
|
+
rm -f "$cmd_file"
|
|
229
|
+
ok "Removed $cmd_file"
|
|
230
|
+
fi
|
|
231
|
+
done
|
|
232
|
+
rmdir "$opencode_cmds_dir" 2>/dev/null || true
|
|
233
|
+
fi
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if [ "$scope" = "project" ]; then
|
|
237
|
+
opencode_commands_dir="$opencode_dir/.opencode/commands"
|
|
238
|
+
else
|
|
239
|
+
opencode_commands_dir="${XDG_CONFIG_HOME:-$HOME/.config}/opencode/commands"
|
|
240
|
+
fi
|
|
241
|
+
remove_opencode_command_dir "$opencode_commands_dir"
|
|
242
|
+
|
|
243
|
+
# Also clean the two paths used by earlier installer revisions, but avoid
|
|
244
|
+
# visiting the canonical path twice. This keeps uninstall idempotent for
|
|
245
|
+
# existing project and --dir installations.
|
|
246
|
+
for legacy_dir in "$opencode_dir/commands" "$opencode_dir/.opencode/commands"; do
|
|
247
|
+
[ "$legacy_dir" = "$opencode_commands_dir" ] && continue
|
|
248
|
+
remove_opencode_command_dir "$legacy_dir"
|
|
249
|
+
done
|
|
250
|
+
|
|
216
251
|
if [ -n "$install_dir" ]; then
|
|
217
252
|
ok "Weave Router uninstalled from $install_dir (opencode)."
|
|
218
253
|
else
|
|
@@ -475,13 +510,13 @@ else
|
|
|
475
510
|
fi
|
|
476
511
|
|
|
477
512
|
if [ -f "$settings_file" ]; then
|
|
478
|
-
# Only remove keys we actually installed: scrub our
|
|
513
|
+
# Only remove keys we actually installed: scrub our env vars, and only
|
|
479
514
|
# delete `statusLine` / `apiKeyHelper` when they point at scripts this
|
|
480
515
|
# installer used in older versions. Otherwise an unrelated user-configured
|
|
481
516
|
# statusLine or apiKeyHelper would be silently clobbered.
|
|
482
517
|
cleaned="$(jq '
|
|
483
518
|
if .env then
|
|
484
|
-
.env |= (del(.ANTHROPIC_BASE_URL, .ANTHROPIC_AUTH_TOKEN, .ANTHROPIC_CUSTOM_HEADERS))
|
|
519
|
+
.env |= (del(.ANTHROPIC_BASE_URL, .ANTHROPIC_AUTH_TOKEN, .ANTHROPIC_CUSTOM_HEADERS, .ENABLE_TOOL_SEARCH))
|
|
485
520
|
| (if (.env | length) == 0 then del(.env) else . end)
|
|
486
521
|
else . end
|
|
487
522
|
| (if (.statusLine.command // "" | tostring | endswith("cc-statusline.sh"))
|
|
@@ -501,7 +536,7 @@ if [ -n "$local_settings_file" ] && [ -f "$local_settings_file" ]; then
|
|
|
501
536
|
# uninstall fully reverts a toggled-off install.
|
|
502
537
|
cleaned="$(jq '
|
|
503
538
|
if .env then
|
|
504
|
-
.env |= (del(.ANTHROPIC_BASE_URL, .ANTHROPIC_AUTH_TOKEN, .ANTHROPIC_CUSTOM_HEADERS))
|
|
539
|
+
.env |= (del(.ANTHROPIC_BASE_URL, .ANTHROPIC_AUTH_TOKEN, .ANTHROPIC_CUSTOM_HEADERS, .ENABLE_TOOL_SEARCH))
|
|
505
540
|
| (if (.env | length) == 0 then del(.env) else . end)
|
|
506
541
|
else . end
|
|
507
542
|
| del(.apiKeyHelper)
|
|
@@ -531,7 +566,7 @@ done
|
|
|
531
566
|
commands_dir="$(dirname "$settings_file")/commands"
|
|
532
567
|
if [ -d "$commands_dir" ]; then
|
|
533
568
|
refuse_if_symlink "$commands_dir"
|
|
534
|
-
for cmd in force-model unforce-model router-feedback fm ufm rf router-off router-on router-status; do
|
|
569
|
+
for cmd in force-model unforce-model router-feedback fm ufm rf router-off router-on router-status router-session; do
|
|
535
570
|
cmd_file="$commands_dir/$cmd.md"
|
|
536
571
|
if [ -f "$cmd_file" ]; then
|
|
537
572
|
refuse_if_symlink "$cmd_file"
|