@malcomsonbrothers/claude-code-permission-hook 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.
- package/LICENSE +21 -0
- package/README.md +209 -0
- package/bin/cc-approve.js +3 -0
- package/dist/cache.d.ts +13 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +153 -0
- package/dist/cache.js.map +1 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +68 -0
- package/dist/config.js.map +1 -0
- package/dist/fast-decisions.d.ts +6 -0
- package/dist/fast-decisions.d.ts.map +1 -0
- package/dist/fast-decisions.js +137 -0
- package/dist/fast-decisions.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +529 -0
- package/dist/index.js.map +1 -0
- package/dist/llm-client.d.ts +3 -0
- package/dist/llm-client.d.ts.map +1 -0
- package/dist/llm-client.js +67 -0
- package/dist/llm-client.js.map +1 -0
- package/dist/logger.d.ts +9 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +45 -0
- package/dist/logger.js.map +1 -0
- package/dist/permission-handler.d.ts +8 -0
- package/dist/permission-handler.d.ts.map +1 -0
- package/dist/permission-handler.js +119 -0
- package/dist/permission-handler.js.map +1 -0
- package/dist/project.d.ts +6 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.js +35 -0
- package/dist/project.js.map +1 -0
- package/dist/types.d.ts +117 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +120 -0
- package/dist/types.js.map +1 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 malcomsonbrothers
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# Claude Code Permission Hook
|
|
2
|
+
|
|
3
|
+
Intelligent auto-approval for Claude Code that reduces friction and maintains security.
|
|
4
|
+
|
|
5
|
+
- Auto-approve safe dev operations (less clicking, more coding)
|
|
6
|
+
- Block destructive commands automatically (no LLM needed)
|
|
7
|
+
- Uses the new PermissionRequest hook type
|
|
8
|
+
- Cache decisions to minimize API costs
|
|
9
|
+
|
|
10
|
+
> **Cost**: Using GPT-4o-mini via OpenRouter, **$1 USD = ~5,000+ LLM decisions**. Most operations use fast allow/deny (no LLM), so $1 can last 6+ months of heavy use.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install -g @malcomsonbrothers/claude-code-permission-hook
|
|
18
|
+
cc-approve install
|
|
19
|
+
cc-approve config
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
**Prerequisites**: Node.js 18+ and Claude Code installed
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Step 1: Install globally
|
|
28
|
+
npm install -g @malcomsonbrothers/claude-code-permission-hook
|
|
29
|
+
|
|
30
|
+
# Step 2: Run the install command to set up the hook
|
|
31
|
+
cc-approve install
|
|
32
|
+
|
|
33
|
+
# Step 3: Configure your API key
|
|
34
|
+
cc-approve config
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The `cc-approve install` command will:
|
|
38
|
+
1. Locate your Claude Code settings
|
|
39
|
+
2. Add the PermissionRequest hook automatically
|
|
40
|
+
3. Verify the setup works
|
|
41
|
+
|
|
42
|
+
### Manual Installation
|
|
43
|
+
|
|
44
|
+
If you prefer to add the hook manually, add this to your Claude Code `settings.json`:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"hooks": {
|
|
49
|
+
"PermissionRequest": [
|
|
50
|
+
{
|
|
51
|
+
"matcher": "*",
|
|
52
|
+
"hooks": [
|
|
53
|
+
{
|
|
54
|
+
"type": "command",
|
|
55
|
+
"command": "cc-approve permission"
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Settings file locations:
|
|
65
|
+
- **User settings**: `~/.claude/settings.json`
|
|
66
|
+
- **Project settings**: `.claude/settings.json`
|
|
67
|
+
- **Project local**: `.claude/settings.local.json`
|
|
68
|
+
|
|
69
|
+
## How It Works
|
|
70
|
+
|
|
71
|
+
This hook uses Claude Code's PermissionRequest hook to intercept tool calls before execution:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
Claude Code Tool Request → cc-approve → Decision → Execute/Block
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Three-Tier Decision System
|
|
78
|
+
|
|
79
|
+
1. **Fast approval** for obviously safe operations (Read, Write, Glob, Edit)
|
|
80
|
+
2. **Fast deny** for destructive patterns (rm -rf /, force push to protected branches)
|
|
81
|
+
3. **LLM analysis** for complex operations with intelligent caching
|
|
82
|
+
|
|
83
|
+
### Authentication Options
|
|
84
|
+
|
|
85
|
+
- **OpenRouter** (recommended for latency/speed)
|
|
86
|
+
- **OpenAI API** (direct or compatible endpoints)
|
|
87
|
+
- **Anthropic API** (direct Claude access)
|
|
88
|
+
|
|
89
|
+
## Configuration
|
|
90
|
+
|
|
91
|
+
### Quick Setup
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Interactive configuration
|
|
95
|
+
cc-approve config
|
|
96
|
+
|
|
97
|
+
# Check current setup
|
|
98
|
+
cc-approve doctor
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Manual Configuration
|
|
102
|
+
|
|
103
|
+
Config is stored at `~/.cc-approve/config.json`:
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"llm": {
|
|
108
|
+
"provider": "openai",
|
|
109
|
+
"model": "gpt-4o-mini",
|
|
110
|
+
"apiKey": "sk-...",
|
|
111
|
+
"baseUrl": "https://openrouter.ai/api/v1"
|
|
112
|
+
},
|
|
113
|
+
"cache": {
|
|
114
|
+
"enabled": true,
|
|
115
|
+
"ttlHours": 168
|
|
116
|
+
},
|
|
117
|
+
"logging": {
|
|
118
|
+
"enabled": true,
|
|
119
|
+
"level": "info"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### OpenRouter Setup (Recommended)
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"llm": {
|
|
129
|
+
"provider": "openai",
|
|
130
|
+
"model": "openai/gpt-4o-mini",
|
|
131
|
+
"apiKey": "sk-or-v1-your-key",
|
|
132
|
+
"baseUrl": "https://openrouter.ai/api/v1"
|
|
133
|
+
},
|
|
134
|
+
"cache": {
|
|
135
|
+
"enabled": true,
|
|
136
|
+
"ttlHours": 168
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Environment Variables
|
|
142
|
+
|
|
143
|
+
You can also use environment variables instead of config file:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
export OPENAI_API_KEY=sk-your-key
|
|
147
|
+
export OPENAI_BASE_URL=https://openrouter.ai/api/v1
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## What Gets Auto-Approved?
|
|
151
|
+
|
|
152
|
+
### Always Allowed (No LLM call)
|
|
153
|
+
- **Read operations**: Read, Glob, Grep, LS, WebFetch, WebSearch
|
|
154
|
+
- **Write operations**: Write, Edit, MultiEdit, NotebookEdit
|
|
155
|
+
- **Interaction tools**: TodoWrite, Task, AskUserQuestion
|
|
156
|
+
- **MCP tools**: All `mcp__*` prefixed tools
|
|
157
|
+
|
|
158
|
+
### Always Blocked (No LLM call)
|
|
159
|
+
- **System destruction**: `rm -rf /`, `rm -rf /usr`, `rm -rf ~`
|
|
160
|
+
- **Protected git branches**: `git push --force origin main/master/production/staging/develop`
|
|
161
|
+
- **Disk operations**: `mkfs`, `fdisk --delete`, `dd` to raw devices, `format C:`
|
|
162
|
+
- **Windows destruction**: `rmdir /s /q C:\`, `del /f /s /q C:\`
|
|
163
|
+
- **Malicious patterns**: Fork bombs, credential theft attempts
|
|
164
|
+
|
|
165
|
+
### LLM Analysis Required
|
|
166
|
+
- **Bash commands**: npm, git (non-force), docker, curl, etc.
|
|
167
|
+
- **Unknown tools**: Any tool not in the allow/deny lists
|
|
168
|
+
|
|
169
|
+
## CLI Commands
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
cc-approve permission # Handle PermissionRequest hook (reads stdin)
|
|
173
|
+
cc-approve install # Add hook to Claude Code settings
|
|
174
|
+
cc-approve uninstall # Remove hook from settings
|
|
175
|
+
cc-approve config # Interactive configuration
|
|
176
|
+
cc-approve doctor # Diagnose configuration and connectivity
|
|
177
|
+
cc-approve clear-cache # Clear all cached decisions
|
|
178
|
+
cc-approve status # Show current configuration
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Caching Behavior
|
|
182
|
+
|
|
183
|
+
- **Enabled by default** for optimal performance
|
|
184
|
+
- **Working directory scoped** for safety across projects
|
|
185
|
+
- **TTL expiration** (default 168 hours / 1 week)
|
|
186
|
+
- **Caches only definitive decisions** (allow/deny from LLM)
|
|
187
|
+
- **Instant responses** for repeated operations
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
# Clear cache if needed
|
|
191
|
+
cc-approve clear-cache
|
|
192
|
+
|
|
193
|
+
# Disable caching in config
|
|
194
|
+
{
|
|
195
|
+
"cache": {
|
|
196
|
+
"enabled": false
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## License
|
|
202
|
+
|
|
203
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
npm install -g @malcomsonbrothers/claude-code-permission-hook && cc-approve install && cc-approve config
|
|
209
|
+
```
|
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CacheEntry } from "./types.js";
|
|
2
|
+
export declare function getCachedDecision(toolName: string, toolInput: Record<string, unknown>, projectRoot?: string): CacheEntry | null;
|
|
3
|
+
export declare function setCachedDecision(toolName: string, toolInput: Record<string, unknown>, decision: "allow" | "deny", reason: string, projectRoot?: string): void;
|
|
4
|
+
export declare function clearCache(): number;
|
|
5
|
+
export declare function clearCacheByDecision(decision: "allow" | "deny"): number;
|
|
6
|
+
export declare function clearCacheByKey(hashKey: string): boolean;
|
|
7
|
+
export declare function clearCacheByGrep(substring: string): number;
|
|
8
|
+
export declare function listCacheEntries(projectRoot?: string): CacheEntry[];
|
|
9
|
+
export declare function getCacheStats(): {
|
|
10
|
+
entries: number;
|
|
11
|
+
oldestTimestamp?: number;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAA8B,MAAM,YAAY,CAAC;AA2CpE,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,WAAW,CAAC,EAAE,MAAM,GACnB,UAAU,GAAG,IAAI,CA0BnB;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,QAAQ,EAAE,OAAO,GAAG,MAAM,EAC1B,MAAM,EAAE,MAAM,EACd,WAAW,CAAC,EAAE,MAAM,GACnB,IAAI,CAqBN;AAED,wBAAgB,UAAU,IAAI,MAAM,CAKnC;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAavE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAQxD;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAyB1D;AAED,wBAAgB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE,CAYnE;AAED,wBAAgB,aAAa,IAAI;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAcA"}
|
package/dist/cache.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { createHash } from "crypto";
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { getConfigDir, loadConfig, ensureConfigDir } from "./config.js";
|
|
5
|
+
import { CacheFileSchema } from "./types.js";
|
|
6
|
+
const CACHE_FILE = "approval_cache.json";
|
|
7
|
+
function getCachePath() {
|
|
8
|
+
return join(getConfigDir(), CACHE_FILE);
|
|
9
|
+
}
|
|
10
|
+
function generateCacheKey(toolName, toolInput, projectRoot) {
|
|
11
|
+
const data = JSON.stringify({
|
|
12
|
+
toolName,
|
|
13
|
+
toolInput,
|
|
14
|
+
projectRoot: projectRoot || "",
|
|
15
|
+
});
|
|
16
|
+
return createHash("sha256").update(data).digest("hex");
|
|
17
|
+
}
|
|
18
|
+
function loadCache() {
|
|
19
|
+
const cachePath = getCachePath();
|
|
20
|
+
if (!existsSync(cachePath)) {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const raw = readFileSync(cachePath, "utf-8");
|
|
25
|
+
const parsed = JSON.parse(raw);
|
|
26
|
+
return CacheFileSchema.parse(parsed);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// Corrupted cache, return empty
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function saveCache(cache) {
|
|
34
|
+
ensureConfigDir();
|
|
35
|
+
const cachePath = getCachePath();
|
|
36
|
+
writeFileSync(cachePath, JSON.stringify(cache, null, 2));
|
|
37
|
+
}
|
|
38
|
+
export function getCachedDecision(toolName, toolInput, projectRoot) {
|
|
39
|
+
const config = loadConfig();
|
|
40
|
+
if (!config.cache.enabled) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const key = generateCacheKey(toolName, toolInput, projectRoot);
|
|
44
|
+
const cache = loadCache();
|
|
45
|
+
const entry = cache[key];
|
|
46
|
+
if (!entry) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
// Check TTL
|
|
50
|
+
const ttlMs = config.cache.ttlHours * 60 * 60 * 1000;
|
|
51
|
+
const age = Date.now() - entry.timestamp;
|
|
52
|
+
if (age > ttlMs) {
|
|
53
|
+
// Expired, remove it
|
|
54
|
+
delete cache[key];
|
|
55
|
+
saveCache(cache);
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return entry;
|
|
59
|
+
}
|
|
60
|
+
export function setCachedDecision(toolName, toolInput, decision, reason, projectRoot) {
|
|
61
|
+
const config = loadConfig();
|
|
62
|
+
if (!config.cache.enabled) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const key = generateCacheKey(toolName, toolInput, projectRoot);
|
|
66
|
+
const cache = loadCache();
|
|
67
|
+
const entry = {
|
|
68
|
+
key,
|
|
69
|
+
decision,
|
|
70
|
+
reason,
|
|
71
|
+
timestamp: Date.now(),
|
|
72
|
+
toolName,
|
|
73
|
+
toolInput,
|
|
74
|
+
projectRoot,
|
|
75
|
+
};
|
|
76
|
+
cache[key] = entry;
|
|
77
|
+
saveCache(cache);
|
|
78
|
+
}
|
|
79
|
+
export function clearCache() {
|
|
80
|
+
const cache = loadCache();
|
|
81
|
+
const count = Object.keys(cache).length;
|
|
82
|
+
saveCache({});
|
|
83
|
+
return count;
|
|
84
|
+
}
|
|
85
|
+
export function clearCacheByDecision(decision) {
|
|
86
|
+
const cache = loadCache();
|
|
87
|
+
let removed = 0;
|
|
88
|
+
for (const [key, entry] of Object.entries(cache)) {
|
|
89
|
+
if (entry.decision === decision) {
|
|
90
|
+
delete cache[key];
|
|
91
|
+
removed++;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (removed > 0) {
|
|
95
|
+
saveCache(cache);
|
|
96
|
+
}
|
|
97
|
+
return removed;
|
|
98
|
+
}
|
|
99
|
+
export function clearCacheByKey(hashKey) {
|
|
100
|
+
const cache = loadCache();
|
|
101
|
+
if (cache[hashKey]) {
|
|
102
|
+
delete cache[hashKey];
|
|
103
|
+
saveCache(cache);
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
export function clearCacheByGrep(substring) {
|
|
109
|
+
const cache = loadCache();
|
|
110
|
+
const lowerSub = substring.toLowerCase();
|
|
111
|
+
let removed = 0;
|
|
112
|
+
for (const [key, entry] of Object.entries(cache)) {
|
|
113
|
+
const searchable = [
|
|
114
|
+
entry.toolName,
|
|
115
|
+
entry.reason,
|
|
116
|
+
entry.projectRoot || "",
|
|
117
|
+
JSON.stringify(entry.toolInput || {}),
|
|
118
|
+
]
|
|
119
|
+
.join(" ")
|
|
120
|
+
.toLowerCase();
|
|
121
|
+
if (searchable.includes(lowerSub)) {
|
|
122
|
+
delete cache[key];
|
|
123
|
+
removed++;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (removed > 0) {
|
|
127
|
+
saveCache(cache);
|
|
128
|
+
}
|
|
129
|
+
return removed;
|
|
130
|
+
}
|
|
131
|
+
export function listCacheEntries(projectRoot) {
|
|
132
|
+
const cache = loadCache();
|
|
133
|
+
let entries = Object.values(cache);
|
|
134
|
+
if (projectRoot) {
|
|
135
|
+
entries = entries.filter((e) => e.projectRoot === projectRoot);
|
|
136
|
+
}
|
|
137
|
+
// Sort by timestamp descending (most recent first)
|
|
138
|
+
entries.sort((a, b) => b.timestamp - a.timestamp);
|
|
139
|
+
return entries;
|
|
140
|
+
}
|
|
141
|
+
export function getCacheStats() {
|
|
142
|
+
const cache = loadCache();
|
|
143
|
+
const entries = Object.values(cache);
|
|
144
|
+
if (entries.length === 0) {
|
|
145
|
+
return { entries: 0 };
|
|
146
|
+
}
|
|
147
|
+
const timestamps = entries.map((e) => e.timestamp);
|
|
148
|
+
return {
|
|
149
|
+
entries: entries.length,
|
|
150
|
+
oldestTimestamp: Math.min(...timestamps),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Config } from "./types.js";
|
|
2
|
+
export declare function getConfigDir(): string;
|
|
3
|
+
export declare function getConfigPath(): string;
|
|
4
|
+
export declare function ensureConfigDir(): void;
|
|
5
|
+
export declare function loadConfig(): Config;
|
|
6
|
+
export declare function saveConfig(config: Config): void;
|
|
7
|
+
export declare function updateConfig(updates: Partial<Config>): Config;
|
|
8
|
+
export declare function clearConfigCache(): void;
|
|
9
|
+
export declare function getApiKey(): string | undefined;
|
|
10
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAgB,MAAM,YAAY,CAAC;AAOlD,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,eAAe,IAAI,IAAI,CAItC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAyBnC;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAI/C;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAK7D;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED,wBAAgB,SAAS,IAAI,MAAM,GAAG,SAAS,CAc9C"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
2
|
+
import { homedir } from "os";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { ConfigSchema } from "./types.js";
|
|
5
|
+
const CONFIG_DIR = join(homedir(), ".cc-approve");
|
|
6
|
+
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
7
|
+
let cachedConfig = null;
|
|
8
|
+
export function getConfigDir() {
|
|
9
|
+
return CONFIG_DIR;
|
|
10
|
+
}
|
|
11
|
+
export function getConfigPath() {
|
|
12
|
+
return CONFIG_FILE;
|
|
13
|
+
}
|
|
14
|
+
export function ensureConfigDir() {
|
|
15
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
16
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function loadConfig() {
|
|
20
|
+
if (cachedConfig) {
|
|
21
|
+
return cachedConfig;
|
|
22
|
+
}
|
|
23
|
+
ensureConfigDir();
|
|
24
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
25
|
+
const defaultConfig = ConfigSchema.parse({});
|
|
26
|
+
saveConfig(defaultConfig);
|
|
27
|
+
cachedConfig = defaultConfig;
|
|
28
|
+
return defaultConfig;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const raw = readFileSync(CONFIG_FILE, "utf-8");
|
|
32
|
+
const parsed = JSON.parse(raw);
|
|
33
|
+
cachedConfig = ConfigSchema.parse(parsed);
|
|
34
|
+
return cachedConfig;
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
// If config is corrupted, use defaults
|
|
38
|
+
const defaultConfig = ConfigSchema.parse({});
|
|
39
|
+
cachedConfig = defaultConfig;
|
|
40
|
+
return defaultConfig;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function saveConfig(config) {
|
|
44
|
+
ensureConfigDir();
|
|
45
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
46
|
+
cachedConfig = config;
|
|
47
|
+
}
|
|
48
|
+
export function updateConfig(updates) {
|
|
49
|
+
const current = loadConfig();
|
|
50
|
+
const updated = ConfigSchema.parse({ ...current, ...updates });
|
|
51
|
+
saveConfig(updated);
|
|
52
|
+
return updated;
|
|
53
|
+
}
|
|
54
|
+
export function clearConfigCache() {
|
|
55
|
+
cachedConfig = null;
|
|
56
|
+
}
|
|
57
|
+
export function getApiKey() {
|
|
58
|
+
const config = loadConfig();
|
|
59
|
+
// Check config first, then environment variables
|
|
60
|
+
if (config.llm.apiKey) {
|
|
61
|
+
return config.llm.apiKey;
|
|
62
|
+
}
|
|
63
|
+
// Check common environment variables
|
|
64
|
+
return (process.env.OPENAI_API_KEY ||
|
|
65
|
+
process.env.ANTHROPIC_API_KEY ||
|
|
66
|
+
process.env.LLM_API_KEY);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface FastDecisionResult {
|
|
2
|
+
decision: "allow" | "deny" | "passthrough" | "llm";
|
|
3
|
+
reason?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function checkFastDecision(toolName: string, toolInput: Record<string, unknown>): FastDecisionResult;
|
|
6
|
+
//# sourceMappingURL=fast-decisions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fast-decisions.d.ts","sourceRoot":"","sources":["../src/fast-decisions.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,aAAa,GAAG,KAAK,CAAC;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAmED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,kBAAkB,CAgFpB"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { loadConfig } from "./config.js";
|
|
2
|
+
// Tools that are always safe to auto-approve
|
|
3
|
+
const INSTANT_ALLOW_TOOLS = new Set([
|
|
4
|
+
// Read-only tools
|
|
5
|
+
"Read",
|
|
6
|
+
"Glob",
|
|
7
|
+
"Grep",
|
|
8
|
+
"LS",
|
|
9
|
+
"WebFetch",
|
|
10
|
+
"WebSearch",
|
|
11
|
+
"NotebookRead",
|
|
12
|
+
"BashOutput",
|
|
13
|
+
// Safe write/interaction tools
|
|
14
|
+
"Write",
|
|
15
|
+
"Edit",
|
|
16
|
+
"MultiEdit",
|
|
17
|
+
"NotebookEdit",
|
|
18
|
+
"TodoWrite",
|
|
19
|
+
"Task",
|
|
20
|
+
]);
|
|
21
|
+
// Tools that should ALWAYS passthrough to native dialog (user must see and respond)
|
|
22
|
+
const INSTANT_PASSTHROUGH_TOOLS = new Set([
|
|
23
|
+
"AskUserQuestion", // User MUST see questions and provide their answer
|
|
24
|
+
]);
|
|
25
|
+
// Patterns that should ALWAYS be denied - system destruction
|
|
26
|
+
const INSTANT_DENY_BASH_PATTERNS = [
|
|
27
|
+
// Unix/Linux system root destruction
|
|
28
|
+
/^rm\s+(-[rf]+\s+)*\/$/,
|
|
29
|
+
/^rm\s+(-[rf]+\s+)*\/usr\b/,
|
|
30
|
+
/^rm\s+(-[rf]+\s+)*\/etc\b/,
|
|
31
|
+
/^rm\s+(-[rf]+\s+)*\/bin\b/,
|
|
32
|
+
/^rm\s+(-[rf]+\s+)*\/sbin\b/,
|
|
33
|
+
/^rm\s+(-[rf]+\s+)*\/boot\b/,
|
|
34
|
+
/^rm\s+(-[rf]+\s+)*\/var\b/,
|
|
35
|
+
/^rm\s+(-[rf]+\s+)*\/home\b/,
|
|
36
|
+
/^rm\s+(-[rf]+\s+)*~\/?$/,
|
|
37
|
+
/^rm\s+(-[rf]+\s+)*\$HOME\/?$/,
|
|
38
|
+
// Windows system destruction
|
|
39
|
+
/^(rmdir|rd)\s+\/s\s+\/q\s+[A-Z]:\\$/i,
|
|
40
|
+
/^del\s+(\/[fqs]\s+)+[A-Z]:\\$/i,
|
|
41
|
+
/^del\s+(\/[fqs]\s+)+[A-Z]:\\Windows/i,
|
|
42
|
+
/^del\s+(\/[fqs]\s+)+[A-Z]:\\System32/i,
|
|
43
|
+
// Disk formatting
|
|
44
|
+
/^mkfs\b/,
|
|
45
|
+
/^fdisk\s+.*--delete/,
|
|
46
|
+
/^dd\s+.*of=\/dev\/(sd[a-z]|nvme|hd[a-z])$/,
|
|
47
|
+
/^format\s+[A-Z]:/i,
|
|
48
|
+
// Protected git operations
|
|
49
|
+
/^git\s+push\s+(-f|--force)\s+(origin\s+)?(main|master|production|staging|develop)\b/i,
|
|
50
|
+
/^git\s+push\s+--force\s+(origin\s+)?(main|master|production|staging|develop)\b/i,
|
|
51
|
+
/^git\s+push\s+.*--force-with-lease\s+.*\b(main|master|production)\b/i,
|
|
52
|
+
// Fork bombs and malicious patterns
|
|
53
|
+
/:\(\)\{\s*:\|:&\s*\};:/,
|
|
54
|
+
/\bfork\s*\(\s*\)\s*while/i,
|
|
55
|
+
// Credential theft attempts
|
|
56
|
+
/curl.*\|.*sh.*password/i,
|
|
57
|
+
/wget.*-O.*-.*\|.*bash/,
|
|
58
|
+
/curl.*\/etc\/passwd/,
|
|
59
|
+
/curl.*\/etc\/shadow/,
|
|
60
|
+
// PowerShell destructive
|
|
61
|
+
/Remove-Item\s+.*-Recurse.*[A-Z]:\\$/i,
|
|
62
|
+
/Remove-Item\s+.*-Recurse.*\$env:SystemRoot/i,
|
|
63
|
+
];
|
|
64
|
+
export function checkFastDecision(toolName, toolInput) {
|
|
65
|
+
const config = loadConfig();
|
|
66
|
+
// Check custom deny patterns first
|
|
67
|
+
for (const pattern of config.customDenyPatterns) {
|
|
68
|
+
const regex = new RegExp(pattern);
|
|
69
|
+
if (regex.test(toolName) || regex.test(JSON.stringify(toolInput))) {
|
|
70
|
+
return {
|
|
71
|
+
decision: "deny",
|
|
72
|
+
reason: `Blocked by custom deny pattern: ${pattern}`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Check instant deny patterns for Bash commands
|
|
77
|
+
if (toolName === "Bash") {
|
|
78
|
+
const command = toolInput.command;
|
|
79
|
+
if (command) {
|
|
80
|
+
for (const pattern of INSTANT_DENY_BASH_PATTERNS) {
|
|
81
|
+
if (pattern.test(command)) {
|
|
82
|
+
return {
|
|
83
|
+
decision: "deny",
|
|
84
|
+
reason: `Blocked destructive command pattern: ${pattern.source}`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Check custom allow patterns
|
|
91
|
+
for (const pattern of config.customAllowPatterns) {
|
|
92
|
+
const regex = new RegExp(pattern);
|
|
93
|
+
if (regex.test(toolName)) {
|
|
94
|
+
return {
|
|
95
|
+
decision: "allow",
|
|
96
|
+
reason: `Allowed by custom pattern: ${pattern}`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Check custom passthrough patterns
|
|
101
|
+
for (const pattern of config.customPassthroughPatterns) {
|
|
102
|
+
const regex = new RegExp(pattern);
|
|
103
|
+
if (regex.test(toolName) || regex.test(JSON.stringify(toolInput))) {
|
|
104
|
+
return {
|
|
105
|
+
decision: "passthrough",
|
|
106
|
+
reason: `Passthrough by custom pattern: ${pattern}`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Check instant passthrough tools (user MUST see and respond to these)
|
|
111
|
+
if (INSTANT_PASSTHROUGH_TOOLS.has(toolName)) {
|
|
112
|
+
return {
|
|
113
|
+
decision: "passthrough",
|
|
114
|
+
reason: `Tool '${toolName}' requires user interaction - showing native dialog`,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
// Check instant allow tools
|
|
118
|
+
if (INSTANT_ALLOW_TOOLS.has(toolName)) {
|
|
119
|
+
return {
|
|
120
|
+
decision: "allow",
|
|
121
|
+
reason: `Tool '${toolName}' is in instant-allow list`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// Check MCP tools (generally safe)
|
|
125
|
+
if (toolName.startsWith("mcp__")) {
|
|
126
|
+
return {
|
|
127
|
+
decision: "allow",
|
|
128
|
+
reason: "MCP tools are auto-approved",
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
// Needs LLM analysis
|
|
132
|
+
return {
|
|
133
|
+
decision: "llm",
|
|
134
|
+
reason: "Requires LLM analysis",
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=fast-decisions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fast-decisions.js","sourceRoot":"","sources":["../src/fast-decisions.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|