@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 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
+ ```
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ import('../dist/index.js');
@@ -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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"}
@@ -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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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}