@workweave/router 0.2.9 → 0.2.11

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/registry.sh ADDED
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Shared, shell-portable directive registry helpers. Columns are documented in
4
+ # directives.tsv, which is the canonical declaration.
5
+ #
6
+ # install.sh is served standalone (WorkWeave serves it for `curl | sh`, and it
7
+ # has no sibling files there), so it carries an embedded copy of both this
8
+ # helper block and the registry data. The region between the markers below is
9
+ # copied verbatim into install.sh; install/tests/registry_test.sh asserts the
10
+ # two never drift. Callers that DO have the files alongside them (uninstall.sh,
11
+ # the packaged installer) source this file instead.
12
+ #
13
+ # Rows come from $WEAVE_REGISTRY_DATA when set (install.sh's embedded copy),
14
+ # otherwise from directives.tsv next to this script.
15
+
16
+ # >>> weave-router registry lib >>>
17
+ weave_registry_rows() {
18
+ if [ -n "${WEAVE_REGISTRY_DATA:-}" ]; then
19
+ printf '%s\n' "$WEAVE_REGISTRY_DATA" | awk -F '|' '!/^([[:space:]]*#|[[:space:]]*$)/ { print }'
20
+ return 0
21
+ fi
22
+ local registry="${WEAVE_REGISTRY_FILE:-}"
23
+ if [ -z "$registry" ]; then
24
+ local dir
25
+ dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd -P)" || return 1
26
+ registry="$dir/directives.tsv"
27
+ fi
28
+ [ -f "$registry" ] || return 1
29
+ awk -F '|' '!/^([[:space:]]*#|[[:space:]]*$)/ { print }' "$registry"
30
+ }
31
+
32
+ # weave_registry_names lists every canonical name and alias a client installs.
33
+ weave_registry_names() {
34
+ local target="$1" canonical aliases capability claude codex opencode pi cursor adapter
35
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
36
+ case "$target" in
37
+ claude) [ "$claude" = yes ] || continue ;; codex) [ "$codex" = yes ] || continue ;;
38
+ opencode) [ "$opencode" = yes ] || continue ;; pi) [ "$pi" = yes ] || continue ;;
39
+ cursor) [ "$cursor" = yes ] || continue ;;
40
+ esac
41
+ printf '%s\n' "$canonical"
42
+ [ -n "$aliases" ] && printf '%s\n' "$aliases" | tr ',' '\n'
43
+ done <<EOF
44
+ $(weave_registry_rows)
45
+ EOF
46
+ }
47
+
48
+ # weave_registry_skill_names lists the prompt directives a client exposes as a
49
+ # native skill. Local-config toggles are excluded: they mutate config this
50
+ # installer owns and are handled per target, not as a generic prompt.
51
+ weave_registry_skill_names() {
52
+ local target="$1" canonical aliases capability claude codex opencode pi cursor adapter
53
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
54
+ [ "$capability" = prompt ] || continue
55
+ case "$target" in
56
+ claude) [ "$claude" = yes ] || continue ;; codex) [ "$codex" = yes ] || continue ;;
57
+ opencode) [ "$opencode" = yes ] || continue ;; pi) [ "$pi" = yes ] || continue ;;
58
+ cursor) [ "$cursor" = yes ] || continue ;;
59
+ esac
60
+ printf '%s\n' "$canonical"
61
+ done <<EOF
62
+ $(weave_registry_rows)
63
+ EOF
64
+ }
65
+
66
+ # weave_registry_skill_assets lists every directive a client ships as a skill
67
+ # file, including local-config toggles such as Codex's disable-routing. Install
68
+ # and uninstall use this for file management; weave_registry_skill_names is the
69
+ # narrower prompt-only set used when generating prompt adapters.
70
+ weave_registry_skill_assets() {
71
+ local target="$1" canonical aliases capability claude codex opencode pi cursor adapter
72
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
73
+ case ",$adapter," in *,skill,*) ;; *) continue ;; esac
74
+ case "$target" in
75
+ claude) [ "$claude" = yes ] || continue ;; codex) [ "$codex" = yes ] || continue ;;
76
+ opencode) [ "$opencode" = yes ] || continue ;; pi) [ "$pi" = yes ] || continue ;;
77
+ cursor) [ "$cursor" = yes ] || continue ;;
78
+ esac
79
+ printf '%s\n' "$canonical"
80
+ done <<EOF
81
+ $(weave_registry_rows)
82
+ EOF
83
+ }
84
+
85
+ # weave_registry_canonical_for resolves a name or alias to its canonical
86
+ # directive, and fails when the name is not in the registry at all.
87
+ weave_registry_canonical_for() {
88
+ local wanted="$1" canonical aliases capability claude codex opencode pi cursor adapter alias
89
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
90
+ [ "$wanted" = "$canonical" ] && { printf '%s' "$canonical"; return 0; }
91
+ IFS=',' read -ra _aliases <<< "$aliases"
92
+ for alias in ${_aliases[@]+"${_aliases[@]}"}; do
93
+ [ "$wanted" = "$alias" ] && { printf '%s' "$canonical"; return 0; }
94
+ done
95
+ done <<EOF
96
+ $(weave_registry_rows)
97
+ EOF
98
+ return 1
99
+ }
100
+ # <<< weave-router registry lib <<<
package/uninstall.sh CHANGED
@@ -27,6 +27,116 @@ 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|no|no|no|manual|command
46
+ router-on||local-toggle|yes|no|no|no|manual|command
47
+ router-status||local-toggle|yes|no|no|no|manual|command
48
+ router-session||prompt|yes|no|no|no|manual|command
49
+ router-models|models|local-toggle|yes|no|no|no|manual|command
50
+ disable-routing||local-toggle|no|yes|no|no|manual|skill
51
+ WEAVE_REGISTRY_EOF
52
+ )
53
+
54
+ # >>> weave-router registry lib >>>
55
+ weave_registry_rows() {
56
+ if [ -n "${WEAVE_REGISTRY_DATA:-}" ]; then
57
+ printf '%s\n' "$WEAVE_REGISTRY_DATA" | awk -F '|' '!/^([[:space:]]*#|[[:space:]]*$)/ { print }'
58
+ return 0
59
+ fi
60
+ local registry="${WEAVE_REGISTRY_FILE:-}"
61
+ if [ -z "$registry" ]; then
62
+ local dir
63
+ dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd -P)" || return 1
64
+ registry="$dir/directives.tsv"
65
+ fi
66
+ [ -f "$registry" ] || return 1
67
+ awk -F '|' '!/^([[:space:]]*#|[[:space:]]*$)/ { print }' "$registry"
68
+ }
69
+
70
+ # weave_registry_names lists every canonical name and alias a client installs.
71
+ weave_registry_names() {
72
+ local target="$1" canonical aliases capability claude codex opencode pi cursor adapter
73
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
74
+ case "$target" in
75
+ claude) [ "$claude" = yes ] || continue ;; codex) [ "$codex" = yes ] || continue ;;
76
+ opencode) [ "$opencode" = yes ] || continue ;; pi) [ "$pi" = yes ] || continue ;;
77
+ cursor) [ "$cursor" = yes ] || continue ;;
78
+ esac
79
+ printf '%s\n' "$canonical"
80
+ [ -n "$aliases" ] && printf '%s\n' "$aliases" | tr ',' '\n'
81
+ done <<EOF
82
+ $(weave_registry_rows)
83
+ EOF
84
+ }
85
+
86
+ # weave_registry_skill_names lists the prompt directives a client exposes as a
87
+ # native skill. Local-config toggles are excluded: they mutate config this
88
+ # installer owns and are handled per target, not as a generic prompt.
89
+ weave_registry_skill_names() {
90
+ local target="$1" canonical aliases capability claude codex opencode pi cursor adapter
91
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
92
+ [ "$capability" = prompt ] || continue
93
+ case "$target" in
94
+ claude) [ "$claude" = yes ] || continue ;; codex) [ "$codex" = yes ] || continue ;;
95
+ opencode) [ "$opencode" = yes ] || continue ;; pi) [ "$pi" = yes ] || continue ;;
96
+ cursor) [ "$cursor" = yes ] || continue ;;
97
+ esac
98
+ printf '%s\n' "$canonical"
99
+ done <<EOF
100
+ $(weave_registry_rows)
101
+ EOF
102
+ }
103
+
104
+ # weave_registry_skill_assets lists every directive a client ships as a skill
105
+ # file, including local-config toggles such as Codex's disable-routing. Install
106
+ # and uninstall use this for file management; weave_registry_skill_names is the
107
+ # narrower prompt-only set used when generating prompt adapters.
108
+ weave_registry_skill_assets() {
109
+ local target="$1" canonical aliases capability claude codex opencode pi cursor adapter
110
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
111
+ case ",$adapter," in *,skill,*) ;; *) continue ;; esac
112
+ case "$target" in
113
+ claude) [ "$claude" = yes ] || continue ;; codex) [ "$codex" = yes ] || continue ;;
114
+ opencode) [ "$opencode" = yes ] || continue ;; pi) [ "$pi" = yes ] || continue ;;
115
+ cursor) [ "$cursor" = yes ] || continue ;;
116
+ esac
117
+ printf '%s\n' "$canonical"
118
+ done <<EOF
119
+ $(weave_registry_rows)
120
+ EOF
121
+ }
122
+
123
+ # weave_registry_canonical_for resolves a name or alias to its canonical
124
+ # directive, and fails when the name is not in the registry at all.
125
+ weave_registry_canonical_for() {
126
+ local wanted="$1" canonical aliases capability claude codex opencode pi cursor adapter alias
127
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
128
+ [ "$wanted" = "$canonical" ] && { printf '%s' "$canonical"; return 0; }
129
+ IFS=',' read -ra _aliases <<< "$aliases"
130
+ for alias in ${_aliases[@]+"${_aliases[@]}"}; do
131
+ [ "$wanted" = "$alias" ] && { printf '%s' "$canonical"; return 0; }
132
+ done
133
+ done <<EOF
134
+ $(weave_registry_rows)
135
+ EOF
136
+ return 1
137
+ }
138
+ # <<< weave-router registry lib <<<
139
+
30
140
  target="claude"
31
141
 
32
142
  err() { printf "\033[31merror:\033[0m %s\n" "$*" >&2; }
@@ -223,14 +333,20 @@ if [ "$target" = "opencode" ]; then
223
333
  local opencode_cmds_dir="$1" cmd cmd_file
224
334
  if [ -d "$opencode_cmds_dir" ]; then
225
335
  refuse_if_symlink "$opencode_cmds_dir"
226
- for cmd in force-model unforce-model router-feedback fm ufm rf; do
336
+ while IFS= read -r cmd; do
227
337
  cmd_file="$opencode_cmds_dir/$cmd.md"
228
338
  if [ -f "$cmd_file" ]; then
229
- refuse_if_symlink "$cmd_file"
230
- rm -f "$cmd_file"
231
- ok "Removed $cmd_file"
339
+ if grep -Fq "<!-- weave-router managed command: $cmd -->" "$cmd_file"; then
340
+ refuse_if_symlink "$cmd_file"
341
+ rm -f "$cmd_file"
342
+ ok "Removed $cmd_file"
343
+ else
344
+ warn "Leaving user-owned opencode command at $cmd_file untouched."
345
+ fi
232
346
  fi
233
- done
347
+ done <<EOF
348
+ $(weave_registry_names opencode)
349
+ EOF
234
350
  rmdir "$opencode_cmds_dir" 2>/dev/null || true
235
351
  fi
236
352
  }
@@ -427,34 +543,54 @@ if [ "$target" = "codex" ]; then
427
543
  codex_prompts_dir="$codex_dir/prompts"
428
544
  if [ -d "$codex_prompts_dir" ]; then
429
545
  refuse_if_symlink "$codex_prompts_dir"
430
- for cmd in force-model unforce-model router-feedback fm ufm rf; do
546
+ while IFS= read -r cmd; do
431
547
  cmd_file="$codex_prompts_dir/$cmd.md"
432
548
  if [ -f "$cmd_file" ]; then
433
549
  refuse_if_symlink "$cmd_file"
434
550
  rm -f "$cmd_file"
435
551
  ok "Removed $cmd_file"
436
552
  fi
437
- done
553
+ done <<EOF
554
+ $(weave_registry_names codex)
555
+ EOF
438
556
  rmdir "$codex_prompts_dir" 2>/dev/null || true
439
557
  fi
440
558
 
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."
559
+ # disable-routing is handled by the registry-driven loop below, alongside
560
+ # every other installer-owned skill.
561
+
562
+ # A symlinked skills/ or per-skill directory would let the marker check and
563
+ # the rm below reach a file outside the Codex tree entirely, so refuse the
564
+ # parents before touching anything beneath them — not just SKILL.md itself.
565
+ if [ -L "$codex_dir/skills" ]; then
566
+ warn "$codex_dir/skills is a symlink; leaving Codex skills untouched."
567
+ else
568
+ while IFS= read -r canonical; do
569
+ skill_dir="$codex_dir/skills/$canonical"
570
+ skill_file="$skill_dir/SKILL.md"
571
+ if [ -L "$skill_dir" ]; then
572
+ warn "$skill_dir is a symlink; leaving it untouched."
573
+ continue
455
574
  fi
456
- fi
457
- rmdir "$codex_skill_dir" 2>/dev/null || true
575
+ if [ -L "$skill_file" ]; then
576
+ warn "$skill_file is a symlink; leaving it untouched."
577
+ continue
578
+ fi
579
+ if [ -f "$skill_file" ]; then
580
+ if grep -Fq "<!-- weave-router managed $canonical skill -->" "$skill_file"; then
581
+ rm -f "$skill_file"
582
+ ok "Removed $skill_file"
583
+ else
584
+ warn "Leaving user-owned Codex skill at $skill_file untouched."
585
+ fi
586
+ rmdir "$skill_dir" 2>/dev/null || true
587
+ fi
588
+ done <<EOF
589
+ $(weave_registry_skill_assets codex)
590
+ EOF
591
+ # Drop skills/ when nothing is left in it, matching how the prompts and
592
+ # Claude command paths clean up their now-empty directories. rmdir refuses
593
+ # a non-empty dir, so an unrelated user skill keeps it.
458
594
  rmdir "$codex_dir/skills" 2>/dev/null || true
459
595
  fi
460
596
 
@@ -558,11 +694,12 @@ fi
558
694
 
559
695
  if [ -n "$local_settings_file" ] && [ -f "$local_settings_file" ]; then
560
696
  # 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.
697
+ # (the off path overrides it to Anthropic in the local file). Project installs
698
+ # also keep WEAVE_ROUTER_BASE_URL here as a private endpoint marker beside the
699
+ # router key; scrub both so uninstall fully reverts the local config.
563
700
  cleaned="$(jq '
564
701
  if .env then
565
- .env |= (del(.ANTHROPIC_BASE_URL, .ANTHROPIC_AUTH_TOKEN, .ANTHROPIC_CUSTOM_HEADERS, .ENABLE_TOOL_SEARCH))
702
+ .env |= (del(.ANTHROPIC_BASE_URL, .ANTHROPIC_AUTH_TOKEN, .ANTHROPIC_CUSTOM_HEADERS, .ENABLE_TOOL_SEARCH, .WEAVE_ROUTER_BASE_URL))
566
703
  | (if (.env | length) == 0 then del(.env) else . end)
567
704
  else . end
568
705
  | del(.apiKeyHelper)
@@ -592,14 +729,20 @@ done
592
729
  commands_dir="$(dirname "$settings_file")/commands"
593
730
  if [ -d "$commands_dir" ]; then
594
731
  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
732
+ while IFS= read -r cmd; do
596
733
  cmd_file="$commands_dir/$cmd.md"
597
734
  if [ -f "$cmd_file" ]; then
598
735
  refuse_if_symlink "$cmd_file"
599
- rm -f "$cmd_file"
600
- ok "Removed $cmd_file"
736
+ if grep -Fq "<!-- weave-router managed command: $cmd -->" "$cmd_file"; then
737
+ rm -f "$cmd_file"
738
+ ok "Removed $cmd_file"
739
+ else
740
+ warn "Leaving user-owned Claude command at $cmd_file untouched."
741
+ fi
601
742
  fi
602
- done
743
+ done <<EOF
744
+ $(weave_registry_names claude)
745
+ EOF
603
746
  # Clean up the dir only if we left nothing behind.
604
747
  rmdir "$commands_dir" 2>/dev/null || true
605
748
  fi