veto-leash 1.2.0 → 2.0.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.
- package/README.md +76 -45
- package/bin/leash +0 -0
- package/bin/leash.js +45 -0
- package/dist/ast/builtins.d.ts.map +1 -1
- package/dist/ast/builtins.js +469 -9
- package/dist/ast/builtins.js.map +1 -1
- package/dist/ast/parser.d.ts +22 -2
- package/dist/ast/parser.d.ts.map +1 -1
- package/dist/ast/parser.js +124 -11
- package/dist/ast/parser.js.map +1 -1
- package/dist/cli.js +81 -31
- package/dist/cli.js.map +1 -1
- package/dist/compiler/llm.js +7 -7
- package/dist/compiler/llm.js.map +1 -1
- package/dist/compiler/prompt.d.ts +1 -1
- package/dist/compiler/prompt.d.ts.map +1 -1
- package/dist/compiler/prompt.js +148 -45
- package/dist/compiler/prompt.js.map +1 -1
- package/dist/config/loader.d.ts +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +27 -11
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +1 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +3 -2
- package/dist/config/schema.js.map +1 -1
- package/dist/native/claude-code.js +6 -5
- package/dist/native/claude-code.js.map +1 -1
- package/dist/native/cursor.d.ts +1 -1
- package/dist/native/cursor.d.ts.map +1 -1
- package/dist/native/cursor.js +65 -8
- package/dist/native/cursor.js.map +1 -1
- package/dist/native/index.js +2 -2
- package/dist/native/index.js.map +1 -1
- package/dist/native/opencode.d.ts +1 -1
- package/dist/native/opencode.d.ts.map +1 -1
- package/dist/native/opencode.js +181 -10
- package/dist/native/opencode.js.map +1 -1
- package/dist/native/validator.js +6 -4
- package/dist/native/validator.js.map +1 -1
- package/dist/native/windsurf.d.ts +1 -1
- package/dist/native/windsurf.d.ts.map +1 -1
- package/dist/native/windsurf.js +63 -8
- package/dist/native/windsurf.js.map +1 -1
- package/dist/opencode-plugin/veto-leash.d.ts +54 -0
- package/dist/opencode-plugin/veto-leash.d.ts.map +1 -0
- package/dist/opencode-plugin/veto-leash.js +226 -0
- package/dist/opencode-plugin/veto-leash.js.map +1 -0
- package/go/leash-darwin-amd64 +0 -0
- package/go/leash-darwin-arm64 +0 -0
- package/go/leash-linux-amd64 +0 -0
- package/go/leash-linux-arm64 +0 -0
- package/go/leash-windows-amd64.exe +0 -0
- package/package.json +9 -4
- package/scripts/postinstall.js +57 -0
- package/languages/tree-sitter-bash.wasm +0 -0
- package/languages/tree-sitter-c.wasm +0 -0
- package/languages/tree-sitter-cpp.wasm +0 -0
- package/languages/tree-sitter-go.wasm +0 -0
- package/languages/tree-sitter-java.wasm +0 -0
- package/languages/tree-sitter-javascript.wasm +0 -0
- package/languages/tree-sitter-kotlin.wasm +0 -0
- package/languages/tree-sitter-php.wasm +0 -0
- package/languages/tree-sitter-python.wasm +0 -0
- package/languages/tree-sitter-ruby.wasm +0 -0
- package/languages/tree-sitter-rust.wasm +0 -0
- package/languages/tree-sitter-tsx.wasm +0 -0
- package/languages/tree-sitter-typescript.wasm +0 -0
package/README.md
CHANGED
|
@@ -15,17 +15,17 @@ Your AI agent has root access to your codebase. You have... vibes.
|
|
|
15
15
|
echo "no lodash
|
|
16
16
|
no any types" > .leash
|
|
17
17
|
|
|
18
|
-
leash
|
|
18
|
+
leash # Interactive dashboard
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
Now every action is validated with **AST-level precision**. Zero false positives. Zero config.
|
|
22
22
|
|
|
23
|
-
## What's New in
|
|
23
|
+
## What's New in 2.0
|
|
24
24
|
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
25
|
+
- **Native Go TUI** - Beautiful interactive dashboard built with Bubble Tea
|
|
26
|
+
- **4.5MB binary** - Instant startup, no Node.js required at runtime
|
|
27
|
+
- **Cross-platform** - Native binaries for macOS, Linux, Windows (arm64 + amd64)
|
|
28
|
+
- **Hybrid engine** - Go for speed, TypeScript for LLM compilation + AST validation
|
|
29
29
|
|
|
30
30
|
## The Problem
|
|
31
31
|
|
|
@@ -39,10 +39,10 @@ veto-leash uses **AST parsing** for surgical precision:
|
|
|
39
39
|
|
|
40
40
|
| Code | Regex Result | AST Result |
|
|
41
41
|
| ------------------------ | ------------ | -------------------------- |
|
|
42
|
-
| `// import lodash` |
|
|
43
|
-
| `"use any type"` |
|
|
44
|
-
| `const anyValue = 5` |
|
|
45
|
-
| `import _ from 'lodash'` |
|
|
42
|
+
| `// import lodash` | BLOCKED | ALLOWED (comment) |
|
|
43
|
+
| `"use any type"` | BLOCKED | ALLOWED (string) |
|
|
44
|
+
| `const anyValue = 5` | BLOCKED | ALLOWED (variable name) |
|
|
45
|
+
| `import _ from 'lodash'` | BLOCKED | BLOCKED (correct) |
|
|
46
46
|
|
|
47
47
|
**This precision is our moat.** No other tool achieves zero false positives.
|
|
48
48
|
|
|
@@ -52,20 +52,28 @@ veto-leash uses **AST parsing** for surgical precision:
|
|
|
52
52
|
# Install globally
|
|
53
53
|
npm install -g veto-leash
|
|
54
54
|
|
|
55
|
-
# Create
|
|
55
|
+
# Create policies
|
|
56
56
|
echo "no lodash
|
|
57
57
|
no any types
|
|
58
|
-
|
|
58
|
+
prefer pnpm" > .leash
|
|
59
59
|
|
|
60
|
-
#
|
|
61
|
-
leash
|
|
60
|
+
# Launch the dashboard
|
|
61
|
+
leash
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
The interactive TUI lets you:
|
|
65
|
+
- Add and manage policies
|
|
66
|
+
- Install hooks for detected agents
|
|
67
|
+
- Monitor enforcement in real-time
|
|
68
|
+
- View audit logs
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
Or use CLI commands directly:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
leash init # Auto-detect agents, install hooks
|
|
74
|
+
leash add "no axios" # Add a policy
|
|
75
|
+
leash sync # Apply to all agents
|
|
76
|
+
```
|
|
69
77
|
|
|
70
78
|
## Simple `.leash` Format
|
|
71
79
|
|
|
@@ -75,11 +83,12 @@ no lodash
|
|
|
75
83
|
no any types - enforces strict TypeScript
|
|
76
84
|
no console.log
|
|
77
85
|
prefer pnpm over npm
|
|
86
|
+
protect .env files
|
|
78
87
|
```
|
|
79
88
|
|
|
80
89
|
Lines starting with `#` are comments. Optional reasons after `-`.
|
|
81
90
|
|
|
82
|
-
## Built-in
|
|
91
|
+
## Built-in Rules
|
|
83
92
|
|
|
84
93
|
These work **instantly** with zero LLM calls:
|
|
85
94
|
|
|
@@ -93,31 +102,58 @@ These work **instantly** with zero LLM calls:
|
|
|
93
102
|
| `no innerhtml` | innerHTML, dangerouslySetInnerHTML |
|
|
94
103
|
| `no debugger` | debugger statements |
|
|
95
104
|
| `no var` | var declarations |
|
|
105
|
+
| `prefer pnpm` | npm/yarn commands blocked |
|
|
106
|
+
| `protect .env` | Environment file modifications blocked |
|
|
107
|
+
|
|
108
|
+
50+ built-in patterns cover most common policies.
|
|
96
109
|
|
|
97
110
|
## Native Agent Support
|
|
98
111
|
|
|
99
|
-
| Agent | How It Works | Status
|
|
100
|
-
| --------------- | ------------------------------------ |
|
|
101
|
-
| **Claude Code** | PreToolUse hooks with AST validation |
|
|
102
|
-
| **
|
|
103
|
-
| **
|
|
104
|
-
| **Windsurf** | Cascade
|
|
105
|
-
| **Aider** | .aider.conf.yml
|
|
106
|
-
| **Any CLI** | Wrapper mode (PATH hijacking) | ✅ Universal |
|
|
112
|
+
| Agent | How It Works | Status |
|
|
113
|
+
| --------------- | ------------------------------------ | ---------- |
|
|
114
|
+
| **Claude Code** | PreToolUse hooks with AST validation | Full |
|
|
115
|
+
| **OpenCode** | AGENTS.md injection | Full |
|
|
116
|
+
| **Cursor** | rules/ directory integration | Full |
|
|
117
|
+
| **Windsurf** | Cascade rules integration | Full |
|
|
118
|
+
| **Aider** | .aider.conf.yml configuration | Full |
|
|
107
119
|
|
|
108
120
|
## Commands
|
|
109
121
|
|
|
110
122
|
```
|
|
111
|
-
leash
|
|
112
|
-
leash
|
|
113
|
-
leash add "<
|
|
114
|
-
leash
|
|
115
|
-
leash explain "<
|
|
116
|
-
leash
|
|
117
|
-
leash
|
|
118
|
-
leash
|
|
123
|
+
leash Interactive dashboard
|
|
124
|
+
leash init Auto-detect agents, install hooks
|
|
125
|
+
leash add "<policy>" Add a policy
|
|
126
|
+
leash list Show current policies
|
|
127
|
+
leash explain "<policy>" Preview what a policy catches
|
|
128
|
+
leash sync [agent] Apply policies to agents
|
|
129
|
+
leash install <agent> Install hooks for specific agent
|
|
130
|
+
leash uninstall <agent> Remove agent hooks
|
|
131
|
+
leash status Show detected agents
|
|
132
|
+
leash audit [--tail] View enforcement log
|
|
119
133
|
```
|
|
120
134
|
|
|
135
|
+
**Agent shortcuts:** `cc` (Claude Code), `oc` (OpenCode), `cursor`, `windsurf`, `aider`
|
|
136
|
+
|
|
137
|
+
## Architecture
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
┌─────────────────────────────────────────────────────────┐
|
|
141
|
+
│ leash (Go, 4.5MB) │
|
|
142
|
+
├─────────────────────────────────────────────────────────┤
|
|
143
|
+
│ TUI Dashboard │ Fast Commands │
|
|
144
|
+
│ - Policy management │ - list, status, sync │
|
|
145
|
+
│ - Agent installation │ - install, uninstall │
|
|
146
|
+
│ - Real-time monitoring │ - Pattern matching │
|
|
147
|
+
├─────────────────────────┴───────────────────────────────┤
|
|
148
|
+
│ TypeScript Engine (when needed) │
|
|
149
|
+
│ - LLM policy compilation (custom rules) │
|
|
150
|
+
│ - AST validation (Tree-sitter) │
|
|
151
|
+
│ - 243 tests │
|
|
152
|
+
└─────────────────────────────────────────────────────────┘
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Key insight**: 95%+ of policies use built-in rules (pure Go, instant). LLM compilation only runs for custom rules.
|
|
156
|
+
|
|
121
157
|
## How It Works
|
|
122
158
|
|
|
123
159
|
```
|
|
@@ -130,17 +166,12 @@ User: "no lodash"
|
|
|
130
166
|
↓
|
|
131
167
|
┌─────────────────────────────────────────┐
|
|
132
168
|
│ 2. Runtime: Write/Edit intercepted │
|
|
133
|
-
│ → Regex pre-filter:
|
|
134
|
-
│ "lodash"? Yes → continue │
|
|
169
|
+
│ → Regex pre-filter: "lodash"? │
|
|
135
170
|
│ → AST parse (5ms, cached) │
|
|
136
|
-
│ → Query: import_statement with │
|
|
137
|
-
│ source matching "lodash" │
|
|
138
171
|
│ → BLOCKED with line/column │
|
|
139
172
|
└─────────────────────────────────────────┘
|
|
140
173
|
```
|
|
141
174
|
|
|
142
|
-
**Key insight**: Regex pre-filter skips 95%+ of files instantly. AST parsing only runs when needed.
|
|
143
|
-
|
|
144
175
|
## Environment Variables
|
|
145
176
|
|
|
146
177
|
| Variable | Description |
|
|
@@ -153,14 +184,14 @@ Get a free API key: https://aistudio.google.com/apikey
|
|
|
153
184
|
|
|
154
185
|
1. **Surgeon-level precision** - AST parsing = zero false positives
|
|
155
186
|
2. **Invisible until needed** - Auto-detection, background enforcement
|
|
156
|
-
3. **
|
|
157
|
-
4. **Natural language
|
|
187
|
+
3. **Native performance** - Go binary, instant startup
|
|
188
|
+
4. **Natural language** - `no lodash` not `{ "rule": "no-import", "pattern": "^lodash" }`
|
|
158
189
|
|
|
159
190
|
## Test Suite
|
|
160
191
|
|
|
161
192
|
```
|
|
162
|
-
|
|
163
|
-
├──
|
|
193
|
+
243 tests passing
|
|
194
|
+
├── 77 AST validation tests
|
|
164
195
|
├── 93 content matching tests
|
|
165
196
|
├── 41 command interception tests
|
|
166
197
|
├── 17 pattern matcher tests
|
package/bin/leash
ADDED
|
Binary file
|
package/bin/leash.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// bin/leash.js - Wrapper that uses native binary or falls back to Node.js
|
|
3
|
+
|
|
4
|
+
import { spawn } from 'child_process';
|
|
5
|
+
import { existsSync } from 'fs';
|
|
6
|
+
import { join, dirname } from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const rootDir = join(__dirname, '..');
|
|
11
|
+
|
|
12
|
+
// Try native binary first
|
|
13
|
+
const nativeBinary = process.platform === 'win32'
|
|
14
|
+
? join(__dirname, 'leash.exe')
|
|
15
|
+
: join(__dirname, 'leash');
|
|
16
|
+
|
|
17
|
+
if (existsSync(nativeBinary)) {
|
|
18
|
+
// Use native binary
|
|
19
|
+
const child = spawn(nativeBinary, process.argv.slice(2), {
|
|
20
|
+
stdio: 'inherit',
|
|
21
|
+
env: process.env,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
child.on('exit', (code) => {
|
|
25
|
+
process.exit(code || 0);
|
|
26
|
+
});
|
|
27
|
+
} else {
|
|
28
|
+
// Fall back to Node.js CLI
|
|
29
|
+
const nodeCLI = join(rootDir, 'dist', 'cli.js');
|
|
30
|
+
|
|
31
|
+
if (!existsSync(nodeCLI)) {
|
|
32
|
+
console.error('leash: Neither native binary nor Node.js CLI found.');
|
|
33
|
+
console.error('Run "pnpm build" to build the CLI.');
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const child = spawn('node', [nodeCLI, ...process.argv.slice(2)], {
|
|
38
|
+
stdio: 'inherit',
|
|
39
|
+
env: process.env,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
child.on('exit', (code) => {
|
|
43
|
+
process.exit(code || 0);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../../src/ast/builtins.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../../src/ast/builtins.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CA+mClD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,EAAE,GAAG,IAAI,CAiEjE;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C"}
|