@workweave/router 0.2.5 → 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 CHANGED
@@ -84,6 +84,18 @@ for the full reference.
84
84
 
85
85
  ## Why npx
86
86
 
87
- `curl -fsSL https://weave.ai/cc/install.sh | sh` still works and is fine.
88
- `npx @workweave/router` adds: Windows support via Git Bash, painless version
89
- pinning, no `curl | sh` aversion, and discoverability via the npm registry.
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
@@ -137,6 +137,7 @@ prices='{
137
137
  "claude-opus-4-6": 0.005,
138
138
  "claude-opus-4-7": 0.005,
139
139
  "claude-opus-4-8": 0.005,
140
+ "claude-opus-5": 0.005,
140
141
  "claude-sonnet-4-5": 0.003,
141
142
  "claude-sonnet-4-6": 0.003,
142
143
  "claude-sonnet-5": 0.003,
@@ -152,6 +153,8 @@ prices='{
152
153
  "gemini-3.1-flash-lite-preview": 0.0001,
153
154
  "gemini-3.1-pro-preview": 0.002,
154
155
  "gemini-3.5-flash": 0.0015,
156
+ "gemini-3.5-flash-lite": 0.0003,
157
+ "gemini-3.6-flash": 0.0015,
155
158
  "google/gemma-4-26b-a4b-it": 0.00015,
156
159
  "gpt-4.1": 0.002,
157
160
  "gpt-4.1-mini": 0.0004,
@@ -170,12 +173,17 @@ prices='{
170
173
  "gpt-5.5-mini": 0.0005,
171
174
  "gpt-5.5-nano": 0.00015,
172
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,
173
180
  "minimax/minimax-m2.7": 0.0003,
174
181
  "minimax/minimax-m3": 0.0003,
175
182
  "mistralai/mistral-small-2603": 0.0002,
176
183
  "moonshotai/kimi-k2.5": 0.0006,
177
184
  "moonshotai/kimi-k2.6": 0.00095,
178
185
  "moonshotai/kimi-k2.7": 0.00095,
186
+ "moonshotai/kimi-k3": 0.003,
179
187
  "qwen/qwen3-235b-a22b-2507": 0.0002266,
180
188
  "qwen/qwen3-30b-a3b-instruct-2507": 0.00015,
181
189
  "qwen/qwen3-coder": 0.0009,
@@ -198,6 +206,7 @@ prices='{
198
206
  "claude-opus-4-6": 0.025,
199
207
  "claude-opus-4-7": 0.025,
200
208
  "claude-opus-4-8": 0.025,
209
+ "claude-opus-5": 0.025,
201
210
  "claude-sonnet-4-5": 0.015,
202
211
  "claude-sonnet-4-6": 0.015,
203
212
  "claude-sonnet-5": 0.015,
@@ -213,6 +222,8 @@ prices='{
213
222
  "gemini-3.1-flash-lite-preview": 0.0004,
214
223
  "gemini-3.1-pro-preview": 0.008,
215
224
  "gemini-3.5-flash": 0.009,
225
+ "gemini-3.5-flash-lite": 0.0025,
226
+ "gemini-3.6-flash": 0.0075,
216
227
  "google/gemma-4-26b-a4b-it": 0.0006,
217
228
  "gpt-4.1": 0.008,
218
229
  "gpt-4.1-mini": 0.0016,
@@ -231,12 +242,17 @@ prices='{
231
242
  "gpt-5.5-mini": 0.0025,
232
243
  "gpt-5.5-nano": 0.0006,
233
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,
234
249
  "minimax/minimax-m2.7": 0.0012,
235
250
  "minimax/minimax-m3": 0.0012,
236
251
  "mistralai/mistral-small-2603": 0.0006,
237
252
  "moonshotai/kimi-k2.5": 0.003,
238
253
  "moonshotai/kimi-k2.6": 0.004,
239
254
  "moonshotai/kimi-k2.7": 0.004,
255
+ "moonshotai/kimi-k3": 0.015,
240
256
  "qwen/qwen3-235b-a22b-2507": 0.0009064,
241
257
  "qwen/qwen3-30b-a3b-instruct-2507": 0.0006,
242
258
  "qwen/qwen3-coder": 0.0027,
@@ -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
- local cmd="npx -y @workweave/router --uninstall"
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
- # Headline models we surface in opencode's picker. The router re-routes
581
- # each request anyway, so this list is mostly UX — what shows up when the
582
- # user runs /models inside opencode. We list a mix of GPT + Claude so the
583
- # picker reflects that the router spans families; whichever model serves the
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,12 +603,7 @@ write_opencode_config() {
601
603
  name: "Weave Router",
602
604
  options: { apiKey: $key, baseURL: $url, headers: $headers },
603
605
  models: {
604
- "claude-sonnet-5": { name: "Claude Sonnet 5 (via Weave Router)" },
605
- "claude-sonnet-4-6": { name: "Claude Sonnet 4.6 (via Weave Router)" },
606
- "claude-opus-4-8": { name: "Claude Opus 4.8 (via Weave Router)" },
607
- "claude-haiku-4-5": { name: "Claude Haiku 4.5 (via Weave Router)" },
608
- "gpt-5.5": { name: "GPT-5.5 (via Weave Router)" },
609
- "gpt-5.4": { name: "GPT-5.4 (via Weave Router)" }
606
+ auto: { name: "Auto" }
610
607
  }
611
608
  }
612
609
  ')"
@@ -656,8 +653,9 @@ write_opencode_config() {
656
653
 
657
654
  # Merge into any existing opencode.json. We always overwrite provider.weave
658
655
  # so re-install reflects the latest key/identity, but we leave the rest of the
659
- # file (other providers, mcp, agent settings) untouched. Top-level `model` is
660
- # only set when the user hasn't already picked one.
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.
661
659
  #
662
660
  # The weave-claude login provider AND the plugin entry are written together
663
661
  # only when the bundled plugin was present and copied ($plugin non-empty): the
@@ -685,12 +683,12 @@ write_opencode_config() {
685
683
  then (.plugin -= [$pluginspec]) | (if (.plugin | length) == 0 then del(.plugin) else . end)
686
684
  else . end)
687
685
  end)
688
- | (if (.model // "") == "" then .model = "weave/claude-sonnet-4-6" else . end)
689
- # Reset the default model if it points at a provider we just removed: the
690
- # retired weave-codex, or weave-claude on a plugin-less re-install (it has
691
- # no models anyway). Otherwise opencode boots with a dangling model.
692
- | (if (.model // "" | tostring | startswith("weave-codex/")) then .model = "weave/claude-sonnet-4-6" else . end)
693
- | (if $plugin == "" and (.model // "" | tostring | startswith("weave-claude/")) then .model = "weave/claude-sonnet-4-6" else . end)
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)
694
692
  | (.["$schema"] //= "https://opencode.ai/config.json")
695
693
  ' "$config_file")"
696
694
  else
@@ -700,7 +698,7 @@ write_opencode_config() {
700
698
  --arg plugin "$plugin_arg" '
701
699
  {
702
700
  "$schema": "https://opencode.ai/config.json",
703
- model: "weave/claude-sonnet-4-6",
701
+ model: "weave/auto",
704
702
  provider: { weave: $block }
705
703
  }
706
704
  | (if $plugin != "" then .provider["weave-claude"] = $claude | .plugin = [$plugin] else . end)
@@ -771,10 +769,12 @@ write_pi_models_config() {
771
769
  headers: $headers,
772
770
  models: [
773
771
  { id: "claude-fable-5", name: "Claude Fable 5 (via Weave Router)", reasoning: true, input: ["text","image"], contextWindow: 1000000, maxTokens: 128000 },
774
- { id: "claude-opus-4-8", name: "Claude Opus 4.8 (via Weave Router)", reasoning: true, input: ["text","image"], contextWindow: 200000, maxTokens: 64000 },
772
+ { id: "claude-opus-5", name: "Claude Opus 5 (via Weave Router)", reasoning: true, input: ["text","image"], contextWindow: 1000000, maxTokens: 128000 },
775
773
  { id: "claude-opus-4-7", name: "Claude Opus 4.7 (via Weave Router)", reasoning: true, input: ["text","image"], contextWindow: 200000, maxTokens: 64000 },
776
774
  { id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6 (via Weave Router)", reasoning: true, input: ["text","image"], contextWindow: 200000, maxTokens: 64000 },
777
- { 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 }
778
778
  ]
779
779
  }
780
780
  ')"
@@ -1573,30 +1573,34 @@ toggle_opencode() {
1573
1573
  ;;
1574
1574
  on)
1575
1575
  if [ "$on" = "true" ]; then ok "opencode is already on — nothing to do."; return 0; fi
1576
- restore_model="weave/claude-sonnet-4-6"
1576
+ restore_model="weave/auto"
1577
1577
  if [ "$parked_present" = "true" ]; then
1578
- restore_model="$(jq -r '.model // "weave/claude-sonnet-4-6"' "$parked")"
1578
+ restore_model="$(jq -r '.model // "weave/auto"' "$parked")"
1579
1579
  elif [ "$has_weave" != "true" ]; then
1580
1580
  warn "opencode isn't configured for the router. Run the installer first."; return 0
1581
1581
  else
1582
1582
  # No parked model (sidecar deleted by hand). Derive the default from the
1583
1583
  # installed provider.weave.models block rather than a hardcoded literal
1584
- # that silently diverges when the installer's default changes — prefer a
1585
- # sonnet entry, else the first model the installer registered.
1584
+ # that silently diverges when the installer's default changes — prefer
1585
+ # the auto-routing entry, else the first model the installer registered.
1586
1586
  restore_model="$(jq -r '
1587
1587
  (.provider.weave.models // {} | keys) as $k
1588
- | (([$k[] | select(test("sonnet"))] | first) // $k[0] // "claude-sonnet-4-6")
1588
+ | (([$k[] | select(. == "auto")] | first) // $k[0] // "auto")
1589
1589
  | "weave/" + .
1590
- ' "$f" 2>/dev/null || echo "weave/claude-sonnet-4-6")"
1590
+ ' "$f" 2>/dev/null || echo "weave/auto")"
1591
1591
  fi
1592
- # Never restore a legacy weave-codex model whose provider is no longer
1593
- # registered (every current install strips weave-codex). Fall back to the
1594
- # `weave` default so `on` can't leave opencode pointing at a missing
1595
- # 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`.
1596
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
+ ;;
1597
1601
  weave-codex/*)
1598
1602
  if [ "$(jq -r '((.provider // {}) | has("weave-codex"))' "$f" 2>/dev/null || true)" != "true" ]; then
1599
- restore_model="weave/claude-sonnet-4-6"
1603
+ restore_model="weave/auto"
1600
1604
  fi
1601
1605
  ;;
1602
1606
  esac
@@ -1689,6 +1693,7 @@ fi
1689
1693
  # Layout:
1690
1694
  # Claude: <settings_dir>/commands/{force-model,unforce-model}.md → /force-model
1691
1695
  # Codex: <codex_dir>/prompts/{force-model,unforce-model}.md → /prompts:force-model
1696
+ # opencode: <commands_dir>/{force-model,unforce-model}.md → /force-model
1692
1697
  #
1693
1698
  # Files come from install/commands/ in the repo (or the colocated commands/
1694
1699
  # directory the npm package ships alongside install.sh).
@@ -1719,8 +1724,8 @@ install_slash_commands() {
1719
1724
  installed="force-model, unforce-model, router-feedback, fm, ufm, rf"
1720
1725
  cmds="force-model unforce-model router-feedback fm ufm rf"
1721
1726
  if [ "$target" = "claude" ]; then
1722
- cmds="$cmds router-off router-on router-status"
1723
- 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"
1724
1729
  fi
1725
1730
 
1726
1731
  # Bake the same scope selector the toggle needs to find this install: --dir
@@ -1830,6 +1835,26 @@ if [ "$target" = "opencode" ]; then
1830
1835
  ok "Updated $gitignore (ignored opencode.json, .weave/)"
1831
1836
  fi
1832
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
+
1833
1858
  # Post-install verification: same probes the Claude/Codex paths run.
1834
1859
  if [ "$quiet" != "true" ]; then
1835
1860
  if ! spin "Pinging $base_url/health" curl -fsS --max-time 5 "$base_url/health"; then
@@ -2078,6 +2103,7 @@ prices='{
2078
2103
  "claude-opus-4-6": 0.005,
2079
2104
  "claude-opus-4-7": 0.005,
2080
2105
  "claude-opus-4-8": 0.005,
2106
+ "claude-opus-5": 0.005,
2081
2107
  "claude-sonnet-4-5": 0.003,
2082
2108
  "claude-sonnet-4-6": 0.003,
2083
2109
  "claude-sonnet-5": 0.003,
@@ -2093,6 +2119,8 @@ prices='{
2093
2119
  "gemini-3.1-flash-lite-preview": 0.0001,
2094
2120
  "gemini-3.1-pro-preview": 0.002,
2095
2121
  "gemini-3.5-flash": 0.0015,
2122
+ "gemini-3.5-flash-lite": 0.0003,
2123
+ "gemini-3.6-flash": 0.0015,
2096
2124
  "google/gemma-4-26b-a4b-it": 0.00015,
2097
2125
  "gpt-4.1": 0.002,
2098
2126
  "gpt-4.1-mini": 0.0004,
@@ -2111,12 +2139,17 @@ prices='{
2111
2139
  "gpt-5.5-mini": 0.0005,
2112
2140
  "gpt-5.5-nano": 0.00015,
2113
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,
2114
2146
  "minimax/minimax-m2.7": 0.0003,
2115
2147
  "minimax/minimax-m3": 0.0003,
2116
2148
  "mistralai/mistral-small-2603": 0.0002,
2117
2149
  "moonshotai/kimi-k2.5": 0.0006,
2118
2150
  "moonshotai/kimi-k2.6": 0.00095,
2119
2151
  "moonshotai/kimi-k2.7": 0.00095,
2152
+ "moonshotai/kimi-k3": 0.003,
2120
2153
  "qwen/qwen3-235b-a22b-2507": 0.0002266,
2121
2154
  "qwen/qwen3-30b-a3b-instruct-2507": 0.00015,
2122
2155
  "qwen/qwen3-coder": 0.0009,
@@ -2139,6 +2172,7 @@ prices='{
2139
2172
  "claude-opus-4-6": 0.025,
2140
2173
  "claude-opus-4-7": 0.025,
2141
2174
  "claude-opus-4-8": 0.025,
2175
+ "claude-opus-5": 0.025,
2142
2176
  "claude-sonnet-4-5": 0.015,
2143
2177
  "claude-sonnet-4-6": 0.015,
2144
2178
  "claude-sonnet-5": 0.015,
@@ -2154,6 +2188,8 @@ prices='{
2154
2188
  "gemini-3.1-flash-lite-preview": 0.0004,
2155
2189
  "gemini-3.1-pro-preview": 0.008,
2156
2190
  "gemini-3.5-flash": 0.009,
2191
+ "gemini-3.5-flash-lite": 0.0025,
2192
+ "gemini-3.6-flash": 0.0075,
2157
2193
  "google/gemma-4-26b-a4b-it": 0.0006,
2158
2194
  "gpt-4.1": 0.008,
2159
2195
  "gpt-4.1-mini": 0.0016,
@@ -2172,12 +2208,17 @@ prices='{
2172
2208
  "gpt-5.5-mini": 0.0025,
2173
2209
  "gpt-5.5-nano": 0.0006,
2174
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,
2175
2215
  "minimax/minimax-m2.7": 0.0012,
2176
2216
  "minimax/minimax-m3": 0.0012,
2177
2217
  "mistralai/mistral-small-2603": 0.0006,
2178
2218
  "moonshotai/kimi-k2.5": 0.003,
2179
2219
  "moonshotai/kimi-k2.6": 0.004,
2180
2220
  "moonshotai/kimi-k2.7": 0.004,
2221
+ "moonshotai/kimi-k3": 0.015,
2181
2222
  "qwen/qwen3-235b-a22b-2507": 0.0009064,
2182
2223
  "qwen/qwen3-30b-a3b-instruct-2507": 0.0006,
2183
2224
  "qwen/qwen3-coder": 0.0027,
@@ -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 turn to the
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 the turn across every model the caller's subs + key can pay
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 turn outside its family.
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.5",
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": [
@@ -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 -y @workweave/router --pi # user scope
13
- WEAVE_ROUTER_KEY=rk_… npx -y @workweave/router --pi --local # local router (http://localhost:8080)
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
@@ -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"