shrinker-ai 0.1.0 → 0.3.1

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.
@@ -1,2 +1,28 @@
1
1
 
2
2
 
3
+
4
+ <!-- shrinker agent rules start -->
5
+ Use `shrinker` for high-volume terminal outputs to reduce tokens.
6
+
7
+ Routing policy:
8
+ - `git status|diff|log|show|reflog|branch|tag|stash` -> `shrinker git ...`
9
+ - `npm test|t|install|i|ci|ls|list` -> `shrinker npm ...`
10
+ - `docker ps|logs|images|compose` -> `shrinker docker ...`
11
+ - `kubectl get|describe|logs` -> `shrinker kubectl ...`
12
+ - `gh pr|issue|run` -> `shrinker gh ...`
13
+ - `rg`, `find`, `tail`, `cat`, `ls`, `dir` -> `shrinker <command> ...`
14
+
15
+ Bypass shrinker when:
16
+ - command modifies remote state and output volume is already tiny
17
+ - command requires interactive stdin
18
+ - command explicitly needs `shrinker --raw`
19
+
20
+ Examples:
21
+ - `shrinker git log -n 20`
22
+ - `shrinker rg "pattern" src`
23
+ - `shrinker docker logs api --tail 500`
24
+ <!-- shrinker agent rules end -->
25
+
26
+
27
+
28
+
package/CLAUDE.md CHANGED
@@ -1,2 +1,28 @@
1
1
 
2
2
 
3
+
4
+ <!-- shrinker agent rules start -->
5
+ Use `shrinker` for high-volume terminal outputs to reduce tokens.
6
+
7
+ Routing policy:
8
+ - `git status|diff|log|show|reflog|branch|tag|stash` -> `shrinker git ...`
9
+ - `npm test|t|install|i|ci|ls|list` -> `shrinker npm ...`
10
+ - `docker ps|logs|images|compose` -> `shrinker docker ...`
11
+ - `kubectl get|describe|logs` -> `shrinker kubectl ...`
12
+ - `gh pr|issue|run` -> `shrinker gh ...`
13
+ - `rg`, `find`, `tail`, `cat`, `ls`, `dir` -> `shrinker <command> ...`
14
+
15
+ Bypass shrinker when:
16
+ - command modifies remote state and output volume is already tiny
17
+ - command requires interactive stdin
18
+ - command explicitly needs `shrinker --raw`
19
+
20
+ Examples:
21
+ - `shrinker git log -n 20`
22
+ - `shrinker rg "pattern" src`
23
+ - `shrinker docker logs api --tail 500`
24
+ <!-- shrinker agent rules end -->
25
+
26
+
27
+
28
+
package/README.md CHANGED
@@ -18,53 +18,89 @@ this POC proves that a few conservative, deterministic filters can save useful c
18
18
 
19
19
  Requires Node.js 22.13 or newer. This is the first Node 22 release where the built-in SQLite module no longer requires an experimental flag.
20
20
 
21
- ### One-command install (Windows PowerShell)
21
+ ### One-command install (macOS zsh)
22
+
23
+ ```bash
24
+ curl -fsSL https://raw.githubusercontent.com/ivanduplenskikh/shrinker/main/integrations/macos/install.sh | bash
25
+ ```
22
26
 
23
- Quick one-liner:
27
+ ### One-command install (Windows PowerShell)
24
28
 
25
29
  ```powershell
26
- irm https://raw.githubusercontent.com/ivanduplenskikh/shrinker/main/integrations/install.ps1 | iex
30
+ irm https://raw.githubusercontent.com/ivanduplenskikh/shrinker/main/integrations/windows/install.ps1 | iex
27
31
  ```
28
32
 
29
- ### Package install from npm
33
+ ### Install from npm package
30
34
 
31
- The installer downloads the published package from the public npm registry, then installs its local integration files.
35
+ Windows PowerShell:
32
36
 
33
37
  ```powershell
34
- irm https://raw.githubusercontent.com/ivanduplenskikh/shrinker/main/integrations/install.ps1 | iex
38
+ npm install --global shrinker-ai --registry=https://registry.npmjs.org
39
+ $pkg = Join-Path ((npm root --global).Trim()) "shrinker-ai"
40
+ pwsh -ExecutionPolicy Bypass -File (Join-Path $pkg "integrations\\windows\\install.ps1") -Local -SkipNpmInstall -SkipBuild -SkipLink
35
41
  ```
36
42
 
37
- This script installs `shrinker-ai` from `https://registry.npmjs.org` and installs Copilot/Claude rules by default.
43
+ To enable automatic PowerShell routing, add `-EnableProfileRouting` to the final command.
38
44
 
39
- To enable automatic PowerShell routing (so `git log` routes through `shrinker`), download the script and pass the option:
45
+ macOS zsh:
40
46
 
41
- ```powershell
42
- $tmp = Join-Path $env:TEMP "install-shrinker.ps1"
43
- Invoke-WebRequest "https://raw.githubusercontent.com/ivanduplenskikh/shrinker/main/integrations/install.ps1" -OutFile $tmp
44
- pwsh -ExecutionPolicy Bypass -File $tmp -EnableProfileRouting
47
+ ```bash
48
+ npm install --global shrinker-ai --registry=https://registry.npmjs.org
49
+ pkg="$(npm root --global)/shrinker-ai"
50
+ bash "$pkg/integrations/macos/install.sh" --local --skip-npm-install --skip-build --skip-link --enable-profile-routing
45
51
  ```
46
52
 
47
- For a local checkout, use the complete installer without profile routing:
53
+ ### Install from local checkout
54
+
55
+ Windows PowerShell:
48
56
 
49
57
  ```powershell
50
- pwsh -ExecutionPolicy Bypass -File .\integrations\install-shrinker.ps1
58
+ pwsh -ExecutionPolicy Bypass -File .\integrations\windows\install.ps1 -Local
59
+ ```
60
+
61
+ macOS zsh:
62
+
63
+ ```bash
64
+ bash ./integrations/macos/install.sh --local
51
65
  ```
52
66
 
53
- This writes managed guidance blocks to:
67
+ This writes managed guidance blocks globally to:
54
68
 
55
- - `.copilot-instructions.md`
56
- - `CLAUDE.md`
69
+ - `~/.copilot/copilot-instructions.md`
70
+ - `~/.claude/CLAUDE.md`
57
71
 
58
- The shared guidance source is `templates/agent-rules.md`; the two files above are generated in the target project.
72
+ The shared guidance source is `templates/agent-rules.md`; the files above are created in the corresponding global agent directory.
59
73
 
60
74
  The rules tell agents to prefer `shrinker <command>` for high-volume commands while leaving native commands untouched.
61
75
 
62
- ### Remote package uninstall
76
+ ### Uninstall
77
+
78
+ If you installed from npm, remove the package first:
79
+
80
+ ```bash
81
+ npm uninstall --global shrinker-ai --registry=https://registry.npmjs.org
82
+ ```
83
+
84
+ If you also installed profile/rules through the package scripts, run the matching local uninstaller from the installed package before uninstalling:
63
85
 
64
- Quick one-liner:
86
+ Windows PowerShell:
65
87
 
66
88
  ```powershell
67
- irm https://raw.githubusercontent.com/ivanduplenskikh/shrinker/main/integrations/uninstall.ps1 | iex
89
+ $pkg = Join-Path ((npm root --global).Trim()) "shrinker-ai"
90
+ pwsh -ExecutionPolicy Bypass -File (Join-Path $pkg "integrations\\windows\\uninstall.ps1") -SkipUnlink
91
+ ```
92
+
93
+ macOS zsh:
94
+
95
+ ```bash
96
+ pkg="$(npm root --global)/shrinker-ai"
97
+ bash "$pkg/integrations/macos/uninstall.sh" --skip-unlink
98
+ ```
99
+
100
+ macOS one-liner uninstall:
101
+
102
+ ```bash
103
+ curl -fsSL https://raw.githubusercontent.com/ivanduplenskikh/shrinker/main/integrations/macos/uninstall.sh | bash
68
104
  ```
69
105
 
70
106
  ### Local repo install/uninstall (contributors)
@@ -72,26 +108,48 @@ irm https://raw.githubusercontent.com/ivanduplenskikh/shrinker/main/integrations
72
108
  If you cloned this repository and want to run scripts directly from the local path:
73
109
 
74
110
  ```powershell
75
- pwsh -ExecutionPolicy Bypass -File .\integrations\install-shrinker.ps1
111
+ pwsh -ExecutionPolicy Bypass -File .\integrations\windows\install.ps1 -Local
112
+ ```
113
+
114
+ Or on macOS:
115
+
116
+ ```bash
117
+ bash ./integrations/macos/install.sh --local
76
118
  ```
77
119
 
78
120
  To uninstall:
79
121
 
80
122
  ```powershell
81
- pwsh -ExecutionPolicy Bypass -File .\integrations\uninstall-shrinker.ps1
123
+ pwsh -ExecutionPolicy Bypass -File .\integrations\windows\install.ps1 -Uninstall
124
+ ```
125
+
126
+ Or on macOS:
127
+
128
+ ```bash
129
+ bash ./integrations/macos/install.sh --uninstall
82
130
  ```
83
131
 
84
132
  Uninstall options:
85
133
 
86
134
  ```powershell
87
- # Remove only profile routing, keep shrinker command installed
88
- pwsh -ExecutionPolicy Bypass -File .\integrations\uninstall-shrinker.ps1 -SkipUnlink
135
+ # Keep shrinker command installed, but remove profile integration and managed rules
136
+ pwsh -ExecutionPolicy Bypass -File .\integrations\windows\install.ps1 -Uninstall -SkipUnlink
137
+
138
+ # Keep managed rules files unchanged while uninstalling command/profile hooks
139
+ pwsh -ExecutionPolicy Bypass -File .\integrations\windows\install.ps1 -Uninstall -SkipAgentRules
140
+ ```
141
+
142
+ macOS uninstall options:
89
143
 
90
- # Remove managed Copilot/Claude rules block only
91
- pwsh -ExecutionPolicy Bypass -File .\integrations\uninstall-shrinker.ps1 -SkipUnlink
144
+ ```bash
145
+ # Keep shrinker command installed, but remove profile integration and managed rules
146
+ bash ./integrations/macos/install.sh --uninstall --skip-unlink
147
+
148
+ # Keep managed rules files unchanged while uninstalling command/profile hooks
149
+ bash ./integrations/macos/install.sh --uninstall --skip-agent-rules
92
150
  ```
93
151
 
94
- If your current terminal had already loaded `shrinker-profile.ps1`, restart terminal (or remove loaded wrapper functions) to fully return to native command behavior.
152
+ If your current terminal had already loaded `shrinker-profile.ps1` or `shrinker-profile.zsh`, restart terminal (or remove loaded wrapper functions) to fully return to native command behavior.
95
153
 
96
154
  ```powershell
97
155
  npm install
@@ -144,11 +202,21 @@ if (!(Test-Path $PROFILE)) {
144
202
  New-Item -ItemType File -Path $PROFILE -Force | Out-Null
145
203
  }
146
204
 
147
- $integration = (Resolve-Path .\integrations\shrinker-profile.ps1).Path
205
+ $integration = (Resolve-Path .\integrations\windows\shrinker-profile.ps1).Path
148
206
  Add-Content $PROFILE "`n. `"$integration`""
149
207
  . $PROFILE
150
208
  ```
151
209
 
210
+ macOS zsh profile integration:
211
+
212
+ ```bash
213
+ echo '' >> ~/.zshrc
214
+ echo '# >>> shrinker integration >>>' >> ~/.zshrc
215
+ echo 'source "'"$(pwd)/integrations/macos/shrinker-profile.zsh"'"' >> ~/.zshrc
216
+ echo '# <<< shrinker integration <<<' >> ~/.zshrc
217
+ source ~/.zshrc
218
+ ```
219
+
152
220
  The default rules are:
153
221
 
154
222
  ```text
@@ -164,7 +232,7 @@ rg/find/tail/cat/ls/dir -> shrinker <command>
164
232
  git push, git fetch, and all other commands -> native executable
165
233
  ```
166
234
 
167
- Edit `$global:ShrinkPowerShellRules` in `integrations\shrinker-profile.ps1` to change the allowlist. The router is now option-aware for common global flags, so forms like `git -C <path> log` and `kubectl --context prod get pods` are routed correctly.
235
+ Edit `$global:ShrinkPowerShellRules` in `integrations\windows\shrinker-profile.ps1` to change the allowlist. The router is now option-aware for common global flags, so forms like `git -C <path> log` and `kubectl --context prod get pods` are routed correctly.
168
236
 
169
237
  ## Savings statistics
170
238
 
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ PACKAGE_NAME="shrinker-ai"
5
+ REGISTRY="https://registry.npmjs.org"
6
+ VERSION=""
7
+ LOCAL=0
8
+ SKIP_NPM_INSTALL=0
9
+ SKIP_BUILD=0
10
+ SKIP_LINK=0
11
+ ENABLE_PROFILE_ROUTING=0
12
+ SKIP_PROFILE=0
13
+ SKIP_AGENT_RULES=0
14
+ COPILOT_ONLY=0
15
+ CLAUDE_ONLY=0
16
+ PROFILE_PATH="${PROFILE_PATH:-$HOME/.zshrc}"
17
+ STEP=0
18
+
19
+ print_message() {
20
+ local emoji="$1"
21
+ local message="$2"
22
+ STEP=$((STEP + 1))
23
+ printf '%d. %s %s\n' "$STEP" "$emoji" "$message"
24
+ }
25
+
26
+ while [[ $# -gt 0 ]]; do
27
+ case "$1" in
28
+ --local) LOCAL=1 ;;
29
+ --package-name) PACKAGE_NAME="${2:-}"; shift ;;
30
+ --registry) REGISTRY="${2:-}"; shift ;;
31
+ --version) VERSION="${2:-}"; shift ;;
32
+ --skip-npm-install) SKIP_NPM_INSTALL=1 ;;
33
+ --skip-build) SKIP_BUILD=1 ;;
34
+ --skip-link) SKIP_LINK=1 ;;
35
+ --enable-profile-routing) ENABLE_PROFILE_ROUTING=1 ;;
36
+ --skip-profile) SKIP_PROFILE=1 ;;
37
+ --skip-agent-rules) SKIP_AGENT_RULES=1 ;;
38
+ --copilot-only) COPILOT_ONLY=1 ;;
39
+ --claude-only) CLAUDE_ONLY=1 ;;
40
+ --profile-path) PROFILE_PATH="${2:-}"; shift ;;
41
+ *) print_message "❌" "Unknown option: $1" >&2; exit 1 ;;
42
+ esac
43
+ shift
44
+ done
45
+
46
+ if (( ENABLE_PROFILE_ROUTING == 1 && SKIP_PROFILE == 1 )); then print_message "❌" "Use either --enable-profile-routing or --skip-profile, not both." >&2; exit 1; fi
47
+ if (( COPILOT_ONLY == 1 && CLAUDE_ONLY == 1 )); then print_message "❌" "Use either --copilot-only or --claude-only, not both." >&2; exit 1; fi
48
+
49
+ if (( LOCAL == 0 )); then
50
+ package_spec="$PACKAGE_NAME"
51
+ [[ -z "$VERSION" ]] || package_spec="$PACKAGE_NAME@$VERSION"
52
+ print_message "📦" "Installing $package_spec from $REGISTRY..."
53
+ npm install --silent --global "$package_spec" "--registry=$REGISTRY"
54
+ package_root="$(npm root --global)/$PACKAGE_NAME"
55
+ entrypoint="$package_root/integrations/macos/install.sh"
56
+ [[ -f "$entrypoint" ]] || { print_message "❌" "Installed package installer not found: $entrypoint" >&2; exit 1; }
57
+ bash "$entrypoint" --local --skip-npm-install --skip-build --skip-link \
58
+ $( (( ENABLE_PROFILE_ROUTING )) && echo --enable-profile-routing ) \
59
+ $( (( SKIP_PROFILE )) && echo --skip-profile ) \
60
+ $( (( SKIP_AGENT_RULES )) && echo --skip-agent-rules ) \
61
+ $( (( COPILOT_ONLY )) && echo --copilot-only ) \
62
+ $( (( CLAUDE_ONLY )) && echo --claude-only ) \
63
+ --profile-path "$PROFILE_PATH"
64
+ exit 0
65
+ fi
66
+
67
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
68
+ REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
69
+ TEMPLATE_PATH="$REPO_ROOT/templates/agent-rules.md"
70
+ INTEGRATION_PATH="$SCRIPT_DIR/shrinker-profile.zsh"
71
+ BLOCK_START="<!-- shrinker agent rules start -->"
72
+ BLOCK_END="<!-- shrinker agent rules end -->"
73
+
74
+ node_version_raw="$(node -v 2>/dev/null || true)"
75
+ [[ -n "$node_version_raw" ]] || { print_message "❌" "Node.js was not found on PATH. Install Node.js 22.13+ first." >&2; exit 1; }
76
+ node_version="${node_version_raw#v}"
77
+ IFS='.' read -r node_major node_minor _ <<< "$node_version"
78
+ (( node_major > 22 || (node_major == 22 && node_minor >= 13) )) || { print_message "❌" "Node.js 22.13+ is required. Found $node_version_raw" >&2; exit 1; }
79
+
80
+ set_agent_rules() {
81
+ local target="$1"
82
+ local body="$2"
83
+ local block="$BLOCK_START"$'\n'"$body"$'\n'"$BLOCK_END"
84
+ mkdir -p "$(dirname "$target")"
85
+ if [[ -f "$target" ]] && grep -Fq "$BLOCK_START" "$target" && grep -Fq "$BLOCK_END" "$target"; then
86
+ local block_file
87
+ block_file="$(mktemp "$(dirname "$target")/.shrinker-rules.XXXXXX")"
88
+ printf '%s\n' "$block" > "$block_file"
89
+ awk -v start="$BLOCK_START" -v end="$BLOCK_END" -v block_file="$block_file" '
90
+ function print_block(line) {
91
+ while ((getline line < block_file) > 0) print line
92
+ close(block_file)
93
+ }
94
+ {
95
+ if (index($0, start) > 0) {
96
+ if (!replaced) print_block()
97
+ replaced = 1
98
+ inblock = 1
99
+ next
100
+ }
101
+ if (inblock && index($0, end) > 0) {
102
+ inblock = 0
103
+ next
104
+ }
105
+ if (!inblock) print
106
+ }
107
+ ' "$target" > "$target.tmp"
108
+ rm -f "$block_file"
109
+ mv "$target.tmp" "$target"
110
+ elif [[ -f "$target" ]]; then printf '\n%s\n' "$block" >> "$target"
111
+ else printf '%s\n' "$block" > "$target"; fi
112
+ print_message "📄" "Installed managed rules in: $target"
113
+ }
114
+
115
+ add_profile_integration() {
116
+ local profile_file="$1"
117
+ mkdir -p "$(dirname "$profile_file")"; touch "$profile_file"
118
+ if ! grep -Fq '# >>> shrinker integration >>>' "$profile_file"; then
119
+ printf '\n# >>> shrinker integration >>>\nsource "%s"\n# <<< shrinker integration <<<\n\n' "$INTEGRATION_PATH" >> "$profile_file"
120
+ fi
121
+ }
122
+
123
+ print_message "📦" "Installing shrinker from: $REPO_ROOT"
124
+ pushd "$REPO_ROOT" >/dev/null
125
+ if (( SKIP_NPM_INSTALL == 0 )); then
126
+ print_message "📥" "Installing dependencies..."
127
+ npm install --silent
128
+ fi
129
+ if (( SKIP_BUILD == 0 )); then
130
+ print_message "🏗️" "Building shrinker..."
131
+ npm run build --silent
132
+ fi
133
+ if (( SKIP_LINK == 0 )); then
134
+ print_message "🔗" "Linking shrinker globally..."
135
+ npm link --silent
136
+ fi
137
+ popd >/dev/null
138
+
139
+ if (( SKIP_PROFILE == 0 && ENABLE_PROFILE_ROUTING == 1 )); then add_profile_integration "$PROFILE_PATH"; fi
140
+ if (( SKIP_AGENT_RULES == 0 )); then
141
+ [[ -f "$TEMPLATE_PATH" ]] || { print_message "❌" "Agent rules template not found: $TEMPLATE_PATH" >&2; exit 1; }
142
+ rules_body="$(cat "$TEMPLATE_PATH")"
143
+ (( CLAUDE_ONLY )) || set_agent_rules "$HOME/.copilot/copilot-instructions.md" "$rules_body"
144
+ (( COPILOT_ONLY )) || set_agent_rules "$HOME/.claude/CLAUDE.md" "$rules_body"
145
+ fi
146
+
147
+ print_message "✅" "Install complete."
148
+ echo ""
149
+ echo "💡 Try: shrinker help"
@@ -0,0 +1,98 @@
1
+ typeset -gA SHRINK_RULES
2
+ SHRINK_RULES=(
3
+ git "status diff log show reflog branch tag stash"
4
+ npm "test t install i ci ls list"
5
+ docker "ps logs images compose"
6
+ kubectl "get describe logs"
7
+ gh "pr issue run"
8
+ rg "*"
9
+ find "*"
10
+ tail "*"
11
+ cat "*"
12
+ ls "*"
13
+ )
14
+
15
+ typeset -gA SHRINK_OPTION_VALUE_FLAGS
16
+ SHRINK_OPTION_VALUE_FLAGS=(
17
+ git "-C -c --git-dir --work-tree --namespace"
18
+ npm "--prefix --cache --registry --workspace --userconfig -w -C"
19
+ docker "-H --host --context --config"
20
+ kubectl "-n --namespace -o --output --context --kubeconfig --cluster --user"
21
+ gh "-R --repo"
22
+ )
23
+
24
+ _shrink_get_subcommand() {
25
+ local cmd="$1"
26
+ shift
27
+
28
+ local -a args
29
+ args=("$@")
30
+
31
+ local -a value_flags
32
+ value_flags=(${=SHRINK_OPTION_VALUE_FLAGS[$cmd]})
33
+
34
+ local i part
35
+ i=1
36
+ while (( i <= ${#args[@]} )); do
37
+ part="${args[$i]}"
38
+ if [[ -z "$part" ]]; then
39
+ (( i++ ))
40
+ continue
41
+ fi
42
+
43
+ if (( ${value_flags[(Ie)$part]} > 0 )); then
44
+ (( i += 2 ))
45
+ continue
46
+ fi
47
+
48
+ if [[ "$part" == -* ]]; then
49
+ (( i++ ))
50
+ continue
51
+ fi
52
+
53
+ print -r -- "${part:l}"
54
+ return 0
55
+ done
56
+
57
+ print -r -- ""
58
+ }
59
+
60
+ _shrink_should_route() {
61
+ local cmd="$1"
62
+ shift
63
+
64
+ local rules="${SHRINK_RULES[$cmd]}"
65
+ [[ -z "$rules" ]] && return 1
66
+ [[ "$rules" == *"*"* ]] && return 0
67
+
68
+ local subcommand
69
+ subcommand="$(_shrink_get_subcommand "$cmd" "$@")"
70
+ [[ -z "$subcommand" ]] && return 1
71
+
72
+ local -a allowlist
73
+ allowlist=(${=rules})
74
+ (( ${allowlist[(Ie)$subcommand]} > 0 ))
75
+ }
76
+
77
+ _shrink_invoke_or_native() {
78
+ local cmd="$1"
79
+ shift
80
+
81
+ if _shrink_should_route "$cmd" "$@" && command -v shrinker >/dev/null 2>&1; then
82
+ command shrinker "$cmd" "$@"
83
+ return $?
84
+ fi
85
+
86
+ command "$cmd" "$@"
87
+ }
88
+
89
+ git() { _shrink_invoke_or_native git "$@"; }
90
+ npm() { _shrink_invoke_or_native npm "$@"; }
91
+ docker() { _shrink_invoke_or_native docker "$@"; }
92
+ kubectl() { _shrink_invoke_or_native kubectl "$@"; }
93
+ gh() { _shrink_invoke_or_native gh "$@"; }
94
+ rg() { _shrink_invoke_or_native rg "$@"; }
95
+ find() { _shrink_invoke_or_native find "$@"; }
96
+ tail() { _shrink_invoke_or_native tail "$@"; }
97
+ cat() { _shrink_invoke_or_native cat "$@"; }
98
+ ls() { _shrink_invoke_or_native ls "$@"; }
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ INSTALL_DIR="${HOME}/.shrinker-src"
5
+ REMOVE_INSTALL_DIR=0
6
+ SKIP_UNLINK=0
7
+ SKIP_AGENT_RULES=0
8
+ COPILOT_ONLY=0
9
+ CLAUDE_ONLY=0
10
+ PROFILE_PATH="${PROFILE_PATH:-$HOME/.zshrc}"
11
+ UNINSTALL_STEP=0
12
+
13
+ print_step() {
14
+ local emoji="$1" message="$2"
15
+ UNINSTALL_STEP=$((UNINSTALL_STEP + 1))
16
+ printf '%d. %s %s\n' "$UNINSTALL_STEP" "$emoji" "$message"
17
+ }
18
+
19
+ while [[ $# -gt 0 ]]; do
20
+ case "$1" in
21
+ --skip-unlink) SKIP_UNLINK=1 ;;
22
+ --skip-agent-rules) SKIP_AGENT_RULES=1 ;;
23
+ --copilot-only) COPILOT_ONLY=1 ;;
24
+ --claude-only) CLAUDE_ONLY=1 ;;
25
+ --profile-path) PROFILE_PATH="${2:-}"; shift ;;
26
+ --install-dir) INSTALL_DIR="${2:-}"; shift ;;
27
+ --remove-install-dir) REMOVE_INSTALL_DIR=1 ;;
28
+ *) echo "Unknown option: $1" >&2; exit 1 ;;
29
+ esac
30
+ shift
31
+ done
32
+
33
+ if (( COPILOT_ONLY == 1 && CLAUDE_ONLY == 1 )); then echo "Use either --copilot-only or --claude-only, not both." >&2; exit 1; fi
34
+ BLOCK_START="<!-- shrinker agent rules start -->"
35
+ BLOCK_END="<!-- shrinker agent rules end -->"
36
+
37
+ remove_agent_rules() {
38
+ local target="$1"
39
+ [[ -f "$target" ]] || return 0
40
+ awk -v start="$BLOCK_START" -v end="$BLOCK_END" 'BEGIN{inblock=0} {if(index($0,start)>0){inblock=1;next} if(inblock&&index($0,end)>0){inblock=0;next} if(!inblock)print}' "$target" > "$target.tmp"
41
+ mv "$target.tmp" "$target"
42
+ }
43
+
44
+ remove_profile_integration() {
45
+ local profile_file="$1"
46
+ [[ -f "$profile_file" ]] || return 0
47
+ awk -v start='# >>> shrinker integration >>>' -v end='# <<< shrinker integration <<<' 'BEGIN{inblock=0} {if(index($0,start)>0){inblock=1;next} if(inblock&&index($0,end)>0){inblock=0;next} if(!inblock)print}' "$profile_file" > "$profile_file.tmp"
48
+ mv "$profile_file.tmp" "$profile_file"
49
+ }
50
+
51
+ if (( SKIP_UNLINK == 0 )); then
52
+ print_step "🔗" "Unlinking shrinker globally..."
53
+ npm unlink --silent --global shrinker-ai
54
+ else
55
+ print_step "⏭️" "Skipped global npm unlink."
56
+ fi
57
+ print_step "🔧" "Removing shell profile integration..."
58
+ remove_profile_integration "$PROFILE_PATH"
59
+ if (( SKIP_AGENT_RULES == 0 )); then
60
+ (( CLAUDE_ONLY )) || remove_agent_rules "$HOME/.copilot/copilot-instructions.md"
61
+ (( COPILOT_ONLY )) || remove_agent_rules "$HOME/.claude/CLAUDE.md"
62
+ else
63
+ print_step "⏭️" "Skipped managed agent rules."
64
+ fi
65
+ print_step "✅" "Uninstall complete."
66
+
67
+ if (( REMOVE_INSTALL_DIR == 1 )) && [[ -d "$INSTALL_DIR" ]]; then
68
+ rm -rf "$INSTALL_DIR"
69
+ print_step "🧹" "Removed install directory: $INSTALL_DIR"
70
+ fi
@@ -0,0 +1,113 @@
1
+ param(
2
+ [switch]$Local,
3
+ [string]$PackageName = "shrinker-ai",
4
+ [string]$Registry = "https://registry.npmjs.org",
5
+ [string]$Version,
6
+ [switch]$SkipNpmInstall,
7
+ [switch]$SkipBuild,
8
+ [switch]$SkipLink,
9
+ [switch]$EnableProfileRouting,
10
+ [switch]$SkipProfile,
11
+ [switch]$SkipAgentRules,
12
+ [switch]$CopilotOnly,
13
+ [switch]$ClaudeOnly,
14
+ [string]$ProfilePath = $PROFILE
15
+ )
16
+
17
+ $ErrorActionPreference = "Stop"
18
+ $InstallStep = 0
19
+
20
+ function Write-InstallStep {
21
+ param([string]$Emoji, [string]$Message)
22
+ $script:InstallStep++
23
+ Write-Host "$($script:InstallStep). $Emoji $Message"
24
+ }
25
+
26
+ if ($EnableProfileRouting -and $SkipProfile) { throw "Use either -EnableProfileRouting or -SkipProfile, not both." }
27
+ if ($CopilotOnly -and $ClaudeOnly) { throw "Use either -CopilotOnly or -ClaudeOnly, not both." }
28
+
29
+ function Set-AgentRules {
30
+ param([string]$Body)
31
+ $start = "<!-- shrinker agent rules start -->"
32
+ $end = "<!-- shrinker agent rules end -->"
33
+ foreach ($target in @((Join-Path $HOME ".copilot\copilot-instructions.md"), (Join-Path $HOME ".claude\CLAUDE.md"))) {
34
+ if ($ClaudeOnly -and $target.EndsWith(".copilot-instructions.md")) { continue }
35
+ if ($CopilotOnly -and $target.EndsWith("CLAUDE.md")) { continue }
36
+ New-Item -ItemType Directory -Path (Split-Path $target) -Force | Out-Null
37
+ $content = if (Test-Path $target) { Get-Content $target -Raw } else { "" }
38
+ $block = "$start`n$Body`n$end"
39
+ if ($null -ne $content -and $content.Contains($start) -and $content.Contains($end)) {
40
+ $content = [regex]::Replace($content, [regex]::Escape($start) + ".*?" + [regex]::Escape($end), $block, 'Singleline')
41
+ Set-Content $target $content
42
+ } elseif ($content) { Add-Content $target "`n$block`n" }
43
+ else { Set-Content $target "$block`n" }
44
+ Write-InstallStep "📄" "Installed managed rules in: $target"
45
+ }
46
+ }
47
+
48
+ function Add-ProfileIntegration {
49
+ param([string]$ProfileFile, [string]$IntegrationFile)
50
+ if (-not (Test-Path $ProfileFile)) { New-Item -ItemType File -Path $ProfileFile -Force | Out-Null }
51
+ $start = "# >>> shrinker integration >>>"
52
+ if ((Get-Content $ProfileFile -Raw).Contains($start)) { return }
53
+ Add-Content $ProfileFile "`n$start`n. `"$IntegrationFile`"`n# <<< shrinker integration <<<`n"
54
+ Write-InstallStep "🔧" "Added shrinker integration block to profile: $ProfileFile"
55
+ }
56
+
57
+ if (-not $Local) {
58
+ $packageSpec = if ($Version) { "$PackageName@$Version" } else { $PackageName }
59
+ Write-InstallStep "📦" "Installing $packageSpec from $Registry..."
60
+ & npm install --silent --global $packageSpec "--registry=$Registry"
61
+ if ($LASTEXITCODE -ne 0) { throw "npm package installation failed." }
62
+ Write-InstallStep "🔎" "Locating the installed package..."
63
+ $globalRoot = (& npm root --global).Trim()
64
+ if (-not $globalRoot) { throw "Could not determine the global npm package directory." }
65
+ $packageRoot = Join-Path $globalRoot ($PackageName -replace '/', '\')
66
+ $entrypoint = Join-Path $packageRoot "integrations\windows\install.ps1"
67
+ if (-not (Test-Path $entrypoint)) { throw "Installed package installer not found: $entrypoint" }
68
+ Write-InstallStep "⚙️" "Configuring the installed package..."
69
+ & pwsh -ExecutionPolicy Bypass -File $entrypoint -Local -SkipNpmInstall -SkipBuild -SkipLink -EnableProfileRouting:$EnableProfileRouting -SkipProfile:$SkipProfile -SkipAgentRules:$SkipAgentRules -CopilotOnly:$CopilotOnly -ClaudeOnly:$ClaudeOnly -ProfilePath $ProfilePath
70
+ if ($LASTEXITCODE -ne 0) { throw "Repository installer failed with exit code $LASTEXITCODE" }
71
+ Write-InstallStep "✅" "Install complete."
72
+ exit 0
73
+ }
74
+
75
+ $scriptDir = $PSScriptRoot
76
+ $repoRoot = (Resolve-Path (Join-Path $scriptDir "..\..")).Path
77
+ $templatePath = Join-Path $repoRoot "templates\agent-rules.md"
78
+ $integrationPath = (Resolve-Path (Join-Path $scriptDir "shrinker-profile.ps1")).Path
79
+ if (-not $SkipAgentRules) {
80
+ if (-not (Test-Path $templatePath)) { throw "Agent rules template not found: $templatePath" }
81
+ $rulesBody = Get-Content $templatePath -Raw
82
+ }
83
+
84
+ $versionText = & node -v 2>$null
85
+ if (-not $versionText) { throw "Node.js was not found on PATH. Install Node.js 22.13+ first." }
86
+ $version = [version]($versionText.TrimStart('v'))
87
+ if ($version -lt [version]'22.13.0') { throw "Node.js 22.13+ is required. Found $versionText" }
88
+
89
+ Push-Location $repoRoot
90
+ try {
91
+ Write-InstallStep "📦" "Installing shrinker from: $repoRoot"
92
+ if (-not $SkipNpmInstall) {
93
+ Write-InstallStep "📥" "Installing dependencies..."
94
+ & npm install --silent
95
+ if ($LASTEXITCODE -ne 0) { throw "npm install failed." }
96
+ }
97
+ if (-not $SkipBuild) {
98
+ Write-InstallStep "🏗️" "Building shrinker..."
99
+ & npm run build --silent
100
+ if ($LASTEXITCODE -ne 0) { throw "npm run build failed." }
101
+ }
102
+ if (-not $SkipLink) {
103
+ Write-InstallStep "🔗" "Linking shrinker globally..."
104
+ & npm link --silent
105
+ if ($LASTEXITCODE -ne 0) { throw "npm link failed." }
106
+ }
107
+ } finally { Pop-Location }
108
+
109
+ if (-not $SkipProfile -and $EnableProfileRouting) { Add-ProfileIntegration $ProfilePath $integrationPath }
110
+ if (-not $SkipAgentRules) { Set-AgentRules $rulesBody }
111
+ Write-InstallStep "✅" "Install complete."
112
+ Write-Host " "
113
+ Write-Host "💡 Try: shrinker help"
@@ -0,0 +1,57 @@
1
+ param(
2
+ [switch]$SkipUnlink,
3
+ [switch]$SkipAgentRules,
4
+ [switch]$CopilotOnly,
5
+ [switch]$ClaudeOnly,
6
+ [string]$ProfilePath = $PROFILE
7
+ )
8
+
9
+ $ErrorActionPreference = "Stop"
10
+ $UninstallStep = 0
11
+
12
+ function Write-UninstallStep {
13
+ param([string]$Emoji, [string]$Message)
14
+ $script:UninstallStep++
15
+ Write-Host "$($script:UninstallStep). $Emoji $Message"
16
+ }
17
+
18
+ function Remove-AgentRules {
19
+ param([string]$Path)
20
+ if (-not (Test-Path $Path)) { return }
21
+ $content = Get-Content $Path -Raw
22
+ $start = "<!-- shrinker agent rules start -->"
23
+ $end = "<!-- shrinker agent rules end -->"
24
+ if ($null -ne $content -and $content.Contains($start) -and $content.Contains($end)) {
25
+ $pattern = [regex]::Escape($start) + ".*?" + [regex]::Escape($end)
26
+ Set-Content $Path ([regex]::Replace($content, $pattern, "", 'Singleline').TrimEnd() + "`n")
27
+ Write-UninstallStep "📄" "Removed managed rules from: $Path"
28
+ }
29
+ }
30
+
31
+ function Remove-ProfileIntegration {
32
+ param([string]$ProfileFile)
33
+ if (-not (Test-Path $ProfileFile)) { return }
34
+ $content = Get-Content $ProfileFile -Raw
35
+ if ($null -eq $content) { return }
36
+ $start = $content.IndexOf("# >>> shrinker integration >>>")
37
+ $endMarker = "# <<< shrinker integration <<<"
38
+ if ($start -ge 0) {
39
+ $end = $content.IndexOf($endMarker, $start)
40
+ if ($end -ge 0) { Set-Content $ProfileFile $content.Remove($start, $end + $endMarker.Length - $start) }
41
+ }
42
+ }
43
+
44
+ if (-not $SkipUnlink) {
45
+ Write-UninstallStep "🔗" "Unlinking shrinker globally..."
46
+ & npm unlink --silent --global shrinker-ai
47
+ if ($LASTEXITCODE -ne 0) { throw "npm unlink failed." }
48
+ }
49
+ else { Write-UninstallStep "⏭️" "Skipped global npm unlink." }
50
+ Write-UninstallStep "🔧" "Removing PowerShell profile integration..."
51
+ Remove-ProfileIntegration $ProfilePath
52
+ if (-not $SkipAgentRules) {
53
+ if (-not $ClaudeOnly) { Remove-AgentRules (Join-Path $HOME ".copilot\copilot-instructions.md") }
54
+ if (-not $CopilotOnly) { Remove-AgentRules (Join-Path $HOME ".claude\CLAUDE.md") }
55
+ }
56
+ else { Write-UninstallStep "⏭️" "Skipped managed agent rules." }
57
+ Write-UninstallStep "✅" "Uninstall complete."
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "shrinker-ai",
3
- "version": "0.1.0",
3
+ "version": "0.3.1",
4
4
  "description": "Local deterministic command-output shrinker for coding agents",
5
5
  "type": "module",
6
6
  "bin": {
7
- "shrinker": "./dist/src/cli.js"
7
+ "shrinker": "dist/src/cli.js"
8
8
  },
9
9
  "scripts": {
10
10
  "start": "tsc -w -p tsconfig.json",
@@ -12,10 +12,14 @@
12
12
  "pack": "npm run build --silent && npm pack",
13
13
  "test": "npm run build --silent && node --test \"dist/tests/*.test.js\"",
14
14
  "demo": "npm run build --silent && node dist/demo/run-demo.js",
15
- "install:local": "pwsh -ExecutionPolicy Bypass -File ./integrations/install-shrinker.ps1",
16
- "uninstall:local": "pwsh -ExecutionPolicy Bypass -File ./integrations/uninstall-shrinker.ps1",
17
- "install:package": "pwsh -ExecutionPolicy Bypass -File ./integrations/install.ps1",
18
- "uninstall:package": "pwsh -ExecutionPolicy Bypass -File ./integrations/uninstall.ps1"
15
+ "install:local": "pwsh -ExecutionPolicy Bypass -File ./integrations/windows/install.ps1 -Local",
16
+ "install:local:macos": "./integrations/macos/install.sh --local",
17
+ "install:github": "pwsh -ExecutionPolicy Bypass -File ./integrations/windows/install.ps1",
18
+ "install:github:macos": "./integrations/macos/install.sh",
19
+ "uninstall:local": "pwsh -ExecutionPolicy Bypass -File ./integrations/windows/uninstall.ps1",
20
+ "uninstall:local:macos": "./integrations/macos/uninstall.sh",
21
+ "uninstall:github": "pwsh -ExecutionPolicy Bypass -File ./integrations/windows/uninstall.ps1",
22
+ "uninstall:github:macos": "./integrations/macos/uninstall.sh"
19
23
  },
20
24
  "devDependencies": {
21
25
  "@types/node": "^24.0.0",
@@ -27,5 +31,9 @@
27
31
  "publishConfig": {
28
32
  "registry": "https://registry.npmjs.org"
29
33
  },
30
- "license": "MIT"
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/ivanduplenskikh/shrinker.git"
38
+ }
31
39
  }
@@ -1,166 +0,0 @@
1
- param(
2
- [switch]$SkipNpmInstall,
3
- [switch]$SkipBuild,
4
- [switch]$SkipLink,
5
- [switch]$EnableProfileRouting,
6
- [switch]$SkipProfile,
7
- [switch]$SkipAgentRules,
8
- [switch]$CopilotOnly,
9
- [switch]$ClaudeOnly,
10
- [string]$ProfilePath = $PROFILE
11
- )
12
-
13
- $ErrorActionPreference = "Stop"
14
-
15
- if ($EnableProfileRouting -and $SkipProfile) {
16
- throw "Use either -EnableProfileRouting or -SkipProfile, not both."
17
- }
18
- if ($CopilotOnly -and $ClaudeOnly) {
19
- throw "Use either -CopilotOnly or -ClaudeOnly, not both."
20
- }
21
-
22
- $blockStart = "<!-- shrinker agent rules start -->"
23
- $blockEnd = "<!-- shrinker agent rules end -->"
24
-
25
- function Set-AgentRules {
26
- param(
27
- [string]$RepoRoot,
28
- [string]$Body
29
- )
30
-
31
- $targets = @()
32
- if (-not $ClaudeOnly) { $targets += (Join-Path $RepoRoot ".copilot-instructions.md") }
33
- if (-not $CopilotOnly) { $targets += (Join-Path $RepoRoot "CLAUDE.md") }
34
-
35
- foreach ($target in $targets) {
36
- $content = if (Test-Path $target) { Get-Content -Path $target -Raw } else { "" }
37
- $newBlock = "$blockStart`n$Body`n$blockEnd"
38
- if ($content -and $content.Contains($blockStart) -and $content.Contains($blockEnd)) {
39
- $pattern = [regex]::Escape($blockStart) + ".*?" + [regex]::Escape($blockEnd)
40
- $content = [regex]::Replace($content, $pattern, $newBlock, [System.Text.RegularExpressions.RegexOptions]::Singleline)
41
- Set-Content -Path $target -Value $content
42
- } elseif ($content) {
43
- Add-Content -Path $target -Value "`n$newBlock`n"
44
- } else {
45
- Set-Content -Path $target -Value "$newBlock`n"
46
- }
47
- Write-Host "Installed managed rules in: $target"
48
- }
49
- }
50
-
51
- function Test-NodeVersion {
52
- $versionText = & node -v 2>$null
53
- if (-not $versionText) {
54
- throw "Node.js was not found on PATH. Install Node.js 22.13+ first."
55
- }
56
-
57
- $match = [regex]::Match($versionText, "^v(\d+)\.(\d+)\.(\d+)$")
58
- if (-not $match.Success) {
59
- throw "Could not parse Node.js version: $versionText"
60
- }
61
-
62
- $major = [int]$match.Groups[1].Value
63
- $minor = [int]$match.Groups[2].Value
64
- $patch = [int]$match.Groups[3].Value
65
-
66
- if ($major -lt 22 -or ($major -eq 22 -and $minor -lt 13)) {
67
- throw "Node.js 22.13+ is required. Found $versionText"
68
- }
69
-
70
- return $versionText
71
- }
72
-
73
- function Add-ProfileIntegration {
74
- param(
75
- [string]$ProfileFile,
76
- [string]$IntegrationFile
77
- )
78
-
79
- if (-not (Test-Path $ProfileFile)) {
80
- New-Item -ItemType File -Path $ProfileFile -Force | Out-Null
81
- }
82
-
83
- $startMarker = "# >>> shrinker integration >>>"
84
- $endMarker = "# <<< shrinker integration <<<"
85
-
86
- $existing = Get-Content -Path $ProfileFile -Raw -ErrorAction SilentlyContinue
87
- if ($existing -and $existing.Contains($startMarker)) {
88
- Write-Host "Profile already contains shrinker integration block: $ProfileFile"
89
- return
90
- }
91
-
92
- $block = @"
93
- $startMarker
94
- . "$IntegrationFile"
95
- $endMarker
96
- "@
97
-
98
- Add-Content -Path $ProfileFile -Value "`n$block`n"
99
- Write-Host "Added shrinker integration block to profile: $ProfileFile"
100
- }
101
-
102
- $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
103
- $templatePath = Join-Path $scriptDir "..\templates\agent-rules.md"
104
- $repoRoot = Resolve-Path (Join-Path $scriptDir "..")
105
- $integrationPath = (Resolve-Path (Join-Path $scriptDir "shrinker-profile.ps1")).Path
106
-
107
- if (-not $SkipAgentRules) {
108
- if (-not (Test-Path $templatePath)) {
109
- throw "Agent rules template not found: $templatePath"
110
- }
111
- $rulesBody = Get-Content -Path $templatePath -Raw
112
- }
113
-
114
- Write-Host "Installing shrinker from: $repoRoot"
115
- $nodeVersion = Test-NodeVersion
116
- Write-Host "Detected Node.js: $nodeVersion"
117
-
118
- Push-Location $repoRoot
119
- try {
120
- if (-not $SkipNpmInstall) {
121
- Write-Host "Running npm install..."
122
- & npm install
123
- if ($LASTEXITCODE -ne 0) {
124
- throw "npm install failed with exit code $LASTEXITCODE"
125
- }
126
- }
127
-
128
- if (-not $SkipBuild) {
129
- Write-Host "Running npm run build..."
130
- & npm run build --silent
131
- if ($LASTEXITCODE -ne 0) {
132
- throw "npm run build failed with exit code $LASTEXITCODE"
133
- }
134
- }
135
-
136
- if (-not $SkipLink) {
137
- Write-Host "Running npm link..."
138
- & npm link
139
- if ($LASTEXITCODE -ne 0) {
140
- throw "npm link failed with exit code $LASTEXITCODE"
141
- }
142
- }
143
- }
144
- finally {
145
- Pop-Location
146
- }
147
-
148
- if (-not $SkipProfile) {
149
- if ($EnableProfileRouting) {
150
- Add-ProfileIntegration -ProfileFile $ProfilePath -IntegrationFile $integrationPath
151
- Write-Host "Reload your profile with: . `$PROFILE"
152
- }
153
- else {
154
- Write-Host "Profile routing not enabled (default). Native commands remain unchanged."
155
- Write-Host "To enable routing later: pwsh -ExecutionPolicy Bypass -File .\integrations\install-shrinker.ps1 -SkipNpmInstall -SkipBuild -SkipLink -EnableProfileRouting"
156
- }
157
- }
158
- else {
159
- Write-Host "Profile routing skipped via -SkipProfile. Native commands remain unchanged."
160
- }
161
-
162
- if (-not $SkipAgentRules) {
163
- Set-AgentRules -RepoRoot (Get-Location).Path -Body $rulesBody
164
- }
165
-
166
- Write-Host "Install complete. Try: shrinker help"
@@ -1,46 +0,0 @@
1
- param(
2
- [string]$PackageName = "shrinker-ai",
3
- [string]$Registry = "https://registry.npmjs.org",
4
- [string]$Version,
5
- [switch]$EnableProfileRouting,
6
- [switch]$SkipAgentRules,
7
- [switch]$CopilotOnly,
8
- [switch]$ClaudeOnly
9
- )
10
-
11
- $ErrorActionPreference = "Stop"
12
-
13
- if ($CopilotOnly -and $ClaudeOnly) {
14
- throw "Use either -CopilotOnly or -ClaudeOnly, not both."
15
- }
16
-
17
- $packageSpec = if ($Version) { "$PackageName@$Version" } else { $PackageName }
18
- Write-Host "Installing $packageSpec from $Registry..."
19
- & npm install --global $packageSpec "--registry=$Registry"
20
- if ($LASTEXITCODE -ne 0) {
21
- throw "npm package installation failed with exit code $LASTEXITCODE"
22
- }
23
-
24
- $globalRoot = (& npm root --global).Trim()
25
- if (-not $globalRoot) {
26
- throw "Could not determine the global npm package directory."
27
- }
28
-
29
- $packageRoot = Join-Path $globalRoot ($PackageName -replace '/', '\')
30
- $localInstaller = Join-Path $packageRoot "integrations\install-shrinker.ps1"
31
- if (-not (Test-Path $localInstaller)) {
32
- throw "Installed package integration not found: $localInstaller"
33
- }
34
-
35
- $localArgs = @("-ExecutionPolicy", "Bypass", "-File", $localInstaller, "-SkipNpmInstall", "-SkipBuild", "-SkipLink")
36
- if ($EnableProfileRouting) { $localArgs += "-EnableProfileRouting" }
37
- if ($SkipAgentRules) { $localArgs += "-SkipAgentRules" }
38
- if ($CopilotOnly) { $localArgs += "-CopilotOnly" }
39
- if ($ClaudeOnly) { $localArgs += "-ClaudeOnly" }
40
-
41
- & pwsh @localArgs
42
- if ($LASTEXITCODE -ne 0) {
43
- throw "Installed package integration failed with exit code $LASTEXITCODE"
44
- }
45
-
46
- Write-Host "Package installation complete. Try: shrinker help"
@@ -1,79 +0,0 @@
1
- param(
2
- [switch]$SkipUnlink,
3
- [switch]$SkipAgentRules,
4
- [switch]$CopilotOnly,
5
- [switch]$ClaudeOnly,
6
- [string]$ProfilePath = $PROFILE
7
- )
8
-
9
- $ErrorActionPreference = "Stop"
10
-
11
- if ($CopilotOnly -and $ClaudeOnly) {
12
- throw "Use either -CopilotOnly or -ClaudeOnly, not both."
13
- }
14
-
15
- $blockStart = "<!-- shrinker agent rules start -->"
16
- $blockEnd = "<!-- shrinker agent rules end -->"
17
-
18
- function Remove-AgentRules {
19
- param([string]$Path)
20
-
21
- if (-not (Test-Path $Path)) { return }
22
- $content = Get-Content -Path $Path -Raw
23
- if (-not ($content.Contains($blockStart) -and $content.Contains($blockEnd))) { return }
24
- $pattern = [regex]::Escape($blockStart) + ".*?" + [regex]::Escape($blockEnd)
25
- Set-Content -Path $Path -Value ([regex]::Replace($content, $pattern, "", [System.Text.RegularExpressions.RegexOptions]::Singleline).TrimEnd() + "`n")
26
- Write-Host "Removed managed rules from: $Path"
27
- }
28
-
29
- function Remove-ProfileIntegration {
30
- param([string]$ProfileFile)
31
-
32
- if (-not (Test-Path $ProfileFile)) {
33
- Write-Host "Profile not found: $ProfileFile"
34
- return
35
- }
36
-
37
- $startMarker = "# >>> shrinker integration >>>"
38
- $endMarker = "# <<< shrinker integration <<<"
39
- $content = Get-Content -Path $ProfileFile -Raw
40
- if ($null -eq $content -or $content.Length -eq 0) {
41
- Write-Host "Profile is empty; nothing to remove."
42
- return
43
- }
44
-
45
- $start = $content.IndexOf($startMarker)
46
- if ($start -lt 0) {
47
- Write-Host "No shrinker integration block found in profile."
48
- return
49
- }
50
-
51
- $end = $content.IndexOf($endMarker, $start)
52
- if ($end -lt 0) {
53
- Write-Host "Integration block start found but end marker is missing; leaving profile unchanged."
54
- return
55
- }
56
-
57
- $end += $endMarker.Length
58
- $updated = $content.Remove($start, $end - $start)
59
- Set-Content -Path $ProfileFile -Value $updated
60
- Write-Host "Removed shrinker integration block from: $ProfileFile"
61
- }
62
-
63
- if (-not $SkipUnlink) {
64
- Write-Host "Running npm unlink -g shrinker..."
65
- & npm unlink -g shrinker
66
- if ($LASTEXITCODE -ne 0) {
67
- throw "npm unlink failed with exit code $LASTEXITCODE"
68
- }
69
- }
70
-
71
- Remove-ProfileIntegration -ProfileFile $ProfilePath
72
- Write-Host "If this terminal previously loaded shrinker-profile.ps1, restart terminal or remove Function:git/Function:rg wrappers from current session."
73
-
74
- if (-not $SkipAgentRules) {
75
- if (-not $ClaudeOnly) { Remove-AgentRules -Path (Join-Path (Get-Location).Path ".copilot-instructions.md") }
76
- if (-not $CopilotOnly) { Remove-AgentRules -Path (Join-Path (Get-Location).Path "CLAUDE.md") }
77
- }
78
-
79
- Write-Host "Uninstall complete."
@@ -1,35 +0,0 @@
1
- param(
2
- [string]$PackageName = "shrinker-ai",
3
- [string]$Registry = "https://registry.npmjs.org",
4
- [switch]$SkipAgentRules,
5
- [switch]$CopilotOnly,
6
- [switch]$ClaudeOnly
7
- )
8
-
9
- $ErrorActionPreference = "Stop"
10
-
11
- if ($CopilotOnly -and $ClaudeOnly) {
12
- throw "Use either -CopilotOnly or -ClaudeOnly, not both."
13
- }
14
-
15
- $globalRoot = (& npm root --global).Trim()
16
- $packageRoot = Join-Path $globalRoot ($PackageName -replace '/', '\')
17
- $localUninstaller = Join-Path $packageRoot "integrations\uninstall-shrinker.ps1"
18
- if (Test-Path $localUninstaller) {
19
- $localArgs = @("-ExecutionPolicy", "Bypass", "-File", $localUninstaller, "-SkipUnlink")
20
- if ($SkipAgentRules) { $localArgs += "-SkipAgentRules" }
21
- if ($CopilotOnly) { $localArgs += "-CopilotOnly" }
22
- if ($ClaudeOnly) { $localArgs += "-ClaudeOnly" }
23
- & pwsh @localArgs
24
- if ($LASTEXITCODE -ne 0) {
25
- throw "Installed package integration failed with exit code $LASTEXITCODE"
26
- }
27
- }
28
-
29
- Write-Host "Removing $PackageName..."
30
- & npm uninstall --global $PackageName "--registry=$Registry"
31
- if ($LASTEXITCODE -ne 0) {
32
- throw "npm package removal failed with exit code $LASTEXITCODE"
33
- }
34
-
35
- Write-Host "Package uninstallation complete."