@workweave/router 0.2.10 → 0.2.12

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.
Files changed (47) hide show
  1. package/README.md +40 -14
  2. package/cc-statusline.sh +274 -23
  3. package/codex-skills/fm/SKILL.md +15 -0
  4. package/codex-skills/fm/scripts/emit.sh +8 -0
  5. package/codex-skills/force-model/SKILL.md +15 -0
  6. package/codex-skills/force-model/scripts/emit.sh +9 -0
  7. package/codex-skills/rf/SKILL.md +15 -0
  8. package/codex-skills/rf/scripts/emit.sh +7 -0
  9. package/codex-skills/router-feedback/SKILL.md +15 -0
  10. package/codex-skills/router-feedback/scripts/emit.sh +9 -0
  11. package/codex-skills/router-models/SKILL.md +51 -0
  12. package/codex-skills/router-off/SKILL.md +22 -0
  13. package/codex-skills/router-on/SKILL.md +22 -0
  14. package/codex-skills/router-status/SKILL.md +19 -0
  15. package/codex-skills/ufm/SKILL.md +14 -0
  16. package/codex-skills/ufm/scripts/emit.sh +3 -0
  17. package/codex-skills/unforce-model/SKILL.md +14 -0
  18. package/codex-skills/unforce-model/scripts/emit.sh +4 -0
  19. package/codex-status.sh +312 -0
  20. package/commands/beta.md +5 -0
  21. package/commands/models.md +46 -0
  22. package/commands/router-models.md +46 -0
  23. package/directives.tsv +13 -0
  24. package/install.sh +1849 -263
  25. package/package.json +7 -1
  26. package/pi-router/README.md +39 -7
  27. package/pi-router/skills/install-lsps/SKILL.md +75 -0
  28. package/pi-router/skills/lsp-guide/SKILL.md +63 -0
  29. package/pi-router/src/beta.ts +21 -0
  30. package/pi-router/src/compaction.ts +46 -8
  31. package/pi-router/src/config.ts +34 -5
  32. package/pi-router/src/context-window.ts +12 -0
  33. package/pi-router/src/dispatch.ts +35 -2
  34. package/pi-router/src/index.ts +12 -1
  35. package/pi-router/src/lsp-broker.ts +255 -0
  36. package/pi-router/src/lsp-client.ts +435 -0
  37. package/pi-router/src/lsp-format.ts +230 -0
  38. package/pi-router/src/lsp-install.ts +215 -0
  39. package/pi-router/src/lsp-protocol.ts +128 -0
  40. package/pi-router/src/lsp-servers.ts +361 -0
  41. package/pi-router/src/lsp.ts +529 -0
  42. package/pi-router/src/pricing.generated.ts +77 -70
  43. package/pi-router/src/provider.ts +15 -2
  44. package/pi-router/src/routed-model.ts +17 -0
  45. package/pi-router/src/savings.ts +1 -1
  46. package/registry.sh +102 -0
  47. package/uninstall.sh +210 -31
package/uninstall.sh CHANGED
@@ -27,6 +27,119 @@ set -euo pipefail
27
27
  scope="user"
28
28
  scope_explicit="false"
29
29
  install_dir=""
30
+ script_dir="$(cd "$(dirname "$0")" 2>/dev/null && pwd || true)"
31
+
32
+ # ---------- directive registry (embedded) ----------
33
+ #
34
+ # uninstall.sh is served standalone too (the npm bin runs it directly, and it
35
+ # can be piped), so it cannot rely on a sibling registry.sh. The data and
36
+ # helpers are embedded verbatim; install/tests/registry_test.sh asserts they
37
+ # never drift from the canonical files. Regenerate with `make embed-registry`.
38
+ WEAVE_REGISTRY_DATA=$(cat <<'WEAVE_REGISTRY_EOF'
39
+ # Weave Router directive registry
40
+ # canonical|aliases|capability|claude|codex|opencode|pi|cursor|adapter
41
+ # aliases are comma-separated; client columns are yes/no. adapter is the native asset kind.
42
+ force-model|fm|prompt|yes|yes|yes|yes|manual|command,skill
43
+ unforce-model|ufm|prompt|yes|yes|yes|yes|manual|command,skill
44
+ router-feedback|rf|prompt|yes|yes|yes|no|manual|command,skill
45
+ router-off||local-toggle|yes|yes|no|no|manual|command,skill
46
+ router-on||local-toggle|yes|yes|no|no|manual|command,skill
47
+ router-status||local-toggle|yes|yes|no|no|manual|command,skill
48
+ router-session||prompt|yes|no|no|no|manual|command
49
+ router-models|models|local-toggle|yes|yes|no|no|manual|command,skill
50
+ disable-routing||local-toggle|no|yes|no|no|manual|skill
51
+ beta||prompt|yes|no|no|yes|manual|command
52
+ WEAVE_REGISTRY_EOF
53
+ )
54
+
55
+ # >>> weave-router registry lib >>>
56
+ weave_registry_rows() {
57
+ if [ -n "${WEAVE_REGISTRY_DATA:-}" ]; then
58
+ printf '%s\n' "$WEAVE_REGISTRY_DATA" | awk -F '|' '!/^([[:space:]]*#|[[:space:]]*$)/ { print }'
59
+ return 0
60
+ fi
61
+ local registry="${WEAVE_REGISTRY_FILE:-}"
62
+ if [ -z "$registry" ]; then
63
+ local dir
64
+ dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd -P)" || return 1
65
+ registry="$dir/directives.tsv"
66
+ fi
67
+ [ -f "$registry" ] || return 1
68
+ awk -F '|' '!/^([[:space:]]*#|[[:space:]]*$)/ { print }' "$registry"
69
+ }
70
+
71
+ # weave_registry_names lists every canonical name and alias a client installs.
72
+ weave_registry_names() {
73
+ local target="$1" canonical aliases capability claude codex opencode pi cursor adapter
74
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
75
+ case "$target" in
76
+ claude) [ "$claude" = yes ] || continue ;; codex) [ "$codex" = yes ] || continue ;;
77
+ opencode) [ "$opencode" = yes ] || continue ;; pi) [ "$pi" = yes ] || continue ;;
78
+ cursor) [ "$cursor" = yes ] || continue ;;
79
+ esac
80
+ printf '%s\n' "$canonical"
81
+ [ -n "$aliases" ] && printf '%s\n' "$aliases" | tr ',' '\n'
82
+ done <<EOF
83
+ $(weave_registry_rows)
84
+ EOF
85
+ }
86
+
87
+ # weave_registry_skill_names lists the prompt directives a client exposes as a
88
+ # native skill. Local-config toggles are excluded: they mutate config this
89
+ # installer owns and are handled per target, not as a generic prompt.
90
+ weave_registry_skill_names() {
91
+ local target="$1" canonical aliases capability claude codex opencode pi cursor adapter
92
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
93
+ [ "$capability" = prompt ] || continue
94
+ case "$target" in
95
+ claude) [ "$claude" = yes ] || continue ;; codex) [ "$codex" = yes ] || continue ;;
96
+ opencode) [ "$opencode" = yes ] || continue ;; pi) [ "$pi" = yes ] || continue ;;
97
+ cursor) [ "$cursor" = yes ] || continue ;;
98
+ esac
99
+ printf '%s\n' "$canonical"
100
+ [ -n "$aliases" ] && printf '%s\n' "$aliases" | tr ',' '\n'
101
+ done <<EOF
102
+ $(weave_registry_rows)
103
+ EOF
104
+ }
105
+
106
+ # weave_registry_skill_assets lists every directive a client ships as a skill
107
+ # file, including local-config toggles such as Codex's disable-routing. Install
108
+ # and uninstall use this for file management; weave_registry_skill_names is the
109
+ # narrower prompt-only set used when generating prompt adapters.
110
+ weave_registry_skill_assets() {
111
+ local target="$1" canonical aliases capability claude codex opencode pi cursor adapter
112
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
113
+ case ",$adapter," in *,skill,*) ;; *) continue ;; esac
114
+ case "$target" in
115
+ claude) [ "$claude" = yes ] || continue ;; codex) [ "$codex" = yes ] || continue ;;
116
+ opencode) [ "$opencode" = yes ] || continue ;; pi) [ "$pi" = yes ] || continue ;;
117
+ cursor) [ "$cursor" = yes ] || continue ;;
118
+ esac
119
+ printf '%s\n' "$canonical"
120
+ [ -n "$aliases" ] && printf '%s\n' "$aliases" | tr ',' '\n'
121
+ done <<EOF
122
+ $(weave_registry_rows)
123
+ EOF
124
+ }
125
+
126
+ # weave_registry_canonical_for resolves a name or alias to its canonical
127
+ # directive, and fails when the name is not in the registry at all.
128
+ weave_registry_canonical_for() {
129
+ local wanted="$1" canonical aliases capability claude codex opencode pi cursor adapter alias
130
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
131
+ [ "$wanted" = "$canonical" ] && { printf '%s' "$canonical"; return 0; }
132
+ IFS=',' read -ra _aliases <<< "$aliases"
133
+ for alias in ${_aliases[@]+"${_aliases[@]}"}; do
134
+ [ "$wanted" = "$alias" ] && { printf '%s' "$canonical"; return 0; }
135
+ done
136
+ done <<EOF
137
+ $(weave_registry_rows)
138
+ EOF
139
+ return 1
140
+ }
141
+ # <<< weave-router registry lib <<<
142
+
30
143
  target="claude"
31
144
 
32
145
  err() { printf "\033[31merror:\033[0m %s\n" "$*" >&2; }
@@ -92,7 +205,6 @@ fi
92
205
  # Markers must stay in sync with install.sh. Keep verbatim.
93
206
  WEAVE_CODEX_BEGIN_MARKER="# >>> weave-router managed (do not edit between markers) >>>"
94
207
  WEAVE_CODEX_END_MARKER="# <<< weave-router managed <<<"
95
- WEAVE_CODEX_SKILL_MARKER="<!-- weave-router managed disable-routing skill -->"
96
208
 
97
209
  # strip_codex_block rewrites config.toml without the managed block and any
98
210
  # top-level `model_provider = "weave"` that lived outside the markers (which
@@ -223,14 +335,20 @@ if [ "$target" = "opencode" ]; then
223
335
  local opencode_cmds_dir="$1" cmd cmd_file
224
336
  if [ -d "$opencode_cmds_dir" ]; then
225
337
  refuse_if_symlink "$opencode_cmds_dir"
226
- for cmd in force-model unforce-model router-feedback fm ufm rf; do
338
+ while IFS= read -r cmd; do
227
339
  cmd_file="$opencode_cmds_dir/$cmd.md"
228
340
  if [ -f "$cmd_file" ]; then
229
- refuse_if_symlink "$cmd_file"
230
- rm -f "$cmd_file"
231
- ok "Removed $cmd_file"
341
+ if grep -Fq "<!-- weave-router managed command: $cmd -->" "$cmd_file"; then
342
+ refuse_if_symlink "$cmd_file"
343
+ rm -f "$cmd_file"
344
+ ok "Removed $cmd_file"
345
+ else
346
+ warn "Leaving user-owned opencode command at $cmd_file untouched."
347
+ fi
232
348
  fi
233
- done
349
+ done <<EOF
350
+ $(weave_registry_names opencode)
351
+ EOF
234
352
  rmdir "$opencode_cmds_dir" 2>/dev/null || true
235
353
  fi
236
354
  }
@@ -405,7 +523,15 @@ if [ "$target" = "codex" ]; then
405
523
  refuse_if_symlink "$codex_dir"
406
524
  fi
407
525
  codex_config_file="$codex_dir/config.toml"
526
+ if [ "$scope" = "user" ] && [ -z "$install_dir" ]; then
527
+ codex_status_file="$HOME/.weave/codex-status.sh"
528
+ else
529
+ codex_status_file="$codex_dir/weave-status.sh"
530
+ fi
531
+ codex_status_disabled_marker="$(dirname "$codex_status_file")/.weave-router-disabled"
408
532
  refuse_if_symlink "$codex_config_file"
533
+ refuse_if_symlink "$codex_status_file"
534
+ refuse_if_symlink "$codex_status_disabled_marker"
409
535
 
410
536
  if [ -f "$codex_config_file" ]; then
411
537
  strip_codex_block "$codex_config_file"
@@ -422,39 +548,85 @@ if [ "$target" = "codex" ]; then
422
548
  info "No Codex config at $codex_config_file (already uninstalled?)"
423
549
  fi
424
550
 
551
+ # A user config with an existing [features] table receives the installer
552
+ # hook setting outside the managed block; remove only our tagged line.
553
+ if [ -f "$codex_config_file" ]; then
554
+ tmp="$(mktemp -t weave-codex-features-uninstall.XXXXXX)"
555
+ awk '$0 != "hooks = true # weave-router managed codex hooks" { print }' "$codex_config_file" >"$tmp"
556
+ mv "$tmp" "$codex_config_file"
557
+ fi
558
+
559
+ if [ -f "$codex_status_file" ]; then
560
+ if grep -Fq '<!-- weave-router managed codex status -->' "$codex_status_file"; then
561
+ rm -f "$codex_status_file"
562
+ rm -f "$codex_status_disabled_marker"
563
+ ok "Removed $codex_status_file"
564
+ rmdir "$(dirname "$codex_status_file")" 2>/dev/null || true
565
+ else
566
+ warn "Leaving user-owned Codex status helper at $codex_status_file untouched."
567
+ fi
568
+ fi
569
+
425
570
  # Remove only the prompt files this installer owns; leave any user-authored
426
571
  # entries in prompts/ alone. The dir itself is dropped only if empty after.
427
572
  codex_prompts_dir="$codex_dir/prompts"
428
573
  if [ -d "$codex_prompts_dir" ]; then
429
574
  refuse_if_symlink "$codex_prompts_dir"
430
- for cmd in force-model unforce-model router-feedback fm ufm rf; do
575
+ while IFS= read -r cmd; do
431
576
  cmd_file="$codex_prompts_dir/$cmd.md"
432
577
  if [ -f "$cmd_file" ]; then
433
578
  refuse_if_symlink "$cmd_file"
434
579
  rm -f "$cmd_file"
435
580
  ok "Removed $cmd_file"
436
581
  fi
437
- done
582
+ done <<EOF
583
+ $(weave_registry_names codex)
584
+ EOF
438
585
  rmdir "$codex_prompts_dir" 2>/dev/null || true
439
586
  fi
440
587
 
441
- # The installer-owned skill switches Codex back to its normal provider. It
442
- # is separate from config.toml, so remove it when removing the router too.
443
- # A same-named skill without our marker belongs to the user and is preserved.
444
- codex_skill_dir="$codex_dir/skills/disable-routing"
445
- codex_skill_file="$codex_skill_dir/SKILL.md"
446
- if [ -d "$codex_skill_dir" ]; then
447
- refuse_if_symlink "$codex_skill_dir"
448
- if [ -f "$codex_skill_file" ]; then
449
- refuse_if_symlink "$codex_skill_file"
450
- if grep -Fq "$WEAVE_CODEX_SKILL_MARKER" "$codex_skill_file"; then
451
- rm -f "$codex_skill_file"
452
- ok "Removed $codex_skill_file"
453
- else
454
- warn "Leaving user-owned Codex skill at $codex_skill_file untouched."
588
+ # disable-routing is handled by the registry-driven loop below, alongside
589
+ # every other installer-owned skill.
590
+
591
+ # A symlinked skills/ or per-skill directory would let the marker check and
592
+ # the rm below reach a file outside the Codex tree entirely, so refuse the
593
+ # parents before touching anything beneath them — not just SKILL.md itself.
594
+ if [ -L "$codex_dir/skills" ]; then
595
+ warn "$codex_dir/skills is a symlink; leaving Codex skills untouched."
596
+ else
597
+ while IFS= read -r canonical; do
598
+ skill_dir="$codex_dir/skills/$canonical"
599
+ skill_file="$skill_dir/SKILL.md"
600
+ if [ -L "$skill_dir" ]; then
601
+ warn "$skill_dir is a symlink; leaving it untouched."
602
+ continue
455
603
  fi
456
- fi
457
- rmdir "$codex_skill_dir" 2>/dev/null || true
604
+ if [ -L "$skill_file" ]; then
605
+ warn "$skill_file is a symlink; leaving it untouched."
606
+ continue
607
+ fi
608
+ if [ -f "$skill_file" ]; then
609
+ if grep -Fq "<!-- weave-router managed $canonical skill -->" "$skill_file"; then
610
+ rm -f "$skill_file"
611
+ ok "Removed $skill_file"
612
+ # The prompt skills also ship scripts/emit.sh; leaving it behind
613
+ # strands a directory Codex still advertises as a skill.
614
+ emit_file="$skill_dir/scripts/emit.sh"
615
+ if [ ! -L "$skill_dir/scripts" ] && [ ! -L "$emit_file" ] && [ -f "$emit_file" ]; then
616
+ rm -f "$emit_file"
617
+ rmdir "$skill_dir/scripts" 2>/dev/null || true
618
+ fi
619
+ else
620
+ warn "Leaving user-owned Codex skill at $skill_file untouched."
621
+ fi
622
+ rmdir "$skill_dir" 2>/dev/null || true
623
+ fi
624
+ done <<EOF
625
+ $(weave_registry_skill_assets codex)
626
+ EOF
627
+ # Drop skills/ when nothing is left in it, matching how the prompts and
628
+ # Claude command paths clean up their now-empty directories. rmdir refuses
629
+ # a non-empty dir, so an unrelated user skill keeps it.
458
630
  rmdir "$codex_dir/skills" 2>/dev/null || true
459
631
  fi
460
632
 
@@ -558,11 +730,12 @@ fi
558
730
 
559
731
  if [ -n "$local_settings_file" ] && [ -f "$local_settings_file" ]; then
560
732
  # ANTHROPIC_BASE_URL only lives here when a project install was toggled off
561
- # (the off path overrides it to Anthropic in the local file); scrub it too so
562
- # uninstall fully reverts a toggled-off install.
733
+ # (the off path overrides it to Anthropic in the local file). Project installs
734
+ # also keep WEAVE_ROUTER_BASE_URL here as a private endpoint marker beside the
735
+ # router key; scrub both so uninstall fully reverts the local config.
563
736
  cleaned="$(jq '
564
737
  if .env then
565
- .env |= (del(.ANTHROPIC_BASE_URL, .ANTHROPIC_AUTH_TOKEN, .ANTHROPIC_CUSTOM_HEADERS, .ENABLE_TOOL_SEARCH))
738
+ .env |= (del(.ANTHROPIC_BASE_URL, .ANTHROPIC_AUTH_TOKEN, .ANTHROPIC_CUSTOM_HEADERS, .ENABLE_TOOL_SEARCH, .WEAVE_ROUTER_BASE_URL))
566
739
  | (if (.env | length) == 0 then del(.env) else . end)
567
740
  else . end
568
741
  | del(.apiKeyHelper)
@@ -592,14 +765,20 @@ done
592
765
  commands_dir="$(dirname "$settings_file")/commands"
593
766
  if [ -d "$commands_dir" ]; then
594
767
  refuse_if_symlink "$commands_dir"
595
- for cmd in force-model unforce-model router-feedback fm ufm rf router-off router-on router-status router-session; do
768
+ while IFS= read -r cmd; do
596
769
  cmd_file="$commands_dir/$cmd.md"
597
770
  if [ -f "$cmd_file" ]; then
598
771
  refuse_if_symlink "$cmd_file"
599
- rm -f "$cmd_file"
600
- ok "Removed $cmd_file"
772
+ if grep -Fq "<!-- weave-router managed command: $cmd -->" "$cmd_file"; then
773
+ rm -f "$cmd_file"
774
+ ok "Removed $cmd_file"
775
+ else
776
+ warn "Leaving user-owned Claude command at $cmd_file untouched."
777
+ fi
601
778
  fi
602
- done
779
+ done <<EOF
780
+ $(weave_registry_names claude)
781
+ EOF
603
782
  # Clean up the dir only if we left nothing behind.
604
783
  rmdir "$commands_dir" 2>/dev/null || true
605
784
  fi