@iloom/cli 0.1.18 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -6
- package/dist/ClaudeContextManager-LVCYRM6Q.js +13 -0
- package/dist/ClaudeService-WVTWB3DK.js +12 -0
- package/dist/{GitHubService-SH4H6VS5.js → GitHubService-7E2S5NNZ.js} +3 -3
- package/dist/{LoomLauncher-FB2MV2ZI.js → LoomLauncher-CTSWJL35.js} +7 -7
- package/dist/{PromptTemplateManager-WM5GIPEF.js → PromptTemplateManager-WII75TKH.js} +2 -2
- package/dist/README.md +771 -0
- package/dist/{SettingsManager-SKLUVE3K.js → SettingsManager-XOYCLH3D.js} +2 -2
- package/dist/{add-issue-L5HX6LEV.js → add-issue-OBI325W7.js} +7 -7
- package/dist/{chunk-SLIMABFA.js → chunk-2PLUQT6J.js} +2 -2
- package/dist/{chunk-VVH3ANF2.js → chunk-4IV6W4U5.js} +4 -4
- package/dist/{chunk-PV3GAXQO.js → chunk-6LEQW46Y.js} +2 -2
- package/dist/{chunk-6OTVPRXH.js → chunk-CVLAZRNB.js} +2 -2
- package/dist/{chunk-FXV24OYZ.js → chunk-DJUGYNQE.js} +9 -2
- package/dist/{chunk-FXV24OYZ.js.map → chunk-DJUGYNQE.js.map} +1 -1
- package/dist/{chunk-KOCQAD2E.js → chunk-HBVFXN7R.js} +3 -3
- package/dist/{chunk-HURVAQRK.js → chunk-LHP6ROUM.js} +4 -4
- package/dist/{chunk-PXZBAC2M.js → chunk-MFU53H6J.js} +2 -2
- package/dist/{chunk-L4QGC27H.js → chunk-PVAVNJKS.js} +13 -1
- package/dist/chunk-PVAVNJKS.js.map +1 -0
- package/dist/{chunk-PR7FKQBG.js → chunk-RF2YI2XJ.js} +2 -2
- package/dist/{chunk-DGEKUT7Q.js → chunk-SWCRXDZC.js} +34 -6
- package/dist/chunk-SWCRXDZC.js.map +1 -0
- package/dist/{chunk-Q2KYPAH2.js → chunk-SYOSCMIT.js} +6 -6
- package/dist/{chunk-VYQLLHZ7.js → chunk-T3KEIB4D.js} +6 -2
- package/dist/{chunk-VYQLLHZ7.js.map → chunk-T3KEIB4D.js.map} +1 -1
- package/dist/{chunk-IIPTBZQW.js → chunk-TS6DL67T.js} +2 -2
- package/dist/{chunk-IO4WFTL2.js → chunk-VETG35MF.js} +2 -2
- package/dist/{chunk-RSRO7564.js → chunk-ZE74H5BR.js} +28 -3
- package/dist/chunk-ZE74H5BR.js.map +1 -0
- package/dist/{claude-7LUVDZZ4.js → claude-ZIWDG4XG.js} +2 -2
- package/dist/{cleanup-ZHROIBSQ.js → cleanup-FEIVZSIV.js} +5 -5
- package/dist/cli.js +41 -31
- package/dist/cli.js.map +1 -1
- package/dist/contribute-EMZKCAC6.js +259 -0
- package/dist/contribute-EMZKCAC6.js.map +1 -0
- package/dist/{enhance-VVMAKMVZ.js → enhance-MNA4ZGXW.js} +7 -7
- package/dist/{feedback-AKHD7QIM.js → feedback-LFNMQBAZ.js} +6 -6
- package/dist/{finish-WGPISUEH.js → finish-TX5CJICB.js} +411 -17
- package/dist/finish-TX5CJICB.js.map +1 -0
- package/dist/{git-OUYMVYJX.js → git-WC6HZLOT.js} +2 -2
- package/dist/{ignite-JEN3K3OT.js → ignite-MQWVJEAB.js} +125 -10
- package/dist/ignite-MQWVJEAB.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +75 -7
- package/dist/index.js.map +1 -1
- package/dist/{init-EVUT4ZQJ.js → init-GJDYN2IK.js} +7 -7
- package/dist/mcp/{claude-YHHHLSXH.js → claude-NDFOCQQQ.js} +2 -2
- package/dist/mcp/github-comment-server.js.map +1 -1
- package/dist/mcp/{terminal-SDCMDVD7.js → terminal-OMNRFWB3.js} +28 -3
- package/dist/mcp/terminal-OMNRFWB3.js.map +1 -0
- package/dist/{open-ETZUFSE4.js → open-NXSN7XOC.js} +4 -4
- package/dist/prompts/init-prompt.txt +32 -1
- package/dist/prompts/issue-prompt.txt +141 -9
- package/dist/{rebase-KBWFDZCN.js → rebase-DUNFOJVS.js} +6 -6
- package/dist/{remote-GJEZWRCC.js → remote-ZCXJVVNW.js} +4 -2
- package/dist/{run-4SVQ3WEU.js → run-O7ZK7CKA.js} +4 -4
- package/dist/schema/settings.schema.json +18 -0
- package/dist/{start-2NEZU7SE.js → start-73I5W7WW.js} +16 -16
- package/dist/{terminal-3D6TUAKJ.js → terminal-BIRBZ4AZ.js} +2 -2
- package/dist/{test-git-MKZATGZN.js → test-git-T76HOTIA.js} +3 -3
- package/dist/{test-prefix-ZNLWDI3K.js → test-prefix-6HJUVQMH.js} +3 -3
- package/dist/{test-tabs-JRKY3QMM.js → test-tabs-RXDBZ6J7.js} +2 -2
- package/package.json +3 -2
- package/dist/ClaudeContextManager-LD3VB6EM.js +0 -13
- package/dist/ClaudeService-CFFI7DD5.js +0 -12
- package/dist/chunk-DGEKUT7Q.js.map +0 -1
- package/dist/chunk-L4QGC27H.js.map +0 -1
- package/dist/chunk-RSRO7564.js.map +0 -1
- package/dist/finish-WGPISUEH.js.map +0 -1
- package/dist/ignite-JEN3K3OT.js.map +0 -1
- package/dist/mcp/terminal-SDCMDVD7.js.map +0 -1
- /package/dist/{ClaudeContextManager-LD3VB6EM.js.map → ClaudeContextManager-LVCYRM6Q.js.map} +0 -0
- /package/dist/{ClaudeService-CFFI7DD5.js.map → ClaudeService-WVTWB3DK.js.map} +0 -0
- /package/dist/{GitHubService-SH4H6VS5.js.map → GitHubService-7E2S5NNZ.js.map} +0 -0
- /package/dist/{LoomLauncher-FB2MV2ZI.js.map → LoomLauncher-CTSWJL35.js.map} +0 -0
- /package/dist/{PromptTemplateManager-WM5GIPEF.js.map → PromptTemplateManager-WII75TKH.js.map} +0 -0
- /package/dist/{SettingsManager-SKLUVE3K.js.map → SettingsManager-XOYCLH3D.js.map} +0 -0
- /package/dist/{add-issue-L5HX6LEV.js.map → add-issue-OBI325W7.js.map} +0 -0
- /package/dist/{chunk-SLIMABFA.js.map → chunk-2PLUQT6J.js.map} +0 -0
- /package/dist/{chunk-VVH3ANF2.js.map → chunk-4IV6W4U5.js.map} +0 -0
- /package/dist/{chunk-PV3GAXQO.js.map → chunk-6LEQW46Y.js.map} +0 -0
- /package/dist/{chunk-6OTVPRXH.js.map → chunk-CVLAZRNB.js.map} +0 -0
- /package/dist/{chunk-KOCQAD2E.js.map → chunk-HBVFXN7R.js.map} +0 -0
- /package/dist/{chunk-HURVAQRK.js.map → chunk-LHP6ROUM.js.map} +0 -0
- /package/dist/{chunk-PXZBAC2M.js.map → chunk-MFU53H6J.js.map} +0 -0
- /package/dist/{chunk-PR7FKQBG.js.map → chunk-RF2YI2XJ.js.map} +0 -0
- /package/dist/{chunk-Q2KYPAH2.js.map → chunk-SYOSCMIT.js.map} +0 -0
- /package/dist/{chunk-IIPTBZQW.js.map → chunk-TS6DL67T.js.map} +0 -0
- /package/dist/{chunk-IO4WFTL2.js.map → chunk-VETG35MF.js.map} +0 -0
- /package/dist/{claude-7LUVDZZ4.js.map → claude-ZIWDG4XG.js.map} +0 -0
- /package/dist/{cleanup-ZHROIBSQ.js.map → cleanup-FEIVZSIV.js.map} +0 -0
- /package/dist/{enhance-VVMAKMVZ.js.map → enhance-MNA4ZGXW.js.map} +0 -0
- /package/dist/{feedback-AKHD7QIM.js.map → feedback-LFNMQBAZ.js.map} +0 -0
- /package/dist/{git-OUYMVYJX.js.map → git-WC6HZLOT.js.map} +0 -0
- /package/dist/{init-EVUT4ZQJ.js.map → init-GJDYN2IK.js.map} +0 -0
- /package/dist/mcp/{claude-YHHHLSXH.js.map → claude-NDFOCQQQ.js.map} +0 -0
- /package/dist/{open-ETZUFSE4.js.map → open-NXSN7XOC.js.map} +0 -0
- /package/dist/{rebase-KBWFDZCN.js.map → rebase-DUNFOJVS.js.map} +0 -0
- /package/dist/{remote-GJEZWRCC.js.map → remote-ZCXJVVNW.js.map} +0 -0
- /package/dist/{run-4SVQ3WEU.js.map → run-O7ZK7CKA.js.map} +0 -0
- /package/dist/{start-2NEZU7SE.js.map → start-73I5W7WW.js.map} +0 -0
- /package/dist/{terminal-3D6TUAKJ.js.map → terminal-BIRBZ4AZ.js.map} +0 -0
- /package/dist/{test-git-MKZATGZN.js.map → test-git-T76HOTIA.js.map} +0 -0
- /package/dist/{test-prefix-ZNLWDI3K.js.map → test-prefix-6HJUVQMH.js.map} +0 -0
- /package/dist/{test-tabs-JRKY3QMM.js.map → test-tabs-RXDBZ6J7.js.map} +0 -0
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "./chunk-BLCTGFZN.js";
|
|
13
13
|
import {
|
|
14
14
|
ClaudeContextManager
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-2PLUQT6J.js";
|
|
16
16
|
import {
|
|
17
17
|
extractSettingsOverrides
|
|
18
18
|
} from "./chunk-GYCR2LOU.js";
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
import "./chunk-2ZPFJQ3B.js";
|
|
26
26
|
import {
|
|
27
27
|
IssueEnhancementService
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-RF2YI2XJ.js";
|
|
29
29
|
import {
|
|
30
30
|
AgentManager
|
|
31
31
|
} from "./chunk-OC4H6HJD.js";
|
|
@@ -33,7 +33,7 @@ import "./chunk-YETJNRQM.js";
|
|
|
33
33
|
import {
|
|
34
34
|
getConfiguredRepoFromSettings,
|
|
35
35
|
hasMultipleRemotes
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-DJUGYNQE.js";
|
|
37
37
|
import {
|
|
38
38
|
calculateForegroundColor,
|
|
39
39
|
generateColorFromBranchName,
|
|
@@ -43,23 +43,23 @@ import {
|
|
|
43
43
|
} from "./chunk-ZZZWQGTS.js";
|
|
44
44
|
import {
|
|
45
45
|
GitHubService
|
|
46
|
-
} from "./chunk-
|
|
47
|
-
import "./chunk-
|
|
48
|
-
import "./chunk-
|
|
49
|
-
import "./chunk-
|
|
50
|
-
import "./chunk-
|
|
46
|
+
} from "./chunk-TS6DL67T.js";
|
|
47
|
+
import "./chunk-SWCRXDZC.js";
|
|
48
|
+
import "./chunk-LHP6ROUM.js";
|
|
49
|
+
import "./chunk-MFU53H6J.js";
|
|
50
|
+
import "./chunk-PVAVNJKS.js";
|
|
51
51
|
import {
|
|
52
52
|
GitWorktreeManager
|
|
53
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-VETG35MF.js";
|
|
54
54
|
import {
|
|
55
55
|
SettingsManager
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-T3KEIB4D.js";
|
|
57
57
|
import {
|
|
58
58
|
branchExists,
|
|
59
59
|
ensureRepositoryHasCommits,
|
|
60
60
|
executeGitCommand,
|
|
61
61
|
findMainWorktreePathWithSettings
|
|
62
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-HBVFXN7R.js";
|
|
63
63
|
import "./chunk-JNKJ7NJV.js";
|
|
64
64
|
import {
|
|
65
65
|
logger
|
|
@@ -311,8 +311,8 @@ var LoomManager = class {
|
|
|
311
311
|
const setArguments = (_j = input.options) == null ? void 0 : _j.setArguments;
|
|
312
312
|
const executablePath = (_k = input.options) == null ? void 0 : _k.executablePath;
|
|
313
313
|
if (enableClaude || enableCode || enableDevServer || enableTerminal) {
|
|
314
|
-
const { LoomLauncher } = await import("./LoomLauncher-
|
|
315
|
-
const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-
|
|
314
|
+
const { LoomLauncher } = await import("./LoomLauncher-CTSWJL35.js");
|
|
315
|
+
const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-LVCYRM6Q.js");
|
|
316
316
|
const claudeContext = new ClaudeContextManager2(void 0, void 0, this.settings);
|
|
317
317
|
const launcher = new LoomLauncher(claudeContext);
|
|
318
318
|
await launcher.launchLoom({
|
|
@@ -654,8 +654,8 @@ var LoomManager = class {
|
|
|
654
654
|
const executablePath = (_i = input.options) == null ? void 0 : _i.executablePath;
|
|
655
655
|
if (enableClaude || enableCode || enableDevServer || enableTerminal) {
|
|
656
656
|
logger.info("Launching workspace components...");
|
|
657
|
-
const { LoomLauncher } = await import("./LoomLauncher-
|
|
658
|
-
const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-
|
|
657
|
+
const { LoomLauncher } = await import("./LoomLauncher-CTSWJL35.js");
|
|
658
|
+
const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-LVCYRM6Q.js");
|
|
659
659
|
const claudeContext = new ClaudeContextManager2(void 0, void 0, this.settings);
|
|
660
660
|
const launcher = new LoomLauncher(claudeContext);
|
|
661
661
|
await launcher.launchLoom({
|
|
@@ -980,4 +980,4 @@ var StartCommand = class {
|
|
|
980
980
|
export {
|
|
981
981
|
StartCommand
|
|
982
982
|
};
|
|
983
|
-
//# sourceMappingURL=start-
|
|
983
|
+
//# sourceMappingURL=start-73I5W7WW.js.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
openDualTerminalWindow,
|
|
6
6
|
openMultipleTerminalWindows,
|
|
7
7
|
openTerminalWindow
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-ZE74H5BR.js";
|
|
9
9
|
export {
|
|
10
10
|
detectITerm2,
|
|
11
11
|
detectPlatform,
|
|
@@ -13,4 +13,4 @@ export {
|
|
|
13
13
|
openMultipleTerminalWindows,
|
|
14
14
|
openTerminalWindow
|
|
15
15
|
};
|
|
16
|
-
//# sourceMappingURL=terminal-
|
|
16
|
+
//# sourceMappingURL=terminal-BIRBZ4AZ.js.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
SettingsManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-T3KEIB4D.js";
|
|
5
5
|
import {
|
|
6
6
|
findMainWorktreePath
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-HBVFXN7R.js";
|
|
8
8
|
import {
|
|
9
9
|
logger
|
|
10
10
|
} from "./chunk-GEHQXLEI.js";
|
|
@@ -49,4 +49,4 @@ var TestGitCommand = class {
|
|
|
49
49
|
export {
|
|
50
50
|
TestGitCommand
|
|
51
51
|
};
|
|
52
|
-
//# sourceMappingURL=test-git-
|
|
52
|
+
//# sourceMappingURL=test-git-T76HOTIA.js.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
SettingsManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-T3KEIB4D.js";
|
|
5
5
|
import {
|
|
6
6
|
generateWorktreePath
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-HBVFXN7R.js";
|
|
8
8
|
import {
|
|
9
9
|
logger
|
|
10
10
|
} from "./chunk-GEHQXLEI.js";
|
|
@@ -65,4 +65,4 @@ var TestPrefixCommand = class {
|
|
|
65
65
|
export {
|
|
66
66
|
TestPrefixCommand
|
|
67
67
|
};
|
|
68
|
-
//# sourceMappingURL=test-prefix-
|
|
68
|
+
//# sourceMappingURL=test-prefix-6HJUVQMH.js.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
detectITerm2,
|
|
4
4
|
openMultipleTerminalWindows
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ZE74H5BR.js";
|
|
6
6
|
import {
|
|
7
7
|
logger
|
|
8
8
|
} from "./chunk-GEHQXLEI.js";
|
|
@@ -66,4 +66,4 @@ var TestTabsCommand = class {
|
|
|
66
66
|
export {
|
|
67
67
|
TestTabsCommand
|
|
68
68
|
};
|
|
69
|
-
//# sourceMappingURL=test-tabs-
|
|
69
|
+
//# sourceMappingURL=test-tabs-RXDBZ6J7.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iloom/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Control plane for maintaining alignment between you and Claude AI as you work across multiple issues using isolated environments, visible context, and multi-agent workflows to scale understanding, not just output",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
},
|
|
47
47
|
"packageManager": "pnpm@10.16.1+sha512.0e155aa2629db8672b49e8475da6226aa4bdea85fdcdfdc15350874946d4f3c91faaf64cbdc4a5d1ab8002f473d5c3fcedcd197989cf0390f9badd3c04678706",
|
|
48
48
|
"scripts": {
|
|
49
|
-
"build": "tsup && pnpm run export-schema",
|
|
49
|
+
"build": "tsup && pnpm run export-schema && pnpm run copy-docs",
|
|
50
|
+
"copy-docs": "tsx scripts/copy-docs.ts",
|
|
50
51
|
"export-schema": "tsx scripts/export-schema.ts",
|
|
51
52
|
"dev": "tsup --watch",
|
|
52
53
|
"test": "vitest run",
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
ClaudeContextManager
|
|
4
|
-
} from "./chunk-SLIMABFA.js";
|
|
5
|
-
import "./chunk-HURVAQRK.js";
|
|
6
|
-
import "./chunk-PXZBAC2M.js";
|
|
7
|
-
import "./chunk-L4QGC27H.js";
|
|
8
|
-
import "./chunk-VYQLLHZ7.js";
|
|
9
|
-
import "./chunk-GEHQXLEI.js";
|
|
10
|
-
export {
|
|
11
|
-
ClaudeContextManager
|
|
12
|
-
};
|
|
13
|
-
//# sourceMappingURL=ClaudeContextManager-LD3VB6EM.js.map
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
ClaudeService
|
|
4
|
-
} from "./chunk-HURVAQRK.js";
|
|
5
|
-
import "./chunk-PXZBAC2M.js";
|
|
6
|
-
import "./chunk-L4QGC27H.js";
|
|
7
|
-
import "./chunk-VYQLLHZ7.js";
|
|
8
|
-
import "./chunk-GEHQXLEI.js";
|
|
9
|
-
export {
|
|
10
|
-
ClaudeService
|
|
11
|
-
};
|
|
12
|
-
//# sourceMappingURL=ClaudeService-CFFI7DD5.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/github.ts"],"sourcesContent":["import { execa } from 'execa'\nimport type {\n\tGitHubIssue,\n\tGitHubPullRequest,\n\tGitHubProject,\n\tGitHubAuthStatus,\n\tBranchNameStrategy,\n\tProjectItem,\n\tProjectField,\n} from '../types/github.js'\nimport { logger } from './logger.js'\n\n// Core GitHub CLI execution wrapper\nexport async function executeGhCommand<T = unknown>(\n\targs: string[],\n\toptions?: { cwd?: string; timeout?: number }\n): Promise<T> {\n\tconst result = await execa('gh', args, {\n\t\tcwd: options?.cwd ?? process.cwd(),\n\t\ttimeout: options?.timeout ?? 30000,\n\t\tencoding: 'utf8',\n\t})\n\n\t// Parse JSON output if --json flag, --format json, or --jq was used\n\tconst isJson =\n\t\targs.includes('--json') ||\n\t\targs.includes('--jq') ||\n\t\t(args.includes('--format') && args[args.indexOf('--format') + 1] === 'json')\n\tconst data = isJson ? JSON.parse(result.stdout) : result.stdout\n\n\treturn data as T\n}\n\n// Authentication checking\nexport async function checkGhAuth(): Promise<GitHubAuthStatus> {\n\ttry {\n\t\tconst output = await executeGhCommand<string>(['auth', 'status'])\n\n\t\t// Parse auth status output\n\t\tconst scopeMatch = output.match(/Token scopes: (.+)/)\n\t\tconst userMatch = output.match(/Logged in to github\\.com as ([^\\s]+)/)\n\n\t\tconst username = userMatch?.[1]\n\n\t\treturn {\n\t\t\thasAuth: true,\n\t\t\tscopes: scopeMatch?.[1]?.split(', ').map(scope => scope.replace(/^'|'$/g, '')) ?? [],\n\t\t\t...(username && { username }),\n\t\t}\n\t} catch (error) {\n\t\t// Only return \"no auth\" for specific authentication errors\n\t\tif (error instanceof Error && 'stderr' in error && (error as {stderr?: string}).stderr?.includes('You are not logged into any GitHub hosts')) {\n\t\t\treturn { hasAuth: false, scopes: [] }\n\t\t}\n\t\t// Re-throw unexpected errors\n\t\tthrow error\n\t}\n}\n\nexport async function hasProjectScope(): Promise<boolean> {\n\tconst auth = await checkGhAuth()\n\treturn auth.scopes.includes('project')\n}\n\n// Issue fetching\nexport async function fetchGhIssue(\n\tissueNumber: number,\n\trepo?: string\n): Promise<GitHubIssue> {\n\tlogger.debug('Fetching GitHub issue', { issueNumber, repo })\n\n\tconst args = [\n\t\t'issue',\n\t\t'view',\n\t\tString(issueNumber),\n\t\t'--json',\n\t\t'number,title,body,state,labels,assignees,url,createdAt,updatedAt',\n\t]\n\n\tif (repo) {\n\t\targs.push('--repo', repo)\n\t}\n\n\treturn executeGhCommand<GitHubIssue>(args)\n}\n\n// PR fetching\nexport async function fetchGhPR(\n\tprNumber: number,\n\trepo?: string\n): Promise<GitHubPullRequest> {\n\tlogger.debug('Fetching GitHub PR', { prNumber, repo })\n\n\tconst args = [\n\t\t'pr',\n\t\t'view',\n\t\tString(prNumber),\n\t\t'--json',\n\t\t'number,title,body,state,headRefName,baseRefName,url,isDraft,mergeable,createdAt,updatedAt',\n\t]\n\n\tif (repo) {\n\t\targs.push('--repo', repo)\n\t}\n\n\treturn executeGhCommand<GitHubPullRequest>(args)\n}\n\n// Project operations\nexport async function fetchProjectList(\n\towner: string\n): Promise<GitHubProject[]> {\n\tconst result = await executeGhCommand<{ projects: GitHubProject[] }>([\n\t\t'project',\n\t\t'list',\n\t\t'--owner',\n\t\towner,\n\t\t'--limit',\n\t\t'100',\n\t\t'--format',\n\t\t'json',\n\t])\n\n\treturn result?.projects ?? []\n}\n\nexport async function fetchProjectItems(\n\tprojectNumber: number,\n\towner: string\n): Promise<ProjectItem[]> {\n\tconst result = await executeGhCommand<{ items: ProjectItem[] }>([\n\t\t'project',\n\t\t'item-list',\n\t\tString(projectNumber),\n\t\t'--owner',\n\t\towner,\n\t\t'--limit',\n\t\t'10000',\n\t\t'--format',\n\t\t'json',\n\t])\n\n\treturn result?.items ?? []\n}\n\nexport async function fetchProjectFields(\n\tprojectNumber: number,\n\towner: string\n): Promise<{ fields: ProjectField[] }> {\n\tconst result = await executeGhCommand<{ fields: ProjectField[] }>([\n\t\t'project',\n\t\t'field-list',\n\t\tString(projectNumber),\n\t\t'--owner',\n\t\towner,\n\t\t'--format',\n\t\t'json',\n\t])\n\n\treturn result ?? { fields: [] }\n}\n\nexport async function updateProjectItemField(\n\titemId: string,\n\tprojectId: string,\n\tfieldId: string,\n\toptionId: string\n): Promise<void> {\n\tawait executeGhCommand([\n\t\t'project',\n\t\t'item-edit',\n\t\t'--id',\n\t\titemId,\n\t\t'--project-id',\n\t\tprojectId,\n\t\t'--field-id',\n\t\tfieldId,\n\t\t'--single-select-option-id',\n\t\toptionId,\n\t\t'--format',\n\t\t'json',\n\t])\n}\n\n// Branch name generation strategies\nexport class SimpleBranchNameStrategy implements BranchNameStrategy {\n\tasync generate(issueNumber: number, title: string): Promise<string> {\n\t\t// Create a simple slug from the title\n\t\tconst slug = title\n\t\t\t.toLowerCase()\n\t\t\t.replace(/[^a-z0-9]+/g, '-')\n\t\t\t.replace(/^-|-$/g, '')\n\t\t\t.substring(0, 20) // Keep it short for the simple strategy\n\n\t\treturn `feat/issue-${issueNumber}-${slug}`\n\t}\n}\n\nexport class ClaudeBranchNameStrategy implements BranchNameStrategy {\n\tconstructor(private claudeModel = 'haiku') {}\n\n\tasync generate(issueNumber: number, title: string): Promise<string> {\n\t\t// Import dynamically to avoid circular dependency\n\t\tconst { generateBranchName } = await import('../utils/claude.js')\n\n\t\t// Delegate to the shared implementation\n\t\treturn generateBranchName(title, issueNumber, this.claudeModel)\n\t}\n}\n\n// Template-based strategy for custom patterns\nexport class TemplateBranchNameStrategy implements BranchNameStrategy {\n\tconstructor(private template = '{prefix}/issue-{number}-{slug}') {}\n\n\tasync generate(issueNumber: number, title: string): Promise<string> {\n\t\t// Determine prefix based on title\n\t\tconst prefix = this.determinePrefix(title)\n\n\t\t// Create slug from title\n\t\tconst slug = title\n\t\t\t.toLowerCase()\n\t\t\t.replace(/[^a-z0-9]+/g, '-')\n\t\t\t.replace(/^-|-$/g, '')\n\t\t\t.substring(0, 30)\n\n\t\treturn this.template\n\t\t\t.replace('{prefix}', prefix)\n\t\t\t.replace('{number}', String(issueNumber))\n\t\t\t.replace('{slug}', slug)\n\t}\n\n\tprivate determinePrefix(title: string): string {\n\t\tconst lowerTitle = title.toLowerCase()\n\t\tif (lowerTitle.includes('fix') || lowerTitle.includes('bug')) return 'fix'\n\t\tif (lowerTitle.includes('doc')) return 'docs'\n\t\tif (lowerTitle.includes('test')) return 'test'\n\t\tif (lowerTitle.includes('refactor')) return 'refactor'\n\t\treturn 'feat'\n\t}\n}\n\n// GitHub Issue Operations\n\ninterface IssueCreateResponse {\n\tnumber: number\n\turl: string\n}\n\n/**\n * Create a new GitHub issue\n * @param title - The issue title\n * @param body - The issue body (markdown supported)\n * @param options - Optional configuration\n * @param options.repo - Repository in format \"owner/repo\" (uses current repo if not provided)\n * @param options.labels - Array of label names to add to the issue\n * @returns Issue metadata including number and URL\n */\nexport async function createIssue(\n\ttitle: string,\n\tbody: string,\n\toptions?: { repo?: string | undefined; labels?: string[] | undefined }\n): Promise<IssueCreateResponse> {\n\tconst { repo, labels } = options ?? {}\n\n\tlogger.debug('Creating GitHub issue', { title, repo, labels })\n\n\tconst args = [\n\t\t'issue',\n\t\t'create',\n\t\t'--title',\n\t\ttitle,\n\t\t'--body',\n\t\tbody,\n\t]\n\n\t// Add repo if provided\n\tif (repo) {\n\t\targs.splice(2, 0, '--repo', repo)\n\t}\n\n\t// Add labels if provided\n\tif (labels && labels.length > 0) {\n\t\targs.push('--label', labels.join(','))\n\t}\n\n\tconst execaOptions: { timeout: number; encoding: 'utf8'; cwd?: string } = {\n\t\ttimeout: 30000,\n\t\tencoding: 'utf8',\n\t}\n\n\tif (!repo) {\n\t\texecaOptions.cwd = process.cwd()\n\t}\n\n\tconst result = await execa('gh', args, execaOptions)\n\n\t// Parse the URL from the output (format: \"https://github.com/owner/repo/issues/123\")\n\tconst urlMatch = result.stdout.trim().match(/https:\\/\\/github\\.com\\/[^/]+\\/[^/]+\\/issues\\/(\\d+)/)\n\tif (!urlMatch?.[1]) {\n\t\tthrow new Error(`Failed to parse issue URL from gh output: ${result.stdout}`)\n\t}\n\n\tconst issueNumber = parseInt(urlMatch[1], 10)\n\tconst issueUrl = urlMatch[0]\n\n\treturn {\n\t\tnumber: issueNumber,\n\t\turl: issueUrl,\n\t}\n}\n\n/**\n * @deprecated Use createIssue with options.repo instead\n * Create a new GitHub issue in a specific repository\n * @param title - Issue title\n * @param body - Issue body (markdown)\n * @param repository - Repository in format \"owner/repo\"\n * @param labels - Optional array of label names to add to the issue\n * @returns Issue number and URL\n */\nexport async function createIssueInRepo(\n\ttitle: string,\n\tbody: string,\n\trepository: string,\n\tlabels?: string[]\n): Promise<IssueCreateResponse> {\n\treturn createIssue(title, body, { repo: repository, labels })\n}\n\n// GitHub Comment Operations\n\ninterface CommentResponse {\n\tid: number\n\turl: string\n\tcreated_at?: string\n\tupdated_at?: string\n}\n\ninterface RepoInfo {\n\towner: string\n\tname: string\n}\n\n/**\n * Create a comment on a GitHub issue\n * @param issueNumber - The issue number\n * @param body - The comment body (markdown supported)\n * @param repo - Optional repo in \"owner/repo\" format\n * @returns Comment metadata including ID and URL\n */\nexport async function createIssueComment(\n\tissueNumber: number,\n\tbody: string,\n\trepo?: string\n): Promise<CommentResponse> {\n\tlogger.debug('Creating issue comment', { issueNumber, repo })\n\n\tconst apiPath = repo\n\t\t? `repos/${repo}/issues/${issueNumber}/comments`\n\t\t: `repos/:owner/:repo/issues/${issueNumber}/comments`\n\n\treturn executeGhCommand<CommentResponse>([\n\t\t'api',\n\t\tapiPath,\n\t\t'-f',\n\t\t`body=${body}`,\n\t\t'--jq',\n\t\t'{id: .id, url: .html_url, created_at: .created_at}',\n\t])\n}\n\n/**\n * Update an existing GitHub comment\n * @param commentId - The comment ID\n * @param body - The updated comment body (markdown supported)\n * @param repo - Optional repo in \"owner/repo\" format\n * @returns Updated comment metadata\n */\nexport async function updateIssueComment(\n\tcommentId: number,\n\tbody: string,\n\trepo?: string\n): Promise<CommentResponse> {\n\tlogger.debug('Updating issue comment', { commentId, repo })\n\n\tconst apiPath = repo\n\t\t? `repos/${repo}/issues/comments/${commentId}`\n\t\t: `repos/:owner/:repo/issues/comments/${commentId}`\n\n\treturn executeGhCommand<CommentResponse>([\n\t\t'api',\n\t\tapiPath,\n\t\t'-X',\n\t\t'PATCH',\n\t\t'-f',\n\t\t`body=${body}`,\n\t\t'--jq',\n\t\t'{id: .id, url: .html_url, updated_at: .updated_at}',\n\t])\n}\n\n/**\n * Create a comment on a GitHub pull request\n * Note: PR comments use the same endpoint as issue comments\n * @param prNumber - The PR number\n * @param body - The comment body (markdown supported)\n * @param repo - Optional repo in \"owner/repo\" format\n * @returns Comment metadata including ID and URL\n */\nexport async function createPRComment(\n\tprNumber: number,\n\tbody: string,\n\trepo?: string\n): Promise<CommentResponse> {\n\tlogger.debug('Creating PR comment', { prNumber, repo })\n\n\tconst apiPath = repo\n\t\t? `repos/${repo}/issues/${prNumber}/comments`\n\t\t: `repos/:owner/:repo/issues/${prNumber}/comments`\n\n\t// PR comments use the issues endpoint\n\treturn executeGhCommand<CommentResponse>([\n\t\t'api',\n\t\tapiPath,\n\t\t'-f',\n\t\t`body=${body}`,\n\t\t'--jq',\n\t\t'{id: .id, url: .html_url, created_at: .created_at}',\n\t])\n}\n\n/**\n * Get repository owner and name from current directory\n * @returns Repository owner and name\n */\nexport async function getRepoInfo(): Promise<RepoInfo> {\n\tlogger.debug('Fetching repository info')\n\n\tconst result = await executeGhCommand<{ owner: { login: string }; name: string }>([\n\t\t'repo',\n\t\t'view',\n\t\t'--json',\n\t\t'owner,name',\n\t])\n\n\treturn {\n\t\towner: result.owner.login,\n\t\tname: result.name,\n\t}\n}"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/PromptTemplateManager.ts"],"sourcesContent":["import { readFile } from 'fs/promises'\nimport { accessSync } from 'fs'\nimport path from 'path'\nimport { fileURLToPath } from 'url'\nimport { logger } from '../utils/logger.js'\n\nexport interface TemplateVariables {\n\tISSUE_NUMBER?: number\n\tPR_NUMBER?: number\n\tISSUE_TITLE?: string\n\tPR_TITLE?: string\n\tWORKSPACE_PATH?: string\n\tPORT?: number\n\tONE_SHOT_MODE?: boolean\n\tSETTINGS_SCHEMA?: string\n\tSETTINGS_JSON?: string\n\tSETTINGS_LOCAL_JSON?: string\n\tSHELL_TYPE?: string\n\tSHELL_CONFIG_PATH?: string\n\tSHELL_CONFIG_CONTENT?: string\n\tREMOTES_INFO?: string\n\tMULTIPLE_REMOTES?: string\n\tSINGLE_REMOTE?: string\n\tSINGLE_REMOTE_NAME?: string\n\tSINGLE_REMOTE_URL?: string\n\tNO_REMOTES?: string\n}\n\nexport class PromptTemplateManager {\n\tprivate templateDir: string\n\n\tconstructor(templateDir?: string) {\n\t\tif (templateDir) {\n\t\t\tthis.templateDir = templateDir\n\t\t} else {\n\t\t\t// Find templates relative to the package installation\n\t\t\t// When running from dist/, templates are copied to dist/prompts/\n\t\t\tconst currentFileUrl = import.meta.url\n\t\t\tconst currentFilePath = fileURLToPath(currentFileUrl)\n\t\t\tconst distDir = path.dirname(currentFilePath) // dist directory (may be chunked file location)\n\n\t\t\t// Walk up to find the dist directory (in case of chunked files)\n\t\t\tlet templateDir = path.join(distDir, 'prompts')\n\t\t\tlet currentDir = distDir\n\n\t\t\t// Try to find the prompts directory by walking up\n\t\t\twhile (currentDir !== path.dirname(currentDir)) {\n\t\t\t\tconst candidatePath = path.join(currentDir, 'prompts')\n\t\t\t\ttry {\n\t\t\t\t\t// Check if this directory exists (sync check for constructor)\n\t\t\t\t\taccessSync(candidatePath)\n\t\t\t\t\ttemplateDir = candidatePath\n\t\t\t\t\tbreak\n\t\t\t\t} catch {\n\t\t\t\t\tcurrentDir = path.dirname(currentDir)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.templateDir = templateDir\n\t\t\tlogger.debug('PromptTemplateManager initialized', {\n\t\t\t\tcurrentFilePath,\n\t\t\t\tdistDir,\n\t\t\t\ttemplateDir: this.templateDir\n\t\t\t})\n\t\t}\n\t}\n\n\t/**\n\t * Load a template file by name\n\t */\n\tasync loadTemplate(templateName: 'issue' | 'pr' | 'regular' | 'init'): Promise<string> {\n\t\tconst templatePath = path.join(this.templateDir, `${templateName}-prompt.txt`)\n\n\t\tlogger.debug('Loading template', {\n\t\t\ttemplateName,\n\t\t\ttemplateDir: this.templateDir,\n\t\t\ttemplatePath\n\t\t})\n\n\t\ttry {\n\t\t\treturn await readFile(templatePath, 'utf-8')\n\t\t} catch (error) {\n\t\t\tlogger.error('Failed to load template', { templateName, templatePath, error })\n\t\t\tthrow new Error(`Template not found: ${templatePath}`)\n\t\t}\n\t}\n\n\t/**\n\t * Substitute variables in a template string\n\t */\n\tsubstituteVariables(template: string, variables: TemplateVariables): string {\n\t\tlet result = template\n\n\t\t// Process conditional sections first\n\t\tresult = this.processConditionalSections(result, variables)\n\n\t\t// Replace each variable if it exists\n\t\tif (variables.ISSUE_NUMBER !== undefined) {\n\t\t\tresult = result.replace(/ISSUE_NUMBER/g, String(variables.ISSUE_NUMBER))\n\t\t}\n\n\t\tif (variables.PR_NUMBER !== undefined) {\n\t\t\tresult = result.replace(/PR_NUMBER/g, String(variables.PR_NUMBER))\n\t\t}\n\n\t\tif (variables.ISSUE_TITLE !== undefined) {\n\t\t\tresult = result.replace(/ISSUE_TITLE/g, variables.ISSUE_TITLE)\n\t\t}\n\n\t\tif (variables.PR_TITLE !== undefined) {\n\t\t\tresult = result.replace(/PR_TITLE/g, variables.PR_TITLE)\n\t\t}\n\n\t\tif (variables.WORKSPACE_PATH !== undefined) {\n\t\t\tresult = result.replace(/WORKSPACE_PATH/g, variables.WORKSPACE_PATH)\n\t\t}\n\n\t\tif (variables.PORT !== undefined) {\n\t\t\tresult = result.replace(/PORT/g, String(variables.PORT))\n\t\t}\n\n\t\tif (variables.SETTINGS_SCHEMA !== undefined) {\n\t\t\tresult = result.replace(/SETTINGS_SCHEMA/g, variables.SETTINGS_SCHEMA)\n\t\t}\n\n\t\tif (variables.SETTINGS_JSON !== undefined) {\n\t\t\tresult = result.replace(/SETTINGS_JSON/g, variables.SETTINGS_JSON)\n\t\t}\n\n\t\tif (variables.SETTINGS_LOCAL_JSON !== undefined) {\n\t\t\tresult = result.replace(/SETTINGS_LOCAL_JSON/g, variables.SETTINGS_LOCAL_JSON)\n\t\t}\n\n\t\tif (variables.SHELL_TYPE !== undefined) {\n\t\t\tresult = result.replace(/SHELL_TYPE/g, variables.SHELL_TYPE)\n\t\t}\n\n\t\tif (variables.SHELL_CONFIG_PATH !== undefined) {\n\t\t\tresult = result.replace(/SHELL_CONFIG_PATH/g, variables.SHELL_CONFIG_PATH)\n\t\t}\n\n\t\tif (variables.SHELL_CONFIG_CONTENT !== undefined) {\n\t\t\tresult = result.replace(/SHELL_CONFIG_CONTENT/g, variables.SHELL_CONFIG_CONTENT)\n\t\t}\n\n\t\tif (variables.REMOTES_INFO !== undefined) {\n\t\t\tresult = result.replace(/REMOTES_INFO/g, variables.REMOTES_INFO)\n\t\t}\n\n\t\tif (variables.MULTIPLE_REMOTES !== undefined) {\n\t\t\tresult = result.replace(/MULTIPLE_REMOTES/g, variables.MULTIPLE_REMOTES)\n\t\t}\n\n\t\tif (variables.SINGLE_REMOTE !== undefined) {\n\t\t\tresult = result.replace(/SINGLE_REMOTE/g, variables.SINGLE_REMOTE)\n\t\t}\n\n\t\tif (variables.SINGLE_REMOTE_NAME !== undefined) {\n\t\t\tresult = result.replace(/SINGLE_REMOTE_NAME/g, variables.SINGLE_REMOTE_NAME)\n\t\t}\n\n\t\tif (variables.SINGLE_REMOTE_URL !== undefined) {\n\t\t\tresult = result.replace(/SINGLE_REMOTE_URL/g, variables.SINGLE_REMOTE_URL)\n\t\t}\n\n\t\tif (variables.NO_REMOTES !== undefined) {\n\t\t\tresult = result.replace(/NO_REMOTES/g, variables.NO_REMOTES)\n\t\t}\n\n\t\treturn result\n\t}\n\n\t/**\n\t * Process conditional sections in template\n\t * Format: {{#IF ONE_SHOT_MODE}}content{{/IF ONE_SHOT_MODE}}\n\t *\n\t * Note: /s flag allows . to match newlines\n\t */\n\tprivate processConditionalSections(template: string, variables: TemplateVariables): string {\n\t\tlet result = template\n\n\t\t// Process ONE_SHOT_MODE conditionals\n\t\tconst oneShotRegex = /\\{\\{#IF ONE_SHOT_MODE\\}\\}(.*?)\\{\\{\\/IF ONE_SHOT_MODE\\}\\}/gs\n\n\t\tif (variables.ONE_SHOT_MODE === true) {\n\t\t\t// Include the content, remove the conditional markers\n\t\t\tresult = result.replace(oneShotRegex, '$1')\n\t\t} else {\n\t\t\t// Remove the entire conditional block\n\t\t\tresult = result.replace(oneShotRegex, '')\n\t\t}\n\n\t\t// Process SETTINGS_JSON conditionals\n\t\tconst settingsJsonRegex = /\\{\\{#IF SETTINGS_JSON\\}\\}(.*?)\\{\\{\\/IF SETTINGS_JSON\\}\\}/gs\n\n\t\tif (variables.SETTINGS_JSON !== undefined && variables.SETTINGS_JSON !== '') {\n\t\t\t// Include the content, remove the conditional markers\n\t\t\tresult = result.replace(settingsJsonRegex, '$1')\n\t\t} else {\n\t\t\t// Remove the entire conditional block\n\t\t\tresult = result.replace(settingsJsonRegex, '')\n\t\t}\n\n\t\t// Process SETTINGS_LOCAL_JSON conditionals\n\t\tconst settingsLocalJsonRegex = /\\{\\{#IF SETTINGS_LOCAL_JSON\\}\\}(.*?)\\{\\{\\/IF SETTINGS_LOCAL_JSON\\}\\}/gs\n\n\t\tif (variables.SETTINGS_LOCAL_JSON !== undefined && variables.SETTINGS_LOCAL_JSON !== '') {\n\t\t\t// Include the content, remove the conditional markers\n\t\t\tresult = result.replace(settingsLocalJsonRegex, '$1')\n\t\t} else {\n\t\t\t// Remove the entire conditional block\n\t\t\tresult = result.replace(settingsLocalJsonRegex, '')\n\t\t}\n\n\t\t// Process MULTIPLE_REMOTES conditionals\n\t\tconst multipleRemotesRegex = /\\{\\{#IF MULTIPLE_REMOTES\\}\\}(.*?)\\{\\{\\/IF MULTIPLE_REMOTES\\}\\}/gs\n\n\t\tif (variables.MULTIPLE_REMOTES !== undefined && variables.MULTIPLE_REMOTES !== '') {\n\t\t\t// Include the content, remove the conditional markers\n\t\t\tresult = result.replace(multipleRemotesRegex, '$1')\n\t\t} else {\n\t\t\t// Remove the entire conditional block\n\t\t\tresult = result.replace(multipleRemotesRegex, '')\n\t\t}\n\n\t\t// Process SINGLE_REMOTE conditionals\n\t\tconst singleRemoteRegex = /\\{\\{#IF SINGLE_REMOTE\\}\\}(.*?)\\{\\{\\/IF SINGLE_REMOTE\\}\\}/gs\n\n\t\tif (variables.SINGLE_REMOTE !== undefined && variables.SINGLE_REMOTE !== '') {\n\t\t\t// Include the content, remove the conditional markers\n\t\t\tresult = result.replace(singleRemoteRegex, '$1')\n\t\t} else {\n\t\t\t// Remove the entire conditional block\n\t\t\tresult = result.replace(singleRemoteRegex, '')\n\t\t}\n\n\t\t// Process NO_REMOTES conditionals\n\t\tconst noRemotesRegex = /\\{\\{#IF NO_REMOTES\\}\\}(.*?)\\{\\{\\/IF NO_REMOTES\\}\\}/gs\n\n\t\tif (variables.NO_REMOTES !== undefined && variables.NO_REMOTES !== '') {\n\t\t\t// Include the content, remove the conditional markers\n\t\t\tresult = result.replace(noRemotesRegex, '$1')\n\t\t} else {\n\t\t\t// Remove the entire conditional block\n\t\t\tresult = result.replace(noRemotesRegex, '')\n\t\t}\n\n\t\treturn result\n\t}\n\n\t/**\n\t * Get a fully processed prompt for a workflow type\n\t */\n\tasync getPrompt(\n\t\ttype: 'issue' | 'pr' | 'regular' | 'init',\n\t\tvariables: TemplateVariables\n\t): Promise<string> {\n\t\tconst template = await this.loadTemplate(type)\n\t\treturn this.substituteVariables(template, variables)\n\t}\n}\n"],"mappings":"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","names":["templateDir"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/terminal.ts"],"sourcesContent":["import { execa } from 'execa'\nimport { existsSync } from 'node:fs'\nimport type { Platform } from '../types/index.js'\n\nexport interface TerminalWindowOptions {\n\tworkspacePath?: string\n\tcommand?: string\n\tbackgroundColor?: { r: number; g: number; b: number }\n\tport?: number\n\tincludeEnvSetup?: boolean // source .env\n\tincludePortExport?: boolean // export PORT=<port>\n\ttitle?: string // Terminal tab title\n}\n\n/**\n * Detect current platform\n */\nexport function detectPlatform(): Platform {\n\tconst platform = process.platform\n\tif (platform === 'darwin') return 'darwin'\n\tif (platform === 'linux') return 'linux'\n\tif (platform === 'win32') return 'win32'\n\treturn 'unsupported'\n}\n\n/**\n * Detect if iTerm2 is installed on macOS\n * Returns false on non-macOS platforms\n */\nexport async function detectITerm2(): Promise<boolean> {\n\tconst platform = detectPlatform()\n\tif (platform !== 'darwin') return false\n\n\t// Check if iTerm.app exists at standard location\n\treturn existsSync('/Applications/iTerm.app')\n}\n\n/**\n * Open new terminal window with specified options\n * Currently supports macOS only\n */\nexport async function openTerminalWindow(\n\toptions: TerminalWindowOptions\n): Promise<void> {\n\tconst platform = detectPlatform()\n\n\tif (platform !== 'darwin') {\n\t\tthrow new Error(\n\t\t\t`Terminal window launching not yet supported on ${platform}. ` +\n\t\t\t\t`Currently only macOS is supported.`\n\t\t)\n\t}\n\n\t// macOS implementation using AppleScript\n\tconst applescript = buildAppleScript(options)\n\n\ttry {\n\t\tawait execa('osascript', ['-e', applescript])\n\n\t\t// Activate Terminal.app to bring windows to front\n\t\tawait execa('osascript', ['-e', 'tell application \"Terminal\" to activate'])\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to open terminal window: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t)\n\t}\n}\n\n/**\n * Build AppleScript for macOS Terminal.app\n */\nfunction buildAppleScript(options: TerminalWindowOptions): string {\n\tconst {\n\t\tworkspacePath,\n\t\tcommand,\n\t\tbackgroundColor,\n\t\tport,\n\t\tincludeEnvSetup,\n\t\tincludePortExport,\n\t} = options\n\n\t// Build command sequence\n\tconst commands: string[] = []\n\n\t// Navigate to workspace\n\tif (workspacePath) {\n\t\tcommands.push(`cd '${escapePathForAppleScript(workspacePath)}'`)\n\t}\n\n\t// Source .env file\n\tif (includeEnvSetup) {\n\t\tcommands.push('source .env')\n\t}\n\n\t// Export PORT variable\n\tif (includePortExport && port !== undefined) {\n\t\tcommands.push(`export PORT=${port}`)\n\t}\n\n\t// Add custom command\n\tif (command) {\n\t\tcommands.push(command)\n\t}\n\n\t// Join with &&\n\tconst fullCommand = commands.join(' && ')\n\n\t// Prefix with space to prevent shell history pollution\n\t// Most shells (bash/zsh) ignore commands starting with space when HISTCONTROL=ignorespace\n\tconst historyFreeCommand = ` ${fullCommand}`\n\n\t// Build AppleScript\n\tlet script = `tell application \"Terminal\"\\n`\n\tscript += ` set newTab to do script \"${escapeForAppleScript(historyFreeCommand)}\"\\n`\n\n\t// Apply background color if provided\n\tif (backgroundColor) {\n\t\tconst { r, g, b } = backgroundColor\n\t\t// Convert 8-bit RGB (0-255) to 16-bit RGB (0-65535)\n\t\tscript += ` set background color of newTab to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}\\n`\n\t}\n\n\tscript += `end tell`\n\n\treturn script\n}\n\n/**\n * Escape path for AppleScript string\n * Single quotes in path need special escaping\n */\nfunction escapePathForAppleScript(path: string): string {\n\t// Replace single quote with '\\''\n\treturn path.replace(/'/g, \"'\\\\''\")\n}\n\n/**\n * Escape command for AppleScript do script\n * Must handle double quotes and backslashes\n */\nfunction escapeForAppleScript(command: string): string {\n\treturn (\n\t\tcommand\n\t\t\t.replace(/\\\\/g, '\\\\\\\\') // Escape backslashes\n\t\t\t.replace(/\"/g, '\\\\\"') // Escape double quotes\n\t)\n}\n\n/**\n * Build command sequence for terminal\n */\nfunction buildCommandSequence(options: TerminalWindowOptions): string {\n\tconst {\n\t\tworkspacePath,\n\t\tcommand,\n\t\tport,\n\t\tincludeEnvSetup,\n\t\tincludePortExport,\n\t} = options\n\n\tconst commands: string[] = []\n\n\t// Navigate to workspace\n\tif (workspacePath) {\n\t\tcommands.push(`cd '${escapePathForAppleScript(workspacePath)}'`)\n\t}\n\n\t// Source .env file\n\tif (includeEnvSetup) {\n\t\tcommands.push('source .env')\n\t}\n\n\t// Export PORT variable\n\tif (includePortExport && port !== undefined) {\n\t\tcommands.push(`export PORT=${port}`)\n\t}\n\n\t// Add custom command\n\tif (command) {\n\t\tcommands.push(command)\n\t}\n\n\t// Join with &&\n\tconst fullCommand = commands.join(' && ')\n\n\t// Prefix with space to prevent shell history pollution\n\treturn ` ${fullCommand}`\n}\n\n/**\n * Build iTerm2 AppleScript for multiple tabs (2+) in single window\n */\nfunction buildITerm2MultiTabScript(\n\toptionsArray: TerminalWindowOptions[]\n): string {\n\tif (optionsArray.length < 2) {\n\t\tthrow new Error('buildITerm2MultiTabScript requires at least 2 terminal options')\n\t}\n\n\tlet script = 'tell application id \"com.googlecode.iterm2\"\\n'\n\tscript += ' create window with default profile\\n'\n\tscript += ' set newWindow to current window\\n'\n\n\t// First tab\n\tconst options1 = optionsArray[0]\n\tif (!options1) {\n\t\tthrow new Error('First terminal option is undefined')\n\t}\n\tconst command1 = buildCommandSequence(options1)\n\n\tscript += ' set s1 to current session of newWindow\\n\\n'\n\n\t// Set background color for first tab\n\tif (options1.backgroundColor) {\n\t\tconst { r, g, b } = options1.backgroundColor\n\t\tscript += ` set background color of s1 to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}\\n`\n\t}\n\n\t// Execute command in first tab\n\tscript += ` tell s1 to write text \"${escapeForAppleScript(command1)}\"\\n\\n`\n\n\t// Set tab title for first tab\n\tif (options1.title) {\n\t\tscript += ` set name of s1 to \"${escapeForAppleScript(options1.title)}\"\\n\\n`\n\t}\n\n\t// Subsequent tabs (2, 3, ...)\n\tfor (let i = 1; i < optionsArray.length; i++) {\n\t\tconst options = optionsArray[i]\n\t\tif (!options) {\n\t\t\tthrow new Error(`Terminal option at index ${i} is undefined`)\n\t\t}\n\t\tconst command = buildCommandSequence(options)\n\t\tconst sessionVar = `s${i + 1}`\n\n\t\t// Create tab\n\t\tscript += ' tell newWindow\\n'\n\t\tscript += ` set newTab${i} to (create tab with default profile)\\n`\n\t\tscript += ' end tell\\n'\n\t\tscript += ` set ${sessionVar} to current session of newTab${i}\\n\\n`\n\n\t\t// Set background color\n\t\tif (options.backgroundColor) {\n\t\t\tconst { r, g, b } = options.backgroundColor\n\t\t\tscript += ` set background color of ${sessionVar} to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}\\n`\n\t\t}\n\n\t\t// Execute command\n\t\tscript += ` tell ${sessionVar} to write text \"${escapeForAppleScript(command)}\"\\n\\n`\n\n\t\t// Set tab title\n\t\tif (options.title) {\n\t\t\tscript += ` set name of ${sessionVar} to \"${escapeForAppleScript(options.title)}\"\\n\\n`\n\t\t}\n\t}\n\n\t// Activate iTerm2\n\tscript += ' activate\\n'\n\tscript += 'end tell'\n\n\treturn script\n}\n\n/**\n * Open multiple terminal windows/tabs (2+) with specified options\n * If iTerm2 is available on macOS, creates single window with multiple tabs\n * Otherwise falls back to multiple separate Terminal.app windows\n */\nexport async function openMultipleTerminalWindows(\n\toptionsArray: TerminalWindowOptions[]\n): Promise<void> {\n\tif (optionsArray.length < 2) {\n\t\tthrow new Error('openMultipleTerminalWindows requires at least 2 terminal options. Use openTerminalWindow for single terminal.')\n\t}\n\n\tconst platform = detectPlatform()\n\n\tif (platform !== 'darwin') {\n\t\tthrow new Error(\n\t\t\t`Terminal window launching not yet supported on ${platform}. ` +\n\t\t\t\t`Currently only macOS is supported.`\n\t\t)\n\t}\n\n\t// Detect if iTerm2 is available\n\tconst hasITerm2 = await detectITerm2()\n\n\tif (hasITerm2) {\n\t\t// Use iTerm2 with multiple tabs in single window\n\t\tconst applescript = buildITerm2MultiTabScript(optionsArray)\n\n\t\ttry {\n\t\t\tawait execa('osascript', ['-e', applescript])\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to open iTerm2 window: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t)\n\t\t}\n\t} else {\n\t\t// Fall back to multiple Terminal.app windows\n\t\tfor (let i = 0; i < optionsArray.length; i++) {\n\t\t\tconst options = optionsArray[i]\n\t\t\tif (!options) {\n\t\t\t\tthrow new Error(`Terminal option at index ${i} is undefined`)\n\t\t\t}\n\t\t\tawait openTerminalWindow(options)\n\n\t\t\t// Brief pause between terminals (except after last one)\n\t\t\tif (i < optionsArray.length - 1) {\n\t\t\t\t// eslint-disable-next-line no-undef\n\t\t\t\tawait new Promise<void>((resolve) => setTimeout(resolve, 1000))\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Open dual terminal windows/tabs with specified options\n * If iTerm2 is available on macOS, creates single window with two tabs\n * Otherwise falls back to two separate Terminal.app windows\n */\nexport async function openDualTerminalWindow(\n\toptions1: TerminalWindowOptions,\n\toptions2: TerminalWindowOptions\n): Promise<void> {\n\t// Delegate to openMultipleTerminalWindows for consistency\n\tawait openMultipleTerminalWindows([options1, options2])\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/ValidationRunner.ts","../src/lib/CommitManager.ts","../src/lib/BuildRunner.ts","../src/commands/finish.ts"],"sourcesContent":["import { logger } from '../utils/logger.js'\nimport { detectPackageManager, runScript } from '../utils/package-manager.js'\nimport { readPackageJson, hasScript } from '../utils/package-json.js'\nimport { detectClaudeCli, launchClaude } from '../utils/claude.js'\nimport type {\n\tValidationOptions,\n\tValidationResult,\n\tValidationStepResult,\n} from '../types/index.js'\n\n/**\n * ValidationRunner orchestrates pre-merge validation pipeline\n * Runs typecheck, lint, and tests in sequence with fail-fast behavior\n */\nexport class ValidationRunner {\n\t/**\n\t * Run all validations in sequence: typecheck → lint → test\n\t * Fails fast on first error\n\t */\n\tasync runValidations(\n\t\tworktreePath: string,\n\t\toptions: ValidationOptions = {}\n\t): Promise<ValidationResult> {\n\t\tconst startTime = Date.now()\n\t\tconst steps: ValidationStepResult[] = []\n\n\t\t// Run typecheck\n\t\tif (!options.skipTypecheck) {\n\t\t\tconst typecheckResult = await this.runTypecheck(\n\t\t\t\tworktreePath,\n\t\t\t\toptions.dryRun ?? false\n\t\t\t)\n\t\t\tsteps.push(typecheckResult)\n\n\t\t\tif (!typecheckResult.passed && !typecheckResult.skipped) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\tsteps,\n\t\t\t\t\ttotalDuration: Date.now() - startTime,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Run lint\n\t\tif (!options.skipLint) {\n\t\t\tconst lintResult = await this.runLint(worktreePath, options.dryRun ?? false)\n\t\t\tsteps.push(lintResult)\n\n\t\t\tif (!lintResult.passed && !lintResult.skipped) {\n\t\t\t\treturn { success: false, steps, totalDuration: Date.now() - startTime }\n\t\t\t}\n\t\t}\n\n\t\t// Run tests\n\t\tif (!options.skipTests) {\n\t\t\tconst testResult = await this.runTests(\n\t\t\t\tworktreePath,\n\t\t\t\toptions.dryRun ?? false\n\t\t\t)\n\t\t\tsteps.push(testResult)\n\n\t\t\tif (!testResult.passed && !testResult.skipped) {\n\t\t\t\treturn { success: false, steps, totalDuration: Date.now() - startTime }\n\t\t\t}\n\t\t}\n\n\t\treturn { success: true, steps, totalDuration: Date.now() - startTime }\n\t}\n\n\t/**\n\t * Run typecheck validation\n\t */\n\tprivate async runTypecheck(\n\t\tworktreePath: string,\n\t\tdryRun: boolean\n\t): Promise<ValidationStepResult> {\n\t\tconst stepStartTime = Date.now()\n\n\t\ttry {\n\t\t\t// Check if typecheck script exists\n\t\t\tconst pkgJson = await readPackageJson(worktreePath)\n\t\t\tconst hasTypecheckScript = hasScript(pkgJson, 'typecheck')\n\n\t\t\tif (!hasTypecheckScript) {\n\t\t\t\tlogger.debug('Skipping typecheck - no typecheck script found')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'typecheck',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: true,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Handle missing package.json - skip validation for non-Node.js projects\n\t\t\tif (error instanceof Error && error.message.includes('package.json not found')) {\n\t\t\t\tlogger.debug('Skipping typecheck - no package.json found (non-Node.js project)')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'typecheck',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: true,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Re-throw other errors\n\t\t\tthrow error\n\t\t}\n\n\t\tconst packageManager = await detectPackageManager(worktreePath)\n\n\t\tif (dryRun) {\n\t\t\tconst command =\n\t\t\t\tpackageManager === 'npm'\n\t\t\t\t\t? 'npm run typecheck'\n\t\t\t\t\t: `${packageManager} typecheck`\n\t\t\tlogger.info(`[DRY RUN] Would run: ${command}`)\n\t\t\treturn {\n\t\t\t\tstep: 'typecheck',\n\t\t\t\tpassed: true,\n\t\t\t\tskipped: false,\n\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t}\n\t\t}\n\n\t\tlogger.info('Running typecheck...')\n\n\t\ttry {\n\t\t\tawait runScript('typecheck', worktreePath, [], { quiet: true })\n\t\t\tlogger.success('Typecheck passed')\n\n\t\t\treturn {\n\t\t\t\tstep: 'typecheck',\n\t\t\t\tpassed: true,\n\t\t\t\tskipped: false,\n\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t}\n\t\t} catch {\n\t\t\t// Attempt Claude-assisted fix before failing\n\t\t\tconst fixed = await this.attemptClaudeFix(\n\t\t\t\t'typecheck',\n\t\t\t\tworktreePath,\n\t\t\t\tpackageManager\n\t\t\t)\n\n\t\t\tif (fixed) {\n\t\t\t\t// logger.success('Typecheck passed after Claude auto-fix')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'typecheck',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: false,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Claude couldn't fix - throw original error\n\t\t\tconst runCommand =\n\t\t\t\tpackageManager === 'npm'\n\t\t\t\t\t? 'npm run typecheck'\n\t\t\t\t\t: `${packageManager} typecheck`\n\n\t\t\tthrow new Error(\n\t\t\t\t`Error: Typecheck failed.\\n` +\n\t\t\t\t\t`Fix type errors before merging.\\n\\n` +\n\t\t\t\t\t`Run '${runCommand}' to see detailed errors.`\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Run lint validation\n\t */\n\tprivate async runLint(\n\t\tworktreePath: string,\n\t\tdryRun: boolean\n\t): Promise<ValidationStepResult> {\n\t\tconst stepStartTime = Date.now()\n\n\t\ttry {\n\t\t\t// Check if lint script exists\n\t\t\tconst pkgJson = await readPackageJson(worktreePath)\n\t\t\tconst hasLintScript = hasScript(pkgJson, 'lint')\n\n\t\t\tif (!hasLintScript) {\n\t\t\t\tlogger.debug('Skipping lint - no lint script found')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'lint',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: true,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Handle missing package.json - skip validation for non-Node.js projects\n\t\t\tif (error instanceof Error && error.message.includes('package.json not found')) {\n\t\t\t\tlogger.debug('Skipping lint - no package.json found (non-Node.js project)')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'lint',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: true,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Re-throw other errors\n\t\t\tthrow error\n\t\t}\n\n\t\tconst packageManager = await detectPackageManager(worktreePath)\n\n\t\tif (dryRun) {\n\t\t\tconst command =\n\t\t\t\tpackageManager === 'npm' ? 'npm run lint' : `${packageManager} lint`\n\t\t\tlogger.info(`[DRY RUN] Would run: ${command}`)\n\t\t\treturn {\n\t\t\t\tstep: 'lint',\n\t\t\t\tpassed: true,\n\t\t\t\tskipped: false,\n\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t}\n\t\t}\n\n\t\tlogger.info('Running lint...')\n\n\t\ttry {\n\t\t\tawait runScript('lint', worktreePath, [], { quiet: true })\n\t\t\tlogger.success('Linting passed')\n\n\t\t\treturn {\n\t\t\t\tstep: 'lint',\n\t\t\t\tpassed: true,\n\t\t\t\tskipped: false,\n\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t}\n\t\t} catch {\n\t\t\t// Attempt Claude-assisted fix before failing\n\t\t\tconst fixed = await this.attemptClaudeFix(\n\t\t\t\t'lint',\n\t\t\t\tworktreePath,\n\t\t\t\tpackageManager\n\t\t\t)\n\n\t\t\tif (fixed) {\n\t\t\t\t// logger.success('Linting passed after Claude auto-fix')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'lint',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: false,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Claude couldn't fix - throw original error\n\t\t\tconst runCommand =\n\t\t\t\tpackageManager === 'npm' ? 'npm run lint' : `${packageManager} lint`\n\n\t\t\tthrow new Error(\n\t\t\t\t`Error: Linting failed.\\n` +\n\t\t\t\t\t`Fix linting errors before merging.\\n\\n` +\n\t\t\t\t\t`Run '${runCommand}' to see detailed errors.`\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Run test validation\n\t */\n\tprivate async runTests(\n\t\tworktreePath: string,\n\t\tdryRun: boolean\n\t): Promise<ValidationStepResult> {\n\t\tconst stepStartTime = Date.now()\n\n\t\ttry {\n\t\t\t// Check if test script exists\n\t\t\tconst pkgJson = await readPackageJson(worktreePath)\n\t\t\tconst hasTestScript = hasScript(pkgJson, 'test')\n\n\t\t\tif (!hasTestScript) {\n\t\t\t\tlogger.debug('Skipping tests - no test script found')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'test',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: true,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Handle missing package.json - skip validation for non-Node.js projects\n\t\t\tif (error instanceof Error && error.message.includes('package.json not found')) {\n\t\t\t\tlogger.debug('Skipping tests - no package.json found (non-Node.js project)')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'test',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: true,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Re-throw other errors\n\t\t\tthrow error\n\t\t}\n\n\t\tconst packageManager = await detectPackageManager(worktreePath)\n\n\t\tif (dryRun) {\n\t\t\tconst command =\n\t\t\t\tpackageManager === 'npm' ? 'npm run test' : `${packageManager} test`\n\t\t\tlogger.info(`[DRY RUN] Would run: ${command}`)\n\t\t\treturn {\n\t\t\t\tstep: 'test',\n\t\t\t\tpassed: true,\n\t\t\t\tskipped: false,\n\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t}\n\t\t}\n\n\t\tlogger.info('Running tests...')\n\n\t\ttry {\n\t\t\tawait runScript('test', worktreePath, [], { quiet: true })\n\t\t\tlogger.success('Tests passed')\n\n\t\t\treturn {\n\t\t\t\tstep: 'test',\n\t\t\t\tpassed: true,\n\t\t\t\tskipped: false,\n\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t}\n\t\t} catch {\n\t\t\t// Attempt Claude-assisted fix before failing\n\t\t\tconst fixed = await this.attemptClaudeFix(\n\t\t\t\t'test',\n\t\t\t\tworktreePath,\n\t\t\t\tpackageManager\n\t\t\t)\n\n\t\t\tif (fixed) {\n\t\t\t\t// logger.success('Tests passed after Claude auto-fix')\n\t\t\t\treturn {\n\t\t\t\t\tstep: 'test',\n\t\t\t\t\tpassed: true,\n\t\t\t\t\tskipped: false,\n\t\t\t\t\tduration: Date.now() - stepStartTime,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Claude couldn't fix - throw original error\n\t\t\tconst runCommand =\n\t\t\t\tpackageManager === 'npm' ? 'npm run test' : `${packageManager} test`\n\n\t\t\tthrow new Error(\n\t\t\t\t`Error: Tests failed.\\n` +\n\t\t\t\t\t`Fix test failures before merging.\\n\\n` +\n\t\t\t\t\t`Run '${runCommand}' to see detailed errors.`\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Attempt to fix validation errors using Claude\n\t * Pattern based on MergeManager.attemptClaudeConflictResolution\n\t *\n\t * @param validationType - Type of validation that failed ('typecheck' | 'lint' | 'test')\n\t * @param worktreePath - Path to the worktree\n\t * @param packageManager - Detected package manager\n\t * @returns true if Claude fixed the issue, false otherwise\n\t */\n\tprivate async attemptClaudeFix(\n\t\tvalidationType: 'typecheck' | 'lint' | 'test',\n\t\tworktreePath: string,\n\t\tpackageManager: string\n\t): Promise<boolean> {\n\t\t// Check if Claude CLI is available\n\t\tconst isClaudeAvailable = await detectClaudeCli()\n\t\tif (!isClaudeAvailable) {\n\t\t\tlogger.debug('Claude CLI not available, skipping auto-fix')\n\t\t\treturn false\n\t\t}\n\n\t\t// Build validation command for the prompt\n\t\tconst validationCommand = this.getValidationCommand(validationType, packageManager)\n\n\t\t// Build prompt based on validation type (matching bash script prompts)\n\t\tconst prompt = this.getClaudePrompt(validationType, validationCommand)\n\n\t\tconst validationTypeCapitalized = validationType.charAt(0).toUpperCase() + validationType.slice(1)\n\t\tlogger.info(`Launching Claude to help fix ${validationTypeCapitalized} errors...`)\n\n\t\ttry {\n\t\t\t// Launch Claude in interactive mode with acceptEdits permission\n\t\t\tawait launchClaude(prompt, {\n\t\t\t\taddDir: worktreePath,\n\t\t\t\theadless: false, // Interactive mode\n\t\t\t\tpermissionMode: 'acceptEdits', // Auto-accept edits\n\t\t\t\tmodel: 'sonnet', // Use Sonnet model\n\t\t\t})\n\n\t\t\t// After Claude completes, re-run validation to verify fix\n\t\t\tlogger.info(`Re-running ${validationTypeCapitalized} after Claude's fixes...`)\n\n\t\t\ttry {\n\t\t\t\tawait runScript(validationType, worktreePath, [], { quiet: true })\n\t\t\t\t// Validation passed after Claude fix\n\t\t\t\tlogger.success(`${validationTypeCapitalized} passed after Claude auto-fix`)\n\t\t\t\treturn true\n\t\t\t} catch {\n\t\t\t\t// Validation still failing after Claude's attempt\n\t\t\t\tlogger.warn(`${validationTypeCapitalized} still failing after Claude's help`)\n\t\t\t\treturn false\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Claude launch failed or crashed\n\t\t\tlogger.warn('Claude auto-fix failed', {\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t})\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Get validation command string for prompts\n\t */\n\tprivate getValidationCommand(\n\t\tvalidationType: 'typecheck' | 'lint' | 'test',\n\t\tpackageManager: string\n\t): string {\n\t\tif (packageManager === 'npm') {\n\t\t\treturn `npm run ${validationType}`\n\t\t}\n\t\treturn `${packageManager} ${validationType}`\n\t}\n\n\t/**\n\t * Get Claude prompt for specific validation type\n\t * Matches bash script prompts exactly\n\t */\n\tprivate getClaudePrompt(\n\t\tvalidationType: 'typecheck' | 'lint' | 'test',\n\t\tvalidationCommand: string\n\t): string {\n\t\tswitch (validationType) {\n\t\t\tcase 'typecheck':\n\t\t\t\treturn (\n\t\t\t\t\t`There are TypeScript errors in this codebase. ` +\n\t\t\t\t\t`Please analyze the typecheck output, identify all type errors, and fix them. ` +\n\t\t\t\t\t`Run '${validationCommand}' to see the errors, then make the necessary code changes to resolve all type issues. ` +\n\t\t\t\t\t`When you are done, tell the user to quit using /exit to continue the validation process.`\n\t\t\t\t)\n\t\t\tcase 'lint':\n\t\t\t\treturn (\n\t\t\t\t\t`There are ESLint errors in this codebase. ` +\n\t\t\t\t\t`Please analyze the linting output, identify all linting issues, and fix them. ` +\n\t\t\t\t\t`Run '${validationCommand}' to see the errors, then make the necessary code changes to resolve all linting issues. ` +\n\t\t\t\t\t`Focus on code quality, consistency, and following the project's linting rules. ` +\n\t\t\t\t\t`When you are done, tell the user to quit using /exit to continue the validation process.`\n\t\t\t\t)\n\t\t\tcase 'test':\n\t\t\t\treturn (\n\t\t\t\t\t`There are unit test failures in this codebase. ` +\n\t\t\t\t\t`Please analyze the test output to understand what's failing, then fix the issues. ` +\n\t\t\t\t\t`This might involve updating test code, fixing bugs in the source code, or updating tests to match new behavior. ` +\n\t\t\t\t\t`Run '${validationCommand}' to see the detailed test failures, then make the necessary changes to get all tests passing. ` +\n\t\t\t\t\t`When you are done, tell the user to quit using /exit to continue the validation process.`\n\t\t\t\t)\n\t\t}\n\t}\n}\n","import { executeGitCommand } from '../utils/git.js'\nimport { logger } from '../utils/logger.js'\nimport { launchClaude, detectClaudeCli } from '../utils/claude.js'\nimport type { GitStatus, CommitOptions } from '../types/index.js'\n\n/**\n * CommitManager handles uncommitted changes detection and auto-commit\n * Ports logic from bash/merge-and-clean.sh lines 610-643\n */\nexport class CommitManager {\n /**\n * Detect uncommitted changes in a worktree\n * Parses git status --porcelain output into structured GitStatus\n */\n async detectUncommittedChanges(worktreePath: string): Promise<GitStatus> {\n // Execute: git status --porcelain\n const porcelainOutput = await executeGitCommand(['status', '--porcelain'], {\n cwd: worktreePath,\n })\n\n // Parse output to get staged and unstaged files\n const { stagedFiles, unstagedFiles } = this.parseGitStatus(porcelainOutput)\n\n // Get current branch name\n const currentBranch = await executeGitCommand(['branch', '--show-current'], {\n cwd: worktreePath,\n })\n\n return {\n hasUncommittedChanges: stagedFiles.length > 0 || unstagedFiles.length > 0,\n unstagedFiles,\n stagedFiles,\n currentBranch: currentBranch.trim(),\n // Defer these to future enhancement\n isAheadOfRemote: false,\n isBehindRemote: false,\n }\n }\n\n\n /**\n * Stage all changes and commit with Claude-generated or simple message\n * Tries Claude first, falls back to simple message if Claude unavailable or fails\n */\n async commitChanges(worktreePath: string, options: CommitOptions): Promise<void> {\n // Step 1: Check dry-run mode\n if (options.dryRun) {\n logger.info('[DRY RUN] Would run: git add -A')\n logger.info('[DRY RUN] Would generate commit message with Claude (if available)')\n const fallbackMessage = this.generateFallbackMessage(options)\n const verifyFlag = options.skipVerify ? ' --no-verify' : ''\n logger.info(`[DRY RUN] Would commit with message${verifyFlag}: ${fallbackMessage}`)\n return\n }\n\n // Step 2: Stage all changes\n await executeGitCommand(['add', '-A'], { cwd: worktreePath })\n\n // Step 3: Generate commit message (try Claude first, fallback to simple)\n let message: string | null = null\n\n // Skip Claude if custom message provided\n if (!options.message) {\n try {\n message = await this.generateClaudeCommitMessage(worktreePath, options.issueNumber)\n } catch (error) {\n logger.debug('Claude commit message generation failed, using fallback', { error })\n }\n }\n\n // Fallback to simple message if Claude failed or unavailable\n message ??= this.generateFallbackMessage(options)\n\n // Step 4: Log warning if --no-verify is configured\n if (options.skipVerify) {\n logger.warn('⚠️ Skipping pre-commit hooks (--no-verify configured in settings)')\n }\n\n // Step 5: Commit with user review via git editor (unless noReview specified)\n try {\n if (options.noReview || options.message) {\n // Direct commit without editor review\n const commitArgs = ['commit', '-m', message]\n if (options.skipVerify) {\n commitArgs.push('--no-verify')\n }\n await executeGitCommand(commitArgs, { cwd: worktreePath })\n } else {\n // Use git editor for user review - pre-populate message and open editor\n logger.info('Opening git editor for commit message review...')\n const commitArgs = ['commit', '-e', '-m', message]\n if (options.skipVerify) {\n commitArgs.push('--no-verify')\n }\n await executeGitCommand(commitArgs, {\n cwd: worktreePath,\n stdio: 'inherit',\n timeout: 300000 // 5 minutes for interactive editing\n })\n }\n } catch (error) {\n // Handle \"nothing to commit\" scenario gracefully\n if (error instanceof Error && error.message.includes('nothing to commit')) {\n logger.info('No changes to commit')\n return\n }\n // Re-throw all other errors (including pre-commit hook failures)\n throw error\n }\n }\n\n\n /**\n * Generate simple fallback commit message when Claude unavailable\n * Used as fallback for Claude-powered commit messages\n */\n private generateFallbackMessage(options: CommitOptions): string {\n // If custom message provided, use it\n if (options.message) {\n return options.message\n }\n\n // Generate WIP message\n if (options.issueNumber) {\n return `WIP: Auto-commit for issue #${options.issueNumber}\\n\\nFixes #${options.issueNumber}`\n } else {\n return 'WIP: Auto-commit uncommitted changes'\n }\n }\n\n /**\n * Parse git status --porcelain output\n * Format: \"XY filename\" where X=index, Y=worktree\n * Examples:\n * \"M file.ts\" - staged modification\n * \" M file.ts\" - unstaged modification\n * \"MM file.ts\" - both staged and unstaged\n * \"?? file.ts\" - untracked\n */\n private parseGitStatus(porcelainOutput: string): {\n stagedFiles: string[]\n unstagedFiles: string[]\n } {\n const stagedFiles: string[] = []\n const unstagedFiles: string[] = []\n\n if (!porcelainOutput.trim()) {\n return { stagedFiles, unstagedFiles }\n }\n\n const lines = porcelainOutput.split('\\n').filter((line) => line.trim())\n\n for (const line of lines) {\n if (line.length < 3) continue\n\n const indexStatus = line[0] // First character - staging area status\n const worktreeStatus = line[1] // Second character - working tree status\n const filename = line.substring(3) // Everything after \"XY \"\n\n // Check if file is staged\n // First char != ' ' and != '?' → staged\n if (indexStatus !== ' ' && indexStatus !== '?') {\n stagedFiles.push(filename)\n }\n\n // Check if file is unstaged\n // Second char != ' ' or line starts with '??' → unstaged\n if (worktreeStatus !== ' ' || line.startsWith('??')) {\n unstagedFiles.push(filename)\n }\n }\n\n return { stagedFiles, unstagedFiles }\n }\n\n /**\n * Generate commit message using Claude AI\n * Claude examines the git repository directly via --add-dir option\n * Returns null if Claude unavailable or fails validation\n */\n private async generateClaudeCommitMessage(\n worktreePath: string,\n issueNumber?: number\n ): Promise<string | null> {\n const startTime = Date.now()\n\n logger.info('Starting Claude commit message generation...', {\n worktreePath: worktreePath.split('/').pop(), // Just show the folder name for privacy\n issueNumber\n })\n\n // Check if Claude CLI is available\n logger.debug('Checking Claude CLI availability...')\n const isClaudeAvailable = await detectClaudeCli()\n if (!isClaudeAvailable) {\n logger.info('Claude CLI not available, skipping Claude commit message generation')\n return null\n }\n logger.debug('Claude CLI is available')\n\n // Build XML-based structured prompt\n logger.debug('Building commit message prompt...')\n const prompt = this.buildCommitMessagePrompt(issueNumber)\n logger.debug('Prompt built', { promptLength: prompt.length })\n\n // Debug log the actual prompt content for troubleshooting\n logger.debug('Claude prompt content:', {\n prompt: prompt,\n truncatedPreview: prompt.substring(0, 500) + (prompt.length > 500 ? '...[truncated]' : '')\n })\n\n try {\n logger.info('Calling Claude CLI for commit message generation...')\n const claudeStartTime = Date.now()\n\n // Debug log the Claude call parameters\n const claudeOptions = {\n headless: true,\n addDir: worktreePath,\n model: 'claude-haiku-4-5-20251001', // Fast, cost-effective model\n timeout: 120000, // 120 second timeout\n }\n logger.debug('Claude CLI call parameters:', {\n options: claudeOptions,\n worktreePathForAnalysis: worktreePath,\n addDirContents: 'Will include entire worktree directory for analysis'\n })\n\n // Launch Claude in headless mode with repository access and shorter timeout for commit messages\n const result = await launchClaude(prompt, claudeOptions)\n\n const claudeDuration = Date.now() - claudeStartTime\n logger.debug('Claude API call completed', { duration: `${claudeDuration}ms` })\n\n if (typeof result !== 'string') {\n logger.warn('Claude returned non-string result', { resultType: typeof result })\n return null\n }\n\n logger.debug('Raw Claude output received', {\n outputLength: result.length,\n preview: result.substring(0, 200) + (result.length > 200 ? '...' : '')\n })\n\n\n // Sanitize output - remove meta-commentary and clean formatting\n logger.debug('Sanitizing Claude output...')\n const sanitized = this.sanitizeClaudeOutput(result)\n logger.debug('Output sanitized', {\n originalLength: result.length,\n sanitizedLength: sanitized.length,\n sanitized: sanitized.substring(0, 200) + (sanitized.length > 200 ? '...' : '')\n })\n\n // Ensure empty strings are rejected\n if (!sanitized) {\n logger.warn('Claude returned empty message after sanitization')\n return null\n }\n\n // Append \"Fixes #N\" trailer if issue number provided\n let finalMessage = sanitized\n if (issueNumber) {\n // Add Fixes trailer if not already present\n if (!finalMessage.includes(`Fixes #${issueNumber}`)) {\n finalMessage = `${finalMessage}\\n\\nFixes #${issueNumber}`\n logger.debug(`Added \"Fixes #${issueNumber}\" trailer to commit message`)\n } else {\n logger.debug(`\"Fixes #${issueNumber}\" already present in commit message`)\n }\n }\n\n const totalDuration = Date.now() - startTime\n logger.info('Claude commit message generated successfully', {\n message: finalMessage,\n totalDuration: `${totalDuration}ms`,\n claudeApiDuration: `${claudeDuration}ms`\n })\n\n return finalMessage\n } catch (error) {\n const totalDuration = Date.now() - startTime\n const errorMessage = error instanceof Error ? error.message : 'Unknown error'\n\n if (errorMessage.includes('timed out') || errorMessage.includes('timeout')) {\n logger.warn('Claude commit message generation timed out after 45 seconds', {\n totalDuration: `${totalDuration}ms`,\n worktreePath: worktreePath.split('/').pop()\n })\n } else {\n logger.warn('Failed to generate commit message with Claude', {\n error: errorMessage,\n totalDuration: `${totalDuration}ms`,\n worktreePath: worktreePath.split('/').pop()\n })\n }\n return null\n }\n }\n\n /**\n * Build structured XML prompt for commit message generation\n * Uses XML format for clear task definition and output expectations\n */\n private buildCommitMessagePrompt(issueNumber?: number): string {\n const issueContext = issueNumber\n ? `\\n<IssueContext>\nThis commit is associated with GitHub issue #${issueNumber}.\nIf the changes appear to resolve the issue, include \"Fixes #${issueNumber}\" at the end of the first line of commit message.\n</IssueContext>`\n : ''\n\n return `<Task>\nYou are a software engineer writing a commit message for this repository.\nExamine the staged changes in the git repository and generate a concise, meaningful commit message.\n</Task>\n\n<Requirements>\n<Format>The first line must be a brief summary of the changes made as a full sentence. If it references an issue, include \"Fixes #N\" at the end of this line.\n\nAdd 2 newlines, then add a bullet-point form description of the changes made, each change on a new line.</Format>\n<Mood>Use imperative mood (e.g., \"Add feature\" not \"Added feature\")</Mood>\n<Focus>Be specific about what was changed and why</Focus>\n<Conciseness>Keep message under 72 characters for subject line when possible</Conciseness>\n<NoMeta>CRITICAL: Do NOT include ANY explanatory text, analysis, or meta-commentary. Output ONLY the raw commit message.</NoMeta>\n<Examples>\nGood: \"Add user authentication with JWT tokens. Fixes #42\n\n- Implement login and registration endpoints\n- Secure routes with JWT middleware\n- Update user model to store hashed passwords\"\nGood: \"Fix navigation bug in sidebar menu.\"\nBad: \"Based on the changes, I'll create: Add user authentication\"\nBad: \"Looking at the files, this commit should be: Fix navigation bug\"\n</Examples>\n${issueContext}\n</Requirements>\n\n<Output>\nIMPORTANT: Your entire response will be used directly as the git commit message.\nDo not include any explanatory text before or after the commit message.\nStart your response immediately with the commit message text.\n</Output>`\n }\n\n /**\n * Sanitize Claude output to remove meta-commentary and clean formatting\n * Handles cases where Claude includes explanatory text despite instructions\n */\n private sanitizeClaudeOutput(rawOutput: string): string {\n let cleaned = rawOutput.trim()\n\n // Remove common meta-commentary patterns (case-insensitive)\n const metaPatterns = [\n /^.*?based on.*?changes.*?:/i,\n /^.*?looking at.*?files.*?:/i,\n /^.*?examining.*?:/i,\n /^.*?analyzing.*?:/i,\n /^.*?i'll.*?generate.*?:/i,\n /^.*?let me.*?:/i,\n /^.*?the commit message.*?should be.*?:/i,\n /^.*?here.*?is.*?commit.*?message.*?:/i,\n ]\n\n for (const pattern of metaPatterns) {\n cleaned = cleaned.replace(pattern, '').trim()\n }\n\n // Extract content after separators only if it looks like meta-commentary\n // Only split on colons if there's clear meta-commentary before it\n if (cleaned.includes(':')) {\n const colonIndex = cleaned.indexOf(':')\n const beforeColon = cleaned.substring(0, colonIndex).trim().toLowerCase()\n\n // Only split if the text before colon looks like meta-commentary\n const metaIndicators = [\n 'here is the commit message',\n 'commit message',\n 'here is',\n 'the message should be',\n 'i suggest',\n 'my suggestion'\n ]\n\n const isMetaCommentary = metaIndicators.some(indicator => beforeColon.includes(indicator))\n\n if (isMetaCommentary) {\n const afterColon = cleaned.substring(colonIndex + 1).trim()\n if (afterColon && afterColon.length > 10) {\n cleaned = afterColon\n }\n }\n }\n\n // Remove quotes if the entire message is wrapped in them\n if ((cleaned.startsWith('\"') && cleaned.endsWith('\"')) ||\n (cleaned.startsWith(\"'\") && cleaned.endsWith(\"'\"))) {\n cleaned = cleaned.slice(1, -1).trim()\n }\n\n return cleaned\n }\n\n\n}\n","import { logger } from '../utils/logger.js'\nimport { detectPackageManager, runScript } from '../utils/package-manager.js'\nimport { readPackageJson, hasScript } from '../utils/package-json.js'\nimport { ProjectCapabilityDetector } from './ProjectCapabilityDetector.js'\n\nexport interface BuildOptions {\n\tdryRun?: boolean\n}\n\nexport interface BuildResult {\n\tsuccess: boolean\n\tskipped: boolean\n\treason?: string\n\tduration: number\n}\n\n/**\n * BuildRunner handles post-merge build verification for CLI projects\n * Only runs build when project has CLI capabilities (bin field in package.json)\n */\nexport class BuildRunner {\n\tprivate capabilityDetector: ProjectCapabilityDetector\n\n\tconstructor(capabilityDetector?: ProjectCapabilityDetector) {\n\t\tthis.capabilityDetector = capabilityDetector ?? new ProjectCapabilityDetector()\n\t}\n\n\t/**\n\t * Run build verification in the specified directory\n\t * @param buildPath - Path where build should run (typically main worktree path)\n\t * @param options - Build options\n\t */\n\tasync runBuild(buildPath: string, options: BuildOptions = {}): Promise<BuildResult> {\n\t\tconst startTime = Date.now()\n\n\t\ttry {\n\t\t\t// Step 1: Check if build script exists\n\t\t\tconst pkgJson = await readPackageJson(buildPath)\n\t\t\tconst hasBuildScript = hasScript(pkgJson, 'build')\n\n\t\t\tif (!hasBuildScript) {\n\t\t\t\tlogger.debug('Skipping build - no build script found')\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tskipped: true,\n\t\t\t\t\treason: 'No build script found in package.json',\n\t\t\t\t\tduration: Date.now() - startTime,\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Handle missing package.json - skip build for non-Node.js projects\n\t\t\tif (error instanceof Error && error.message.includes('package.json not found')) {\n\t\t\t\tlogger.debug('Skipping build - no package.json found (non-Node.js project)')\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tskipped: true,\n\t\t\t\t\treason: 'No package.json found in project',\n\t\t\t\t\tduration: Date.now() - startTime,\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Re-throw other errors\n\t\t\tthrow error\n\t\t}\n\n\t\t// Step 2: Check if project has CLI capability (bin field)\n\t\tconst capabilities = await this.capabilityDetector.detectCapabilities(buildPath)\n\t\tconst isCLIProject = capabilities.capabilities.includes('cli')\n\n\t\tif (!isCLIProject) {\n\t\t\tlogger.debug('Skipping build - not a CLI project (no bin field)')\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tskipped: true,\n\t\t\t\treason: 'Project is not a CLI project (no bin field in package.json)',\n\t\t\t\tduration: Date.now() - startTime,\n\t\t\t}\n\t\t}\n\n\t\t// Step 3: Detect package manager\n\t\tconst packageManager = await detectPackageManager(buildPath)\n\n\t\t// Step 4: Handle dry-run mode\n\t\tif (options.dryRun) {\n\t\t\tconst command =\n\t\t\t\tpackageManager === 'npm' ? 'npm run build' : `${packageManager} build`\n\t\t\tlogger.info(`[DRY RUN] Would run: ${command}`)\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tskipped: false,\n\t\t\t\tduration: Date.now() - startTime,\n\t\t\t}\n\t\t}\n\n\t\t// Step 5: Execute build\n\t\tlogger.info('Running build...')\n\n\t\ttry {\n\t\t\tawait runScript('build', buildPath, [], { quiet: true })\n\t\t\tlogger.success('Build completed successfully')\n\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tskipped: false,\n\t\t\t\tduration: Date.now() - startTime,\n\t\t\t}\n\t\t} catch {\n\t\t\t// Step 6: Throw detailed error on failure\n\t\t\tconst runCommand =\n\t\t\t\tpackageManager === 'npm' ? 'npm run build' : `${packageManager} build`\n\n\t\t\tthrow new Error(\n\t\t\t\t`Error: Build failed.\\n` +\n\t\t\t\t\t`Fix build errors before proceeding.\\n\\n` +\n\t\t\t\t\t`Run '${runCommand}' to see detailed errors.`\n\t\t\t)\n\t\t}\n\t}\n}\n","import { logger } from '../utils/logger.js'\nimport { GitHubService } from '../lib/GitHubService.js'\nimport { GitWorktreeManager } from '../lib/GitWorktreeManager.js'\nimport { ValidationRunner } from '../lib/ValidationRunner.js'\nimport { CommitManager } from '../lib/CommitManager.js'\nimport { MergeManager } from '../lib/MergeManager.js'\nimport { IdentifierParser } from '../utils/IdentifierParser.js'\nimport { ResourceCleanup } from '../lib/ResourceCleanup.js'\nimport { ProcessManager } from '../lib/process/ProcessManager.js'\nimport { BuildRunner } from '../lib/BuildRunner.js'\nimport { DatabaseManager } from '../lib/DatabaseManager.js'\nimport { EnvironmentManager } from '../lib/EnvironmentManager.js'\nimport { CLIIsolationManager } from '../lib/CLIIsolationManager.js'\nimport { SettingsManager } from '../lib/SettingsManager.js'\nimport { findMainWorktreePathWithSettings } from '../utils/git.js'\nimport { loadEnvIntoProcess } from '../utils/env.js'\nimport { installDependencies } from '../utils/package-manager.js'\nimport { createNeonProviderFromSettings } from '../utils/neon-helpers.js'\nimport { getConfiguredRepoFromSettings, hasMultipleRemotes } from '../utils/remote.js'\nimport type { FinishOptions, GitWorktree, CommitOptions, MergeOptions, PullRequest } from '../types/index.js'\nimport type { ResourceCleanupOptions, CleanupResult } from '../types/cleanup.js'\nimport type { ParsedInput } from './start.js'\nimport path from 'path'\n\nexport interface FinishCommandInput {\n\tidentifier?: string | undefined // Optional - can be auto-detected\n\toptions: FinishOptions\n}\n\nexport interface ParsedFinishInput {\n\ttype: 'issue' | 'pr' | 'branch'\n\tnumber?: number // For issues and PRs\n\tbranchName?: string // For branch inputs\n\toriginalInput: string // Raw input for error messages\n\tautoDetected?: boolean // True if detected from current directory\n}\n\nexport class FinishCommand {\n\tprivate gitHubService: GitHubService\n\tprivate gitWorktreeManager: GitWorktreeManager\n\tprivate validationRunner: ValidationRunner\n\tprivate commitManager: CommitManager\n\tprivate mergeManager: MergeManager\n\tprivate identifierParser: IdentifierParser\n\tprivate resourceCleanup?: ResourceCleanup\n\tprivate buildRunner: BuildRunner\n\tprivate settingsManager: SettingsManager\n\n\tconstructor(\n\t\tgitHubService?: GitHubService,\n\t\tgitWorktreeManager?: GitWorktreeManager,\n\t\tvalidationRunner?: ValidationRunner,\n\t\tcommitManager?: CommitManager,\n\t\tmergeManager?: MergeManager,\n\t\tidentifierParser?: IdentifierParser,\n\t\tresourceCleanup?: ResourceCleanup,\n\t\tbuildRunner?: BuildRunner,\n\t\tsettingsManager?: SettingsManager\n\t) {\n\t\t// Load environment variables first\n\t\tconst envResult = loadEnvIntoProcess()\n\t\tif (envResult.error) {\n\t\t\tlogger.debug(`Environment loading warning: ${envResult.error.message}`)\n\t\t}\n\t\tif (envResult.parsed) {\n\t\t\tlogger.debug(`Loaded ${Object.keys(envResult.parsed).length} environment variables`)\n\t\t}\n\n\t\t// Dependency injection for testing\n\t\tthis.gitHubService = gitHubService ?? new GitHubService()\n\t\tthis.gitWorktreeManager = gitWorktreeManager ?? new GitWorktreeManager()\n\t\tthis.validationRunner = validationRunner ?? new ValidationRunner()\n\t\tthis.commitManager = commitManager ?? new CommitManager()\n\t\tthis.mergeManager = mergeManager ?? new MergeManager()\n\t\tthis.identifierParser = identifierParser ?? new IdentifierParser(this.gitWorktreeManager)\n\n\t\t// Initialize settingsManager first (needed for ResourceCleanup)\n\t\tthis.settingsManager = settingsManager ?? new SettingsManager()\n\n\t\t// ResourceCleanup will be initialized lazily with proper configuration\n\t\tif (resourceCleanup) {\n\t\t\tthis.resourceCleanup = resourceCleanup\n\t\t}\n\n\t\tthis.buildRunner = buildRunner ?? new BuildRunner()\n\t}\n\n\t/**\n\t * Lazy initialization of ResourceCleanup with properly configured DatabaseManager\n\t */\n\tprivate async ensureResourceCleanup(): Promise<void> {\n\t\tif (this.resourceCleanup) {\n\t\t\treturn\n\t\t}\n\n\t\tconst settings = await this.settingsManager.loadSettings()\n\t\tconst databaseUrlEnvVarName = settings.capabilities?.database?.databaseUrlEnvVarName ?? 'DATABASE_URL'\n\n\t\tconst environmentManager = new EnvironmentManager()\n\t\tconst neonProvider = createNeonProviderFromSettings(settings)\n\t\tconst databaseManager = new DatabaseManager(neonProvider, environmentManager, databaseUrlEnvVarName)\n\t\tconst cliIsolationManager = new CLIIsolationManager()\n\n\t\tthis.resourceCleanup = new ResourceCleanup(\n\t\t\tthis.gitWorktreeManager,\n\t\t\tnew ProcessManager(),\n\t\t\tdatabaseManager,\n\t\t\tcliIsolationManager\n\t\t)\n\t}\n\n\t/**\n\t * Main entry point for finish command\n\t */\n\tpublic async execute(input: FinishCommandInput): Promise<void> {\n\t\ttry {\n\t\t\t// Step 0: Load settings and get configured repo for GitHub operations\n\t\t\tconst settings = await this.settingsManager.loadSettings()\n\t\t\tlet repo: string | undefined\n\n\t\t\tconst multipleRemotes = await hasMultipleRemotes()\n\t\t\tif (multipleRemotes) {\n\t\t\t\trepo = await getConfiguredRepoFromSettings(settings)\n\t\t\t\tlogger.info(`Using GitHub repository: ${repo}`)\n\t\t\t}\n\n\t\t\t// Step 1: Parse input (or auto-detect from current directory)\n\t\t\tconst parsed = await this.parseInput(input.identifier, input.options)\n\n\t\t\t// Step 2: Validate based on type and get worktrees\n\t\t\tconst worktrees = await this.validateInput(parsed, input.options, repo)\n\n\t\t\t// Step 3: Log success\n\t\t\tlogger.info(`Validated input: ${this.formatParsedInput(parsed)}`)\n\n\t\t\t// Get worktree for workflow execution\n\t\t\tconst worktree = worktrees[0]\n\t\t\tif (!worktree) {\n\t\t\t\tthrow new Error('No worktree found')\n\t\t\t}\n\n\t\t\t// Step 4: Branch based on input type\n\t\t\tif (parsed.type === 'pr') {\n\t\t\t\t// Fetch PR to get current state\n\t\t\t\tif (!parsed.number) {\n\t\t\t\t\tthrow new Error('Invalid PR number')\n\t\t\t\t}\n\t\t\t\tconst pr = await this.gitHubService.fetchPR(parsed.number, repo)\n\t\t\t\tawait this.executePRWorkflow(parsed, input.options, worktree, pr)\n\t\t\t} else {\n\t\t\t\t// Execute traditional issue/branch workflow\n\t\t\t\tawait this.executeIssueWorkflow(parsed, input.options, worktree)\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) {\n\t\t\t\tlogger.error(`${error.message}`)\n\t\t\t} else {\n\t\t\t\tlogger.error('An unknown error occurred')\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Parse input to determine type and extract relevant data\n\t * Supports auto-detection from current directory when identifier is undefined\n\t */\n\tprivate async parseInput(\n\t\tidentifier: string | undefined,\n\t\toptions: FinishOptions\n\t): Promise<ParsedFinishInput> {\n\t\t// Priority 1: --pr flag overrides everything\n\t\tif (options.pr !== undefined) {\n\t\t\treturn {\n\t\t\t\ttype: 'pr',\n\t\t\t\tnumber: options.pr,\n\t\t\t\toriginalInput: `--pr ${options.pr}`,\n\t\t\t\tautoDetected: false,\n\t\t\t}\n\t\t}\n\n\t\t// Priority 2: Explicit identifier provided\n\t\tif (identifier?.trim()) {\n\t\t\treturn await this.parseExplicitInput(identifier.trim())\n\t\t}\n\n\t\t// Priority 3: Auto-detect from current directory\n\t\treturn await this.autoDetectFromCurrentDirectory()\n\t}\n\n\t/**\n\t * Parse explicit identifier input using pattern-based detection\n\t * (No GitHub API calls - uses IdentifierParser)\n\t */\n\tprivate async parseExplicitInput(\n\t\tidentifier: string\n\t): Promise<ParsedFinishInput> {\n\t\t// Check for PR-specific formats: pr/123, PR-123, PR/123\n\t\tconst prPattern = /^(?:pr|PR)[/-](\\d+)$/\n\t\tconst prMatch = identifier.match(prPattern)\n\t\tif (prMatch?.[1]) {\n\t\t\treturn {\n\t\t\t\ttype: 'pr',\n\t\t\t\tnumber: parseInt(prMatch[1], 10),\n\t\t\t\toriginalInput: identifier,\n\t\t\t\tautoDetected: false,\n\t\t\t}\n\t\t}\n\n\t\t// Use IdentifierParser for pattern-based detection\n\t\t// (checks existing worktrees, no GitHub API calls)\n\t\tconst parsed = await this.identifierParser.parseForPatternDetection(identifier)\n\n\t\t// Description type should never reach finish command (converted in start)\n\t\tif (parsed.type === 'description') {\n\t\t\tthrow new Error('Description input type is not supported in finish command')\n\t\t}\n\n\t\t// Convert ParsedInput to ParsedFinishInput (add autoDetected field)\n\t\tconst result: ParsedFinishInput = {\n\t\t\ttype: parsed.type,\n\t\t\toriginalInput: parsed.originalInput,\n\t\t\tautoDetected: false,\n\t\t}\n\n\t\t// Add number or branchName based on type\n\t\tif (parsed.number !== undefined) {\n\t\t\tresult.number = parsed.number\n\t\t}\n\t\tif (parsed.branchName !== undefined) {\n\t\t\tresult.branchName = parsed.branchName\n\t\t}\n\n\t\treturn result\n\t}\n\n\t/**\n\t * Auto-detect PR or issue from current directory\n\t * Ports logic from merge-current-issue.sh lines 30-52\n\t */\n\tprivate async autoDetectFromCurrentDirectory(): Promise<ParsedFinishInput> {\n\t\tconst currentDir = path.basename(process.cwd())\n\n\t\t// Check for PR worktree pattern: _pr_N suffix\n\t\t// Pattern: /.*_pr_(\\d+)$/\n\t\tconst prPattern = /_pr_(\\d+)$/\n\t\tconst prMatch = currentDir.match(prPattern)\n\n\t\tif (prMatch?.[1]) {\n\t\t\tconst prNumber = parseInt(prMatch[1], 10)\n\t\t\tlogger.debug(`Auto-detected PR #${prNumber} from directory: ${currentDir}`)\n\t\t\treturn {\n\t\t\t\ttype: 'pr',\n\t\t\t\tnumber: prNumber,\n\t\t\t\toriginalInput: currentDir,\n\t\t\t\tautoDetected: true,\n\t\t\t}\n\t\t}\n\n\t\t// Check for issue pattern in directory or branch name\n\t\t// Pattern: /issue-(\\d+)/\n\t\tconst issuePattern = /issue-(\\d+)/\n\t\tconst issueMatch = currentDir.match(issuePattern)\n\n\t\tif (issueMatch?.[1]) {\n\t\t\tconst issueNumber = parseInt(issueMatch[1], 10)\n\t\t\tlogger.debug(\n\t\t\t\t`Auto-detected issue #${issueNumber} from directory: ${currentDir}`\n\t\t\t)\n\t\t\treturn {\n\t\t\t\ttype: 'issue',\n\t\t\t\tnumber: issueNumber,\n\t\t\t\toriginalInput: currentDir,\n\t\t\t\tautoDetected: true,\n\t\t\t}\n\t\t}\n\n\t\t// Fallback: get current branch name\n\t\tconst repoInfo = await this.gitWorktreeManager.getRepoInfo()\n\t\tconst currentBranch = repoInfo.currentBranch\n\n\t\tif (!currentBranch) {\n\t\t\tthrow new Error(\n\t\t\t\t'Could not auto-detect identifier. Please provide an issue number, PR number, or branch name.\\n' +\n\t\t\t\t\t'Expected directory pattern: feat/issue-XX-description OR worktree with _pr_N suffix'\n\t\t\t)\n\t\t}\n\n\t\t// Try to extract issue from branch name\n\t\tconst branchIssueMatch = currentBranch.match(issuePattern)\n\t\tif (branchIssueMatch?.[1]) {\n\t\t\tconst issueNumber = parseInt(branchIssueMatch[1], 10)\n\t\t\tlogger.debug(\n\t\t\t\t`Auto-detected issue #${issueNumber} from branch: ${currentBranch}`\n\t\t\t)\n\t\t\treturn {\n\t\t\t\ttype: 'issue',\n\t\t\t\tnumber: issueNumber,\n\t\t\t\toriginalInput: currentBranch,\n\t\t\t\tautoDetected: true,\n\t\t\t}\n\t\t}\n\n\t\t// Last resort: use branch name\n\t\treturn {\n\t\t\ttype: 'branch',\n\t\t\tbranchName: currentBranch,\n\t\t\toriginalInput: currentBranch,\n\t\t\tautoDetected: true,\n\t\t}\n\t}\n\n\t/**\n\t * Validate the parsed input based on its type\n\t */\n\tprivate async validateInput(\n\t\tparsed: ParsedFinishInput,\n\t\toptions: FinishOptions,\n\t\trepo?: string\n\t): Promise<GitWorktree[]> {\n\t\tswitch (parsed.type) {\n\t\t\tcase 'pr': {\n\t\t\t\tif (!parsed.number) {\n\t\t\t\t\tthrow new Error('Invalid PR number')\n\t\t\t\t}\n\n\t\t\t\t// Fetch PR from GitHub\n\t\t\t\tconst pr = await this.gitHubService.fetchPR(parsed.number)\n\n\t\t\t\t// For PRs, we allow closed/merged state (cleanup-only mode)\n\t\t\t\t// But we still validate it exists\n\t\t\t\tlogger.debug(`Validated PR #${parsed.number} (state: ${pr.state})`)\n\n\t\t\t\t// Find associated worktree\n\t\t\t\treturn await this.findWorktreeForIdentifier(parsed)\n\t\t\t}\n\n\t\t\tcase 'issue': {\n\t\t\t\tif (!parsed.number) {\n\t\t\t\t\tthrow new Error('Invalid issue number')\n\t\t\t\t}\n\n\t\t\t\t// Fetch issue from GitHub\n\t\t\t\tconst issue = await this.gitHubService.fetchIssue(parsed.number, repo)\n\n\t\t\t\t// Validate issue state (warn if closed unless --force)\n\t\t\t\tif (issue.state === 'closed' && !options.force) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Issue #${parsed.number} is closed. Use --force to finish anyway.`\n\t\t\t\t\t)\n\t\t\t\t}\n\n\t\t\t\tlogger.debug(`Validated issue #${parsed.number} (state: ${issue.state})`)\n\n\t\t\t\t// Find associated worktree\n\t\t\t\treturn await this.findWorktreeForIdentifier(parsed)\n\t\t\t}\n\n\t\t\tcase 'branch': {\n\t\t\t\tif (!parsed.branchName) {\n\t\t\t\t\tthrow new Error('Invalid branch name')\n\t\t\t\t}\n\n\t\t\t\t// Validate branch name format\n\t\t\t\tif (!this.isValidBranchName(parsed.branchName)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t'Invalid branch name. Use only letters, numbers, hyphens, underscores, and slashes'\n\t\t\t\t\t)\n\t\t\t\t}\n\n\t\t\t\tlogger.debug(`Validated branch name: ${parsed.branchName}`)\n\n\t\t\t\t// Find associated worktree\n\t\t\t\treturn await this.findWorktreeForIdentifier(parsed)\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tconst unknownType = parsed as { type: string }\n\t\t\t\tthrow new Error(`Unknown input type: ${unknownType.type}`)\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Find worktree for the given identifier using specific methods based on type\n\t * (uses precise pattern matching instead of broad substring matching)\n\t * Throws error if not found\n\t */\n\tprivate async findWorktreeForIdentifier(\n\t\tparsed: ParsedFinishInput\n\t): Promise<GitWorktree[]> {\n\t\tlet worktree: GitWorktree | null = null\n\n\t\t// Use specific finding methods based on parsed type\n\t\tswitch (parsed.type) {\n\t\t\tcase 'pr': {\n\t\t\t\tif (!parsed.number) {\n\t\t\t\t\tthrow new Error('Invalid PR number')\n\t\t\t\t}\n\t\t\t\t// Pass empty string for branch name since we don't know it yet\n\t\t\t\tworktree = await this.gitWorktreeManager.findWorktreeForPR(\n\t\t\t\t\tparsed.number,\n\t\t\t\t\t''\n\t\t\t\t)\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcase 'issue': {\n\t\t\t\tif (!parsed.number) {\n\t\t\t\t\tthrow new Error('Invalid issue number')\n\t\t\t\t}\n\t\t\t\tworktree = await this.gitWorktreeManager.findWorktreeForIssue(\n\t\t\t\t\tparsed.number\n\t\t\t\t)\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcase 'branch': {\n\t\t\t\tif (!parsed.branchName) {\n\t\t\t\t\tthrow new Error('Invalid branch name')\n\t\t\t\t}\n\t\t\t\tworktree = await this.gitWorktreeManager.findWorktreeForBranch(\n\t\t\t\t\tparsed.branchName\n\t\t\t\t)\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tconst unknownType = parsed as { type: string }\n\t\t\t\tthrow new Error(`Unknown input type: ${unknownType.type}`)\n\t\t\t}\n\t\t}\n\n\t\tif (!worktree) {\n\t\t\tthrow new Error(\n\t\t\t\t`No worktree found for ${this.formatParsedInput(parsed)}. ` +\n\t\t\t\t\t`Use 'il list' to see available worktrees.`\n\t\t\t)\n\t\t}\n\n\t\tlogger.debug(`Found worktree: ${worktree.path}`)\n\n\t\treturn [worktree]\n\t}\n\n\t/**\n\t * Validate branch name format\n\t */\n\tprivate isValidBranchName(branch: string): boolean {\n\t\t// Pattern from bash script and StartCommand\n\t\treturn /^[a-zA-Z0-9/_-]+$/.test(branch)\n\t}\n\n\t/**\n\t * Format parsed input for display\n\t */\n\tprivate formatParsedInput(parsed: ParsedFinishInput): string {\n\t\tconst autoLabel = parsed.autoDetected ? ' (auto-detected)' : ''\n\n\t\tswitch (parsed.type) {\n\t\t\tcase 'pr':\n\t\t\t\treturn `PR #${parsed.number}${autoLabel}`\n\t\t\tcase 'issue':\n\t\t\t\treturn `Issue #${parsed.number}${autoLabel}`\n\t\t\tcase 'branch':\n\t\t\t\treturn `Branch '${parsed.branchName}'${autoLabel}`\n\t\t\tdefault:\n\t\t\t\treturn 'Unknown input'\n\t\t}\n\t}\n\n\t/**\n\t * Execute workflow for issues and branches (merge into main)\n\t * This is the traditional workflow: validate → commit → rebase → merge → cleanup\n\t */\n\tprivate async executeIssueWorkflow(\n\t\tparsed: ParsedFinishInput,\n\t\toptions: FinishOptions,\n\t\tworktree: GitWorktree\n\t): Promise<void> {\n\t\t// Step 1: Run pre-merge validations FIRST (Sub-Issue #47)\n\t\tif (!options.dryRun) {\n\t\t\tlogger.info('Running pre-merge validations...')\n\n\t\t\tawait this.validationRunner.runValidations(worktree.path, {\n\t\t\t\tdryRun: options.dryRun ?? false,\n\t\t\t})\n\t\t\tlogger.success('All validations passed')\n\t\t} else {\n\t\t\tlogger.info('[DRY RUN] Would run pre-merge validations')\n\t\t}\n\n\t\t// Step 2: Detect uncommitted changes AFTER validation passes\n\t\tconst gitStatus = await this.commitManager.detectUncommittedChanges(worktree.path)\n\n\t\t// Step 3: Commit changes only if validation passed AND changes exist\n\t\tif (gitStatus.hasUncommittedChanges) {\n\t\t\tif (options.dryRun) {\n\t\t\t\tlogger.info('[DRY RUN] Would auto-commit uncommitted changes (validation passed)')\n\t\t\t} else {\n\t\t\t\tlogger.info('Validation passed, auto-committing uncommitted changes...')\n\n\t\t\t\t// Load settings to get skipVerify configuration\n\t\t\t\tconst settings = await this.settingsManager.loadSettings(worktree.path)\n\t\t\t\tconst skipVerify = settings.workflows?.issue?.noVerify ?? false\n\n\t\t\t\tconst commitOptions: CommitOptions = {\n\t\t\t\t\tdryRun: options.dryRun ?? false,\n\t\t\t\t\tskipVerify,\n\t\t\t\t}\n\n\t\t\t\t// Only add issueNumber if it's an issue\n\t\t\t\tif (parsed.type === 'issue' && parsed.number) {\n\t\t\t\t\tcommitOptions.issueNumber = parsed.number\n\t\t\t\t}\n\n\t\t\t\tawait this.commitManager.commitChanges(worktree.path, commitOptions)\n\n\t\t\t\tlogger.success('Changes committed successfully')\n\t\t\t}\n\t\t} else {\n\t\t\tlogger.debug('No uncommitted changes found')\n\t\t}\n\n\t\t// Step 4: Rebase branch on main\n\t\tlogger.info('Rebasing branch on main...')\n\n\t\tconst mergeOptions: MergeOptions = {\n\t\t\tdryRun: options.dryRun ?? false,\n\t\t\tforce: options.force ?? false,\n\t\t}\n\n\t\tawait this.mergeManager.rebaseOnMain(worktree.path, mergeOptions)\n\t\tlogger.success('Branch rebased successfully')\n\n\t\t// Step 5: Perform fast-forward merge\n\t\tlogger.info('Performing fast-forward merge...')\n\t\tawait this.mergeManager.performFastForwardMerge(worktree.branch, worktree.path, mergeOptions)\n\t\tlogger.success('Fast-forward merge completed successfully')\n\n\t\t// Step 5.5: Install dependencies in main worktree\n\t\tif (options.dryRun) {\n\t\t\tlogger.info('[DRY RUN] Would install dependencies in main worktree')\n\t\t} else {\n\t\t\tlogger.info('Installing dependencies in main worktree...')\n\t\t\tconst mainWorktreePath = await findMainWorktreePathWithSettings(worktree.path, this.settingsManager)\n\t\t\tawait installDependencies(mainWorktreePath, true)\n\t\t}\n\n\t\t// Step 5.6: Run post-merge build verification (CLI projects only)\n\t\tif (!options.skipBuild) {\n\t\t\tawait this.runPostMergeBuild(worktree.path, options)\n\t\t} else {\n\t\t\tlogger.debug('Skipping build verification (--skip-build flag provided)')\n\t\t}\n\n\t\t// Step 6: Post-merge cleanup\n\t\tawait this.performPostMergeCleanup(parsed, options, worktree)\n\t}\n\n\t/**\n\t * Execute workflow for Pull Requests\n\t * Behavior depends on PR state:\n\t * - OPEN: Commit changes, push to remote, keep worktree active\n\t * - CLOSED/MERGED: Skip to cleanup\n\t */\n\tprivate async executePRWorkflow(\n\t\tparsed: ParsedFinishInput,\n\t\toptions: FinishOptions,\n\t\tworktree: GitWorktree,\n\t\tpr: PullRequest\n\t): Promise<void> {\n\t\t// Branch based on PR state\n\t\tif (pr.state === 'closed' || pr.state === 'merged') {\n\t\t\t// Closed/Merged PR workflow\n\t\t\tlogger.info(`PR #${parsed.number} is ${pr.state.toUpperCase()} - skipping to cleanup`)\n\n\t\t\t// Check for uncommitted changes and warn (unless --force)\n\t\t\tconst gitStatus = await this.commitManager.detectUncommittedChanges(worktree.path)\n\t\t\tif (gitStatus.hasUncommittedChanges && !options.force) {\n\t\t\t\tlogger.warn('PR has uncommitted changes')\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'Cannot cleanup PR with uncommitted changes. ' +\n\t\t\t\t\t'Commit or stash changes, then run again with --force to cleanup anyway.'\n\t\t\t\t)\n\t\t\t}\n\n\t\t\t// Call cleanup directly with deleteBranch: true\n\t\t\tawait this.performPRCleanup(parsed, options, worktree)\n\n\t\t\tlogger.success(`PR #${parsed.number} cleanup completed`)\n\t\t} else {\n\t\t\t// Open PR workflow\n\t\t\tlogger.info(`PR #${parsed.number} is OPEN - will push changes and keep worktree active`)\n\n\t\t\t// Step 1: Detect uncommitted changes\n\t\t\tconst gitStatus = await this.commitManager.detectUncommittedChanges(worktree.path)\n\n\t\t\t// Step 2: Commit changes if any exist\n\t\t\tif (gitStatus.hasUncommittedChanges) {\n\t\t\t\tif (options.dryRun) {\n\t\t\t\t\tlogger.info('[DRY RUN] Would commit uncommitted changes')\n\t\t\t\t} else {\n\t\t\t\t\tlogger.info('Committing uncommitted changes...')\n\n\t\t\t\t\t// Load settings to get skipVerify configuration\n\t\t\t\t\tconst settings = await this.settingsManager.loadSettings(worktree.path)\n\t\t\t\t\tconst skipVerify = settings.workflows?.pr?.noVerify ?? false\n\n\t\t\t\t\tawait this.commitManager.commitChanges(worktree.path, {\n\t\t\t\t\t\tdryRun: false,\n\t\t\t\t\t\tskipVerify,\n\t\t\t\t\t\t// Do NOT pass issueNumber for PRs - no \"Fixes #\" trailer needed\n\t\t\t\t\t})\n\t\t\t\t\tlogger.success('Changes committed')\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlogger.debug('No uncommitted changes found')\n\t\t\t}\n\n\t\t\t// Step 3: Push to remote\n\t\t\tif (options.dryRun) {\n\t\t\t\tlogger.info(`[DRY RUN] Would push changes to origin/${pr.branch}`)\n\t\t\t} else {\n\t\t\t\tlogger.info('Pushing changes to remote...')\n\t\t\t\tconst { pushBranchToRemote } = await import('../utils/git.js')\n\t\t\t\tawait pushBranchToRemote(pr.branch, worktree.path, {\n\t\t\t\t\tdryRun: false\n\t\t\t\t})\n\t\t\t\tlogger.success(`Changes pushed to PR #${parsed.number}`)\n\t\t\t}\n\n\t\t\t// Step 4: Log success and guidance\n\t\t\tlogger.success(`PR #${parsed.number} updated successfully`)\n\t\t\tlogger.info('Worktree remains active for continued work')\n\t\t\tlogger.info(`To cleanup when done: il cleanup ${parsed.number}`)\n\t\t}\n\t}\n\n\t/**\n\t * Perform cleanup for closed/merged PRs\n\t * Similar to performPostMergeCleanup but with different messaging\n\t */\n\tprivate async performPRCleanup(\n\t\tparsed: ParsedFinishInput,\n\t\toptions: FinishOptions,\n\t\tworktree: GitWorktree\n\t): Promise<void> {\n\t\t// Convert to ParsedInput format\n\t\tconst cleanupInput: ParsedInput = {\n\t\t\ttype: parsed.type,\n\t\t\toriginalInput: parsed.originalInput,\n\t\t\t...(parsed.number !== undefined && { number: parsed.number }),\n\t\t\t...(parsed.branchName !== undefined && { branchName: parsed.branchName }),\n\t\t}\n\n\t\tconst cleanupOptions: ResourceCleanupOptions = {\n\t\t\tdryRun: options.dryRun ?? false,\n\t\t\tdeleteBranch: true, // Delete branch for closed/merged PRs\n\t\t\tkeepDatabase: false,\n\t\t\tforce: options.force ?? false,\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.ensureResourceCleanup()\n\t\t\tif (!this.resourceCleanup) {\n\t\t\t\tthrow new Error('Failed to initialize ResourceCleanup')\n\t\t\t}\n\t\t\tconst result = await this.resourceCleanup.cleanupWorktree(cleanupInput, cleanupOptions)\n\n\t\t\tthis.reportCleanupResults(result)\n\n\t\t\tif (!result.success) {\n\t\t\t\tlogger.warn('Some cleanup operations failed - manual cleanup may be required')\n\t\t\t\tthis.showManualCleanupInstructions(worktree)\n\t\t\t} else {\n\t\t\t\t// Warn if running from within the worktree being finished (only on successful cleanup)\n\t\t\t\tif (this.isRunningFromWithinWorktree(worktree.path)) {\n\t\t\t\t\tthis.showTerminalCloseWarning(worktree)\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : 'Unknown error'\n\t\t\tlogger.warn(`Cleanup failed: ${errorMessage}`)\n\t\t\tthis.showManualCleanupInstructions(worktree)\n\t\t\tthrow error // Re-throw to fail the command\n\t\t}\n\t}\n\n\t/**\n\t * Run post-merge build verification for CLI projects\n\t * Runs in main worktree to verify merged code builds successfully\n\t */\n\tprivate async runPostMergeBuild(\n\t\tworktreePath: string,\n\t\toptions: FinishOptions\n\t): Promise<void> {\n\t\t// Find main worktree path\n\t\tconst mainWorktreePath = await findMainWorktreePathWithSettings(worktreePath, this.settingsManager)\n\n\t\t// Check if dry-run\n\t\tif (options.dryRun) {\n\t\t\tlogger.info('[DRY RUN] Would run post-merge build')\n\t\t\treturn\n\t\t}\n\n\t\tlogger.info('Running post-merge build...')\n\n\t\tconst result = await this.buildRunner.runBuild(mainWorktreePath, {\n\t\t\tdryRun: options.dryRun ?? false,\n\t\t})\n\n\t\tif (result.skipped) {\n\t\t\tlogger.debug(`Build skipped: ${result.reason}`)\n\t\t} else {\n\t\t\tlogger.success('Post-merge build completed successfully')\n\t\t}\n\t}\n\n\t/**\n\t * Perform post-merge cleanup operations\n\t * Converts ParsedFinishInput to ParsedInput and calls ResourceCleanup\n\t * Handles failures gracefully without throwing\n\t */\n\tprivate async performPostMergeCleanup(\n\t\tparsed: ParsedFinishInput,\n\t\toptions: FinishOptions,\n\t\tworktree: GitWorktree\n\t): Promise<void> {\n\t\t// Convert ParsedFinishInput to ParsedInput (drop autoDetected field)\n\t\tconst cleanupInput: ParsedInput = {\n\t\t\ttype: parsed.type,\n\t\t\toriginalInput: parsed.originalInput,\n\t\t\t...(parsed.number !== undefined && { number: parsed.number }),\n\t\t\t...(parsed.branchName !== undefined && { branchName: parsed.branchName }),\n\t\t}\n\n\t\tconst cleanupOptions: ResourceCleanupOptions = {\n\t\t\tdryRun: options.dryRun ?? false,\n\t\t\tdeleteBranch: true, // Delete branch after successful merge\n\t\t\tkeepDatabase: false, // Clean up database after merge\n\t\t\tforce: options.force ?? false,\n\t\t}\n\n\t\ttry {\n\t\t\tlogger.info('Starting post-merge cleanup...')\n\n\t\t\tawait this.ensureResourceCleanup()\n\t\t\tif (!this.resourceCleanup) {\n\t\t\t\tthrow new Error('Failed to initialize ResourceCleanup')\n\t\t\t}\n\t\t\tconst result = await this.resourceCleanup.cleanupWorktree(cleanupInput, cleanupOptions)\n\n\t\t\t// Report cleanup results\n\t\t\tthis.reportCleanupResults(result)\n\n\t\t\tif (!result.success) {\n\t\t\t\tlogger.warn('Some cleanup operations failed - manual cleanup may be required')\n\t\t\t\t// Show helpful recovery message\n\t\t\t\tthis.showManualCleanupInstructions(worktree)\n\t\t\t} else {\n\t\t\t\tlogger.success('Post-merge cleanup completed successfully')\n\t\t\t}\n\n\t\t\t// Warn if running from within the worktree being finished\n\t\t\tif (this.isRunningFromWithinWorktree(worktree.path)) {\n\t\t\t\tthis.showTerminalCloseWarning(worktree)\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Catch cleanup errors to prevent finish command from failing\n\t\t\t// (merge already succeeded - cleanup failures are non-fatal)\n\t\t\tconst errorMessage = error instanceof Error ? error.message : 'Unknown error'\n\t\t\tlogger.warn(`Cleanup failed: ${errorMessage}`)\n\t\t\tlogger.warn('Merge completed successfully, but manual cleanup is required')\n\t\t\tthis.showManualCleanupInstructions(worktree)\n\t\t}\n\t}\n\n\t/**\n\t * Report cleanup operation results to user\n\t */\n\tprivate reportCleanupResults(result: CleanupResult): void {\n\t\tif (result.operations.length === 0) {\n\t\t\treturn\n\t\t}\n\n\t\tlogger.info('Cleanup operations:')\n\t\tfor (const op of result.operations) {\n\t\t\tconst status = op.success ? '✓' : '✗'\n\t\t\tconst message = op.error ? `${op.message}: ${op.error}` : op.message\n\n\t\t\tif (op.success) {\n\t\t\t\tlogger.info(` ${status} ${message}`)\n\t\t\t} else {\n\t\t\t\tlogger.warn(` ${status} ${message}`)\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Show manual cleanup instructions when cleanup fails\n\t */\n\tprivate showManualCleanupInstructions(worktree: GitWorktree): void {\n\t\tlogger.info('\\nManual cleanup commands:')\n\t\tlogger.info(` 1. Remove worktree: git worktree remove ${worktree.path}`)\n\t\tlogger.info(` 2. Delete branch: git branch -d ${worktree.branch}`)\n\t\tlogger.info(` 3. Check dev servers: lsof -i :PORT (and kill if needed)`)\n\t}\n\n\t/**\n\t * Check if current working directory is within the target worktree\n\t */\n\tprivate isRunningFromWithinWorktree(worktreePath: string): boolean {\n\t\tconst normalizedCwd = path.normalize(process.cwd())\n\t\tconst normalizedWorktree = path.normalize(worktreePath)\n\t\treturn normalizedCwd.startsWith(normalizedWorktree)\n\t}\n\n\t/**\n\t * Display warning to close terminal/IDE when running from within finished loom\n\t */\n\tprivate showTerminalCloseWarning(worktree: GitWorktree): void {\n\t\tlogger.info('')\n\t\tlogger.info('You are currently in the directory of the loom that was just finished.')\n\t\tlogger.info('Please close this terminal and any IDE/terminal windows using this directory.')\n\t\tlogger.info(`Directory: ${worktree.path}`)\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/ignite.ts"],"sourcesContent":["import path from 'path'\nimport { logger } from '../utils/logger.js'\nimport { ClaudeWorkflowOptions } from '../lib/ClaudeService.js'\nimport { GitWorktreeManager } from '../lib/GitWorktreeManager.js'\nimport { launchClaude, ClaudeCliOptions } from '../utils/claude.js'\nimport { PromptTemplateManager, TemplateVariables } from '../lib/PromptTemplateManager.js'\nimport { generateGitHubCommentMcpConfig } from '../utils/mcp.js'\nimport { AgentManager } from '../lib/AgentManager.js'\nimport { SettingsManager } from '../lib/SettingsManager.js'\nimport { extractSettingsOverrides } from '../utils/cli-overrides.js'\n\n/**\n * IgniteCommand: Auto-detect workspace context and launch Claude\n *\n * This command:\n * 1. Auto-detects context from current directory and git branch\n * 2. Loads appropriate prompt template with variable substitution\n * 3. Launches Claude with existing agent system (NO changes to agent loading)\n * 4. Executes in current terminal (not opening a new window)\n *\n * CRITICAL: This command works with agents exactly as they currently function.\n * NO modifications to agent loading mechanisms.\n */\nexport class IgniteCommand {\n\tprivate templateManager: PromptTemplateManager\n\tprivate gitWorktreeManager: GitWorktreeManager\n\tprivate agentManager: AgentManager\n\tprivate settingsManager: SettingsManager\n\tprivate settings?: import('../lib/SettingsManager.js').IloomSettings\n\n\tconstructor(\n\t\ttemplateManager?: PromptTemplateManager,\n\t\tgitWorktreeManager?: GitWorktreeManager,\n\t\tagentManager?: AgentManager,\n\t\tsettingsManager?: SettingsManager\n\t) {\n\t\tthis.templateManager = templateManager ?? new PromptTemplateManager()\n\t\tthis.gitWorktreeManager = gitWorktreeManager ?? new GitWorktreeManager()\n\t\tthis.agentManager = agentManager ?? new AgentManager()\n\t\tthis.settingsManager = settingsManager ?? new SettingsManager()\n\t}\n\n\t/**\n\t * Main entry point for spin command\n\t */\n\tasync execute(oneShot: import('../types/index.js').OneShotMode = 'default'): Promise<void> {\n\t\ttry {\n\t\t\tlogger.info('🚀 Your loom is spinning up, please wait...')\n\n\t\t\t// Step 1: Auto-detect workspace context\n\t\t\tconst context = await this.detectWorkspaceContext()\n\n\t\t\tlogger.debug('Auto-detected workspace context', { context })\n\n\t\t\t// Inform user what context was detected\n\t\t\tthis.logDetectedContext(context)\n\n\t\t\tlogger.info('📝 Loading prompt template and preparing Claude...')\n\n\t\t\t// Step 2: Get prompt template with variable substitution\n\t\t\tconst variables = this.buildTemplateVariables(context, oneShot)\n\t\t\tconst systemInstructions = await this.templateManager.getPrompt(context.type, variables)\n\n\t\t\t// User prompt to trigger the workflow (includes one-shot bypass instructions if needed)\n\t\t\tconst userPrompt = this.buildUserPrompt(oneShot)\n\n\t\t\t// Step 2.5: Load settings if not cached with CLI overrides\n\t\t\t// Settings are pre-validated at CLI startup, so no error handling needed here\n\t\t\tif (!this.settings) {\n\t\t\t\tconst cliOverrides = extractSettingsOverrides()\n\t\t\t\tthis.settings = await this.settingsManager.loadSettings(undefined, cliOverrides)\n\t\t\t}\n\n\t\t\t// Step 3: Determine model and permission mode based on workflow type\n\t\t\tconst model = this.getModelForWorkflow(context.type)\n\t\t\tlet permissionMode = this.getPermissionModeForWorkflow(context.type)\n\n\t\t\t// Override permission mode if bypassPermissions oneShot mode\n\t\t\tif (oneShot === 'bypassPermissions') {\n\t\t\t\tpermissionMode = 'bypassPermissions'\n\t\t\t}\n\n\t\t\t// Display warning if bypassPermissions is used\n\t\t\tif (permissionMode === 'bypassPermissions') {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t'⚠️ WARNING: Using bypassPermissions mode - Claude will execute all tool calls without confirmation. ' +\n\t\t\t\t\t\t'This can be dangerous. Use with caution.'\n\t\t\t\t)\n\t\t\t}\n\n\t\t\t// Step 4: Build Claude CLI options\n\t\t\tconst claudeOptions: ClaudeCliOptions = {\n\t\t\t\theadless: false, // Enable stdio: 'inherit' for current terminal\n\t\t\t\taddDir: context.workspacePath,\n\t\t\t}\n\n\t\t\t// Add optional model if present\n\t\t\tif (model !== undefined) {\n\t\t\t\tclaudeOptions.model = model\n\t\t\t}\n\n\t\t\t// Add permission mode if not default\n\t\t\tif (permissionMode !== undefined && permissionMode !== 'default') {\n\t\t\t\tclaudeOptions.permissionMode = permissionMode\n\t\t\t}\n\n\t\t\t// Add optional branch name for context\n\t\t\tif (context.branchName !== undefined) {\n\t\t\t\tclaudeOptions.branchName = context.branchName\n\t\t\t}\n\n\t\t\t// Step 4.5: Generate MCP config and tool filtering for issue/PR workflows\n\t\t\tlet mcpConfig: Record<string, unknown>[] | undefined\n\t\t\tlet allowedTools: string[] | undefined\n\t\t\tlet disallowedTools: string[] | undefined\n\n\t\t\tif (context.type === 'issue' || context.type === 'pr') {\n\t\t\t\ttry {\n\t\t\t\t\tmcpConfig = await generateGitHubCommentMcpConfig(context.type)\n\t\t\t\t\tlogger.debug('Generated MCP configuration for GitHub comment broker')\n\n\t\t\t\t\t// Configure tool filtering for issue/PR workflows\n\t\t\t\t\tallowedTools = [\n\t\t\t\t\t\t'mcp__github_comment__create_comment',\n\t\t\t\t\t\t'mcp__github_comment__update_comment',\n\t\t\t\t\t]\n\t\t\t\t\tdisallowedTools = ['Bash(gh api:*)']\n\n\t\t\t\t\tlogger.debug('Configured tool filtering for issue/PR workflow', { allowedTools, disallowedTools })\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Log warning but continue without MCP\n\t\t\t\t\tlogger.warn(`Failed to generate MCP config: ${error instanceof Error ? error.message : 'Unknown error'}`)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Step 4.6: Load agent configurations using cached settings\n\t\t\tlet agents: Record<string, unknown> | undefined\n\t\t\ttry {\n\t\t\t\t// Use cached settings from Step 2.5\n\t\t\t\tif (this.settings?.agents && Object.keys(this.settings.agents).length > 0) {\n\t\t\t\t\tlogger.debug('Loaded project settings', {\n\t\t\t\t\t\tagentOverrides: Object.keys(this.settings.agents),\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\t// Load agents with settings overrides\n\t\t\t\tconst loadedAgents = await this.agentManager.loadAgents(this.settings)\n\t\t\t\tagents = this.agentManager.formatForCli(loadedAgents)\n\t\t\t\tlogger.debug('Loaded agent configurations', {\n\t\t\t\t\tagentCount: Object.keys(agents).length,\n\t\t\t\t\tagentNames: Object.keys(agents),\n\t\t\t\t})\n\t\t\t} catch (error) {\n\t\t\t\t// Log warning but continue without agents\n\t\t\t\tlogger.warn(`Failed to load agents: ${error instanceof Error ? error.message : 'Unknown error'}`)\n\t\t\t}\n\n\t\t\tlogger.debug('Launching Claude in current terminal', {\n\t\t\t\ttype: context.type,\n\t\t\t\tmodel,\n\t\t\t\tpermissionMode,\n\t\t\t\tworkspacePath: context.workspacePath,\n\t\t\t\thasMcpConfig: !!mcpConfig,\n\t\t\t})\n\n\t\t\tlogger.info('✨ Launching Claude in current terminal...')\n\n\t\t\t// Step 5: Launch Claude with system instructions appended and user prompt\n\t\t\tawait launchClaude(userPrompt, {\n\t\t\t\t...claudeOptions,\n\t\t\t\tappendSystemPrompt: systemInstructions,\n\t\t\t\t...(mcpConfig && { mcpConfig }),\n\t\t\t\t...(allowedTools && { allowedTools }),\n\t\t\t\t...(disallowedTools && { disallowedTools }),\n\t\t\t\t...(agents && { agents }),\n\t\t\t})\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : 'Unknown error'\n\t\t\tlogger.error(`Failed to launch Claude: ${errorMessage}`)\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Log user-friendly information about detected context\n\t */\n\tprivate logDetectedContext(context: ClaudeWorkflowOptions): void {\n\t\tif (context.type === 'issue') {\n\t\t\tlogger.info(`🎯 Detected issue workflow: Issue #${context.issueNumber}`)\n\t\t} else if (context.type === 'pr') {\n\t\t\tlogger.info(`🔄 Detected PR workflow: PR #${context.prNumber}`)\n\t\t} else {\n\t\t\tlogger.info('🌟 Detected regular workflow')\n\t\t}\n\n\t\tif (context.branchName) {\n\t\t\tlogger.info(`🌿 Working on branch: ${context.branchName}`)\n\t\t}\n\n\t\tif (context.port) {\n\t\t\tlogger.info(`🌐 Development server port: ${context.port}`)\n\t\t}\n\t}\n\n\t/**\n\t * Build template variables from context\n\t */\n\tprivate buildTemplateVariables(context: ClaudeWorkflowOptions, oneShot: import('../types/index.js').OneShotMode): TemplateVariables {\n\t\tconst variables: TemplateVariables = {\n\t\t\tWORKSPACE_PATH: context.workspacePath,\n\t\t}\n\n\t\tif (context.issueNumber !== undefined) {\n\t\t\tvariables.ISSUE_NUMBER = context.issueNumber\n\t\t}\n\n\t\tif (context.prNumber !== undefined) {\n\t\t\tvariables.PR_NUMBER = context.prNumber\n\t\t}\n\n\t\tif (context.title !== undefined) {\n\t\t\tif (context.type === 'issue') {\n\t\t\t\tvariables.ISSUE_TITLE = context.title\n\t\t\t} else if (context.type === 'pr') {\n\t\t\t\tvariables.PR_TITLE = context.title\n\t\t\t}\n\t\t}\n\n\t\tif (context.port !== undefined) {\n\t\t\tvariables.PORT = context.port\n\t\t}\n\n\t\t// Set ONE_SHOT_MODE flag for template conditional sections\n\t\tif (oneShot === 'noReview' || oneShot === 'bypassPermissions') {\n\t\t\tvariables.ONE_SHOT_MODE = true\n\t\t}\n\n\t\treturn variables\n\t}\n\n\t/**\n\t * Get the appropriate model for a workflow type\n\t * Same logic as ClaudeService.getModelForWorkflow()\n\t */\n\tprivate getModelForWorkflow(type: 'issue' | 'pr' | 'regular'): string | undefined {\n\t\t// Issue workflows use claude-sonnet-4-20250514\n\t\tif (type === 'issue') {\n\t\t\treturn 'claude-sonnet-4-20250514'\n\t\t}\n\t\t// For PR and regular workflows, use Claude's default model\n\t\treturn undefined\n\t}\n\n\t/**\n\t * Get the appropriate permission mode for a workflow type\n\t * Same logic as ClaudeService.getPermissionModeForWorkflow()\n\t */\n\tprivate getPermissionModeForWorkflow(\n\t\ttype: 'issue' | 'pr' | 'regular'\n\t): ClaudeCliOptions['permissionMode'] {\n\t\t// Check settings for configured permission mode\n\t\tif (this.settings?.workflows) {\n\t\t\tconst workflowConfig =\n\t\t\t\ttype === 'issue'\n\t\t\t\t\t? this.settings.workflows.issue\n\t\t\t\t\t: type === 'pr'\n\t\t\t\t\t\t? this.settings.workflows.pr\n\t\t\t\t\t\t: this.settings.workflows.regular\n\n\t\t\tif (workflowConfig?.permissionMode) {\n\t\t\t\treturn workflowConfig.permissionMode\n\t\t\t}\n\t\t}\n\n\t\t// Fall back to current defaults\n\t\tif (type === 'issue') {\n\t\t\treturn 'acceptEdits'\n\t\t}\n\t\t// For PR and regular workflows, use default permissions\n\t\treturn 'default'\n\t}\n\n\t/**\n\t * Auto-detect workspace context from current directory and git branch\n\t *\n\t * Detection priority:\n\t * 1. Directory name patterns (_pr_N, issue-N)\n\t * 2. Git branch name patterns\n\t * 3. Fallback to 'regular' workflow\n\t *\n\t * This leverages the same logic as FinishCommand.autoDetectFromCurrentDirectory()\n\t */\n\tprivate async detectWorkspaceContext(): Promise<ClaudeWorkflowOptions> {\n\t\tconst workspacePath = process.cwd()\n\t\tconst currentDir = path.basename(workspacePath)\n\n\t\t// Check for PR worktree pattern: _pr_N suffix\n\t\t// Pattern: /.*_pr_(\\d+)$/\n\t\tconst prPattern = /_pr_(\\d+)$/\n\t\tconst prMatch = currentDir.match(prPattern)\n\n\t\tif (prMatch?.[1]) {\n\t\t\tconst prNumber = parseInt(prMatch[1], 10)\n\t\t\tlogger.debug(`Auto-detected PR #${prNumber} from directory: ${currentDir}`)\n\n\t\t\treturn this.buildContextForPR(prNumber, workspacePath)\n\t\t}\n\n\t\t// Check for issue pattern in directory name\n\t\t// Pattern: /issue-(\\d+)/\n\t\tconst issuePattern = /issue-(\\d+)/\n\t\tconst issueMatch = currentDir.match(issuePattern)\n\n\t\tif (issueMatch?.[1]) {\n\t\t\tconst issueNumber = parseInt(issueMatch[1], 10)\n\t\t\tlogger.debug(`Auto-detected issue #${issueNumber} from directory: ${currentDir}`)\n\n\t\t\treturn this.buildContextForIssue(issueNumber, workspacePath)\n\t\t}\n\n\t\t// Fallback: Try to extract from git branch name\n\t\ttry {\n\t\t\tconst repoInfo = await this.gitWorktreeManager.getRepoInfo()\n\t\t\tconst currentBranch = repoInfo.currentBranch\n\n\t\t\tif (currentBranch) {\n\t\t\t\t// Try to extract issue from branch name\n\t\t\t\tconst branchIssueMatch = currentBranch.match(issuePattern)\n\t\t\t\tif (branchIssueMatch?.[1]) {\n\t\t\t\t\tconst issueNumber = parseInt(branchIssueMatch[1], 10)\n\t\t\t\t\tlogger.debug(`Auto-detected issue #${issueNumber} from branch: ${currentBranch}`)\n\n\t\t\t\t\treturn this.buildContextForIssue(issueNumber, workspacePath, currentBranch)\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Git command failed - not a git repo or other git error\n\t\t\tlogger.debug('Could not detect from git branch', { error })\n\t\t}\n\n\t\t// Last resort: use regular workflow\n\t\tlogger.debug('No specific context detected, using regular workflow')\n\t\treturn this.buildContextForRegular(workspacePath)\n\t}\n\n\t/**\n\t * Build context for issue workflow\n\t */\n\tprivate async buildContextForIssue(\n\t\tissueNumber: number,\n\t\tworkspacePath: string,\n\t\tbranchName?: string\n\t): Promise<ClaudeWorkflowOptions> {\n\t\t// Get branch name if not provided\n\t\tif (!branchName) {\n\t\t\ttry {\n\t\t\t\tconst repoInfo = await this.gitWorktreeManager.getRepoInfo()\n\t\t\t\tbranchName = repoInfo.currentBranch ?? undefined\n\t\t\t} catch {\n\t\t\t\t// Ignore git errors\n\t\t\t}\n\t\t}\n\n\t\tconst port = this.getPortFromEnv()\n\t\tconst context: ClaudeWorkflowOptions = {\n\t\t\ttype: 'issue',\n\t\t\tissueNumber,\n\t\t\tworkspacePath,\n\t\t\theadless: false, // Interactive mode\n\t\t}\n\n\t\tif (port !== undefined) {\n\t\t\tcontext.port = port\n\t\t}\n\n\t\tif (branchName !== undefined) {\n\t\t\tcontext.branchName = branchName\n\t\t}\n\n\t\treturn context\n\t}\n\n\t/**\n\t * Build context for PR workflow\n\t */\n\tprivate async buildContextForPR(\n\t\tprNumber: number,\n\t\tworkspacePath: string\n\t): Promise<ClaudeWorkflowOptions> {\n\t\t// Get branch name\n\t\tlet branchName: string | undefined\n\t\ttry {\n\t\t\tconst repoInfo = await this.gitWorktreeManager.getRepoInfo()\n\t\t\tbranchName = repoInfo.currentBranch ?? undefined\n\t\t} catch {\n\t\t\t// Ignore git errors\n\t\t}\n\n\t\tconst port = this.getPortFromEnv()\n\t\tconst context: ClaudeWorkflowOptions = {\n\t\t\ttype: 'pr',\n\t\t\tprNumber,\n\t\t\tworkspacePath,\n\t\t\theadless: false, // Interactive mode\n\t\t}\n\n\t\tif (port !== undefined) {\n\t\t\tcontext.port = port\n\t\t}\n\n\t\tif (branchName !== undefined) {\n\t\t\tcontext.branchName = branchName\n\t\t}\n\n\t\treturn context\n\t}\n\n\t/**\n\t * Build context for regular workflow\n\t */\n\tprivate async buildContextForRegular(workspacePath: string): Promise<ClaudeWorkflowOptions> {\n\t\t// Get branch name\n\t\tlet branchName: string | undefined\n\t\ttry {\n\t\t\tconst repoInfo = await this.gitWorktreeManager.getRepoInfo()\n\t\t\tbranchName = repoInfo.currentBranch ?? undefined\n\t\t} catch {\n\t\t\t// Ignore git errors\n\t\t}\n\n\t\tconst port = this.getPortFromEnv()\n\t\tconst context: ClaudeWorkflowOptions = {\n\t\t\ttype: 'regular',\n\t\t\tworkspacePath,\n\t\t\theadless: false, // Interactive mode\n\t\t}\n\n\t\tif (port !== undefined) {\n\t\t\tcontext.port = port\n\t\t}\n\n\t\tif (branchName !== undefined) {\n\t\t\tcontext.branchName = branchName\n\t\t}\n\n\t\treturn context\n\t}\n\n\t/**\n\t * Get PORT from environment variables\n\t * Returns undefined if PORT is not set or invalid\n\t */\n\tprivate getPortFromEnv(): number | undefined {\n\t\tconst portStr = process.env.PORT\n\t\tif (!portStr) {\n\t\t\treturn undefined\n\t\t}\n\n\t\tconst port = parseInt(portStr, 10)\n\t\tif (isNaN(port)) {\n\t\t\tlogger.warn(`Invalid PORT environment variable: ${portStr}`)\n\t\t\treturn undefined\n\t\t}\n\n\t\treturn port\n\t}\n\n\n\t/**\n\t * Build user prompt based on one-shot mode\n\t */\n\tprivate buildUserPrompt(oneShot: import('../types/index.js').OneShotMode = 'default'): string {\n\t\t// For one-shot modes, add bypass instructions to override template approval requirements\n\t\tif (oneShot === 'noReview' || oneShot === 'bypassPermissions') {\n\t\t\treturn 'Guide the user through the iloom workflow! The user has requested you move through the workflow without awaiting confirmation. This supersedes any other guidance.'\n\t\t}\n\n\t\t// Default mode: simple \"Go!\" prompt\n\t\treturn 'Guide the user through the iloom workflow!'\n\t}\n}\n"],"mappings":"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","names":[]}
|