forkoff 1.0.11 → 1.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +7 -4
  2. package/dist/__tests__/cli-commands.test.d.ts +6 -0
  3. package/dist/__tests__/cli-commands.test.d.ts.map +1 -0
  4. package/dist/__tests__/cli-commands.test.js +213 -0
  5. package/dist/__tests__/cli-commands.test.js.map +1 -0
  6. package/dist/__tests__/startup.test.d.ts +11 -0
  7. package/dist/__tests__/startup.test.d.ts.map +1 -0
  8. package/dist/__tests__/startup.test.js +234 -0
  9. package/dist/__tests__/startup.test.js.map +1 -0
  10. package/dist/__tests__/tools/claude-process.test.js +221 -15
  11. package/dist/__tests__/tools/claude-process.test.js.map +1 -1
  12. package/dist/__tests__/tools/permission-hook.test.d.ts +17 -0
  13. package/dist/__tests__/tools/permission-hook.test.d.ts.map +1 -0
  14. package/dist/__tests__/tools/permission-hook.test.js +616 -0
  15. package/dist/__tests__/tools/permission-hook.test.js.map +1 -0
  16. package/dist/__tests__/tools/permission-ipc.test.d.ts +11 -0
  17. package/dist/__tests__/tools/permission-ipc.test.d.ts.map +1 -0
  18. package/dist/__tests__/tools/permission-ipc.test.js +612 -0
  19. package/dist/__tests__/tools/permission-ipc.test.js.map +1 -0
  20. package/dist/config.js +1 -1
  21. package/dist/index.d.ts +2 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +1010 -898
  24. package/dist/index.js.map +1 -1
  25. package/dist/startup.d.ts.map +1 -1
  26. package/dist/startup.js +45 -15
  27. package/dist/startup.js.map +1 -1
  28. package/dist/tools/__tests__/claude-sessions.test.d.ts +2 -0
  29. package/dist/tools/__tests__/claude-sessions.test.d.ts.map +1 -0
  30. package/dist/tools/__tests__/claude-sessions.test.js +306 -0
  31. package/dist/tools/__tests__/claude-sessions.test.js.map +1 -0
  32. package/dist/tools/claude-process.d.ts +81 -4
  33. package/dist/tools/claude-process.d.ts.map +1 -1
  34. package/dist/tools/claude-process.js +332 -20
  35. package/dist/tools/claude-process.js.map +1 -1
  36. package/dist/tools/claude-sessions.d.ts +5 -0
  37. package/dist/tools/claude-sessions.d.ts.map +1 -1
  38. package/dist/tools/claude-sessions.js +16 -2
  39. package/dist/tools/claude-sessions.js.map +1 -1
  40. package/dist/tools/index.d.ts +1 -0
  41. package/dist/tools/index.d.ts.map +1 -1
  42. package/dist/tools/index.js +3 -1
  43. package/dist/tools/index.js.map +1 -1
  44. package/dist/tools/permission-hook.d.ts +41 -0
  45. package/dist/tools/permission-hook.d.ts.map +1 -0
  46. package/dist/tools/permission-hook.js +312 -0
  47. package/dist/tools/permission-hook.js.map +1 -0
  48. package/dist/tools/permission-ipc.d.ts +109 -0
  49. package/dist/tools/permission-ipc.d.ts.map +1 -0
  50. package/dist/tools/permission-ipc.js +295 -0
  51. package/dist/tools/permission-ipc.js.map +1 -0
  52. package/dist/websocket.d.ts +14 -0
  53. package/dist/websocket.d.ts.map +1 -1
  54. package/dist/websocket.js +34 -4
  55. package/dist/websocket.js.map +1 -1
  56. package/jest.config.js +3 -0
  57. package/package.json +1 -1
@@ -0,0 +1,616 @@
1
+ "use strict";
2
+ /**
3
+ * Tests for Permission Hook Script (permission-hook.ts)
4
+ *
5
+ * The permission hook is a standalone script spawned by Claude Code as a
6
+ * PreToolUse hook. It reads JSON from stdin, decides whether to auto-approve
7
+ * (safe tools) or request approval via temp files (dangerous tools), and
8
+ * writes a JSON decision to stdout.
9
+ *
10
+ * These tests spawn the real hook script as a child process using ts-node,
11
+ * write JSON to its stdin, and verify stdout output and exit codes.
12
+ *
13
+ * For dangerous-tool tests, we also watch the temp directory for the
14
+ * .request.json file the hook writes, then write a .response.json file
15
+ * to simulate the IPC manager's response.
16
+ */
17
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ var desc = Object.getOwnPropertyDescriptor(m, k);
20
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
+ desc = { enumerable: true, get: function() { return m[k]; } };
22
+ }
23
+ Object.defineProperty(o, k2, desc);
24
+ }) : (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ o[k2] = m[k];
27
+ }));
28
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
30
+ }) : function(o, v) {
31
+ o["default"] = v;
32
+ });
33
+ var __importStar = (this && this.__importStar) || (function () {
34
+ var ownKeys = function(o) {
35
+ ownKeys = Object.getOwnPropertyNames || function (o) {
36
+ var ar = [];
37
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
+ return ar;
39
+ };
40
+ return ownKeys(o);
41
+ };
42
+ return function (mod) {
43
+ if (mod && mod.__esModule) return mod;
44
+ var result = {};
45
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
+ __setModuleDefault(result, mod);
47
+ return result;
48
+ };
49
+ })();
50
+ Object.defineProperty(exports, "__esModule", { value: true });
51
+ const child_process_1 = require("child_process");
52
+ const fs = __importStar(require("fs"));
53
+ const os = __importStar(require("os"));
54
+ const path = __importStar(require("path"));
55
+ // Give child processes plenty of time
56
+ jest.setTimeout(30000);
57
+ // ---------------------------------------------------------------------------
58
+ // Constants
59
+ // ---------------------------------------------------------------------------
60
+ const HOOK_SCRIPT = path.resolve(__dirname, '../../tools/permission-hook.ts');
61
+ const TEMP_DIR = path.join(os.tmpdir(), 'forkoff-permissions');
62
+ /** All tools the hook considers safe by default (must match DEFAULT_SAFE_TOOLS in the hook). */
63
+ const SAFE_TOOLS = [
64
+ 'Read', 'Glob', 'Grep', 'WebSearch', 'WebFetch',
65
+ 'TaskCreate', 'TaskUpdate', 'TaskGet', 'TaskList',
66
+ 'TaskOutput', 'TaskStop', 'AskUserQuestion', 'Skill',
67
+ 'EnterPlanMode', 'ExitPlanMode',
68
+ 'mcp__ide__getDiagnostics', 'mcp__ide__executeCode',
69
+ ];
70
+ /**
71
+ * Build a standard hook stdin payload.
72
+ */
73
+ function makeInput(overrides = {}) {
74
+ return {
75
+ session_id: 'test-session-1',
76
+ cwd: '/home/user/project',
77
+ hook_event_name: 'PreToolUse',
78
+ tool_name: 'Read',
79
+ tool_input: { file_path: '/some/file.ts' },
80
+ tool_use_id: 'toolu_test_01',
81
+ ...overrides,
82
+ };
83
+ }
84
+ /**
85
+ * Spawn the hook script via ts-node, write input to stdin, and collect
86
+ * stdout/stderr/exitCode.
87
+ *
88
+ * @param stdinData - The string to write to the child's stdin (or null to
89
+ * close stdin immediately with no data).
90
+ */
91
+ function runHook(stdinData) {
92
+ return new Promise((resolve) => {
93
+ // Use node directly to run ts-node's bin.js (avoids .cmd spawn issues on Windows)
94
+ const projectRoot = path.resolve(__dirname, '../../..');
95
+ const tsNodeBin = path.join(projectRoot, 'node_modules', 'ts-node', 'dist', 'bin.js');
96
+ const child = (0, child_process_1.spawn)(process.execPath, [tsNodeBin, '--transpile-only', HOOK_SCRIPT], {
97
+ cwd: projectRoot,
98
+ stdio: ['pipe', 'pipe', 'pipe'],
99
+ env: { ...process.env },
100
+ });
101
+ let stdout = '';
102
+ let stderr = '';
103
+ child.stdout.on('data', (chunk) => {
104
+ stdout += chunk.toString();
105
+ });
106
+ child.stderr.on('data', (chunk) => {
107
+ stderr += chunk.toString();
108
+ });
109
+ child.on('error', (err) => {
110
+ resolve({ stdout, stderr, exitCode: null, parsed: null });
111
+ });
112
+ child.on('close', (code) => {
113
+ let parsed = null;
114
+ try {
115
+ // The hook's respond() function throws 'unreachable' after writing
116
+ // stdout, which triggers the top-level .catch() handler that writes
117
+ // a second JSON line. We only care about the FIRST JSON line.
118
+ const lines = stdout.trim().split('\n').filter(Boolean);
119
+ if (lines.length > 0) {
120
+ parsed = JSON.parse(lines[0]);
121
+ }
122
+ }
123
+ catch {
124
+ // not parseable
125
+ }
126
+ resolve({ stdout, stderr, exitCode: code, parsed });
127
+ });
128
+ // Write stdin data and close the stream
129
+ if (stdinData !== null) {
130
+ child.stdin.write(stdinData);
131
+ }
132
+ child.stdin.end();
133
+ });
134
+ }
135
+ /**
136
+ * Watch the temp directory for a new .request.json file that was NOT present
137
+ * in the `excludeFiles` set. This prevents picking up stale files from
138
+ * previous tests.
139
+ */
140
+ function waitForRequestFile(excludeFiles = new Set(), timeoutMs = 15000, pollMs = 100) {
141
+ return new Promise((resolve, reject) => {
142
+ const start = Date.now();
143
+ const check = () => {
144
+ if (Date.now() - start > timeoutMs) {
145
+ reject(new Error(`No new .request.json file appeared in ${TEMP_DIR} within ${timeoutMs}ms`));
146
+ return;
147
+ }
148
+ try {
149
+ if (fs.existsSync(TEMP_DIR)) {
150
+ const files = fs.readdirSync(TEMP_DIR).filter((f) => f.endsWith('.request.json') && !excludeFiles.has(f));
151
+ if (files.length > 0) {
152
+ const filePath = path.join(TEMP_DIR, files[0]);
153
+ const raw = fs.readFileSync(filePath, 'utf-8');
154
+ const content = JSON.parse(raw);
155
+ resolve({ filePath, content });
156
+ return;
157
+ }
158
+ }
159
+ }
160
+ catch {
161
+ // retry
162
+ }
163
+ setTimeout(check, pollMs);
164
+ };
165
+ check();
166
+ });
167
+ }
168
+ /**
169
+ * Snapshot the current set of files in the temp directory.
170
+ */
171
+ function snapshotTempDir() {
172
+ try {
173
+ if (fs.existsSync(TEMP_DIR)) {
174
+ return new Set(fs.readdirSync(TEMP_DIR));
175
+ }
176
+ }
177
+ catch {
178
+ // ignore
179
+ }
180
+ return new Set();
181
+ }
182
+ /**
183
+ * Write a response file for the hook to pick up.
184
+ */
185
+ function writeResponseFile(promptId, decision, reason = '') {
186
+ const responseFile = path.join(TEMP_DIR, `${promptId}.response.json`);
187
+ const data = { decision };
188
+ if (reason) {
189
+ data.reason = reason;
190
+ }
191
+ fs.writeFileSync(responseFile, JSON.stringify(data), 'utf-8');
192
+ }
193
+ /**
194
+ * Clean up the temp directory before/after tests.
195
+ */
196
+ function cleanTempDir() {
197
+ try {
198
+ if (fs.existsSync(TEMP_DIR)) {
199
+ const files = fs.readdirSync(TEMP_DIR);
200
+ for (const file of files) {
201
+ try {
202
+ fs.unlinkSync(path.join(TEMP_DIR, file));
203
+ }
204
+ catch {
205
+ // ignore
206
+ }
207
+ }
208
+ }
209
+ }
210
+ catch {
211
+ // ignore
212
+ }
213
+ }
214
+ // ===========================================================================
215
+ // TEST SUITES
216
+ // ===========================================================================
217
+ describe('Permission Hook Script', () => {
218
+ beforeEach(() => {
219
+ cleanTempDir();
220
+ });
221
+ afterEach(() => {
222
+ cleanTempDir();
223
+ });
224
+ // =========================================================================
225
+ // 1. Safe tool (Read) -> auto-approved, exit code 0
226
+ // =========================================================================
227
+ describe('safe tool auto-approval', () => {
228
+ it('auto-approves Read tool with exit code 0', async () => {
229
+ const input = makeInput({ tool_name: 'Read' });
230
+ const result = await runHook(JSON.stringify(input));
231
+ expect(result.exitCode).toBe(0);
232
+ expect(result.parsed).not.toBeNull();
233
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('allow');
234
+ expect(result.parsed.hookSpecificOutput.permissionDecisionReason).toContain('Auto-approved');
235
+ expect(result.parsed.hookSpecificOutput.hookEventName).toBe('PreToolUse');
236
+ });
237
+ // =========================================================================
238
+ // 2. Safe tool (Glob) -> same
239
+ // =========================================================================
240
+ it('auto-approves Glob tool with exit code 0', async () => {
241
+ const input = makeInput({ tool_name: 'Glob', tool_input: { pattern: '**/*.ts' } });
242
+ const result = await runHook(JSON.stringify(input));
243
+ expect(result.exitCode).toBe(0);
244
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('allow');
245
+ });
246
+ it('auto-approves Grep tool', async () => {
247
+ const input = makeInput({ tool_name: 'Grep', tool_input: { pattern: 'TODO' } });
248
+ const result = await runHook(JSON.stringify(input));
249
+ expect(result.exitCode).toBe(0);
250
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('allow');
251
+ });
252
+ it('auto-approves WebSearch tool', async () => {
253
+ const input = makeInput({ tool_name: 'WebSearch', tool_input: { query: 'test' } });
254
+ const result = await runHook(JSON.stringify(input));
255
+ expect(result.exitCode).toBe(0);
256
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('allow');
257
+ });
258
+ it('auto-approves TaskCreate tool', async () => {
259
+ const input = makeInput({ tool_name: 'TaskCreate' });
260
+ const result = await runHook(JSON.stringify(input));
261
+ expect(result.exitCode).toBe(0);
262
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('allow');
263
+ });
264
+ it('auto-approves mcp__ide__getDiagnostics tool', async () => {
265
+ const input = makeInput({ tool_name: 'mcp__ide__getDiagnostics' });
266
+ const result = await runHook(JSON.stringify(input));
267
+ expect(result.exitCode).toBe(0);
268
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('allow');
269
+ });
270
+ it('treats NotebookEdit as dangerous by default (requires approval)', async () => {
271
+ const input = makeInput({ tool_name: 'NotebookEdit' });
272
+ const existing = snapshotTempDir();
273
+ const hookPromise = runHook(JSON.stringify(input));
274
+ const { content } = await waitForRequestFile(existing);
275
+ expect(content.toolName).toBe('NotebookEdit');
276
+ writeResponseFile(content.promptId, 'allow');
277
+ const result = await hookPromise;
278
+ expect(result.exitCode).toBe(0);
279
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('allow');
280
+ });
281
+ it('does NOT write any temp files for safe tools', async () => {
282
+ const existingBefore = snapshotTempDir();
283
+ const input = makeInput({ tool_name: 'Read' });
284
+ await runHook(JSON.stringify(input));
285
+ // Check that no NEW request files were created
286
+ if (fs.existsSync(TEMP_DIR)) {
287
+ const newFiles = fs.readdirSync(TEMP_DIR).filter((f) => f.endsWith('.request.json') && !existingBefore.has(f));
288
+ expect(newFiles).toHaveLength(0);
289
+ }
290
+ });
291
+ });
292
+ // =========================================================================
293
+ // 3. Dangerous tool (Bash) -> writes request file, allow response -> exit 0
294
+ // =========================================================================
295
+ describe('dangerous tool with allow response', () => {
296
+ it('Bash tool: writes request file and exits 0 when allowed', async () => {
297
+ const input = makeInput({
298
+ tool_name: 'Bash',
299
+ tool_input: { command: 'npm install' },
300
+ tool_use_id: 'toolu_bash_01',
301
+ });
302
+ const existing = snapshotTempDir();
303
+ const hookPromise = runHook(JSON.stringify(input));
304
+ const { content } = await waitForRequestFile(existing);
305
+ expect(content.toolName).toBe('Bash');
306
+ expect(content.toolInput).toEqual({ command: 'npm install' });
307
+ expect(content.toolUseId).toBe('toolu_bash_01');
308
+ expect(content.promptId).toBeDefined();
309
+ writeResponseFile(content.promptId, 'allow', 'User approved via mobile');
310
+ const result = await hookPromise;
311
+ expect(result.exitCode).toBe(0);
312
+ expect(result.parsed).not.toBeNull();
313
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('allow');
314
+ expect(result.parsed.hookSpecificOutput.hookEventName).toBe('PreToolUse');
315
+ });
316
+ it('Edit tool: writes request file and exits 0 when allowed', async () => {
317
+ const input = makeInput({
318
+ tool_name: 'Edit',
319
+ tool_input: { file_path: '/src/app.ts', old_string: 'a', new_string: 'b' },
320
+ });
321
+ const existing = snapshotTempDir();
322
+ const hookPromise = runHook(JSON.stringify(input));
323
+ const { content } = await waitForRequestFile(existing);
324
+ expect(content.toolName).toBe('Edit');
325
+ writeResponseFile(content.promptId, 'allow');
326
+ const result = await hookPromise;
327
+ expect(result.exitCode).toBe(0);
328
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('allow');
329
+ });
330
+ });
331
+ // =========================================================================
332
+ // 4. Dangerous tool (Write) -> writes request file, deny response -> exit 2
333
+ // =========================================================================
334
+ describe('dangerous tool with deny response', () => {
335
+ it('Write tool: writes request file and exits 2 when denied', async () => {
336
+ const input = makeInput({
337
+ tool_name: 'Write',
338
+ tool_input: { file_path: '/etc/passwd', content: 'bad stuff' },
339
+ tool_use_id: 'toolu_write_01',
340
+ });
341
+ const existing = snapshotTempDir();
342
+ const hookPromise = runHook(JSON.stringify(input));
343
+ const { content } = await waitForRequestFile(existing);
344
+ expect(content.toolName).toBe('Write');
345
+ expect(content.toolInput).toEqual({ file_path: '/etc/passwd', content: 'bad stuff' });
346
+ writeResponseFile(content.promptId, 'deny', 'Too risky');
347
+ const result = await hookPromise;
348
+ expect(result.exitCode).toBe(2);
349
+ expect(result.parsed).not.toBeNull();
350
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('deny');
351
+ });
352
+ it('Bash tool: exits 2 when denied', async () => {
353
+ const input = makeInput({
354
+ tool_name: 'Bash',
355
+ tool_input: { command: 'rm -rf /' },
356
+ });
357
+ const existing = snapshotTempDir();
358
+ const hookPromise = runHook(JSON.stringify(input));
359
+ const { content } = await waitForRequestFile(existing);
360
+ writeResponseFile(content.promptId, 'deny', 'Absolutely not');
361
+ const result = await hookPromise;
362
+ expect(result.exitCode).toBe(2);
363
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('deny');
364
+ });
365
+ });
366
+ // =========================================================================
367
+ // 5. Empty stdin -> deny
368
+ // =========================================================================
369
+ describe('empty stdin', () => {
370
+ it('denies with exit code 2 when stdin is empty', async () => {
371
+ const result = await runHook('');
372
+ expect(result.exitCode).toBe(2);
373
+ expect(result.parsed).not.toBeNull();
374
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('deny');
375
+ expect(result.parsed.hookSpecificOutput.permissionDecisionReason).toContain('No input');
376
+ });
377
+ it('denies with exit code 2 when stdin is null (closed immediately)', async () => {
378
+ const result = await runHook(null);
379
+ expect(result.exitCode).toBe(2);
380
+ expect(result.parsed).not.toBeNull();
381
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('deny');
382
+ });
383
+ });
384
+ // =========================================================================
385
+ // 6. Invalid JSON stdin -> deny
386
+ // =========================================================================
387
+ describe('invalid JSON stdin', () => {
388
+ it('denies with exit code 2 when stdin is not valid JSON', async () => {
389
+ const result = await runHook('this is not json {{{');
390
+ expect(result.exitCode).toBe(2);
391
+ expect(result.parsed).not.toBeNull();
392
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('deny');
393
+ expect(result.parsed.hookSpecificOutput.permissionDecisionReason).toContain('parse');
394
+ });
395
+ it('denies with exit code 2 for truncated JSON', async () => {
396
+ const result = await runHook('{"tool_name": "Bash", "tool_input"');
397
+ expect(result.exitCode).toBe(2);
398
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('deny');
399
+ });
400
+ });
401
+ // =========================================================================
402
+ // Output format validation
403
+ // =========================================================================
404
+ describe('output format', () => {
405
+ it('stdout is valid JSON with correct structure', async () => {
406
+ const input = makeInput({ tool_name: 'Read' });
407
+ const result = await runHook(JSON.stringify(input));
408
+ // Must parse as JSON
409
+ expect(result.parsed).not.toBeNull();
410
+ // Must have the required nested structure
411
+ const output = result.parsed;
412
+ expect(output).toHaveProperty('hookSpecificOutput');
413
+ expect(output.hookSpecificOutput).toHaveProperty('hookEventName');
414
+ expect(output.hookSpecificOutput).toHaveProperty('permissionDecision');
415
+ expect(output.hookSpecificOutput).toHaveProperty('permissionDecisionReason');
416
+ });
417
+ it('hookEventName is always PreToolUse', async () => {
418
+ const input = makeInput({ tool_name: 'Glob' });
419
+ const result = await runHook(JSON.stringify(input));
420
+ expect(result.parsed.hookSpecificOutput.hookEventName).toBe('PreToolUse');
421
+ });
422
+ });
423
+ // =========================================================================
424
+ // Request file content validation (for dangerous tools)
425
+ // =========================================================================
426
+ describe('request file content', () => {
427
+ it('request file contains promptId, toolName, toolInput, toolUseId, and timestamp', async () => {
428
+ const input = makeInput({
429
+ tool_name: 'Bash',
430
+ tool_input: { command: 'echo hello' },
431
+ tool_use_id: 'toolu_verify_fields',
432
+ });
433
+ const existing = snapshotTempDir();
434
+ const hookPromise = runHook(JSON.stringify(input));
435
+ const { content } = await waitForRequestFile(existing);
436
+ expect(content).toHaveProperty('promptId');
437
+ expect(typeof content.promptId).toBe('string');
438
+ expect(content.promptId.length).toBeGreaterThan(0);
439
+ expect(content.toolName).toBe('Bash');
440
+ expect(content.toolInput).toEqual({ command: 'echo hello' });
441
+ expect(content.toolUseId).toBe('toolu_verify_fields');
442
+ expect(content).toHaveProperty('timestamp');
443
+ expect(typeof content.timestamp).toBe('number');
444
+ writeResponseFile(content.promptId, 'allow');
445
+ await hookPromise;
446
+ });
447
+ it('request file is written to forkoff-permissions under os.tmpdir()', async () => {
448
+ const input = makeInput({ tool_name: 'Bash' });
449
+ const existing = snapshotTempDir();
450
+ const hookPromise = runHook(JSON.stringify(input));
451
+ const { filePath, content } = await waitForRequestFile(existing);
452
+ expect(path.dirname(filePath)).toBe(TEMP_DIR);
453
+ const fileName = path.basename(filePath);
454
+ expect(fileName).toMatch(/^.+\.request\.json$/);
455
+ writeResponseFile(content.promptId, 'allow');
456
+ await hookPromise;
457
+ });
458
+ });
459
+ // =========================================================================
460
+ // Temp file cleanup by hook
461
+ // =========================================================================
462
+ describe('temp file cleanup', () => {
463
+ it('hook cleans up request and response files after processing', async () => {
464
+ const input = makeInput({ tool_name: 'Bash' });
465
+ const existing = snapshotTempDir();
466
+ const hookPromise = runHook(JSON.stringify(input));
467
+ const { content } = await waitForRequestFile(existing);
468
+ writeResponseFile(content.promptId, 'allow');
469
+ await hookPromise;
470
+ // After the hook exits, both files should be cleaned up
471
+ const requestFile = path.join(TEMP_DIR, `${content.promptId}.request.json`);
472
+ const responseFile = path.join(TEMP_DIR, `${content.promptId}.response.json`);
473
+ expect(fs.existsSync(requestFile)).toBe(false);
474
+ expect(fs.existsSync(responseFile)).toBe(false);
475
+ });
476
+ });
477
+ // =========================================================================
478
+ // Unknown/new tools default to dangerous
479
+ // =========================================================================
480
+ describe('unknown tools', () => {
481
+ it('treats unknown tool names as dangerous (writes request file)', async () => {
482
+ const input = makeInput({
483
+ tool_name: 'SomeNewDangerousTool',
484
+ tool_input: { arg: 'value' },
485
+ });
486
+ const existing = snapshotTempDir();
487
+ const hookPromise = runHook(JSON.stringify(input));
488
+ const { content } = await waitForRequestFile(existing);
489
+ expect(content.toolName).toBe('SomeNewDangerousTool');
490
+ writeResponseFile(content.promptId, 'deny', 'Unknown tool denied');
491
+ const result = await hookPromise;
492
+ expect(result.exitCode).toBe(2);
493
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('deny');
494
+ });
495
+ });
496
+ // =========================================================================
497
+ // Dynamic rules loading (loadRules / matchesAnyPattern)
498
+ // =========================================================================
499
+ describe('dynamic rules', () => {
500
+ const RULES_FILE = path.join(TEMP_DIR, 'rules.json');
501
+ afterEach(() => {
502
+ // Clean up rules file
503
+ try {
504
+ if (fs.existsSync(RULES_FILE))
505
+ fs.unlinkSync(RULES_FILE);
506
+ }
507
+ catch {
508
+ // ignore
509
+ }
510
+ });
511
+ it('uses default safe tools when no rules file exists', async () => {
512
+ // Ensure rules file does not exist
513
+ try {
514
+ fs.unlinkSync(RULES_FILE);
515
+ }
516
+ catch { /* ok */ }
517
+ const input = makeInput({ tool_name: 'Read' });
518
+ const result = await runHook(JSON.stringify(input));
519
+ expect(result.exitCode).toBe(0);
520
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('allow');
521
+ });
522
+ it('auto-approves Write when rules file marks it as allow', async () => {
523
+ // Write rules that allow Write
524
+ if (!fs.existsSync(TEMP_DIR))
525
+ fs.mkdirSync(TEMP_DIR, { recursive: true });
526
+ const rules = [
527
+ { tool: 'Read', action: 'allow' },
528
+ { tool: 'Write', action: 'allow' },
529
+ { tool: 'Bash', action: 'ask' },
530
+ ];
531
+ fs.writeFileSync(RULES_FILE, JSON.stringify(rules), 'utf-8');
532
+ const input = makeInput({
533
+ tool_name: 'Write',
534
+ tool_input: { file_path: '/test.txt', content: 'hello' },
535
+ });
536
+ const result = await runHook(JSON.stringify(input));
537
+ expect(result.exitCode).toBe(0);
538
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('allow');
539
+ });
540
+ it('requires approval for Read when rules file marks it as ask', async () => {
541
+ // Write rules that require approval for Read
542
+ if (!fs.existsSync(TEMP_DIR))
543
+ fs.mkdirSync(TEMP_DIR, { recursive: true });
544
+ const rules = [
545
+ { tool: 'Read', action: 'ask' },
546
+ { tool: 'Bash', action: 'ask' },
547
+ ];
548
+ fs.writeFileSync(RULES_FILE, JSON.stringify(rules), 'utf-8');
549
+ const input = makeInput({ tool_name: 'Read' });
550
+ const existing = snapshotTempDir();
551
+ const hookPromise = runHook(JSON.stringify(input));
552
+ const { content } = await waitForRequestFile(existing);
553
+ expect(content.toolName).toBe('Read');
554
+ writeResponseFile(content.promptId, 'allow');
555
+ const result = await hookPromise;
556
+ expect(result.exitCode).toBe(0);
557
+ });
558
+ it('auto-approves Bash command when it matches a pattern', async () => {
559
+ // Write rules: Bash is allowed with patterns
560
+ if (!fs.existsSync(TEMP_DIR))
561
+ fs.mkdirSync(TEMP_DIR, { recursive: true });
562
+ const rules = [
563
+ { tool: 'Bash', action: 'allow', patterns: ['npm *', 'git status'] },
564
+ { tool: 'Read', action: 'allow' },
565
+ ];
566
+ fs.writeFileSync(RULES_FILE, JSON.stringify(rules), 'utf-8');
567
+ const input = makeInput({
568
+ tool_name: 'Bash',
569
+ tool_input: { command: 'npm test' },
570
+ });
571
+ const result = await runHook(JSON.stringify(input));
572
+ expect(result.exitCode).toBe(0);
573
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('allow');
574
+ expect(result.parsed.hookSpecificOutput.permissionDecisionReason).toContain('pattern');
575
+ });
576
+ it('requires approval for Bash command that does NOT match any pattern', async () => {
577
+ // Write rules: Bash is allowed but only for specific patterns
578
+ if (!fs.existsSync(TEMP_DIR))
579
+ fs.mkdirSync(TEMP_DIR, { recursive: true });
580
+ const rules = [
581
+ { tool: 'Bash', action: 'allow', patterns: ['npm *', 'git status'] },
582
+ { tool: 'Read', action: 'allow' },
583
+ ];
584
+ fs.writeFileSync(RULES_FILE, JSON.stringify(rules), 'utf-8');
585
+ const input = makeInput({
586
+ tool_name: 'Bash',
587
+ tool_input: { command: 'rm -rf /' },
588
+ });
589
+ const existing = snapshotTempDir();
590
+ const hookPromise = runHook(JSON.stringify(input));
591
+ const { content } = await waitForRequestFile(existing);
592
+ expect(content.toolName).toBe('Bash');
593
+ writeResponseFile(content.promptId, 'deny', 'Not a safe command');
594
+ const result = await hookPromise;
595
+ expect(result.exitCode).toBe(2);
596
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('deny');
597
+ });
598
+ it('falls back to defaults when rules file has invalid JSON', async () => {
599
+ if (!fs.existsSync(TEMP_DIR))
600
+ fs.mkdirSync(TEMP_DIR, { recursive: true });
601
+ fs.writeFileSync(RULES_FILE, 'not valid json!!!', 'utf-8');
602
+ const input = makeInput({ tool_name: 'Read' });
603
+ const result = await runHook(JSON.stringify(input));
604
+ // Read is in defaults, so should be auto-approved
605
+ expect(result.exitCode).toBe(0);
606
+ expect(result.parsed.hookSpecificOutput.permissionDecision).toBe('allow');
607
+ });
608
+ });
609
+ });
610
+ // ===========================================================================
611
+ // Unit tests for exported helpers (loadRules, matchesAnyPattern)
612
+ // These use integration-style tests via the hook subprocess since the module
613
+ // runs main() on import. loadRules is tested via rules.json file + subprocess,
614
+ // and matchesAnyPattern is tested via Bash patterns + subprocess.
615
+ // ===========================================================================
616
+ //# sourceMappingURL=permission-hook.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission-hook.test.js","sourceRoot":"","sources":["../../../src/__tests__/tools/permission-hook.test.ts"],"names":[],"mappings":"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"}