claude-issue-solver 1.42.1 → 1.43.1
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/dist/utils/helpers.d.ts +10 -0
- package/dist/utils/helpers.js +26 -12
- package/dist/utils/helpers.test.d.ts +1 -0
- package/dist/utils/helpers.test.js +102 -0
- package/dist/utils/terminal.d.ts +7 -0
- package/dist/utils/terminal.js +78 -34
- package/dist/utils/terminal.test.js +37 -7
- package/package.json +1 -1
package/dist/utils/helpers.d.ts
CHANGED
|
@@ -3,6 +3,16 @@ export declare function checkRequirements(): {
|
|
|
3
3
|
ok: boolean;
|
|
4
4
|
missing: string[];
|
|
5
5
|
};
|
|
6
|
+
/**
|
|
7
|
+
* Generate AppleScript for opening a script in iTerm2.
|
|
8
|
+
* Sends 'n' first to dismiss any oh-my-zsh update prompts, then runs the script with bash.
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateITermOpenScript(script: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Generate AppleScript for opening a script in Terminal.app.
|
|
13
|
+
* Sends 'n' first to dismiss any oh-my-zsh update prompts, then runs the script with bash.
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateTerminalOpenScript(script: string): string;
|
|
6
16
|
export declare function openInNewTerminal(script: string): void;
|
|
7
17
|
export declare function copyEnvFiles(from: string, to: string): void;
|
|
8
18
|
export declare function symlinkNodeModules(from: string, to: string): void;
|
package/dist/utils/helpers.js
CHANGED
|
@@ -35,6 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.slugify = slugify;
|
|
37
37
|
exports.checkRequirements = checkRequirements;
|
|
38
|
+
exports.generateITermOpenScript = generateITermOpenScript;
|
|
39
|
+
exports.generateTerminalOpenScript = generateTerminalOpenScript;
|
|
38
40
|
exports.openInNewTerminal = openInNewTerminal;
|
|
39
41
|
exports.copyEnvFiles = copyEnvFiles;
|
|
40
42
|
exports.symlinkNodeModules = symlinkNodeModules;
|
|
@@ -71,16 +73,14 @@ function checkRequirements() {
|
|
|
71
73
|
}
|
|
72
74
|
return { ok: missing.length === 0, missing };
|
|
73
75
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
// For iTerm: send 'n' to dismiss any prompt, wait briefly, then run the command
|
|
83
|
-
const iTermScript = `
|
|
76
|
+
/**
|
|
77
|
+
* Generate AppleScript for opening a script in iTerm2.
|
|
78
|
+
* Sends 'n' first to dismiss any oh-my-zsh update prompts, then runs the script with bash.
|
|
79
|
+
*/
|
|
80
|
+
function generateITermOpenScript(script) {
|
|
81
|
+
const escapedScript = script.replace(/"/g, '\\"');
|
|
82
|
+
const bashCommand = `/bin/bash "${escapedScript}"`;
|
|
83
|
+
return `
|
|
84
84
|
tell application "iTerm"
|
|
85
85
|
activate
|
|
86
86
|
set newWindow to (create window with default profile)
|
|
@@ -91,13 +91,27 @@ function openInNewTerminal(script) {
|
|
|
91
91
|
end tell
|
|
92
92
|
end tell
|
|
93
93
|
`;
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Generate AppleScript for opening a script in Terminal.app.
|
|
97
|
+
* Sends 'n' first to dismiss any oh-my-zsh update prompts, then runs the script with bash.
|
|
98
|
+
*/
|
|
99
|
+
function generateTerminalOpenScript(script) {
|
|
100
|
+
const escapedScript = script.replace(/"/g, '\\"');
|
|
101
|
+
const bashCommand = `/bin/bash "${escapedScript}"`;
|
|
102
|
+
return `
|
|
96
103
|
tell application "Terminal"
|
|
97
104
|
activate
|
|
98
105
|
do script "n; ${bashCommand.replace(/"/g, '\\"')}"
|
|
99
106
|
end tell
|
|
100
107
|
`;
|
|
108
|
+
}
|
|
109
|
+
function openInNewTerminal(script) {
|
|
110
|
+
const platform = os.platform();
|
|
111
|
+
if (platform === 'darwin') {
|
|
112
|
+
// macOS - try iTerm2 first, then Terminal
|
|
113
|
+
const iTermScript = generateITermOpenScript(script);
|
|
114
|
+
const terminalScript = generateTerminalOpenScript(script);
|
|
101
115
|
try {
|
|
102
116
|
// Check if iTerm is installed
|
|
103
117
|
if (fs.existsSync('/Applications/iTerm.app')) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const helpers_1 = require("./helpers");
|
|
5
|
+
(0, vitest_1.describe)('helpers utilities', () => {
|
|
6
|
+
(0, vitest_1.describe)('slugify', () => {
|
|
7
|
+
(0, vitest_1.it)('should convert text to lowercase slug', () => {
|
|
8
|
+
(0, vitest_1.expect)((0, helpers_1.slugify)('Hello World')).toBe('hello-world');
|
|
9
|
+
});
|
|
10
|
+
(0, vitest_1.it)('should remove brackets prefix', () => {
|
|
11
|
+
(0, vitest_1.expect)((0, helpers_1.slugify)('[Bug] Fix login issue')).toBe('fix-login-issue');
|
|
12
|
+
(0, vitest_1.expect)((0, helpers_1.slugify)('[FAQ] How to reset password')).toBe('how-to-reset-password');
|
|
13
|
+
});
|
|
14
|
+
(0, vitest_1.it)('should remove special characters', () => {
|
|
15
|
+
(0, vitest_1.expect)((0, helpers_1.slugify)('Fix: issue #123!')).toBe('fix-issue-123');
|
|
16
|
+
});
|
|
17
|
+
(0, vitest_1.it)('should remove duplicate consecutive words', () => {
|
|
18
|
+
(0, vitest_1.expect)((0, helpers_1.slugify)('[FAQ] FAQ question')).toBe('faq-question');
|
|
19
|
+
});
|
|
20
|
+
(0, vitest_1.it)('should limit slug to 30 characters', () => {
|
|
21
|
+
const longTitle = 'This is a very long issue title that should be truncated';
|
|
22
|
+
(0, vitest_1.expect)((0, helpers_1.slugify)(longTitle).length).toBeLessThanOrEqual(30);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
(0, vitest_1.describe)('generateITermOpenScript', () => {
|
|
26
|
+
(0, vitest_1.it)('should generate valid AppleScript for iTerm', () => {
|
|
27
|
+
const script = (0, helpers_1.generateITermOpenScript)('/path/to/script.sh');
|
|
28
|
+
(0, vitest_1.expect)(script).toContain('tell application "iTerm"');
|
|
29
|
+
(0, vitest_1.expect)(script).toContain('create window with default profile');
|
|
30
|
+
(0, vitest_1.expect)(script).toContain('write text');
|
|
31
|
+
});
|
|
32
|
+
(0, vitest_1.it)('should send "n" to dismiss oh-my-zsh update prompts', () => {
|
|
33
|
+
const script = (0, helpers_1.generateITermOpenScript)('/path/to/script.sh');
|
|
34
|
+
(0, vitest_1.expect)(script).toContain('write text "n"');
|
|
35
|
+
});
|
|
36
|
+
(0, vitest_1.it)('should include delay after dismissing prompt', () => {
|
|
37
|
+
const script = (0, helpers_1.generateITermOpenScript)('/path/to/script.sh');
|
|
38
|
+
(0, vitest_1.expect)(script).toContain('delay 0.3');
|
|
39
|
+
});
|
|
40
|
+
(0, vitest_1.it)('should use /bin/bash to run the script', () => {
|
|
41
|
+
const script = (0, helpers_1.generateITermOpenScript)('/path/to/script.sh');
|
|
42
|
+
(0, vitest_1.expect)(script).toContain('/bin/bash');
|
|
43
|
+
(0, vitest_1.expect)(script).toContain('/path/to/script.sh');
|
|
44
|
+
});
|
|
45
|
+
(0, vitest_1.it)('should handle double quotes in script path without breaking AppleScript', () => {
|
|
46
|
+
const script = (0, helpers_1.generateITermOpenScript)('/path/to/"quoted"/script.sh');
|
|
47
|
+
// Should still contain the path and be valid AppleScript structure
|
|
48
|
+
(0, vitest_1.expect)(script).toContain('tell application "iTerm"');
|
|
49
|
+
(0, vitest_1.expect)(script).toContain('/bin/bash');
|
|
50
|
+
(0, vitest_1.expect)(script).toContain('quoted');
|
|
51
|
+
});
|
|
52
|
+
(0, vitest_1.it)('should handle paths with spaces', () => {
|
|
53
|
+
const script = (0, helpers_1.generateITermOpenScript)('/path/with spaces/script.sh');
|
|
54
|
+
(0, vitest_1.expect)(script).toContain('/path/with spaces/script.sh');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
(0, vitest_1.describe)('generateTerminalOpenScript', () => {
|
|
58
|
+
(0, vitest_1.it)('should generate valid AppleScript for Terminal.app', () => {
|
|
59
|
+
const script = (0, helpers_1.generateTerminalOpenScript)('/path/to/script.sh');
|
|
60
|
+
(0, vitest_1.expect)(script).toContain('tell application "Terminal"');
|
|
61
|
+
(0, vitest_1.expect)(script).toContain('do script');
|
|
62
|
+
});
|
|
63
|
+
(0, vitest_1.it)('should send "n" to dismiss oh-my-zsh update prompts', () => {
|
|
64
|
+
const script = (0, helpers_1.generateTerminalOpenScript)('/path/to/script.sh');
|
|
65
|
+
(0, vitest_1.expect)(script).toContain('n;');
|
|
66
|
+
});
|
|
67
|
+
(0, vitest_1.it)('should use /bin/bash to run the script', () => {
|
|
68
|
+
const script = (0, helpers_1.generateTerminalOpenScript)('/path/to/script.sh');
|
|
69
|
+
(0, vitest_1.expect)(script).toContain('/bin/bash');
|
|
70
|
+
(0, vitest_1.expect)(script).toContain('/path/to/script.sh');
|
|
71
|
+
});
|
|
72
|
+
(0, vitest_1.it)('should handle double quotes in script path without breaking AppleScript', () => {
|
|
73
|
+
const script = (0, helpers_1.generateTerminalOpenScript)('/path/to/"quoted"/script.sh');
|
|
74
|
+
// Should still contain the path and be valid AppleScript structure
|
|
75
|
+
(0, vitest_1.expect)(script).toContain('tell application "Terminal"');
|
|
76
|
+
(0, vitest_1.expect)(script).toContain('/bin/bash');
|
|
77
|
+
(0, vitest_1.expect)(script).toContain('quoted');
|
|
78
|
+
});
|
|
79
|
+
(0, vitest_1.it)('should handle paths with spaces', () => {
|
|
80
|
+
const script = (0, helpers_1.generateTerminalOpenScript)('/path/with spaces/script.sh');
|
|
81
|
+
(0, vitest_1.expect)(script).toContain('/path/with spaces/script.sh');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
(0, vitest_1.describe)('oh-my-zsh bypass behavior', () => {
|
|
85
|
+
(0, vitest_1.it)('iTerm script should have prompt dismissal before command execution', () => {
|
|
86
|
+
const script = (0, helpers_1.generateITermOpenScript)('/test/script.sh');
|
|
87
|
+
const lines = script.split('\n');
|
|
88
|
+
// Find the indices of the relevant lines
|
|
89
|
+
const dismissIndex = lines.findIndex(line => line.includes('write text "n"'));
|
|
90
|
+
const commandIndex = lines.findIndex(line => line.includes('/bin/bash'));
|
|
91
|
+
// Dismissal should come before command
|
|
92
|
+
(0, vitest_1.expect)(dismissIndex).toBeGreaterThan(-1);
|
|
93
|
+
(0, vitest_1.expect)(commandIndex).toBeGreaterThan(-1);
|
|
94
|
+
(0, vitest_1.expect)(dismissIndex).toBeLessThan(commandIndex);
|
|
95
|
+
});
|
|
96
|
+
(0, vitest_1.it)('Terminal script should combine dismiss and command in single do script', () => {
|
|
97
|
+
const script = (0, helpers_1.generateTerminalOpenScript)('/test/script.sh');
|
|
98
|
+
// Should have "n; /bin/bash..." in a single do script call
|
|
99
|
+
(0, vitest_1.expect)(script).toMatch(/do script "n;.*\/bin\/bash/);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|
package/dist/utils/terminal.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export declare function getSearchPatterns(options: CloseTerminalOptions): string
|
|
|
10
10
|
/**
|
|
11
11
|
* Generate AppleScript to close iTerm2 windows/tabs matching patterns
|
|
12
12
|
* Uses a two-pass approach: first collect IDs, then close them
|
|
13
|
+
* Matches both window names AND session working directories for reliability
|
|
13
14
|
*/
|
|
14
15
|
export declare function generateITermCloseScript(patterns: string[]): string;
|
|
15
16
|
/**
|
|
@@ -24,6 +25,11 @@ export declare function generateVSCodeCloseScript(patterns: string[]): string;
|
|
|
24
25
|
* Execute AppleScript and handle errors gracefully
|
|
25
26
|
*/
|
|
26
27
|
export declare function executeAppleScript(script: string, timeout?: number): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Find and terminate shell processes running in the given directory
|
|
30
|
+
* This is a fallback approach when AppleScript matching fails
|
|
31
|
+
*/
|
|
32
|
+
export declare function killProcessesInDirectory(dirPath: string): boolean;
|
|
27
33
|
/**
|
|
28
34
|
* Close terminal windows and VS Code windows associated with a worktree
|
|
29
35
|
* Returns an object indicating which applications had windows closed
|
|
@@ -32,4 +38,5 @@ export declare function closeWindowsForWorktree(options: CloseTerminalOptions):
|
|
|
32
38
|
iTerm: boolean;
|
|
33
39
|
terminal: boolean;
|
|
34
40
|
vscode: boolean;
|
|
41
|
+
processes: boolean;
|
|
35
42
|
};
|
package/dist/utils/terminal.js
CHANGED
|
@@ -38,6 +38,7 @@ exports.generateITermCloseScript = generateITermCloseScript;
|
|
|
38
38
|
exports.generateTerminalCloseScript = generateTerminalCloseScript;
|
|
39
39
|
exports.generateVSCodeCloseScript = generateVSCodeCloseScript;
|
|
40
40
|
exports.executeAppleScript = executeAppleScript;
|
|
41
|
+
exports.killProcessesInDirectory = killProcessesInDirectory;
|
|
41
42
|
exports.closeWindowsForWorktree = closeWindowsForWorktree;
|
|
42
43
|
const child_process_1 = require("child_process");
|
|
43
44
|
const os = __importStar(require("os"));
|
|
@@ -48,6 +49,10 @@ function getSearchPatterns(options) {
|
|
|
48
49
|
const { folderPath, issueNumber, prNumber } = options;
|
|
49
50
|
const folderName = folderPath.split('/').pop() || '';
|
|
50
51
|
const patterns = [];
|
|
52
|
+
// Full folder path (most reliable for working directory matching)
|
|
53
|
+
if (folderPath) {
|
|
54
|
+
patterns.push(folderPath);
|
|
55
|
+
}
|
|
51
56
|
// Folder name pattern (e.g., "project-issue-38-slug")
|
|
52
57
|
if (folderName) {
|
|
53
58
|
patterns.push(folderName);
|
|
@@ -66,6 +71,7 @@ function getSearchPatterns(options) {
|
|
|
66
71
|
/**
|
|
67
72
|
* Generate AppleScript to close iTerm2 windows/tabs matching patterns
|
|
68
73
|
* Uses a two-pass approach: first collect IDs, then close them
|
|
74
|
+
* Matches both window names AND session working directories for reliability
|
|
69
75
|
*/
|
|
70
76
|
function generateITermCloseScript(patterns) {
|
|
71
77
|
// Escape patterns for AppleScript string comparison
|
|
@@ -73,51 +79,39 @@ function generateITermCloseScript(patterns) {
|
|
|
73
79
|
return `
|
|
74
80
|
tell application "iTerm"
|
|
75
81
|
set windowsToClose to {}
|
|
76
|
-
set sessionsToClose to {}
|
|
77
82
|
|
|
78
|
-
-- First pass: collect windows
|
|
83
|
+
-- First pass: collect windows to close (by name or by session working directory)
|
|
79
84
|
repeat with w in windows
|
|
80
85
|
try
|
|
81
86
|
set windowName to name of w
|
|
82
87
|
set windowId to id of w
|
|
83
|
-
|
|
84
|
-
end try
|
|
88
|
+
set shouldClose to false
|
|
85
89
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
repeat with s in sessions of t
|
|
89
|
-
try
|
|
90
|
-
set sessionName to name of s
|
|
91
|
-
set sessionId to unique id of s
|
|
92
|
-
${escapedPatterns.map((p) => `if sessionName contains "${p}" then set end of sessionsToClose to {windowId, sessionId}`).join('\n ')}
|
|
93
|
-
end try
|
|
94
|
-
end repeat
|
|
95
|
-
end repeat
|
|
96
|
-
end repeat
|
|
90
|
+
-- Match by window name
|
|
91
|
+
${escapedPatterns.map((p) => `if windowName contains "${p}" then set shouldClose to true`).join('\n ')}
|
|
97
92
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
close s
|
|
111
|
-
end if
|
|
112
|
-
end repeat
|
|
113
|
-
end repeat
|
|
114
|
-
end if
|
|
93
|
+
-- Match by session working directory path (more reliable)
|
|
94
|
+
if not shouldClose then
|
|
95
|
+
repeat with t in tabs of w
|
|
96
|
+
repeat with s in sessions of t
|
|
97
|
+
try
|
|
98
|
+
set sessionPath to ""
|
|
99
|
+
try
|
|
100
|
+
set sessionPath to path of s
|
|
101
|
+
end try
|
|
102
|
+
${escapedPatterns.map((p) => `if sessionPath contains "${p}" then set shouldClose to true`).join('\n ')}
|
|
103
|
+
end try
|
|
104
|
+
end repeat
|
|
115
105
|
end repeat
|
|
116
106
|
end if
|
|
107
|
+
|
|
108
|
+
if shouldClose and windowsToClose does not contain windowId then
|
|
109
|
+
set end of windowsToClose to windowId
|
|
110
|
+
end if
|
|
117
111
|
end try
|
|
118
112
|
end repeat
|
|
119
113
|
|
|
120
|
-
--
|
|
114
|
+
-- Second pass: close windows
|
|
121
115
|
repeat with targetWindowId in windowsToClose
|
|
122
116
|
try
|
|
123
117
|
repeat with w in windows
|
|
@@ -214,13 +208,60 @@ function executeAppleScript(script, timeout = 5000) {
|
|
|
214
208
|
return false;
|
|
215
209
|
}
|
|
216
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* Find and terminate shell processes running in the given directory
|
|
213
|
+
* This is a fallback approach when AppleScript matching fails
|
|
214
|
+
*/
|
|
215
|
+
function killProcessesInDirectory(dirPath) {
|
|
216
|
+
if (os.platform() !== 'darwin' && os.platform() !== 'linux') {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
// Use lsof to find processes with their current working directory in the target path
|
|
221
|
+
// +D flag finds processes with files open in the directory (including cwd)
|
|
222
|
+
const output = (0, child_process_1.execSync)(`lsof +D "${dirPath}" 2>/dev/null || true`, {
|
|
223
|
+
encoding: 'utf8',
|
|
224
|
+
timeout: 5000,
|
|
225
|
+
});
|
|
226
|
+
if (!output.trim()) {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
// Parse lsof output to get PIDs of shell processes
|
|
230
|
+
const lines = output.split('\n').slice(1); // Skip header
|
|
231
|
+
const pids = new Set();
|
|
232
|
+
for (const line of lines) {
|
|
233
|
+
const parts = line.split(/\s+/);
|
|
234
|
+
if (parts.length >= 2) {
|
|
235
|
+
const command = parts[0].toLowerCase();
|
|
236
|
+
const pid = parts[1];
|
|
237
|
+
// Only kill shell processes and their children, not system processes
|
|
238
|
+
if (['bash', 'zsh', 'sh', 'fish', 'claude', 'node'].some(s => command.includes(s))) {
|
|
239
|
+
pids.add(pid);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// Send SIGTERM to each process
|
|
244
|
+
for (const pid of pids) {
|
|
245
|
+
try {
|
|
246
|
+
(0, child_process_1.execSync)(`kill -TERM ${pid} 2>/dev/null || true`, { stdio: 'pipe' });
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
// Process may have already exited
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return pids.size > 0;
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
217
258
|
/**
|
|
218
259
|
* Close terminal windows and VS Code windows associated with a worktree
|
|
219
260
|
* Returns an object indicating which applications had windows closed
|
|
220
261
|
*/
|
|
221
262
|
function closeWindowsForWorktree(options) {
|
|
222
263
|
if (os.platform() !== 'darwin') {
|
|
223
|
-
return { iTerm: false, terminal: false, vscode: false };
|
|
264
|
+
return { iTerm: false, terminal: false, vscode: false, processes: false };
|
|
224
265
|
}
|
|
225
266
|
const patterns = getSearchPatterns(options);
|
|
226
267
|
// Try to close iTerm2 windows/sessions
|
|
@@ -232,9 +273,12 @@ function closeWindowsForWorktree(options) {
|
|
|
232
273
|
// Try to close VS Code windows
|
|
233
274
|
const vscodeScript = generateVSCodeCloseScript(patterns);
|
|
234
275
|
const vscodeResult = executeAppleScript(vscodeScript, 10000);
|
|
276
|
+
// Fallback: kill processes running in the worktree directory
|
|
277
|
+
const processResult = killProcessesInDirectory(options.folderPath);
|
|
235
278
|
return {
|
|
236
279
|
iTerm: iTermResult,
|
|
237
280
|
terminal: terminalResult,
|
|
238
281
|
vscode: vscodeResult,
|
|
282
|
+
processes: processResult,
|
|
239
283
|
};
|
|
240
284
|
}
|
|
@@ -10,10 +10,21 @@ const terminal_1 = require("./terminal");
|
|
|
10
10
|
issueNumber: '42',
|
|
11
11
|
};
|
|
12
12
|
const patterns = (0, terminal_1.getSearchPatterns)(options);
|
|
13
|
+
// Should include full path for working directory matching
|
|
14
|
+
(0, vitest_1.expect)(patterns).toContain('/Users/test/project-issue-42-fix-bug');
|
|
13
15
|
(0, vitest_1.expect)(patterns).toContain('project-issue-42-fix-bug');
|
|
14
16
|
(0, vitest_1.expect)(patterns).toContain('Issue #42');
|
|
15
17
|
(0, vitest_1.expect)(patterns).toContain('issue-42-');
|
|
16
18
|
});
|
|
19
|
+
(0, vitest_1.it)('should include full folder path for working directory matching', () => {
|
|
20
|
+
const options = {
|
|
21
|
+
folderPath: '/Users/dev/myproject-issue-123-feature',
|
|
22
|
+
issueNumber: '123',
|
|
23
|
+
};
|
|
24
|
+
const patterns = (0, terminal_1.getSearchPatterns)(options);
|
|
25
|
+
// Full path should be first for best matching
|
|
26
|
+
(0, vitest_1.expect)(patterns[0]).toBe('/Users/dev/myproject-issue-123-feature');
|
|
27
|
+
});
|
|
17
28
|
(0, vitest_1.it)('should include PR patterns when prNumber is provided', () => {
|
|
18
29
|
const options = {
|
|
19
30
|
folderPath: '/Users/test/project-issue-42-fix-bug',
|
|
@@ -51,7 +62,6 @@ const terminal_1 = require("./terminal");
|
|
|
51
62
|
(0, vitest_1.expect)(script).toContain('project-issue-42');
|
|
52
63
|
(0, vitest_1.expect)(script).toContain('Issue #42');
|
|
53
64
|
(0, vitest_1.expect)(script).toContain('windowsToClose');
|
|
54
|
-
(0, vitest_1.expect)(script).toContain('sessionsToClose');
|
|
55
65
|
});
|
|
56
66
|
(0, vitest_1.it)('should escape double quotes in patterns', () => {
|
|
57
67
|
const patterns = ['Issue "quoted"'];
|
|
@@ -61,12 +71,18 @@ const terminal_1 = require("./terminal");
|
|
|
61
71
|
(0, vitest_1.it)('should use two-pass approach for closing', () => {
|
|
62
72
|
const patterns = ['test'];
|
|
63
73
|
const script = (0, terminal_1.generateITermCloseScript)(patterns);
|
|
64
|
-
// First pass collects
|
|
74
|
+
// First pass collects windows to close
|
|
65
75
|
(0, vitest_1.expect)(script).toContain('First pass: collect');
|
|
66
|
-
// Second pass closes
|
|
67
|
-
(0, vitest_1.expect)(script).toContain('Second pass: close
|
|
68
|
-
|
|
69
|
-
|
|
76
|
+
// Second pass closes windows
|
|
77
|
+
(0, vitest_1.expect)(script).toContain('Second pass: close windows');
|
|
78
|
+
});
|
|
79
|
+
(0, vitest_1.it)('should match by session working directory path', () => {
|
|
80
|
+
const patterns = ['/Users/test/worktree'];
|
|
81
|
+
const script = (0, terminal_1.generateITermCloseScript)(patterns);
|
|
82
|
+
// Should include path matching
|
|
83
|
+
(0, vitest_1.expect)(script).toContain('set sessionPath to');
|
|
84
|
+
(0, vitest_1.expect)(script).toContain('path of s');
|
|
85
|
+
(0, vitest_1.expect)(script).toContain('sessionPath contains');
|
|
70
86
|
});
|
|
71
87
|
});
|
|
72
88
|
(0, vitest_1.describe)('generateTerminalCloseScript', () => {
|
|
@@ -116,9 +132,11 @@ const terminal_1 = require("./terminal");
|
|
|
116
132
|
(0, vitest_1.expect)(result).toHaveProperty('iTerm');
|
|
117
133
|
(0, vitest_1.expect)(result).toHaveProperty('terminal');
|
|
118
134
|
(0, vitest_1.expect)(result).toHaveProperty('vscode');
|
|
135
|
+
(0, vitest_1.expect)(result).toHaveProperty('processes');
|
|
119
136
|
(0, vitest_1.expect)(typeof result.iTerm).toBe('boolean');
|
|
120
137
|
(0, vitest_1.expect)(typeof result.terminal).toBe('boolean');
|
|
121
138
|
(0, vitest_1.expect)(typeof result.vscode).toBe('boolean');
|
|
139
|
+
(0, vitest_1.expect)(typeof result.processes).toBe('boolean');
|
|
122
140
|
});
|
|
123
141
|
(0, vitest_1.it)('should handle prNumber parameter', () => {
|
|
124
142
|
const result = (0, terminal_1.closeWindowsForWorktree)({
|
|
@@ -129,6 +147,7 @@ const terminal_1 = require("./terminal");
|
|
|
129
147
|
(0, vitest_1.expect)(result).toHaveProperty('iTerm');
|
|
130
148
|
(0, vitest_1.expect)(result).toHaveProperty('terminal');
|
|
131
149
|
(0, vitest_1.expect)(result).toHaveProperty('vscode');
|
|
150
|
+
(0, vitest_1.expect)(result).toHaveProperty('processes');
|
|
132
151
|
});
|
|
133
152
|
});
|
|
134
153
|
(0, vitest_1.describe)('pattern matching edge cases', () => {
|
|
@@ -175,7 +194,8 @@ const terminal_1 = require("./terminal");
|
|
|
175
194
|
const script = (0, terminal_1.generateITermCloseScript)(patterns);
|
|
176
195
|
// Script should be syntactically valid (quotes should be escaped)
|
|
177
196
|
(0, vitest_1.expect)(script).toContain('test\\"pattern');
|
|
178
|
-
|
|
197
|
+
// Should not have broken string like contains "" (empty pattern)
|
|
198
|
+
(0, vitest_1.expect)(script).not.toMatch(/contains ""/);
|
|
179
199
|
});
|
|
180
200
|
(0, vitest_1.it)('should not have nested quotes issues in Terminal script', () => {
|
|
181
201
|
const patterns = ['test"pattern'];
|
|
@@ -188,4 +208,14 @@ const terminal_1 = require("./terminal");
|
|
|
188
208
|
(0, vitest_1.expect)(script).toContain('test\\"pattern');
|
|
189
209
|
});
|
|
190
210
|
});
|
|
211
|
+
(0, vitest_1.describe)('killProcessesInDirectory', () => {
|
|
212
|
+
(0, vitest_1.it)('should return false for non-existent directory', () => {
|
|
213
|
+
const result = (0, terminal_1.killProcessesInDirectory)('/nonexistent/path/that/does/not/exist');
|
|
214
|
+
(0, vitest_1.expect)(result).toBe(false);
|
|
215
|
+
});
|
|
216
|
+
(0, vitest_1.it)('should return boolean result', () => {
|
|
217
|
+
const result = (0, terminal_1.killProcessesInDirectory)('/tmp');
|
|
218
|
+
(0, vitest_1.expect)(typeof result).toBe('boolean');
|
|
219
|
+
});
|
|
220
|
+
});
|
|
191
221
|
});
|