shrinker-ai 0.1.0

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 (35) hide show
  1. package/.copilot-instructions.md +2 -0
  2. package/CLAUDE.md +2 -0
  3. package/README.md +295 -0
  4. package/dist/src/cli.js +265 -0
  5. package/dist/src/execution/raw-output-store.js +132 -0
  6. package/dist/src/execution/run-command.js +172 -0
  7. package/dist/src/filters/cat.js +13 -0
  8. package/dist/src/filters/docker.js +42 -0
  9. package/dist/src/filters/find.js +63 -0
  10. package/dist/src/filters/generic-log.js +38 -0
  11. package/dist/src/filters/gh.js +38 -0
  12. package/dist/src/filters/git-diff.js +56 -0
  13. package/dist/src/filters/git-list.js +25 -0
  14. package/dist/src/filters/git-log.js +256 -0
  15. package/dist/src/filters/git-status.js +67 -0
  16. package/dist/src/filters/kubectl.js +76 -0
  17. package/dist/src/filters/npm.js +44 -0
  18. package/dist/src/filters/rg.js +64 -0
  19. package/dist/src/filters/select-filter.js +119 -0
  20. package/dist/src/filters/table.js +27 -0
  21. package/dist/src/filters/tail.js +6 -0
  22. package/dist/src/filters/test-output.js +54 -0
  23. package/dist/src/filters/types.js +2 -0
  24. package/dist/src/formatting/ansi.js +13 -0
  25. package/dist/src/formatting/limits.js +17 -0
  26. package/dist/src/metrics/dashboard.js +138 -0
  27. package/dist/src/metrics/measure.js +29 -0
  28. package/dist/src/metrics/stats-store.js +166 -0
  29. package/integrations/install-shrinker.ps1 +166 -0
  30. package/integrations/install.ps1 +46 -0
  31. package/integrations/shrinker-profile.ps1 +136 -0
  32. package/integrations/uninstall-shrinker.ps1 +79 -0
  33. package/integrations/uninstall.ps1 +35 -0
  34. package/package.json +31 -0
  35. package/templates/agent-rules.md +19 -0
@@ -0,0 +1,136 @@
1
+ $global:ShrinkPowerShellRules = @{
2
+ git = @("status", "diff", "log", "show", "reflog", "branch", "tag", "stash")
3
+ npm = @("test", "t", "install", "i", "ci", "ls", "list")
4
+ docker = @("ps", "logs", "images", "compose")
5
+ kubectl = @("get", "describe", "logs")
6
+ gh = @("pr", "issue", "run")
7
+ rg = @("*")
8
+ find = @("*")
9
+ tail = @("*")
10
+ cat = @("*")
11
+ ls = @("*")
12
+ dir = @("*")
13
+ }
14
+
15
+ $global:ShrinkOptionValueFlags = @{
16
+ git = @("-C", "-c", "--git-dir", "--work-tree", "--namespace")
17
+ npm = @("--prefix", "--cache", "--registry", "--workspace", "--userconfig", "-w", "-C")
18
+ docker = @("-H", "--host", "--context", "--config")
19
+ kubectl = @("-n", "--namespace", "-o", "--output", "--context", "--kubeconfig", "--cluster", "--user")
20
+ gh = @("-R", "--repo")
21
+ }
22
+
23
+ $global:ShrinkNativePaths = @{}
24
+ foreach ($name in @("git", "npm", "docker", "kubectl", "gh", "rg", "find", "tail")) {
25
+ $command = Get-Command $name -CommandType Application -ErrorAction SilentlyContinue | Select-Object -First 1
26
+ if ($command) {
27
+ $global:ShrinkNativePaths[$name] = $command.Source
28
+ }
29
+ }
30
+
31
+ function Get-ShrinkSubcommand {
32
+ param(
33
+ [string]$CommandName,
34
+ [object[]]$Arguments
35
+ )
36
+
37
+ $valueFlags = @($global:ShrinkOptionValueFlags[$CommandName])
38
+ for ($i = 0; $i -lt $Arguments.Count; $i += 1) {
39
+ $part = [string]$Arguments[$i]
40
+ if (-not $part) { continue }
41
+ if ($valueFlags -contains $part) {
42
+ $i += 1
43
+ continue
44
+ }
45
+ if ($part.StartsWith("-")) { continue }
46
+ return $part.ToLowerInvariant()
47
+ }
48
+
49
+ return ""
50
+ }
51
+
52
+ function Use-ShrinkRouting {
53
+ param(
54
+ [string]$CommandName,
55
+ [object[]]$Arguments
56
+ )
57
+
58
+ $allowlist = @($global:ShrinkPowerShellRules[$CommandName])
59
+ if ($allowlist.Count -eq 0) {
60
+ return $false
61
+ }
62
+ if ($allowlist -contains "*") {
63
+ return $true
64
+ }
65
+
66
+ $subcommand = Get-ShrinkSubcommand -CommandName $CommandName -Arguments $Arguments
67
+ return $allowlist -contains $subcommand
68
+ }
69
+
70
+ function Get-ShrinkCommandPath {
71
+ $candidates = Get-Command shrinker -All -ErrorAction SilentlyContinue
72
+ if (-not $candidates) {
73
+ return $null
74
+ }
75
+
76
+ foreach ($candidate in $candidates) {
77
+ $source = [string]$candidate.Source
78
+ if ($source -and $source.ToLowerInvariant().EndsWith(".cmd")) {
79
+ return $source
80
+ }
81
+ }
82
+ foreach ($candidate in $candidates) {
83
+ $source = [string]$candidate.Source
84
+ if ($source -and $source.ToLowerInvariant().EndsWith(".exe")) {
85
+ return $source
86
+ }
87
+ }
88
+ foreach ($candidate in $candidates) {
89
+ $source = [string]$candidate.Source
90
+ if ($source -and $source.ToLowerInvariant().EndsWith(".ps1")) {
91
+ return $source
92
+ }
93
+ }
94
+
95
+ return [string]($candidates | Select-Object -First 1).Source
96
+ }
97
+
98
+ function Invoke-ShrinkOrNative {
99
+ param(
100
+ [string]$CommandName,
101
+ [object[]]$Arguments
102
+ )
103
+
104
+ $routeToShrink = Use-ShrinkRouting -CommandName $CommandName -Arguments $Arguments
105
+ $shrinkCommand = Get-ShrinkCommandPath
106
+
107
+ if ($routeToShrink -and $shrinkCommand) {
108
+ & $shrinkCommand $CommandName @Arguments
109
+ return
110
+ }
111
+
112
+ $nativePath = $global:ShrinkNativePaths[$CommandName]
113
+ if ($nativePath) {
114
+ & $nativePath @Arguments
115
+ return
116
+ }
117
+
118
+ switch ($CommandName) {
119
+ "cat" { Microsoft.PowerShell.Management\Get-Content @Arguments; return }
120
+ "ls" { Microsoft.PowerShell.Management\Get-ChildItem @Arguments; return }
121
+ "dir" { Microsoft.PowerShell.Management\Get-ChildItem @Arguments; return }
122
+ default { throw "No native fallback found for '$CommandName'." }
123
+ }
124
+ }
125
+
126
+ function global:git { Invoke-ShrinkOrNative -CommandName "git" -Arguments $args }
127
+ function global:npm { Invoke-ShrinkOrNative -CommandName "npm" -Arguments $args }
128
+ function global:docker { Invoke-ShrinkOrNative -CommandName "docker" -Arguments $args }
129
+ function global:kubectl { Invoke-ShrinkOrNative -CommandName "kubectl" -Arguments $args }
130
+ function global:gh { Invoke-ShrinkOrNative -CommandName "gh" -Arguments $args }
131
+ function global:rg { Invoke-ShrinkOrNative -CommandName "rg" -Arguments $args }
132
+ function global:find { Invoke-ShrinkOrNative -CommandName "find" -Arguments $args }
133
+ function global:tail { Invoke-ShrinkOrNative -CommandName "tail" -Arguments $args }
134
+ function global:cat { Invoke-ShrinkOrNative -CommandName "cat" -Arguments $args }
135
+ function global:ls { Invoke-ShrinkOrNative -CommandName "ls" -Arguments $args }
136
+ function global:dir { Invoke-ShrinkOrNative -CommandName "dir" -Arguments $args }
@@ -0,0 +1,79 @@
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."
@@ -0,0 +1,35 @@
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."
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "shrinker-ai",
3
+ "version": "0.1.0",
4
+ "description": "Local deterministic command-output shrinker for coding agents",
5
+ "type": "module",
6
+ "bin": {
7
+ "shrinker": "./dist/src/cli.js"
8
+ },
9
+ "scripts": {
10
+ "start": "tsc -w -p tsconfig.json",
11
+ "build": "tsc -p tsconfig.json",
12
+ "pack": "npm run build --silent && npm pack",
13
+ "test": "npm run build --silent && node --test \"dist/tests/*.test.js\"",
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"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^24.0.0",
22
+ "typescript": "^5.9.0"
23
+ },
24
+ "engines": {
25
+ "node": ">=22.13"
26
+ },
27
+ "publishConfig": {
28
+ "registry": "https://registry.npmjs.org"
29
+ },
30
+ "license": "MIT"
31
+ }
@@ -0,0 +1,19 @@
1
+ Use `shrinker` for high-volume terminal outputs to reduce tokens.
2
+
3
+ Routing policy:
4
+ - `git status|diff|log|show|reflog|branch|tag|stash` -> `shrinker git ...`
5
+ - `npm test|t|install|i|ci|ls|list` -> `shrinker npm ...`
6
+ - `docker ps|logs|images|compose` -> `shrinker docker ...`
7
+ - `kubectl get|describe|logs` -> `shrinker kubectl ...`
8
+ - `gh pr|issue|run` -> `shrinker gh ...`
9
+ - `rg`, `find`, `tail`, `cat`, `ls`, `dir` -> `shrinker <command> ...`
10
+
11
+ Bypass shrinker when:
12
+ - command modifies remote state and output volume is already tiny
13
+ - command requires interactive stdin
14
+ - command explicitly needs `shrinker --raw`
15
+
16
+ Examples:
17
+ - `shrinker git log -n 20`
18
+ - `shrinker rg "pattern" src`
19
+ - `shrinker docker logs api --tail 500`