gencode-ai 0.1.1 → 0.1.2
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/.gencode/settings.local.json +7 -0
- package/README.md +11 -11
- package/dist/agent/agent.d.ts +42 -1
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +82 -15
- package/dist/agent/agent.js.map +1 -1
- package/dist/cli/components/App.d.ts +8 -1
- package/dist/cli/components/App.d.ts.map +1 -1
- package/dist/cli/components/App.js +231 -29
- package/dist/cli/components/App.js.map +1 -1
- package/dist/cli/components/CommandSuggestions.d.ts.map +1 -1
- package/dist/cli/components/CommandSuggestions.js +2 -0
- package/dist/cli/components/CommandSuggestions.js.map +1 -1
- package/dist/cli/components/Header.d.ts +1 -1
- package/dist/cli/components/Header.d.ts.map +1 -1
- package/dist/cli/components/Header.js +4 -6
- package/dist/cli/components/Header.js.map +1 -1
- package/dist/cli/components/Logo.d.ts +1 -0
- package/dist/cli/components/Logo.d.ts.map +1 -1
- package/dist/cli/components/Logo.js +16 -3
- package/dist/cli/components/Logo.js.map +1 -1
- package/dist/cli/components/Messages.d.ts +4 -4
- package/dist/cli/components/Messages.d.ts.map +1 -1
- package/dist/cli/components/Messages.js +51 -25
- package/dist/cli/components/Messages.js.map +1 -1
- package/dist/cli/components/PermissionPrompt.d.ts +60 -0
- package/dist/cli/components/PermissionPrompt.d.ts.map +1 -0
- package/dist/cli/components/PermissionPrompt.js +192 -0
- package/dist/cli/components/PermissionPrompt.js.map +1 -0
- package/dist/cli/components/ProviderManager.js +3 -3
- package/dist/cli/components/ProviderManager.js.map +1 -1
- package/dist/cli/components/Spinner.d.ts +7 -2
- package/dist/cli/components/Spinner.d.ts.map +1 -1
- package/dist/cli/components/Spinner.js +116 -25
- package/dist/cli/components/Spinner.js.map +1 -1
- package/dist/cli/components/TodoList.d.ts +7 -0
- package/dist/cli/components/TodoList.d.ts.map +1 -0
- package/dist/cli/components/TodoList.js +34 -0
- package/dist/cli/components/TodoList.js.map +1 -0
- package/dist/cli/components/index.d.ts +1 -0
- package/dist/cli/components/index.d.ts.map +1 -1
- package/dist/cli/components/index.js +1 -0
- package/dist/cli/components/index.js.map +1 -1
- package/dist/cli/index.js +47 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/config/index.d.ts +13 -4
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +18 -3
- package/dist/config/index.js.map +1 -1
- package/dist/config/levels.d.ts +49 -0
- package/dist/config/levels.d.ts.map +1 -0
- package/dist/config/levels.js +222 -0
- package/dist/config/levels.js.map +1 -0
- package/dist/config/loader.d.ts +46 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +153 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/manager.d.ts +115 -15
- package/dist/config/manager.d.ts.map +1 -1
- package/dist/config/manager.js +260 -34
- package/dist/config/manager.js.map +1 -1
- package/dist/config/manager.test.d.ts +5 -0
- package/dist/config/manager.test.d.ts.map +1 -0
- package/dist/config/manager.test.js +192 -0
- package/dist/config/manager.test.js.map +1 -0
- package/dist/config/merger.d.ts +56 -0
- package/dist/config/merger.d.ts.map +1 -0
- package/dist/config/merger.js +177 -0
- package/dist/config/merger.js.map +1 -0
- package/dist/config/test-utils.d.ts +24 -0
- package/dist/config/test-utils.d.ts.map +1 -0
- package/dist/config/test-utils.js +55 -0
- package/dist/config/test-utils.js.map +1 -0
- package/dist/config/types.d.ts +78 -9
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +52 -2
- package/dist/config/types.js.map +1 -1
- package/dist/memory/import-resolver.d.ts +46 -0
- package/dist/memory/import-resolver.d.ts.map +1 -0
- package/dist/memory/import-resolver.js +117 -0
- package/dist/memory/import-resolver.js.map +1 -0
- package/dist/memory/index.d.ts +7 -6
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/index.js +7 -5
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/init-prompt.d.ts +22 -0
- package/dist/memory/init-prompt.d.ts.map +1 -0
- package/dist/memory/init-prompt.js +103 -0
- package/dist/memory/init-prompt.js.map +1 -0
- package/dist/memory/memory-manager.d.ts +119 -0
- package/dist/memory/memory-manager.d.ts.map +1 -0
- package/dist/memory/memory-manager.js +587 -0
- package/dist/memory/memory-manager.js.map +1 -0
- package/dist/memory/rules-parser.d.ts +38 -0
- package/dist/memory/rules-parser.d.ts.map +1 -0
- package/dist/memory/rules-parser.js +69 -0
- package/dist/memory/rules-parser.js.map +1 -0
- package/dist/memory/test-utils.d.ts +20 -0
- package/dist/memory/test-utils.d.ts.map +1 -0
- package/dist/memory/test-utils.js +44 -0
- package/dist/memory/test-utils.js.map +1 -0
- package/dist/memory/types.d.ts +70 -63
- package/dist/memory/types.d.ts.map +1 -1
- package/dist/memory/types.js +42 -2
- package/dist/memory/types.js.map +1 -1
- package/dist/permissions/audit.d.ts +82 -0
- package/dist/permissions/audit.d.ts.map +1 -0
- package/dist/permissions/audit.js +229 -0
- package/dist/permissions/audit.js.map +1 -0
- package/dist/permissions/index.d.ts +11 -1
- package/dist/permissions/index.d.ts.map +1 -1
- package/dist/permissions/index.js +15 -0
- package/dist/permissions/index.js.map +1 -1
- package/dist/permissions/manager.d.ts +149 -13
- package/dist/permissions/manager.d.ts.map +1 -1
- package/dist/permissions/manager.js +480 -35
- package/dist/permissions/manager.js.map +1 -1
- package/dist/permissions/manager.test.d.ts +5 -0
- package/dist/permissions/manager.test.d.ts.map +1 -0
- package/dist/permissions/manager.test.js +213 -0
- package/dist/permissions/manager.test.js.map +1 -0
- package/dist/permissions/persistence.d.ts +74 -0
- package/dist/permissions/persistence.d.ts.map +1 -0
- package/dist/permissions/persistence.js +248 -0
- package/dist/permissions/persistence.js.map +1 -0
- package/dist/permissions/persistence.test.d.ts +5 -0
- package/dist/permissions/persistence.test.d.ts.map +1 -0
- package/dist/permissions/persistence.test.js +171 -0
- package/dist/permissions/persistence.test.js.map +1 -0
- package/dist/permissions/prompt-matcher.d.ts +64 -0
- package/dist/permissions/prompt-matcher.d.ts.map +1 -0
- package/dist/permissions/prompt-matcher.js +415 -0
- package/dist/permissions/prompt-matcher.js.map +1 -0
- package/dist/permissions/prompt-matcher.test.d.ts +5 -0
- package/dist/permissions/prompt-matcher.test.d.ts.map +1 -0
- package/dist/permissions/prompt-matcher.test.js +107 -0
- package/dist/permissions/prompt-matcher.test.js.map +1 -0
- package/dist/permissions/types.d.ts +157 -0
- package/dist/permissions/types.d.ts.map +1 -1
- package/dist/permissions/types.js +43 -8
- package/dist/permissions/types.js.map +1 -1
- package/dist/prompts/index.d.ts +92 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +241 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/tools/builtin/bash.d.ts.map +1 -1
- package/dist/tools/builtin/bash.js +2 -1
- package/dist/tools/builtin/bash.js.map +1 -1
- package/dist/tools/builtin/edit.d.ts.map +1 -1
- package/dist/tools/builtin/edit.js +2 -1
- package/dist/tools/builtin/edit.js.map +1 -1
- package/dist/tools/builtin/glob.d.ts.map +1 -1
- package/dist/tools/builtin/glob.js +2 -1
- package/dist/tools/builtin/glob.js.map +1 -1
- package/dist/tools/builtin/grep.d.ts.map +1 -1
- package/dist/tools/builtin/grep.js +2 -1
- package/dist/tools/builtin/grep.js.map +1 -1
- package/dist/tools/builtin/read.d.ts.map +1 -1
- package/dist/tools/builtin/read.js +2 -1
- package/dist/tools/builtin/read.js.map +1 -1
- package/dist/tools/builtin/todowrite.d.ts +15 -0
- package/dist/tools/builtin/todowrite.d.ts.map +1 -0
- package/dist/tools/builtin/todowrite.js +88 -0
- package/dist/tools/builtin/todowrite.js.map +1 -0
- package/dist/tools/builtin/webfetch.d.ts.map +1 -1
- package/dist/tools/builtin/webfetch.js +2 -5
- package/dist/tools/builtin/webfetch.js.map +1 -1
- package/dist/tools/builtin/websearch.d.ts.map +1 -1
- package/dist/tools/builtin/websearch.js +2 -16
- package/dist/tools/builtin/websearch.js.map +1 -1
- package/dist/tools/builtin/write.d.ts.map +1 -1
- package/dist/tools/builtin/write.js +2 -1
- package/dist/tools/builtin/write.js.map +1 -1
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/types.d.ts +22 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js +8 -0
- package/dist/tools/types.js.map +1 -1
- package/docs/config-system-comparison.md +707 -0
- package/docs/memory-system.md +238 -0
- package/docs/permissions.md +368 -0
- package/docs/proposals/0005-todo-system.md +350 -85
- package/docs/proposals/0006-memory-system.md +11 -10
- package/docs/proposals/0012-ask-user-question.md +941 -206
- package/docs/proposals/0023-permission-enhancements.md +61 -2
- package/docs/proposals/0041-configuration-system.md +33 -2
- package/docs/proposals/0042-prompt-optimization.md +866 -0
- package/docs/proposals/README.md +6 -5
- package/jest.config.js +26 -0
- package/package.json +8 -2
- package/src/agent/agent.ts +111 -16
- package/src/cli/components/App.tsx +309 -36
- package/src/cli/components/CommandSuggestions.tsx +2 -0
- package/src/cli/components/Header.tsx +11 -17
- package/src/cli/components/Logo.tsx +76 -9
- package/src/cli/components/Messages.tsx +73 -53
- package/src/cli/components/PermissionPrompt.tsx +388 -0
- package/src/cli/components/ProviderManager.tsx +5 -5
- package/src/cli/components/Spinner.tsx +138 -25
- package/src/cli/components/TodoList.tsx +54 -0
- package/src/cli/components/index.ts +6 -0
- package/src/cli/index.tsx +54 -6
- package/src/config/index.ts +78 -4
- package/src/config/levels.test.ts +163 -0
- package/src/config/levels.ts +285 -0
- package/src/config/loader.test.ts +120 -0
- package/src/config/loader.ts +178 -0
- package/src/config/manager.test.ts +215 -0
- package/src/config/manager.ts +328 -40
- package/src/config/merger.test.ts +360 -0
- package/src/config/merger.ts +221 -0
- package/src/config/test-utils.ts +79 -0
- package/src/config/types.ts +152 -9
- package/src/memory/import-resolver.test.ts +117 -0
- package/src/memory/import-resolver.ts +149 -0
- package/src/memory/index.ts +11 -0
- package/src/memory/init-prompt.ts +113 -0
- package/src/memory/memory-manager.test.ts +198 -0
- package/src/memory/memory-manager.ts +716 -0
- package/src/memory/rules-parser.test.ts +182 -0
- package/src/memory/rules-parser.ts +82 -0
- package/src/memory/test-utils.ts +60 -0
- package/src/memory/types.ts +119 -0
- package/src/permissions/audit.ts +284 -0
- package/src/permissions/index.ts +20 -1
- package/src/permissions/manager.test.ts +260 -0
- package/src/permissions/manager.ts +592 -40
- package/src/permissions/persistence.test.ts +220 -0
- package/src/permissions/persistence.ts +301 -0
- package/src/permissions/prompt-matcher.test.ts +213 -0
- package/src/permissions/prompt-matcher.ts +472 -0
- package/src/permissions/types.ts +236 -8
- package/src/prompts/index.test.ts +279 -0
- package/src/prompts/index.ts +306 -0
- package/src/prompts/system/anthropic.txt +29 -0
- package/src/prompts/system/base.txt +124 -0
- package/src/prompts/system/gemini.txt +35 -0
- package/src/prompts/system/generic.txt +128 -0
- package/src/prompts/system/openai.txt +29 -0
- package/src/prompts/tools/bash.txt +60 -0
- package/src/prompts/tools/edit.txt +29 -0
- package/src/prompts/tools/glob.txt +35 -0
- package/src/prompts/tools/grep.txt +43 -0
- package/src/prompts/tools/read.txt +22 -0
- package/src/prompts/tools/todowrite.txt +71 -0
- package/src/prompts/tools/webfetch.txt +34 -0
- package/src/prompts/tools/websearch.txt +41 -0
- package/src/prompts/tools/write.txt +23 -0
- package/src/tools/builtin/bash.ts +2 -1
- package/src/tools/builtin/edit.ts +2 -1
- package/src/tools/builtin/glob.ts +2 -1
- package/src/tools/builtin/grep.ts +2 -1
- package/src/tools/builtin/read.ts +2 -1
- package/src/tools/builtin/todowrite.ts +102 -0
- package/src/tools/builtin/webfetch.ts +2 -5
- package/src/tools/builtin/websearch.ts +2 -16
- package/src/tools/builtin/write.ts +2 -1
- package/src/tools/index.ts +4 -0
- package/src/tools/types.ts +12 -0
- package/tsconfig.json +1 -1
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PermissionPersistence Tests
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from 'fs/promises';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import * as os from 'os';
|
|
7
|
+
import { PermissionPersistence } from './persistence.js';
|
|
8
|
+
describe('PermissionPersistence', () => {
|
|
9
|
+
let tempDir;
|
|
10
|
+
let projectDir;
|
|
11
|
+
beforeEach(async () => {
|
|
12
|
+
// Create temp directories for testing
|
|
13
|
+
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'gencode-perm-test-'));
|
|
14
|
+
projectDir = path.join(tempDir, 'project');
|
|
15
|
+
await fs.mkdir(projectDir, { recursive: true });
|
|
16
|
+
});
|
|
17
|
+
afterEach(async () => {
|
|
18
|
+
// Cleanup temp directories
|
|
19
|
+
await fs.rm(tempDir, { recursive: true, force: true });
|
|
20
|
+
});
|
|
21
|
+
describe('addRule', () => {
|
|
22
|
+
it('should add a rule to project scope', async () => {
|
|
23
|
+
const projectPermDir = path.join(projectDir, '.claude');
|
|
24
|
+
await fs.mkdir(projectPermDir, { recursive: true });
|
|
25
|
+
const persistence = new PermissionPersistence(projectDir);
|
|
26
|
+
const rule = await persistence.addRule('WebSearch', 'auto', {
|
|
27
|
+
scope: 'project',
|
|
28
|
+
});
|
|
29
|
+
expect(rule.id).toBeDefined();
|
|
30
|
+
expect(rule.tool).toBe('WebSearch');
|
|
31
|
+
expect(rule.mode).toBe('auto');
|
|
32
|
+
expect(rule.scope).toBe('project');
|
|
33
|
+
});
|
|
34
|
+
it('should add a rule with pattern', async () => {
|
|
35
|
+
const projectPermDir = path.join(projectDir, '.claude');
|
|
36
|
+
await fs.mkdir(projectPermDir, { recursive: true });
|
|
37
|
+
const persistence = new PermissionPersistence(projectDir);
|
|
38
|
+
const rule = await persistence.addRule('Bash', 'auto', {
|
|
39
|
+
pattern: 'git add:*',
|
|
40
|
+
scope: 'project',
|
|
41
|
+
description: 'Test rule',
|
|
42
|
+
});
|
|
43
|
+
expect(rule.pattern).toBe('git add:*');
|
|
44
|
+
expect(rule.description).toBe('Test rule');
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe('getRules', () => {
|
|
48
|
+
it('should return empty array for non-existent project file', async () => {
|
|
49
|
+
const projectPermDir = path.join(projectDir, '.claude');
|
|
50
|
+
await fs.mkdir(projectPermDir, { recursive: true });
|
|
51
|
+
const persistence = new PermissionPersistence(projectDir);
|
|
52
|
+
const rules = await persistence.getRules('project');
|
|
53
|
+
expect(rules).toEqual([]);
|
|
54
|
+
});
|
|
55
|
+
it('should return saved project rules', async () => {
|
|
56
|
+
const projectPermDir = path.join(projectDir, '.claude');
|
|
57
|
+
await fs.mkdir(projectPermDir, { recursive: true });
|
|
58
|
+
const persistence = new PermissionPersistence(projectDir);
|
|
59
|
+
await persistence.addRule('Bash', 'auto', {
|
|
60
|
+
pattern: 'npm test:*',
|
|
61
|
+
scope: 'project',
|
|
62
|
+
});
|
|
63
|
+
const rules = await persistence.getRules('project');
|
|
64
|
+
expect(rules.length).toBe(1);
|
|
65
|
+
expect(rules[0].tool).toBe('Bash');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe('removeRule', () => {
|
|
69
|
+
it('should remove a rule by ID', async () => {
|
|
70
|
+
const projectPermDir = path.join(projectDir, '.claude');
|
|
71
|
+
await fs.mkdir(projectPermDir, { recursive: true });
|
|
72
|
+
const persistence = new PermissionPersistence(projectDir);
|
|
73
|
+
const rule = await persistence.addRule('Bash', 'auto', {
|
|
74
|
+
pattern: 'npm:*',
|
|
75
|
+
scope: 'project',
|
|
76
|
+
});
|
|
77
|
+
const removed = await persistence.removeRule(rule.id, 'project');
|
|
78
|
+
expect(removed).toBe(true);
|
|
79
|
+
const rules = await persistence.getRules('project');
|
|
80
|
+
expect(rules.length).toBe(0);
|
|
81
|
+
});
|
|
82
|
+
it('should return false for non-existent rule', async () => {
|
|
83
|
+
const projectPermDir = path.join(projectDir, '.claude');
|
|
84
|
+
await fs.mkdir(projectPermDir, { recursive: true });
|
|
85
|
+
const persistence = new PermissionPersistence(projectDir);
|
|
86
|
+
const removed = await persistence.removeRule('non-existent-id', 'project');
|
|
87
|
+
expect(removed).toBe(false);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
describe('parseSettingsPermissions', () => {
|
|
91
|
+
it('should parse allow rules', () => {
|
|
92
|
+
const persistence = new PermissionPersistence(projectDir);
|
|
93
|
+
const rules = persistence.parseSettingsPermissions({
|
|
94
|
+
allow: ['Bash(git add:*)', 'WebSearch'],
|
|
95
|
+
});
|
|
96
|
+
expect(rules.length).toBe(2);
|
|
97
|
+
expect(rules[0].tool).toBe('Bash');
|
|
98
|
+
expect(rules[0].mode).toBe('auto');
|
|
99
|
+
expect(rules[0].pattern).toBe('git add:*');
|
|
100
|
+
expect(rules[1].tool).toBe('WebSearch');
|
|
101
|
+
expect(rules[1].mode).toBe('auto');
|
|
102
|
+
});
|
|
103
|
+
it('should parse ask rules', () => {
|
|
104
|
+
const persistence = new PermissionPersistence(projectDir);
|
|
105
|
+
const rules = persistence.parseSettingsPermissions({
|
|
106
|
+
ask: ['Bash(npm run:*)'],
|
|
107
|
+
});
|
|
108
|
+
expect(rules.length).toBe(1);
|
|
109
|
+
expect(rules[0].tool).toBe('Bash');
|
|
110
|
+
expect(rules[0].mode).toBe('confirm');
|
|
111
|
+
expect(rules[0].pattern).toBe('npm run:*');
|
|
112
|
+
});
|
|
113
|
+
it('should parse deny rules', () => {
|
|
114
|
+
const persistence = new PermissionPersistence(projectDir);
|
|
115
|
+
const rules = persistence.parseSettingsPermissions({
|
|
116
|
+
deny: ['Bash(rm -rf:*)'],
|
|
117
|
+
});
|
|
118
|
+
expect(rules.length).toBe(1);
|
|
119
|
+
expect(rules[0].tool).toBe('Bash');
|
|
120
|
+
expect(rules[0].mode).toBe('deny');
|
|
121
|
+
expect(rules[0].pattern).toBe('rm -rf:*');
|
|
122
|
+
});
|
|
123
|
+
it('should parse mixed rules', () => {
|
|
124
|
+
const persistence = new PermissionPersistence(projectDir);
|
|
125
|
+
const rules = persistence.parseSettingsPermissions({
|
|
126
|
+
allow: ['Bash(git:*)'],
|
|
127
|
+
ask: ['Bash(npm run:*)'],
|
|
128
|
+
deny: ['Bash(rm -rf:*)'],
|
|
129
|
+
});
|
|
130
|
+
expect(rules.length).toBe(3);
|
|
131
|
+
const allowRule = rules.find(r => r.pattern === 'git:*');
|
|
132
|
+
const askRule = rules.find(r => r.pattern === 'npm run:*');
|
|
133
|
+
const denyRule = rules.find(r => r.pattern === 'rm -rf:*');
|
|
134
|
+
expect(allowRule?.mode).toBe('auto');
|
|
135
|
+
expect(askRule?.mode).toBe('confirm');
|
|
136
|
+
expect(denyRule?.mode).toBe('deny');
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
describe('persistedToRuntime', () => {
|
|
140
|
+
it('should convert persisted rules to runtime format', () => {
|
|
141
|
+
const persistence = new PermissionPersistence(projectDir);
|
|
142
|
+
const persisted = [
|
|
143
|
+
{
|
|
144
|
+
id: 'test-id',
|
|
145
|
+
tool: 'Bash',
|
|
146
|
+
pattern: 'git:*',
|
|
147
|
+
mode: 'auto',
|
|
148
|
+
scope: 'global',
|
|
149
|
+
createdAt: new Date().toISOString(),
|
|
150
|
+
description: 'Test',
|
|
151
|
+
},
|
|
152
|
+
];
|
|
153
|
+
const runtime = persistence.persistedToRuntime(persisted);
|
|
154
|
+
expect(runtime.length).toBe(1);
|
|
155
|
+
expect(runtime[0].tool).toBe('Bash');
|
|
156
|
+
expect(runtime[0].mode).toBe('auto');
|
|
157
|
+
expect(runtime[0].pattern).toBe('git:*');
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe('clearRules', () => {
|
|
161
|
+
it('should clear all rules for a scope', async () => {
|
|
162
|
+
const persistence = new PermissionPersistence(projectDir);
|
|
163
|
+
await persistence.addRule('Bash', 'auto', { scope: 'global' });
|
|
164
|
+
await persistence.addRule('WebSearch', 'auto', { scope: 'global' });
|
|
165
|
+
await persistence.clearRules('global');
|
|
166
|
+
const rules = await persistence.getRules('global');
|
|
167
|
+
expect(rules.length).toBe(0);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
//# sourceMappingURL=persistence.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence.test.js","sourceRoot":"","sources":["../../src/permissions/persistence.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,IAAI,OAAe,CAAC;IACpB,IAAI,UAAkB,CAAC;IAEvB,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,sCAAsC;QACtC,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,oBAAoB,CAAC,CAAC,CAAC;QACzE,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAE3C,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,2BAA2B;QAC3B,MAAM,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;QACvB,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;YACxD,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAEpD,MAAM,WAAW,GAAG,IAAI,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAE1D,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE;gBAC1D,KAAK,EAAE,SAAS;aACjB,CAAC,CAAC;YAEH,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACpC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC/B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;YACxD,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAEpD,MAAM,WAAW,GAAG,IAAI,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAE1D,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE;gBACrD,OAAO,EAAE,WAAW;gBACpB,KAAK,EAAE,SAAS;gBAChB,WAAW,EAAE,WAAW;aACzB,CAAC,CAAC;YAEH,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACvC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;QACxB,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;YACvE,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;YACxD,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAEpD,MAAM,WAAW,GAAG,IAAI,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAE1D,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YACpD,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YACjD,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;YACxD,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAEpD,MAAM,WAAW,GAAG,IAAI,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAE1D,MAAM,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE;gBACxC,OAAO,EAAE,YAAY;gBACrB,KAAK,EAAE,SAAS;aACjB,CAAC,CAAC;YAEH,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YACpD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC7B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;QAC1B,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;YAC1C,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;YACxD,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAEpD,MAAM,WAAW,GAAG,IAAI,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAE1D,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE;gBACrD,OAAO,EAAE,OAAO;gBAChB,KAAK,EAAE,SAAS;aACjB,CAAC,CAAC;YAEH,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;YACjE,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAE3B,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YACpD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;YACzD,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;YACxD,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAEpD,MAAM,WAAW,GAAG,IAAI,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAE1D,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAC;YAC3E,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACxC,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;YAClC,MAAM,WAAW,GAAG,IAAI,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAE1D,MAAM,KAAK,GAAG,WAAW,CAAC,wBAAwB,CAAC;gBACjD,KAAK,EAAE,CAAC,iBAAiB,EAAE,WAAW,CAAC;aACxC,CAAC,CAAC;YAEH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC7B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACnC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACnC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC3C,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACxC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;YAChC,MAAM,WAAW,GAAG,IAAI,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAE1D,MAAM,KAAK,GAAG,WAAW,CAAC,wBAAwB,CAAC;gBACjD,GAAG,EAAE,CAAC,iBAAiB,CAAC;aACzB,CAAC,CAAC;YAEH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC7B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACnC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;YACjC,MAAM,WAAW,GAAG,IAAI,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAE1D,MAAM,KAAK,GAAG,WAAW,CAAC,wBAAwB,CAAC;gBACjD,IAAI,EAAE,CAAC,gBAAgB,CAAC;aACzB,CAAC,CAAC;YAEH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC7B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACnC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACnC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;YAClC,MAAM,WAAW,GAAG,IAAI,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAE1D,MAAM,KAAK,GAAG,WAAW,CAAC,wBAAwB,CAAC;gBACjD,KAAK,EAAE,CAAC,aAAa,CAAC;gBACtB,GAAG,EAAE,CAAC,iBAAiB,CAAC;gBACxB,IAAI,EAAE,CAAC,gBAAgB,CAAC;aACzB,CAAC,CAAC;YAEH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAE7B,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC;YACzD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,WAAW,CAAC,CAAC;YAC3D,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC;YAE3D,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,WAAW,GAAG,IAAI,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAE1D,MAAM,SAAS,GAAG;gBAChB;oBACE,EAAE,EAAE,SAAS;oBACb,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE,OAAO;oBAChB,IAAI,EAAE,MAAe;oBACrB,KAAK,EAAE,QAAiB;oBACxB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBACnC,WAAW,EAAE,MAAM;iBACpB;aACF,CAAC;YAEF,MAAM,OAAO,GAAG,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;YAE1D,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;QAC1B,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,MAAM,WAAW,GAAG,IAAI,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAE1D,MAAM,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC/D,MAAM,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;YAEpE,MAAM,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAEvC,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACnD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Matcher - Semantic permission matching for Claude Code style prompts
|
|
3
|
+
*
|
|
4
|
+
* Matches semantic descriptions like "run tests" to actual commands like "npm test".
|
|
5
|
+
* Used for ExitPlanMode allowedPrompts feature.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Pattern matcher function type
|
|
9
|
+
*/
|
|
10
|
+
type PatternMatcher = (input: unknown) => boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Prompt Matcher class
|
|
13
|
+
* Matches semantic permission prompts to actual tool inputs
|
|
14
|
+
*/
|
|
15
|
+
export declare class PromptMatcher {
|
|
16
|
+
private customPatterns;
|
|
17
|
+
/**
|
|
18
|
+
* Register a custom pattern
|
|
19
|
+
*/
|
|
20
|
+
registerPattern(prompt: string, matcher: PatternMatcher): void;
|
|
21
|
+
/**
|
|
22
|
+
* Check if input matches a semantic prompt
|
|
23
|
+
*/
|
|
24
|
+
matches(prompt: string, input: unknown): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Fuzzy keyword-based matching for custom prompts
|
|
27
|
+
*/
|
|
28
|
+
private fuzzyMatch;
|
|
29
|
+
/**
|
|
30
|
+
* Convert input to searchable string
|
|
31
|
+
*/
|
|
32
|
+
private inputToString;
|
|
33
|
+
/**
|
|
34
|
+
* Get list of available built-in patterns
|
|
35
|
+
*/
|
|
36
|
+
getBuiltinPatterns(): string[];
|
|
37
|
+
/**
|
|
38
|
+
* Get list of custom patterns
|
|
39
|
+
*/
|
|
40
|
+
getCustomPatterns(): string[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Pattern string parser for Claude Code style patterns
|
|
44
|
+
* Parses "Bash(git add:*)" into { tool: "Bash", pattern: "git add:*" }
|
|
45
|
+
*/
|
|
46
|
+
export declare function parsePatternString(pattern: string): {
|
|
47
|
+
tool: string;
|
|
48
|
+
pattern?: string;
|
|
49
|
+
} | null;
|
|
50
|
+
/**
|
|
51
|
+
* Check if an input matches a pattern string
|
|
52
|
+
* Pattern format: "git add:*" or "npm install:*"
|
|
53
|
+
*
|
|
54
|
+
* Supports:
|
|
55
|
+
* - "git:*" - prefix matching (: becomes whitespace)
|
|
56
|
+
* - "npm *" - wildcard matching
|
|
57
|
+
* - "* install" - suffix matching
|
|
58
|
+
* - "git * main" - middle wildcard
|
|
59
|
+
* - Shell operator awareness: "safe-cmd:*" won't match "safe-cmd && malicious-cmd"
|
|
60
|
+
* - Path patterns for Read/Edit: "src/**", "~/.zshrc"
|
|
61
|
+
*/
|
|
62
|
+
export declare function matchesPatternString(pattern: string, input: unknown, tool?: string): boolean;
|
|
63
|
+
export {};
|
|
64
|
+
//# sourceMappingURL=prompt-matcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-matcher.d.ts","sourceRoot":"","sources":["../../src/permissions/prompt-matcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,KAAK,cAAc,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;AAgOlD;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,cAAc,CAA0C;IAEhE;;OAEG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI;IAI9D;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO;IAmBhD;;OAEG;IACH,OAAO,CAAC,UAAU;IAiBlB;;OAEG;IACH,OAAO,CAAC,aAAa;IAwBrB;;OAEG;IACH,kBAAkB,IAAI,MAAM,EAAE;IAI9B;;OAEG;IACH,iBAAiB,IAAI,MAAM,EAAE;CAG9B;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAS7F;AAyED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAyC5F"}
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Matcher - Semantic permission matching for Claude Code style prompts
|
|
3
|
+
*
|
|
4
|
+
* Matches semantic descriptions like "run tests" to actual commands like "npm test".
|
|
5
|
+
* Used for ExitPlanMode allowedPrompts feature.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Built-in semantic patterns for common development operations
|
|
9
|
+
*/
|
|
10
|
+
const BUILTIN_PATTERNS = new Map();
|
|
11
|
+
/**
|
|
12
|
+
* Command extraction helpers
|
|
13
|
+
*/
|
|
14
|
+
function getCommand(input) {
|
|
15
|
+
if (typeof input === 'string')
|
|
16
|
+
return input;
|
|
17
|
+
if (input && typeof input === 'object' && 'command' in input) {
|
|
18
|
+
return String(input.command);
|
|
19
|
+
}
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
22
|
+
function getFilePath(input) {
|
|
23
|
+
if (typeof input === 'string')
|
|
24
|
+
return input;
|
|
25
|
+
if (input && typeof input === 'object') {
|
|
26
|
+
const obj = input;
|
|
27
|
+
return String(obj.file_path || obj.filePath || obj.path || '');
|
|
28
|
+
}
|
|
29
|
+
return '';
|
|
30
|
+
}
|
|
31
|
+
function getUrl(input) {
|
|
32
|
+
if (typeof input === 'string')
|
|
33
|
+
return input;
|
|
34
|
+
if (input && typeof input === 'object' && 'url' in input) {
|
|
35
|
+
return String(input.url);
|
|
36
|
+
}
|
|
37
|
+
return '';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Initialize built-in semantic patterns
|
|
41
|
+
*/
|
|
42
|
+
function initBuiltinPatterns() {
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// Testing
|
|
45
|
+
// ============================================================================
|
|
46
|
+
BUILTIN_PATTERNS.set('run tests', (input) => {
|
|
47
|
+
const cmd = getCommand(input).toLowerCase();
|
|
48
|
+
return (cmd.startsWith('npm test') ||
|
|
49
|
+
cmd.startsWith('npm run test') ||
|
|
50
|
+
cmd.startsWith('yarn test') ||
|
|
51
|
+
cmd.startsWith('pnpm test') ||
|
|
52
|
+
cmd.startsWith('bun test') ||
|
|
53
|
+
cmd.startsWith('pytest') ||
|
|
54
|
+
cmd.startsWith('python -m pytest') ||
|
|
55
|
+
cmd.startsWith('go test') ||
|
|
56
|
+
cmd.startsWith('jest') ||
|
|
57
|
+
cmd.startsWith('vitest') ||
|
|
58
|
+
cmd.startsWith('mocha') ||
|
|
59
|
+
cmd.startsWith('cargo test') ||
|
|
60
|
+
cmd.startsWith('make test') ||
|
|
61
|
+
cmd.includes('npm run test') ||
|
|
62
|
+
cmd.includes('npx jest') ||
|
|
63
|
+
cmd.includes('npx vitest'));
|
|
64
|
+
});
|
|
65
|
+
// ============================================================================
|
|
66
|
+
// Dependencies
|
|
67
|
+
// ============================================================================
|
|
68
|
+
BUILTIN_PATTERNS.set('install dependencies', (input) => {
|
|
69
|
+
const cmd = getCommand(input).toLowerCase();
|
|
70
|
+
return (cmd.startsWith('npm install') ||
|
|
71
|
+
cmd.startsWith('npm i') ||
|
|
72
|
+
cmd.startsWith('npm ci') ||
|
|
73
|
+
cmd.startsWith('yarn install') ||
|
|
74
|
+
cmd.startsWith('yarn add') ||
|
|
75
|
+
cmd.startsWith('pnpm install') ||
|
|
76
|
+
cmd.startsWith('pnpm add') ||
|
|
77
|
+
cmd.startsWith('bun install') ||
|
|
78
|
+
cmd.startsWith('bun add') ||
|
|
79
|
+
cmd.startsWith('pip install') ||
|
|
80
|
+
cmd.startsWith('pip3 install') ||
|
|
81
|
+
cmd.startsWith('poetry install') ||
|
|
82
|
+
cmd.startsWith('go mod download') ||
|
|
83
|
+
cmd.startsWith('go get') ||
|
|
84
|
+
cmd.startsWith('cargo build') ||
|
|
85
|
+
cmd.startsWith('cargo fetch') ||
|
|
86
|
+
cmd.startsWith('bundle install') ||
|
|
87
|
+
cmd.startsWith('composer install'));
|
|
88
|
+
});
|
|
89
|
+
// ============================================================================
|
|
90
|
+
// Building
|
|
91
|
+
// ============================================================================
|
|
92
|
+
BUILTIN_PATTERNS.set('build the project', (input) => {
|
|
93
|
+
const cmd = getCommand(input).toLowerCase();
|
|
94
|
+
return (cmd.startsWith('npm run build') ||
|
|
95
|
+
cmd.startsWith('yarn build') ||
|
|
96
|
+
cmd.startsWith('pnpm build') ||
|
|
97
|
+
cmd.startsWith('bun run build') ||
|
|
98
|
+
cmd.startsWith('make') ||
|
|
99
|
+
cmd.startsWith('go build') ||
|
|
100
|
+
cmd.startsWith('cargo build') ||
|
|
101
|
+
cmd.startsWith('mvn package') ||
|
|
102
|
+
cmd.startsWith('gradle build') ||
|
|
103
|
+
cmd.startsWith('tsc') ||
|
|
104
|
+
cmd.includes('webpack') ||
|
|
105
|
+
cmd.includes('vite build') ||
|
|
106
|
+
cmd.includes('rollup'));
|
|
107
|
+
});
|
|
108
|
+
// ============================================================================
|
|
109
|
+
// Git Operations
|
|
110
|
+
// ============================================================================
|
|
111
|
+
BUILTIN_PATTERNS.set('git operations', (input) => {
|
|
112
|
+
const cmd = getCommand(input).toLowerCase();
|
|
113
|
+
return cmd.startsWith('git ');
|
|
114
|
+
});
|
|
115
|
+
BUILTIN_PATTERNS.set('git status', (input) => {
|
|
116
|
+
const cmd = getCommand(input).toLowerCase();
|
|
117
|
+
return cmd.startsWith('git status') || cmd.startsWith('git diff') || cmd.startsWith('git log');
|
|
118
|
+
});
|
|
119
|
+
BUILTIN_PATTERNS.set('git commit', (input) => {
|
|
120
|
+
const cmd = getCommand(input).toLowerCase();
|
|
121
|
+
return (cmd.startsWith('git add') ||
|
|
122
|
+
cmd.startsWith('git commit') ||
|
|
123
|
+
cmd.startsWith('git stash'));
|
|
124
|
+
});
|
|
125
|
+
BUILTIN_PATTERNS.set('git push', (input) => {
|
|
126
|
+
const cmd = getCommand(input).toLowerCase();
|
|
127
|
+
return cmd.startsWith('git push');
|
|
128
|
+
});
|
|
129
|
+
BUILTIN_PATTERNS.set('git pull', (input) => {
|
|
130
|
+
const cmd = getCommand(input).toLowerCase();
|
|
131
|
+
return cmd.startsWith('git pull') || cmd.startsWith('git fetch');
|
|
132
|
+
});
|
|
133
|
+
// ============================================================================
|
|
134
|
+
// Linting & Formatting
|
|
135
|
+
// ============================================================================
|
|
136
|
+
BUILTIN_PATTERNS.set('lint code', (input) => {
|
|
137
|
+
const cmd = getCommand(input).toLowerCase();
|
|
138
|
+
return (cmd.startsWith('npm run lint') ||
|
|
139
|
+
cmd.startsWith('eslint') ||
|
|
140
|
+
cmd.startsWith('npx eslint') ||
|
|
141
|
+
cmd.startsWith('pylint') ||
|
|
142
|
+
cmd.startsWith('flake8') ||
|
|
143
|
+
cmd.startsWith('golint') ||
|
|
144
|
+
cmd.startsWith('cargo clippy'));
|
|
145
|
+
});
|
|
146
|
+
BUILTIN_PATTERNS.set('format code', (input) => {
|
|
147
|
+
const cmd = getCommand(input).toLowerCase();
|
|
148
|
+
return (cmd.startsWith('npm run format') ||
|
|
149
|
+
cmd.startsWith('prettier') ||
|
|
150
|
+
cmd.startsWith('npx prettier') ||
|
|
151
|
+
cmd.startsWith('black') ||
|
|
152
|
+
cmd.startsWith('gofmt') ||
|
|
153
|
+
cmd.startsWith('cargo fmt'));
|
|
154
|
+
});
|
|
155
|
+
// ============================================================================
|
|
156
|
+
// Development Server
|
|
157
|
+
// ============================================================================
|
|
158
|
+
BUILTIN_PATTERNS.set('start dev server', (input) => {
|
|
159
|
+
const cmd = getCommand(input).toLowerCase();
|
|
160
|
+
return (cmd.startsWith('npm run dev') ||
|
|
161
|
+
cmd.startsWith('npm start') ||
|
|
162
|
+
cmd.startsWith('yarn dev') ||
|
|
163
|
+
cmd.startsWith('pnpm dev') ||
|
|
164
|
+
cmd.startsWith('bun dev') ||
|
|
165
|
+
cmd.startsWith('python manage.py runserver') ||
|
|
166
|
+
cmd.startsWith('go run') ||
|
|
167
|
+
cmd.startsWith('cargo run'));
|
|
168
|
+
});
|
|
169
|
+
// ============================================================================
|
|
170
|
+
// Read Operations (file system)
|
|
171
|
+
// ============================================================================
|
|
172
|
+
BUILTIN_PATTERNS.set('read files', (input) => {
|
|
173
|
+
const cmd = getCommand(input).toLowerCase();
|
|
174
|
+
return (cmd.startsWith('cat ') ||
|
|
175
|
+
cmd.startsWith('less ') ||
|
|
176
|
+
cmd.startsWith('head ') ||
|
|
177
|
+
cmd.startsWith('tail ') ||
|
|
178
|
+
cmd.startsWith('ls ') ||
|
|
179
|
+
cmd.startsWith('find ') ||
|
|
180
|
+
cmd.startsWith('grep '));
|
|
181
|
+
});
|
|
182
|
+
// ============================================================================
|
|
183
|
+
// Type Checking
|
|
184
|
+
// ============================================================================
|
|
185
|
+
BUILTIN_PATTERNS.set('type check', (input) => {
|
|
186
|
+
const cmd = getCommand(input).toLowerCase();
|
|
187
|
+
return (cmd.startsWith('tsc --noEmit') ||
|
|
188
|
+
cmd.startsWith('npx tsc') ||
|
|
189
|
+
cmd.startsWith('npm run typecheck') ||
|
|
190
|
+
cmd.startsWith('mypy') ||
|
|
191
|
+
cmd.startsWith('pyright'));
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
// Initialize patterns on module load
|
|
195
|
+
initBuiltinPatterns();
|
|
196
|
+
/**
|
|
197
|
+
* Prompt Matcher class
|
|
198
|
+
* Matches semantic permission prompts to actual tool inputs
|
|
199
|
+
*/
|
|
200
|
+
export class PromptMatcher {
|
|
201
|
+
customPatterns = new Map();
|
|
202
|
+
/**
|
|
203
|
+
* Register a custom pattern
|
|
204
|
+
*/
|
|
205
|
+
registerPattern(prompt, matcher) {
|
|
206
|
+
this.customPatterns.set(prompt.toLowerCase(), matcher);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Check if input matches a semantic prompt
|
|
210
|
+
*/
|
|
211
|
+
matches(prompt, input) {
|
|
212
|
+
const normalizedPrompt = prompt.toLowerCase().trim();
|
|
213
|
+
// Check custom patterns first
|
|
214
|
+
const customMatcher = this.customPatterns.get(normalizedPrompt);
|
|
215
|
+
if (customMatcher) {
|
|
216
|
+
return customMatcher(input);
|
|
217
|
+
}
|
|
218
|
+
// Check built-in patterns
|
|
219
|
+
const builtinMatcher = BUILTIN_PATTERNS.get(normalizedPrompt);
|
|
220
|
+
if (builtinMatcher) {
|
|
221
|
+
return builtinMatcher(input);
|
|
222
|
+
}
|
|
223
|
+
// Fuzzy matching: check if any keywords from prompt appear in input
|
|
224
|
+
return this.fuzzyMatch(normalizedPrompt, input);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Fuzzy keyword-based matching for custom prompts
|
|
228
|
+
*/
|
|
229
|
+
fuzzyMatch(prompt, input) {
|
|
230
|
+
const inputStr = this.inputToString(input).toLowerCase();
|
|
231
|
+
// Extract meaningful keywords (skip common words)
|
|
232
|
+
const stopWords = new Set([
|
|
233
|
+
'the', 'a', 'an', 'to', 'for', 'in', 'on', 'at', 'with',
|
|
234
|
+
'run', 'execute', 'do', 'perform', 'make', 'this', 'that',
|
|
235
|
+
]);
|
|
236
|
+
const keywords = prompt
|
|
237
|
+
.split(/\s+/)
|
|
238
|
+
.filter((word) => word.length > 2 && !stopWords.has(word));
|
|
239
|
+
// Require at least one keyword match
|
|
240
|
+
return keywords.some((keyword) => inputStr.includes(keyword));
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Convert input to searchable string
|
|
244
|
+
*/
|
|
245
|
+
inputToString(input) {
|
|
246
|
+
if (typeof input === 'string')
|
|
247
|
+
return input;
|
|
248
|
+
if (input === null || input === undefined)
|
|
249
|
+
return '';
|
|
250
|
+
// Extract relevant fields
|
|
251
|
+
const parts = [];
|
|
252
|
+
if (typeof input === 'object') {
|
|
253
|
+
const obj = input;
|
|
254
|
+
// Common input fields
|
|
255
|
+
if (obj.command)
|
|
256
|
+
parts.push(String(obj.command));
|
|
257
|
+
if (obj.file_path)
|
|
258
|
+
parts.push(String(obj.file_path));
|
|
259
|
+
if (obj.filePath)
|
|
260
|
+
parts.push(String(obj.filePath));
|
|
261
|
+
if (obj.path)
|
|
262
|
+
parts.push(String(obj.path));
|
|
263
|
+
if (obj.url)
|
|
264
|
+
parts.push(String(obj.url));
|
|
265
|
+
if (obj.query)
|
|
266
|
+
parts.push(String(obj.query));
|
|
267
|
+
if (obj.pattern)
|
|
268
|
+
parts.push(String(obj.pattern));
|
|
269
|
+
if (obj.content)
|
|
270
|
+
parts.push(String(obj.content).slice(0, 100));
|
|
271
|
+
}
|
|
272
|
+
return parts.join(' ');
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Get list of available built-in patterns
|
|
276
|
+
*/
|
|
277
|
+
getBuiltinPatterns() {
|
|
278
|
+
return Array.from(BUILTIN_PATTERNS.keys());
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Get list of custom patterns
|
|
282
|
+
*/
|
|
283
|
+
getCustomPatterns() {
|
|
284
|
+
return Array.from(this.customPatterns.keys());
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Pattern string parser for Claude Code style patterns
|
|
289
|
+
* Parses "Bash(git add:*)" into { tool: "Bash", pattern: "git add:*" }
|
|
290
|
+
*/
|
|
291
|
+
export function parsePatternString(pattern) {
|
|
292
|
+
// Format: Tool(pattern) or just Tool
|
|
293
|
+
const match = pattern.match(/^(\w+)(?:\(([^)]+)\))?$/);
|
|
294
|
+
if (!match)
|
|
295
|
+
return null;
|
|
296
|
+
return {
|
|
297
|
+
tool: match[1],
|
|
298
|
+
pattern: match[2],
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Check if command contains shell operators (&&, ||, ;, |).
|
|
303
|
+
* Commands with shell operators should NOT be auto-approved for security.
|
|
304
|
+
*/
|
|
305
|
+
function containsShellOperators(command) {
|
|
306
|
+
// Check for shell operators: &&, ||, ;, |
|
|
307
|
+
// Order matters: check || before | to avoid partial matching
|
|
308
|
+
const operatorPattern = /(?:&&|\|\||[;|])/;
|
|
309
|
+
return operatorPattern.test(command);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Extract the first command from a shell command string (for display/logging).
|
|
313
|
+
*/
|
|
314
|
+
function extractFirstCommand(command) {
|
|
315
|
+
const operatorPattern = /\s*(?:&&|\|\||[;|])\s*/;
|
|
316
|
+
const match = command.match(operatorPattern);
|
|
317
|
+
if (match && match.index !== undefined) {
|
|
318
|
+
return command.slice(0, match.index).trim();
|
|
319
|
+
}
|
|
320
|
+
return command.trim();
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Extract file path from input for Read/Edit tools
|
|
324
|
+
*/
|
|
325
|
+
function extractFilePath(input) {
|
|
326
|
+
if (typeof input === 'string')
|
|
327
|
+
return input;
|
|
328
|
+
if (input && typeof input === 'object') {
|
|
329
|
+
const obj = input;
|
|
330
|
+
const path = obj.file_path ?? obj.filePath ?? obj.path;
|
|
331
|
+
if (typeof path === 'string')
|
|
332
|
+
return path;
|
|
333
|
+
}
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Match a path pattern against a file path (gitignore-style)
|
|
338
|
+
* Supports:
|
|
339
|
+
* - ** for any depth
|
|
340
|
+
* - * for single directory level
|
|
341
|
+
* - ~ for home directory
|
|
342
|
+
*/
|
|
343
|
+
function matchesPathPattern(pattern, filePath) {
|
|
344
|
+
// Expand ~ to home directory
|
|
345
|
+
let expandedPattern = pattern;
|
|
346
|
+
if (pattern.startsWith('~/')) {
|
|
347
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? '';
|
|
348
|
+
expandedPattern = home + pattern.slice(1);
|
|
349
|
+
}
|
|
350
|
+
// Convert glob pattern to regex
|
|
351
|
+
// First escape special regex chars except * and /
|
|
352
|
+
let regexStr = expandedPattern
|
|
353
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&');
|
|
354
|
+
// Handle ** (any depth) - must be done before * handling
|
|
355
|
+
regexStr = regexStr.replace(/\*\*/g, '{{DOUBLE_STAR}}');
|
|
356
|
+
// Handle * (single level, no slashes)
|
|
357
|
+
regexStr = regexStr.replace(/\*/g, '[^/]*');
|
|
358
|
+
// Restore ** as .* (any characters including /)
|
|
359
|
+
regexStr = regexStr.replace(/\{\{DOUBLE_STAR\}\}/g, '.*');
|
|
360
|
+
const regex = new RegExp(`^${regexStr}`);
|
|
361
|
+
return regex.test(filePath);
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Check if an input matches a pattern string
|
|
365
|
+
* Pattern format: "git add:*" or "npm install:*"
|
|
366
|
+
*
|
|
367
|
+
* Supports:
|
|
368
|
+
* - "git:*" - prefix matching (: becomes whitespace)
|
|
369
|
+
* - "npm *" - wildcard matching
|
|
370
|
+
* - "* install" - suffix matching
|
|
371
|
+
* - "git * main" - middle wildcard
|
|
372
|
+
* - Shell operator awareness: "safe-cmd:*" won't match "safe-cmd && malicious-cmd"
|
|
373
|
+
* - Path patterns for Read/Edit: "src/**", "~/.zshrc"
|
|
374
|
+
*/
|
|
375
|
+
export function matchesPatternString(pattern, input, tool) {
|
|
376
|
+
// For file operations, use path matching
|
|
377
|
+
if (tool && ['Read', 'Edit', 'Write', 'Glob'].includes(tool)) {
|
|
378
|
+
const filePath = extractFilePath(input);
|
|
379
|
+
if (filePath) {
|
|
380
|
+
return matchesPathPattern(pattern, filePath);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
// Extract command string from input
|
|
384
|
+
let inputStr;
|
|
385
|
+
if (typeof input === 'string') {
|
|
386
|
+
inputStr = input;
|
|
387
|
+
}
|
|
388
|
+
else if (input && typeof input === 'object') {
|
|
389
|
+
const obj = input;
|
|
390
|
+
if (obj.command && typeof obj.command === 'string') {
|
|
391
|
+
const command = obj.command;
|
|
392
|
+
// Shell operator awareness: reject commands with operators for security
|
|
393
|
+
// This prevents bypassing permissions with "safe-cmd && malicious-cmd"
|
|
394
|
+
if (containsShellOperators(command)) {
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
inputStr = command;
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
inputStr = JSON.stringify(input);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
inputStr = JSON.stringify(input);
|
|
405
|
+
}
|
|
406
|
+
// Convert glob pattern to regex
|
|
407
|
+
// : is a separator (e.g., "git add:*" means "git add" followed by anything)
|
|
408
|
+
const regexStr = pattern
|
|
409
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape special chars except * and :
|
|
410
|
+
.replace(/:/g, '\\s*') // : becomes optional whitespace
|
|
411
|
+
.replace(/\*/g, '.*'); // * becomes .*
|
|
412
|
+
const regex = new RegExp(`^${regexStr}`, 'i');
|
|
413
|
+
return regex.test(inputStr);
|
|
414
|
+
}
|
|
415
|
+
//# sourceMappingURL=prompt-matcher.js.map
|