@iloom/cli 0.2.0 → 0.3.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.
Files changed (169) hide show
  1. package/README.md +274 -30
  2. package/dist/BranchNamingService-3OQPRSWT.js +13 -0
  3. package/dist/ClaudeContextManager-MUQSDY2E.js +13 -0
  4. package/dist/ClaudeService-HG4VQ7AW.js +12 -0
  5. package/dist/GitHubService-EBOETDIW.js +11 -0
  6. package/dist/{LoomLauncher-CTSWJL35.js → LoomLauncher-FLEMBCSQ.js} +63 -32
  7. package/dist/LoomLauncher-FLEMBCSQ.js.map +1 -0
  8. package/dist/ProjectCapabilityDetector-34LU7JJ4.js +9 -0
  9. package/dist/{PromptTemplateManager-WII75TKH.js → PromptTemplateManager-A52RUAMS.js} +2 -2
  10. package/dist/README.md +274 -30
  11. package/dist/{SettingsManager-XOYCLH3D.js → SettingsManager-WHHFGSL7.js} +12 -4
  12. package/dist/SettingsMigrationManager-AGIIIPDQ.js +10 -0
  13. package/dist/agents/iloom-issue-analyze-and-plan.md +125 -35
  14. package/dist/agents/iloom-issue-analyzer.md +284 -32
  15. package/dist/agents/iloom-issue-complexity-evaluator.md +40 -21
  16. package/dist/agents/iloom-issue-enhancer.md +69 -48
  17. package/dist/agents/iloom-issue-implementer.md +36 -25
  18. package/dist/agents/iloom-issue-planner.md +35 -24
  19. package/dist/agents/iloom-issue-reviewer.md +62 -9
  20. package/dist/chunk-3KATJIKO.js +55 -0
  21. package/dist/chunk-3KATJIKO.js.map +1 -0
  22. package/dist/{chunk-SWCRXDZC.js → chunk-3RUPPQRG.js} +1 -18
  23. package/dist/chunk-3RUPPQRG.js.map +1 -0
  24. package/dist/{chunk-RF2YI2XJ.js → chunk-47KSHUCR.js} +3 -3
  25. package/dist/chunk-47KSHUCR.js.map +1 -0
  26. package/dist/{chunk-VETG35MF.js → chunk-4HHRTA7Q.js} +3 -3
  27. package/dist/{chunk-VETG35MF.js.map → chunk-4HHRTA7Q.js.map} +1 -1
  28. package/dist/chunk-5EF7Z346.js +1987 -0
  29. package/dist/chunk-5EF7Z346.js.map +1 -0
  30. package/dist/{chunk-4IV6W4U5.js → chunk-AWOFAD5O.js} +12 -12
  31. package/dist/chunk-AWOFAD5O.js.map +1 -0
  32. package/dist/{chunk-2PLUQT6J.js → chunk-C5QCTEQK.js} +2 -2
  33. package/dist/{chunk-CWR2SANQ.js → chunk-EBISESAP.js} +1 -1
  34. package/dist/{chunk-LHP6ROUM.js → chunk-FIAT22G7.js} +4 -16
  35. package/dist/chunk-FIAT22G7.js.map +1 -0
  36. package/dist/{chunk-TS6DL67T.js → chunk-G2IEYOLQ.js} +11 -38
  37. package/dist/chunk-G2IEYOLQ.js.map +1 -0
  38. package/dist/{chunk-ZMNQBJUI.js → chunk-IP7SMKIF.js} +61 -22
  39. package/dist/chunk-IP7SMKIF.js.map +1 -0
  40. package/dist/{chunk-JNKJ7NJV.js → chunk-JKXJ7BGL.js} +6 -2
  41. package/dist/{chunk-JNKJ7NJV.js.map → chunk-JKXJ7BGL.js.map} +1 -1
  42. package/dist/{chunk-LAPY6NAE.js → chunk-JQFO7QQN.js} +68 -12
  43. package/dist/{chunk-LAPY6NAE.js.map → chunk-JQFO7QQN.js.map} +1 -1
  44. package/dist/{SettingsMigrationManager-MTQIMI54.js → chunk-KLBYVHPK.js} +3 -2
  45. package/dist/{chunk-HBVFXN7R.js → chunk-MAVL6PJF.js} +26 -3
  46. package/dist/chunk-MAVL6PJF.js.map +1 -0
  47. package/dist/{chunk-USVVV3FP.js → chunk-MKWYLDFK.js} +5 -5
  48. package/dist/chunk-ML3NRPNB.js +396 -0
  49. package/dist/chunk-ML3NRPNB.js.map +1 -0
  50. package/dist/{chunk-DJUGYNQE.js → chunk-PA6Q6AWM.js} +16 -3
  51. package/dist/chunk-PA6Q6AWM.js.map +1 -0
  52. package/dist/chunk-RO26VS3W.js +444 -0
  53. package/dist/chunk-RO26VS3W.js.map +1 -0
  54. package/dist/{chunk-6LEQW46Y.js → chunk-VAYCCUXW.js} +72 -2
  55. package/dist/{chunk-6LEQW46Y.js.map → chunk-VAYCCUXW.js.map} +1 -1
  56. package/dist/{chunk-SPYPLHMK.js → chunk-VU3QMIP2.js} +34 -2
  57. package/dist/chunk-VU3QMIP2.js.map +1 -0
  58. package/dist/{chunk-PVAVNJKS.js → chunk-WEN5C5DM.js} +10 -1
  59. package/dist/chunk-WEN5C5DM.js.map +1 -0
  60. package/dist/{chunk-MFU53H6J.js → chunk-XXV3UFZL.js} +3 -3
  61. package/dist/{chunk-MFU53H6J.js.map → chunk-XXV3UFZL.js.map} +1 -1
  62. package/dist/{chunk-GZP4UGGM.js → chunk-ZM3CFL5L.js} +2 -2
  63. package/dist/{chunk-BLCTGFZN.js → chunk-ZT3YZB4K.js} +3 -4
  64. package/dist/chunk-ZT3YZB4K.js.map +1 -0
  65. package/dist/{claude-ZIWDG4XG.js → claude-GOP6PFC7.js} +2 -2
  66. package/dist/{cleanup-FEIVZSIV.js → cleanup-7RWLBSLE.js} +86 -25
  67. package/dist/cleanup-7RWLBSLE.js.map +1 -0
  68. package/dist/cli.js +2511 -62
  69. package/dist/cli.js.map +1 -1
  70. package/dist/{contribute-EMZKCAC6.js → contribute-BS2L4FZR.js} +6 -6
  71. package/dist/{feedback-LFNMQBAZ.js → feedback-N4ECWIPF.js} +15 -14
  72. package/dist/{feedback-LFNMQBAZ.js.map → feedback-N4ECWIPF.js.map} +1 -1
  73. package/dist/{git-WC6HZLOT.js → git-TDXKRTXM.js} +4 -2
  74. package/dist/{ignite-MQWVJEAB.js → ignite-VM64QO3J.js} +32 -27
  75. package/dist/ignite-VM64QO3J.js.map +1 -0
  76. package/dist/index.d.ts +359 -45
  77. package/dist/index.js +1266 -502
  78. package/dist/index.js.map +1 -1
  79. package/dist/{init-GJDYN2IK.js → init-G3T64SC4.js} +104 -40
  80. package/dist/init-G3T64SC4.js.map +1 -0
  81. package/dist/mcp/issue-management-server.js +934 -0
  82. package/dist/mcp/issue-management-server.js.map +1 -0
  83. package/dist/{neon-helpers-ZVIRPKCI.js → neon-helpers-WPUACUVC.js} +3 -3
  84. package/dist/neon-helpers-WPUACUVC.js.map +1 -0
  85. package/dist/{open-NXSN7XOC.js → open-KXDXEKRZ.js} +39 -36
  86. package/dist/open-KXDXEKRZ.js.map +1 -0
  87. package/dist/{prompt-ANTQWHUF.js → prompt-7INJ7YRU.js} +4 -2
  88. package/dist/prompt-7INJ7YRU.js.map +1 -0
  89. package/dist/prompts/init-prompt.txt +538 -95
  90. package/dist/prompts/issue-prompt.txt +27 -27
  91. package/dist/{rebase-DUNFOJVS.js → rebase-Q7GMM7EI.js} +6 -6
  92. package/dist/{remote-ZCXJVVNW.js → remote-VUNCQZ6J.js} +3 -2
  93. package/dist/remote-VUNCQZ6J.js.map +1 -0
  94. package/dist/{run-O7ZK7CKA.js → run-PAWJJCSX.js} +39 -36
  95. package/dist/run-PAWJJCSX.js.map +1 -0
  96. package/dist/schema/settings.schema.json +56 -0
  97. package/dist/{test-git-T76HOTIA.js → test-git-3WDLNQCA.js} +3 -3
  98. package/dist/{test-prefix-6HJUVQMH.js → test-prefix-EVGAWAJW.js} +3 -3
  99. package/dist/{test-webserver-M2I3EV4J.js → test-webserver-DAHONWCS.js} +4 -4
  100. package/dist/test-webserver-DAHONWCS.js.map +1 -0
  101. package/package.json +2 -1
  102. package/dist/ClaudeContextManager-LVCYRM6Q.js +0 -13
  103. package/dist/ClaudeService-WVTWB3DK.js +0 -12
  104. package/dist/GitHubService-7E2S5NNZ.js +0 -11
  105. package/dist/LoomLauncher-CTSWJL35.js.map +0 -1
  106. package/dist/add-issue-OBI325W7.js +0 -69
  107. package/dist/add-issue-OBI325W7.js.map +0 -1
  108. package/dist/chunk-4IV6W4U5.js.map +0 -1
  109. package/dist/chunk-BLCTGFZN.js.map +0 -1
  110. package/dist/chunk-CVLAZRNB.js +0 -54
  111. package/dist/chunk-CVLAZRNB.js.map +0 -1
  112. package/dist/chunk-DJUGYNQE.js.map +0 -1
  113. package/dist/chunk-H4E4THUZ.js +0 -55
  114. package/dist/chunk-H4E4THUZ.js.map +0 -1
  115. package/dist/chunk-H5LDRGVK.js +0 -642
  116. package/dist/chunk-H5LDRGVK.js.map +0 -1
  117. package/dist/chunk-HBVFXN7R.js.map +0 -1
  118. package/dist/chunk-LHP6ROUM.js.map +0 -1
  119. package/dist/chunk-PVAVNJKS.js.map +0 -1
  120. package/dist/chunk-RF2YI2XJ.js.map +0 -1
  121. package/dist/chunk-SPYPLHMK.js.map +0 -1
  122. package/dist/chunk-SWCRXDZC.js.map +0 -1
  123. package/dist/chunk-SYOSCMIT.js +0 -545
  124. package/dist/chunk-SYOSCMIT.js.map +0 -1
  125. package/dist/chunk-T3KEIB4D.js +0 -243
  126. package/dist/chunk-T3KEIB4D.js.map +0 -1
  127. package/dist/chunk-TS6DL67T.js.map +0 -1
  128. package/dist/chunk-ZMNQBJUI.js.map +0 -1
  129. package/dist/cleanup-FEIVZSIV.js.map +0 -1
  130. package/dist/enhance-MNA4ZGXW.js +0 -176
  131. package/dist/enhance-MNA4ZGXW.js.map +0 -1
  132. package/dist/finish-TX5CJICB.js +0 -1749
  133. package/dist/finish-TX5CJICB.js.map +0 -1
  134. package/dist/ignite-MQWVJEAB.js.map +0 -1
  135. package/dist/init-GJDYN2IK.js.map +0 -1
  136. package/dist/mcp/chunk-6SDFJ42P.js +0 -62
  137. package/dist/mcp/chunk-6SDFJ42P.js.map +0 -1
  138. package/dist/mcp/claude-NDFOCQQQ.js +0 -249
  139. package/dist/mcp/claude-NDFOCQQQ.js.map +0 -1
  140. package/dist/mcp/color-QS5BFCNN.js +0 -168
  141. package/dist/mcp/color-QS5BFCNN.js.map +0 -1
  142. package/dist/mcp/github-comment-server.js +0 -168
  143. package/dist/mcp/github-comment-server.js.map +0 -1
  144. package/dist/mcp/terminal-OMNRFWB3.js +0 -227
  145. package/dist/mcp/terminal-OMNRFWB3.js.map +0 -1
  146. package/dist/open-NXSN7XOC.js.map +0 -1
  147. package/dist/run-O7ZK7CKA.js.map +0 -1
  148. package/dist/start-73I5W7WW.js +0 -983
  149. package/dist/start-73I5W7WW.js.map +0 -1
  150. package/dist/test-webserver-M2I3EV4J.js.map +0 -1
  151. /package/dist/{ClaudeContextManager-LVCYRM6Q.js.map → BranchNamingService-3OQPRSWT.js.map} +0 -0
  152. /package/dist/{ClaudeService-WVTWB3DK.js.map → ClaudeContextManager-MUQSDY2E.js.map} +0 -0
  153. /package/dist/{GitHubService-7E2S5NNZ.js.map → ClaudeService-HG4VQ7AW.js.map} +0 -0
  154. /package/dist/{PromptTemplateManager-WII75TKH.js.map → GitHubService-EBOETDIW.js.map} +0 -0
  155. /package/dist/{SettingsManager-XOYCLH3D.js.map → ProjectCapabilityDetector-34LU7JJ4.js.map} +0 -0
  156. /package/dist/{claude-ZIWDG4XG.js.map → PromptTemplateManager-A52RUAMS.js.map} +0 -0
  157. /package/dist/{git-WC6HZLOT.js.map → SettingsManager-WHHFGSL7.js.map} +0 -0
  158. /package/dist/{neon-helpers-ZVIRPKCI.js.map → SettingsMigrationManager-AGIIIPDQ.js.map} +0 -0
  159. /package/dist/{chunk-2PLUQT6J.js.map → chunk-C5QCTEQK.js.map} +0 -0
  160. /package/dist/{chunk-CWR2SANQ.js.map → chunk-EBISESAP.js.map} +0 -0
  161. /package/dist/{SettingsMigrationManager-MTQIMI54.js.map → chunk-KLBYVHPK.js.map} +0 -0
  162. /package/dist/{chunk-USVVV3FP.js.map → chunk-MKWYLDFK.js.map} +0 -0
  163. /package/dist/{chunk-GZP4UGGM.js.map → chunk-ZM3CFL5L.js.map} +0 -0
  164. /package/dist/{prompt-ANTQWHUF.js.map → claude-GOP6PFC7.js.map} +0 -0
  165. /package/dist/{contribute-EMZKCAC6.js.map → contribute-BS2L4FZR.js.map} +0 -0
  166. /package/dist/{remote-ZCXJVVNW.js.map → git-TDXKRTXM.js.map} +0 -0
  167. /package/dist/{rebase-DUNFOJVS.js.map → rebase-Q7GMM7EI.js.map} +0 -0
  168. /package/dist/{test-git-T76HOTIA.js.map → test-git-3WDLNQCA.js.map} +0 -0
  169. /package/dist/{test-prefix-6HJUVQMH.js.map → test-prefix-EVGAWAJW.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/ValidationRunner.ts","../src/lib/CommitManager.ts","../src/lib/BuildRunner.ts","../src/lib/PRManager.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 { executeGhCommand } from '../utils/github.js'\nimport { launchClaude, detectClaudeCli } from '../utils/claude.js'\nimport { getEffectivePRTargetRemote, getConfiguredRepoFromSettings, parseGitRemotes } from '../utils/remote.js'\nimport { openBrowser } from '../utils/browser.js'\nimport { logger } from '../utils/logger.js'\nimport type { IloomSettings } from './SettingsManager.js'\n\ninterface ExistingPR {\n\tnumber: number\n\turl: string\n}\n\ninterface PRCreationResult {\n\turl: string\n\tnumber: number\n\twasExisting: boolean\n}\n\nexport class PRManager {\n\tconstructor(private settings: IloomSettings) {}\n\n\t/**\n\t * Check if a PR already exists for the given branch\n\t * @param branchName - Branch to check\n\t * @param cwd - Working directory\n\t * @returns Existing PR info or null if none found\n\t */\n\tasync checkForExistingPR(branchName: string, cwd?: string): Promise<ExistingPR | null> {\n\t\ttry {\n\t\t\tconst prList = await executeGhCommand<Array<{ number: number; url: string }>>(\n\t\t\t\t['pr', 'list', '--head', branchName, '--state', 'open', '--json', 'number,url'],\n\t\t\t\tcwd ? { cwd } : undefined\n\t\t\t)\n\n\t\t\tif (prList.length > 0) {\n\t\t\t\treturn prList[0] ?? null // Return first match\n\t\t\t}\n\n\t\t\treturn null\n\t\t} catch (error) {\n\t\t\tlogger.debug('Error checking for existing PR', { error })\n\t\t\treturn null\n\t\t}\n\t}\n\n\t/**\n\t * Generate PR body using Claude if available, otherwise use simple template\n\t * @param issueNumber - Issue number to include in body\n\t * @param worktreePath - Path to worktree for context\n\t * @returns PR body markdown\n\t */\n\tasync generatePRBody(issueNumber: number | undefined, worktreePath: string): Promise<string> {\n\t\t// Try Claude first for rich body generation\n\t\tconst hasClaudeCli = await detectClaudeCli()\n\n\t\tif (hasClaudeCli) {\n\t\t\ttry {\n\t\t\t\tconst prompt = this.buildPRBodyPrompt(issueNumber)\n\n\t\t\t\tconst body = await launchClaude(prompt, {\n\t\t\t\t\theadless: true,\n\t\t\t\t\taddDir: worktreePath,\n\t\t\t\t\ttimeout: 30000,\n\t\t\t\t})\n\n\t\t\t\tif (body && typeof body === 'string' && body.trim()) {\n\t\t\t\t\tconst sanitized = this.sanitizeClaudeOutput(body)\n\t\t\t\t\tif (sanitized) {\n\t\t\t\t\t\treturn sanitized\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tlogger.debug('Claude PR body generation failed, using template', { error })\n\t\t\t}\n\t\t}\n\n\t\t// Fallback to simple template\n\t\tlet body = 'This PR contains changes from the iloom workflow.\\n\\n'\n\n\t\tif (issueNumber) {\n\t\t\tbody += `Fixes #${issueNumber}`\n\t\t}\n\n\t\treturn body\n\t}\n\n\t/**\n\t * Build structured XML prompt for PR body generation\n\t * Uses XML format for clear task definition and output expectations\n\t */\n\tprivate buildPRBodyPrompt(issueNumber?: number): string {\n\t\tconst issueContext = issueNumber\n\t\t\t? `\\n<IssueContext>\nThis PR is associated with GitHub issue #${issueNumber}.\nInclude \"Fixes #${issueNumber}\" at the end of the body on its own line.\n</IssueContext>`\n\t\t\t: ''\n\n\t\treturn `<Task>\nYou are a software engineer writing a pull request body for this repository.\nExamine the changes in the git repository and generate a concise, professional PR description.\n</Task>\n\n<Requirements>\n<Format>Write 2-3 sentences summarizing what was changed and why.${issueNumber ? `\\n\\nEnd with \"Fixes #${issueNumber}\" on its own line.` : ''}</Format>\n<Tone>Professional and concise</Tone>\n<Focus>Summarize the changes and their purpose</Focus>\n<NoMeta>CRITICAL: Do NOT include ANY explanatory text, analysis, or meta-commentary. Output ONLY the raw PR body text.</NoMeta>\n<Examples>\nGood: \"Add user authentication with JWT tokens to secure the API endpoints. This includes login and registration endpoints with proper password hashing.\n\nFixes #42\"\nGood: \"Fix navigation bug in sidebar menu that caused incorrect highlighting on nested routes.\"\nBad: \"Here's the PR body:\\n\\n---\\n\\nAdd user authentication...\"\nBad: \"Based on the changes, I'll write: Fix navigation bug...\"\n</Examples>\n${issueContext}\n</Requirements>\n\n<Output>\nIMPORTANT: Your entire response will be used directly as the GitHub pull request body.\nDo not include any explanatory text, headers, or separators before or after the body.\nStart your response immediately with the PR body text.\n</Output>`\n\t}\n\n\t/**\n\t * Sanitize Claude output to remove meta-commentary and clean formatting\n\t * Handles cases where Claude includes explanatory text despite instructions\n\t */\n\tprivate sanitizeClaudeOutput(rawOutput: string): string {\n\t\tlet cleaned = rawOutput.trim()\n\n\t\t// Remove common meta-commentary patterns (case-insensitive)\n\t\tconst metaPatterns = [\n\t\t\t/^.*?based on.*?changes.*?:/i,\n\t\t\t/^.*?looking at.*?files.*?:/i,\n\t\t\t/^.*?examining.*?:/i,\n\t\t\t/^.*?analyzing.*?:/i,\n\t\t\t/^.*?i'll.*?generate.*?:/i,\n\t\t\t/^.*?let me.*?:/i,\n\t\t\t/^.*?here.*?is.*?(?:the\\s+)?(?:pr|pull request).*?body.*?:/i,\n\t\t\t/^.*?here's.*?(?:the\\s+)?(?:pr|pull request).*?body.*?:/i,\n\t\t]\n\n\t\tfor (const pattern of metaPatterns) {\n\t\t\tcleaned = cleaned.replace(pattern, '').trim()\n\t\t}\n\n\t\t// Remove leading separator lines (---, ===, etc.)\n\t\tcleaned = cleaned.replace(/^[-=]{3,}\\s*/m, '').trim()\n\n\t\t// Extract content after separators only if it looks like meta-commentary\n\t\tif (cleaned.includes(':')) {\n\t\t\tconst colonIndex = cleaned.indexOf(':')\n\t\t\tconst beforeColon = cleaned.substring(0, colonIndex).trim().toLowerCase()\n\n\t\t\t// Only split if the text before colon looks like meta-commentary\n\t\t\tconst metaIndicators = [\n\t\t\t\t'here is the pr body',\n\t\t\t\t'here is the pull request body',\n\t\t\t\t'pr body',\n\t\t\t\t'pull request body',\n\t\t\t\t'here is',\n\t\t\t\t\"here's\",\n\t\t\t\t'the body should be',\n\t\t\t\t'i suggest',\n\t\t\t\t'my suggestion'\n\t\t\t]\n\n\t\t\tconst isMetaCommentary = metaIndicators.some(indicator => beforeColon.includes(indicator))\n\n\t\t\tif (isMetaCommentary) {\n\t\t\t\tconst afterColon = cleaned.substring(colonIndex + 1).trim()\n\t\t\t\t// Remove leading separator after colon\n\t\t\t\tconst afterSeparator = afterColon.replace(/^[-=]{3,}\\s*/m, '').trim()\n\t\t\t\tif (afterSeparator && afterSeparator.length > 10) {\n\t\t\t\t\tcleaned = afterSeparator\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Remove quotes if the entire message is wrapped in them\n\t\tif ((cleaned.startsWith('\"') && cleaned.endsWith('\"')) ||\n\t\t\t(cleaned.startsWith(\"'\") && cleaned.endsWith(\"'\"))) {\n\t\t\tcleaned = cleaned.slice(1, -1).trim()\n\t\t}\n\n\t\treturn cleaned\n\t}\n\n\t/**\n\t * Create a GitHub PR for the branch\n\t * @param branchName - Branch to create PR from (used as --head)\n\t * @param title - PR title\n\t * @param body - PR body\n\t * @param baseBranch - Base branch to target (usually main/master)\n\t * @param cwd - Working directory\n\t * @returns PR URL\n\t */\n\tasync createPR(\n\t\tbranchName: string,\n\t\ttitle: string,\n\t\tbody: string,\n\t\tbaseBranch: string,\n\t\tcwd?: string\n\t): Promise<string> {\n\t\ttry {\n\t\t\t// Get the target remote for the PR\n\t\t\tconst targetRemote = await getEffectivePRTargetRemote(this.settings, cwd)\n\n\t\t\t// Determine the correct --head value\n\t\t\t// For fork workflows (target != origin), we need \"username:branch\" format\n\t\t\t// See: https://github.com/cli/cli/issues/2691\n\t\t\tlet headValue = branchName\n\n\t\t\tif (targetRemote !== 'origin') {\n\t\t\t\t// Fork workflow: need to specify the head as \"owner:branch\"\n\t\t\t\t// Get the owner of the origin remote (where we pushed the branch)\n\t\t\t\tconst remotes = await parseGitRemotes(cwd)\n\t\t\t\tconst originRemote = remotes.find(r => r.name === 'origin')\n\n\t\t\t\tif (originRemote) {\n\t\t\t\t\theadValue = `${originRemote.owner}:${branchName}`\n\t\t\t\t\tlogger.debug(`Fork workflow detected, using head: ${headValue}`)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Build gh pr create command\n\t\t\t// Note: gh pr create returns a plain URL string, not JSON\n\t\t\tconst args = ['pr', 'create', '--head', headValue, '--title', title, '--body', body, '--base', baseBranch]\n\n\t\t\t// If target remote is not 'origin', we need to specify the repo\n\t\t\tif (targetRemote !== 'origin') {\n\t\t\t\tconst repo = await getConfiguredRepoFromSettings(this.settings, cwd)\n\t\t\t\targs.push('--repo', repo)\n\t\t\t}\n\n\t\t\t// gh pr create returns the PR URL as plain text (not JSON)\n\t\t\tconst result = await executeGhCommand<string>(args, cwd ? { cwd } : undefined)\n\n\t\t\t// Result is a string URL like \"https://github.com/owner/repo/pull/123\"\n\t\t\tconst url = typeof result === 'string' ? result.trim() : String(result).trim()\n\n\t\t\tif (!url.includes('github.com') || !url.includes('/pull/')) {\n\t\t\t\tthrow new Error(`Unexpected response from gh pr create: ${url}`)\n\t\t\t}\n\n\t\t\treturn url\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error)\n\n\t\t\t// Provide helpful error message for common GraphQL errors\n\t\t\tif (errorMessage.includes(\"Head sha can't be blank\") || errorMessage.includes(\"No commits between\")) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to create pull request: ${errorMessage}\\n\\n` +\n\t\t\t\t\t`This error typically occurs when:\\n` +\n\t\t\t\t\t` - The branch was not fully pushed to the remote\\n` +\n\t\t\t\t\t` - There's a race condition between push and PR creation\\n` +\n\t\t\t\t\t` - The branch has no commits ahead of the base branch\\n\\n` +\n\t\t\t\t\t`Try running: git push -u origin ${branchName}\\n` +\n\t\t\t\t\t`Then retry: il finish`\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tthrow new Error(`Failed to create pull request: ${errorMessage}`)\n\t\t}\n\t}\n\n\t/**\n\t * Open PR URL in browser\n\t * @param url - PR URL to open\n\t */\n\tasync openPRInBrowser(url: string): Promise<void> {\n\t\ttry {\n\t\t\tawait openBrowser(url)\n\t\t\tlogger.debug('Opened PR in browser', { url })\n\t\t} catch (error) {\n\t\t\t// Don't fail the whole operation if browser opening fails\n\t\t\tlogger.warn('Failed to open PR in browser', { error })\n\t\t}\n\t}\n\n\t/**\n\t * Complete PR workflow: check for existing, create if needed, optionally open in browser\n\t * @param branchName - Branch to create PR from\n\t * @param title - PR title\n\t * @param issueNumber - Optional issue number for body generation\n\t * @param baseBranch - Base branch to target\n\t * @param worktreePath - Path to worktree\n\t * @param openInBrowser - Whether to open PR in browser\n\t * @returns PR creation result\n\t */\n\tasync createOrOpenPR(\n\t\tbranchName: string,\n\t\ttitle: string,\n\t\tissueNumber: number | undefined,\n\t\tbaseBranch: string,\n\t\tworktreePath: string,\n\t\topenInBrowser: boolean\n\t): Promise<PRCreationResult> {\n\t\t// Check for existing PR\n\t\tconst existingPR = await this.checkForExistingPR(branchName, worktreePath)\n\n\t\tif (existingPR) {\n\t\t\tlogger.info(`Pull request already exists: ${existingPR.url}`)\n\n\t\t\tif (openInBrowser) {\n\t\t\t\tawait this.openPRInBrowser(existingPR.url)\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\turl: existingPR.url,\n\t\t\t\tnumber: existingPR.number,\n\t\t\t\twasExisting: true,\n\t\t\t}\n\t\t}\n\n\t\t// Generate PR body\n\t\tconst body = await this.generatePRBody(issueNumber, worktreePath)\n\n\t\t// Create new PR\n\t\tlogger.info('Creating pull request...')\n\t\tconst url = await this.createPR(branchName, title, body, baseBranch, worktreePath)\n\n\t\t// Extract PR number from URL\n\t\tconst prNumber = this.extractPRNumberFromUrl(url)\n\n\t\tif (openInBrowser) {\n\t\t\tawait this.openPRInBrowser(url)\n\t\t}\n\n\t\treturn {\n\t\t\turl,\n\t\t\tnumber: prNumber,\n\t\t\twasExisting: false,\n\t\t}\n\t}\n\n\t/**\n\t * Extract PR number from GitHub PR URL\n\t * @param url - PR URL (e.g., https://github.com/owner/repo/pull/123)\n\t * @returns PR number\n\t */\n\tprivate extractPRNumberFromUrl(url: string): number {\n\t\tconst match = url.match(/\\/pull\\/(\\d+)/)\n\t\tif (match?.[1]) {\n\t\t\treturn parseInt(match[1], 10)\n\t\t}\n\t\tthrow new Error(`Could not extract PR number from URL: ${url}`)\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 { PRManager } from '../lib/PRManager.js'\nimport { findMainWorktreePathWithSettings, pushBranchToRemote } 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 { promptConfirmation } from '../utils/prompt.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 3.5: Check merge mode from settings and branch workflow\n\t\tconst settings = await this.settingsManager.loadSettings(worktree.path)\n\t\tconst mergeBehavior = settings.mergeBehavior ?? { mode: 'local' }\n\n\t\tif (mergeBehavior.mode === 'github-pr') {\n\t\t\t// Execute github-pr workflow instead of local merge\n\t\t\tawait this.executeGitHubPRWorkflow(parsed, options, worktree, settings)\n\t\t\treturn\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 * Execute workflow for GitHub PR creation (github-pr merge mode)\n\t * Validates → Commits → Pushes → Creates PR → Prompts for cleanup\n\t */\n\tprivate async executeGitHubPRWorkflow(\n\t\tparsed: ParsedFinishInput,\n\t\toptions: FinishOptions,\n\t\tworktree: GitWorktree,\n\t\tsettings: import('../lib/SettingsManager.js').IloomSettings\n\t): Promise<void> {\n\t\t// Step 1: Push branch to origin\n\t\tif (options.dryRun) {\n\t\t\tlogger.info('[DRY RUN] Would push branch to origin')\n\t\t} else {\n\t\t\tlogger.info('Pushing branch to origin...')\n\t\t\tawait pushBranchToRemote(worktree.branch, worktree.path, { dryRun: false })\n\t\t\tlogger.success('Branch pushed successfully')\n\t\t}\n\n\t\t// Step 2: Initialize PRManager with settings\n\t\tconst prManager = new PRManager(settings)\n\n\t\t// Step 3: Generate PR title from issue if available\n\t\tlet prTitle = `Work from ${worktree.branch}`\n\t\tif (parsed.type === 'issue' && parsed.number) {\n\t\t\t// Try to fetch issue title for better PR title\n\t\t\ttry {\n\t\t\t\tconst issue = await this.gitHubService.fetchIssue(parsed.number)\n\t\t\t\tprTitle = issue.title\n\t\t\t} catch (error) {\n\t\t\t\tlogger.debug('Could not fetch issue title, using branch name', { error })\n\t\t\t}\n\t\t}\n\n\t\t// Step 4: Create or open PR\n\t\tif (options.dryRun) {\n\t\t\tlogger.info('[DRY RUN] Would create GitHub PR')\n\t\t\tlogger.info(` Title: ${prTitle}`)\n\t\t\tlogger.info(` Base: ${settings.mainBranch ?? 'main'}`)\n\t\t} else {\n\t\t\tconst baseBranch = settings.mainBranch ?? 'main'\n\t\t\tconst openInBrowser = options.noBrowser !== true\n\n\t\t\tconst result = await prManager.createOrOpenPR(\n\t\t\t\tworktree.branch,\n\t\t\t\tprTitle,\n\t\t\t\tparsed.type === 'issue' ? parsed.number : undefined,\n\t\t\t\tbaseBranch,\n\t\t\t\tworktree.path,\n\t\t\t\topenInBrowser\n\t\t\t)\n\n\t\t\tif (result.wasExisting) {\n\t\t\t\tlogger.success(`Existing pull request: ${result.url}`)\n\t\t\t} else {\n\t\t\t\tlogger.success(`Pull request created: ${result.url}`)\n\t\t\t}\n\n\t\t\t// Step 5: Interactive cleanup prompt (unless flags override)\n\t\t\tawait this.handlePRCleanupPrompt(parsed, options, worktree)\n\t\t}\n\t}\n\n\t/**\n\t * Handle cleanup prompt after PR creation\n\t * Respects --cleanup and --no-cleanup flags, otherwise prompts user\n\t */\n\tprivate async handlePRCleanupPrompt(\n\t\tparsed: ParsedFinishInput,\n\t\toptions: FinishOptions,\n\t\tworktree: GitWorktree\n\t): Promise<void> {\n\t\tif (options.cleanup === true) {\n\t\t\t// Explicit --cleanup flag: perform cleanup\n\t\t\tlogger.info('Cleaning up worktree (--cleanup flag)...')\n\t\t\tawait this.performWorktreeCleanup(parsed, options, worktree)\n\t\t} else if (options.cleanup === false) {\n\t\t\t// Explicit --no-cleanup flag: keep worktree\n\t\t\tlogger.info('Worktree kept active for continued work (--no-cleanup flag)')\n\t\t\tlogger.info(`To cleanup later: il cleanup ${parsed.originalInput}`)\n\t\t} else {\n\t\t\t// No flag: prompt user for decision\n\t\t\tlogger.info('')\n\t\t\tlogger.info('PR created successfully. Would you like to clean up the worktree?')\n\t\t\tlogger.info(` Worktree: ${worktree.path}`)\n\t\t\tlogger.info(` Branch: ${worktree.branch}`)\n\t\t\tlogger.info('')\n\n\t\t\tconst shouldCleanup = await promptConfirmation(\n\t\t\t\t'Clean up worktree now?',\n\t\t\t\tfalse // Default to keeping worktree (safer option)\n\t\t\t)\n\n\t\t\tif (shouldCleanup) {\n\t\t\t\tawait this.performWorktreeCleanup(parsed, options, worktree)\n\t\t\t} else {\n\t\t\t\tlogger.info('Worktree kept active. Run `il cleanup` when ready.')\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Perform worktree cleanup (used by GitHub PR workflow)\n\t * Similar to performPostMergeCleanup but for PR workflow\n\t */\n\tprivate async performWorktreeCleanup(\n\t\tparsed: ParsedFinishInput,\n\t\toptions: FinishOptions,\n\t\tworktree: GitWorktree\n\t): Promise<void> {\n\t\t// Convert ParsedFinishInput to ParsedInput\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: false, // Don't delete branch - PR still needs it\n\t\t\tkeepDatabase: false, // Clean up database\n\t\t\tforce: options.force ?? false,\n\t\t}\n\n\t\ttry {\n\t\t\tlogger.info('Starting worktree 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\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\tthis.showManualCleanupInstructions(worktree)\n\t\t\t} else {\n\t\t\t\tlogger.success('Worktree 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\tconst errorMessage = error instanceof Error ? error.message : 'Unknown error'\n\t\t\tlogger.warn(`Cleanup failed: ${errorMessage}`)\n\t\t\tlogger.warn('Manual cleanup may be required')\n\t\t\tthis.showManualCleanupInstructions(worktree)\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":["body","settings","pushBranchToRemote"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/ignite.ts","../src/utils/FirstRunManager.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'\nimport { FirstRunManager } from '../utils/FirstRunManager.js'\nimport { readFile } from 'fs/promises'\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 firstRunManager: FirstRunManager\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\tfirstRunManager?: FirstRunManager\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\tthis.firstRunManager = firstRunManager ?? new FirstRunManager('spin')\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 0.5: Check if this is first-time user\n\t\t\tconst isFirstRun = await this.firstRunManager.isFirstRun()\n\t\t\tif (isFirstRun) {\n\t\t\t\tlogger.success('Welcome to iloom! Preparing first-time experience...')\n\t\t\t}\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\n\t\t\t// Step 2.5: Add first-time user context if needed\n\t\t\tif (isFirstRun) {\n\t\t\t\tvariables.FIRST_TIME_USER = true\n\t\t\t\tvariables.README_CONTENT = await this.loadReadmeContent()\n\t\t\t\tvariables.SETTINGS_SCHEMA_CONTENT = await this.loadSettingsSchemaContent()\n\t\t\t}\n\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\n\t\t\t// Step 6: Mark as run after successful launch\n\t\t\tif (isFirstRun) {\n\t\t\t\tawait this.firstRunManager.markAsRun()\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\t/**\n\t * Load README.md content for first-time users\n\t * Walks up from dist directory to find README.md in project root\n\t */\n\tprivate async loadReadmeContent(): Promise<string> {\n\t\ttry {\n\t\t\t// Walk up from current file location to find README.md\n\t\t\t// Use same pattern as PromptTemplateManager for finding files\n\t\t\tlet currentDir = path.dirname(new URL(import.meta.url).pathname)\n\n\t\t\t// Walk up to find README.md\n\t\t\twhile (currentDir !== path.dirname(currentDir)) {\n\t\t\t\tconst readmePath = path.join(currentDir, 'README.md')\n\t\t\t\ttry {\n\t\t\t\t\tconst content = await readFile(readmePath, 'utf-8')\n\t\t\t\t\tlogger.debug('Loaded README.md for first-time user', { readmePath })\n\t\t\t\t\treturn content\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\tlogger.debug('README.md not found, returning empty string')\n\t\t\treturn ''\n\t\t} catch (error) {\n\t\t\t// Graceful degradation - return empty string on error\n\t\t\tlogger.debug(`Failed to load README.md: ${error}`)\n\t\t\treturn ''\n\t\t}\n\t}\n\n\t/**\n\t * Load settings schema content for first-time users\n\t * Walks up from dist directory to find .iloom/README.md\n\t */\n\tprivate async loadSettingsSchemaContent(): Promise<string> {\n\t\ttry {\n\t\t\t// Walk up from current file location to find .iloom/README.md\n\t\t\tlet currentDir = path.dirname(new URL(import.meta.url).pathname)\n\n\t\t\t// Walk up to find .iloom/README.md\n\t\t\twhile (currentDir !== path.dirname(currentDir)) {\n\t\t\t\tconst schemaPath = path.join(currentDir, '.iloom', 'README.md')\n\t\t\t\ttry {\n\t\t\t\t\tconst content = await readFile(schemaPath, 'utf-8')\n\t\t\t\t\tlogger.debug('Loaded .iloom/README.md for first-time user', { schemaPath })\n\t\t\t\t\treturn content\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\tlogger.debug('.iloom/README.md not found, returning empty string')\n\t\t\treturn ''\n\t\t} catch (error) {\n\t\t\t// Graceful degradation - return empty string on error\n\t\t\tlogger.debug(`Failed to load .iloom/README.md: ${error}`)\n\t\t\treturn ''\n\t\t}\n\t}\n}\n","import os from 'os'\nimport path from 'path'\nimport fs from 'fs-extra'\nimport { logger } from './logger.js'\n\n/**\n * FirstRunManager: Detect and track first-time spin usage via marker file\n *\n * Follows the same pattern as UpdateNotifier for file-based state tracking\n * in ~/.config/iloom-ai/ directory.\n */\nexport class FirstRunManager {\n\tprivate markerFilePath: string\n\n\tconstructor(feature: string = 'spin') {\n\t\tconst configDir = path.join(os.homedir(), '.config', 'iloom-ai')\n\t\tthis.markerFilePath = path.join(configDir, `${feature}-first-run`)\n\t\tlogger.debug('FirstRunManager initialized', {\n\t\t\tfeature,\n\t\t\tmarkerFilePath: this.markerFilePath\n\t\t})\n\t}\n\n\t/**\n\t * Check if this is the first run of the feature\n\t * Returns true if marker file doesn't exist\n\t * Handles errors gracefully by returning true (treat as first-run on error)\n\t */\n\tasync isFirstRun(): Promise<boolean> {\n\t\tlogger.debug('isFirstRun: Checking for marker file', { markerFilePath: this.markerFilePath })\n\t\ttry {\n\t\t\tconst exists = await fs.pathExists(this.markerFilePath)\n\t\t\tlogger.debug(`isFirstRun: Marker file exists=${exists}`)\n\t\t\treturn !exists\n\t\t} catch (error) {\n\t\t\t// On error, gracefully degrade by treating as first-run\n\t\t\tlogger.debug(`isFirstRun: Error checking marker file, treating as first-run: ${error}`)\n\t\t\treturn true\n\t\t}\n\t}\n\n\t/**\n\t * Mark the feature as having been run\n\t * Creates the marker file in config directory\n\t * Handles errors gracefully without throwing\n\t */\n\tasync markAsRun(): Promise<void> {\n\t\tlogger.debug('markAsRun: Attempting to create marker file', { markerFilePath: this.markerFilePath })\n\t\ttry {\n\t\t\t// Ensure directory exists\n\t\t\tconst configDir = path.dirname(this.markerFilePath)\n\t\t\tlogger.debug(`markAsRun: Ensuring config directory exists: ${configDir}`)\n\t\t\tawait fs.ensureDir(configDir)\n\n\t\t\t// Write marker file with timestamp for debugging\n\t\t\tconst markerContent = {\n\t\t\t\tfirstRun: new Date().toISOString(),\n\t\t\t}\n\t\t\tawait fs.writeFile(this.markerFilePath, JSON.stringify(markerContent, null, 2), 'utf8')\n\t\t\tlogger.debug('markAsRun: Marker file created successfully')\n\t\t} catch (error) {\n\t\t\t// Don't throw on errors - just log debug message\n\t\t\t// Failing to write marker shouldn't break the workflow\n\t\t\tlogger.debug(`markAsRun: Failed to create marker file: ${error}`)\n\t\t}\n\t}\n}\n"],"mappings":"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","names":["path","path"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/init.ts"],"sourcesContent":["import { logger } from '../utils/logger.js'\nimport { ShellCompletion } from '../lib/ShellCompletion.js'\nimport chalk from 'chalk'\nimport { mkdir, writeFile, readFile } from 'fs/promises'\nimport { existsSync } from 'fs'\nimport path from 'path'\nimport { detectClaudeCli, launchClaude } from '../utils/claude.js'\nimport { PromptTemplateManager } from '../lib/PromptTemplateManager.js'\nimport { fileURLToPath } from 'url'\n\n/**\n * Initialize iloom configuration and setup shell autocomplete\n * Implements the `il init` command requested in issue #94\n */\nexport class InitCommand {\n private readonly shellCompletion: ShellCompletion\n private readonly templateManager: PromptTemplateManager\n\n constructor(shellCompletion?: ShellCompletion, templateManager?: PromptTemplateManager) {\n this.shellCompletion = shellCompletion ?? new ShellCompletion()\n this.templateManager = templateManager ?? new PromptTemplateManager()\n }\n\n /**\n * Main entry point for the init command\n * Prompts user for autocomplete setup and displays instructions\n * @param customInitialMessage Optional custom initial message to send to Claude (defaults to \"Help me configure iloom settings.\")\n */\n public async execute(customInitialMessage?: string): Promise<void> {\n try {\n logger.debug('InitCommand.execute() starting', {\n cwd: process.cwd(),\n nodeVersion: process.version,\n hasCustomInitialMessage: !!customInitialMessage\n })\n\n logger.info(chalk.bold('Welcome to iloom setup'))\n\n // Setup project configuration\n logger.info(chalk.bold('Verifying current setup...'))\n\n await this.setupProjectConfiguration()\n\n // Launch guided Claude configuration if available\n await this.launchGuidedInit(customInitialMessage)\n\n logger.info(chalk.green('Setup complete! Enjoy using iloom CLI.'))\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error'\n logger.error(`Initialization failed: ${message}`)\n throw error\n }\n }\n\n /**\n * Setup project configuration files\n * Creates settings.local.json and updates .gitignore\n */\n private async setupProjectConfiguration(): Promise<void> {\n logger.debug('setupProjectConfiguration() starting')\n\n // Migrate legacy .hatchbox settings to .iloom (BEFORE creating new files)\n try {\n logger.debug('Loading SettingsMigrationManager for legacy migration')\n const { SettingsMigrationManager } = await import('../lib/SettingsMigrationManager.js')\n const migrationManager = new SettingsMigrationManager()\n logger.debug('Running settings migration check')\n await migrationManager.migrateSettingsIfNeeded()\n logger.debug('Settings migration check completed')\n } catch (error) {\n // Log warning but don't fail\n logger.warn(`Settings migration failed: ${error instanceof Error ? error.message : 'Unknown'}`)\n logger.debug('Settings migration error details', { error })\n }\n\n // Ensure .iloom directory exists\n const iloomDir = path.join(process.cwd(), '.iloom')\n logger.debug('Creating .iloom directory', { iloomDir })\n await mkdir(iloomDir, { recursive: true })\n logger.debug('.iloom directory created/verified')\n\n // Create settings.local.json if it doesn't exist\n const settingsLocalPath = path.join(iloomDir, 'settings.local.json')\n logger.debug('Checking for existing settings.local.json', { settingsLocalPath })\n\n if (!existsSync(settingsLocalPath)) {\n logger.debug('Creating settings.local.json file')\n await writeFile(settingsLocalPath, '{}\\n', 'utf-8')\n logger.info('Created .iloom/settings.local.json')\n logger.debug('settings.local.json file created successfully')\n } else {\n logger.debug('settings.local.json file already exists, skipping')\n }\n\n // Update .gitignore\n logger.debug('Starting .gitignore update')\n await this.updateGitignore()\n logger.debug('setupProjectConfiguration() completed')\n }\n\n /**\n * Add settings.local.json to .gitignore if not already present\n */\n private async updateGitignore(): Promise<void> {\n const gitignorePath = path.join(process.cwd(), '.gitignore')\n const entryToAdd = '.iloom/settings.local.json'\n\n logger.debug('updateGitignore() starting', {\n gitignorePath,\n entryToAdd\n })\n\n // Read existing .gitignore or create empty\n let content = ''\n if (existsSync(gitignorePath)) {\n logger.debug('.gitignore file exists, reading content')\n content = await readFile(gitignorePath, 'utf-8')\n logger.debug('Read .gitignore content', {\n contentLength: content.length,\n lineCount: content.split('\\n').length\n })\n } else {\n logger.debug('.gitignore file does not exist, will create new one')\n }\n\n // Check if entry already exists\n const lines = content.split('\\n')\n const entryExists = lines.some(line => line.trim() === entryToAdd)\n logger.debug('Checking if entry already exists', {\n entryExists,\n totalLines: lines.length\n })\n\n if (entryExists) {\n logger.debug('Entry already exists, skipping .gitignore update')\n return\n }\n\n // Add entry with comment\n const commentLine = '\\n# Added by iloom CLI'\n const separator = content.endsWith('\\n') || content === '' ? '' : '\\n'\n const newContent = content + separator + commentLine + '\\n' + entryToAdd + '\\n'\n\n logger.debug('Writing updated .gitignore', {\n originalLength: content.length,\n newLength: newContent.length,\n addedLines: 3 // comment + entry + newline\n })\n\n await writeFile(gitignorePath, newContent, 'utf-8')\n logger.info('Added .iloom/settings.local.json to .gitignore')\n logger.debug('.gitignore update completed successfully')\n }\n\n /**\n * Launch interactive Claude-guided configuration\n * @param customInitialMessage Optional custom initial message to send to Claude\n */\n private async launchGuidedInit(customInitialMessage?: string): Promise<void> {\n logger.debug('launchGuidedInit() starting', { hasCustomInitialMessage: !!customInitialMessage })\n logger.info(chalk.bold('Starting interactive Claude-guided configuration...'))\n\n // Check if Claude CLI is available\n logger.debug('Checking Claude CLI availability')\n const claudeAvailable = await detectClaudeCli()\n logger.debug('Claude CLI availability check result', { claudeAvailable })\n\n if (!claudeAvailable) {\n logger.warn('Claude Code not detected. Skipping guided configuration.')\n logger.info('iloom won\\'t be able to help you much without Claude Code, so please install it: npm install -g @anthropic-ai/claude-code')\n logger.debug('Exiting launchGuidedInit() due to missing Claude CLI')\n return\n }\n\n try {\n // Load schema from dist/schema/settings.schema.json\n // Use similar approach to PromptTemplateManager for path resolution\n const __filename = fileURLToPath(import.meta.url)\n const __dirname = path.dirname(__filename)\n\n // Walk up to find the schema directory (in case of chunked files)\n let schemaPath = path.join(__dirname, 'schema', 'settings.schema.json')\n\n logger.debug('Loading settings schema', {\n __filename,\n __dirname,\n schemaPath,\n schemaExists: existsSync(schemaPath)\n })\n\n let schemaContent = ''\n if (existsSync(schemaPath)) {\n logger.debug('Reading schema file')\n schemaContent = await readFile(schemaPath, 'utf-8')\n logger.debug('Schema file loaded', {\n contentLength: schemaContent.length,\n isValidJson: ((): boolean => {\n try {\n JSON.parse(schemaContent)\n return true\n } catch {\n return false\n }\n })()\n })\n } else {\n logger.warn('Schema file not found - Claude will work without schema validation')\n logger.debug('Schema file not found at expected path', { schemaPath })\n }\n\n // Check for existing settings - read BOTH files if they exist\n const settingsLocalPath = path.join(process.cwd(), '.iloom', 'settings.local.json')\n const settingsCommittedPath = path.join(process.cwd(), '.iloom', 'settings.json')\n\n let settingsJson = ''\n let settingsLocalJson = ''\n\n logger.debug('Checking for settings files', {\n settingsLocalPath,\n settingsCommittedPath,\n localExists: existsSync(settingsLocalPath),\n committedExists: existsSync(settingsCommittedPath)\n })\n\n // Read settings.json if it exists\n if (existsSync(settingsCommittedPath)) {\n logger.debug('Reading settings.json')\n const content = await readFile(settingsCommittedPath, 'utf-8')\n const trimmed = content.trim()\n if (trimmed !== '{}' && trimmed !== '') {\n settingsJson = content\n logger.debug('settings.json loaded', {\n contentLength: content.length,\n isValidJson: ((): boolean => {\n try {\n JSON.parse(content)\n return true\n } catch {\n return false\n }\n })()\n })\n } else {\n logger.debug('settings.json is empty, skipping')\n }\n } else {\n logger.debug('settings.json does not exist')\n }\n\n // Read settings.local.json if it exists\n if (existsSync(settingsLocalPath)) {\n logger.debug('Reading settings.local.json')\n const content = await readFile(settingsLocalPath, 'utf-8')\n const trimmed = content.trim()\n if (trimmed !== '{}' && trimmed !== '') {\n settingsLocalJson = content\n logger.debug('settings.local.json loaded', {\n contentLength: content.length,\n isValidJson: ((): boolean => {\n try {\n JSON.parse(content)\n return true\n } catch {\n return false\n }\n })()\n })\n } else {\n logger.debug('settings.local.json is empty, skipping')\n }\n } else {\n logger.debug('settings.local.json does not exist')\n }\n\n // Log summary\n logger.debug('Settings files summary', {\n hasSettingsJson: !!settingsJson,\n hasSettingsLocalJson: !!settingsLocalJson,\n settingsJsonLength: settingsJson.length,\n settingsLocalJsonLength: settingsLocalJson.length\n })\n\n // Detect shell and read config\n logger.debug('Detecting user shell for autocomplete setup')\n const shell = this.shellCompletion.detectShell()\n logger.debug('Shell detection result', { shell })\n\n let shellConfigPath = ''\n let shellConfigContent = ''\n\n if (shell !== 'unknown') {\n logger.debug('Reading shell config file')\n const shellConfig = await this.shellCompletion.readShellConfig(shell)\n if (shellConfig) {\n shellConfigPath = shellConfig.path\n shellConfigContent = shellConfig.content\n logger.debug('Shell config loaded', {\n path: shellConfigPath,\n contentLength: shellConfigContent.length,\n configExists: existsSync(shellConfigPath)\n })\n } else {\n logger.debug('Could not read shell config')\n }\n } else {\n logger.debug('Unknown shell detected, skipping config read')\n }\n\n // Detect git remotes for GitHub configuration\n logger.debug('Detecting git remotes for GitHub configuration')\n const { parseGitRemotes } = await import('../utils/remote.js')\n const remotes = await parseGitRemotes()\n logger.debug('Git remotes detected', { count: remotes.length, remotes })\n\n let remotesInfo = ''\n let multipleRemotes = ''\n let singleRemote = ''\n let singleRemoteName = ''\n let singleRemoteUrl = ''\n let noRemotes = ''\n\n if (remotes.length === 0) {\n noRemotes = 'true'\n remotesInfo = 'No git remotes detected in this repository.'\n } else if (remotes.length === 1 && remotes[0]) {\n singleRemote = 'true'\n singleRemoteName = remotes[0].name\n singleRemoteUrl = remotes[0].url\n remotesInfo = `Detected Remote:\\n- **${remotes[0].name}**: ${remotes[0].url} (${remotes[0].owner}/${remotes[0].repo})`\n } else {\n multipleRemotes = 'true'\n remotesInfo = `Detected Remotes (${remotes.length}):\\n` +\n remotes.map(r => `- **${r.name}**: ${r.url} (${r.owner}/${r.repo})`).join('\\n')\n }\n\n // Build template variables\n const variables = {\n SETTINGS_SCHEMA: schemaContent,\n SETTINGS_JSON: settingsJson,\n SETTINGS_LOCAL_JSON: settingsLocalJson,\n SHELL_TYPE: shell,\n SHELL_CONFIG_PATH: shellConfigPath,\n SHELL_CONFIG_CONTENT: shellConfigContent,\n REMOTES_INFO: remotesInfo,\n MULTIPLE_REMOTES: multipleRemotes,\n SINGLE_REMOTE: singleRemote,\n SINGLE_REMOTE_NAME: singleRemoteName,\n SINGLE_REMOTE_URL: singleRemoteUrl,\n NO_REMOTES: noRemotes\n }\n\n logger.debug('Building template variables', {\n variableKeys: Object.keys(variables),\n schemaContentLength: schemaContent.length,\n settingsJsonLength: settingsJson.length,\n settingsLocalJsonLength: settingsLocalJson.length\n })\n\n // Get init prompt\n logger.debug('Loading init prompt template')\n const prompt = await this.templateManager.getPrompt('init', variables)\n\n logger.debug('Init prompt loaded', {\n promptLength: prompt.length,\n containsSchema: prompt.includes('SETTINGS_SCHEMA'),\n containsExistingSettings: prompt.includes('EXISTING_SETTINGS')\n })\n\n const claudeOptions = {\n headless: false,\n appendSystemPrompt: prompt,\n addDir: process.cwd(),\n }\n\n logger.debug('Launching Claude with options', {\n optionKeys: Object.keys(claudeOptions),\n headless: claudeOptions.headless,\n hasSystemPrompt: !!claudeOptions.appendSystemPrompt,\n addDir: claudeOptions.addDir,\n promptLength: prompt.length,\n hasCustomInitialMessage: !!customInitialMessage\n })\n\n // Launch Claude in interactive mode with custom initial message if provided\n const initialMessage = customInitialMessage ?? 'Help me configure iloom settings.'\n await launchClaude(initialMessage, claudeOptions)\n logger.debug('Claude session completed')\n\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error'\n logger.warn(`Guided configuration failed: ${message}`)\n logger.debug('launchGuidedInit() error details', { error })\n logger.info('You can manually edit .iloom/settings.json to configure iloom.')\n }\n\n logger.debug('launchGuidedInit() completed')\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,62 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/utils/logger.ts
4
- import chalk, { Chalk } from "chalk";
5
- var stdoutChalk = new Chalk({ level: chalk.level });
6
- var stderrChalk = new Chalk({ level: chalk.level });
7
- function formatMessage(message, ...args) {
8
- const formattedArgs = args.map(
9
- (arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)
10
- );
11
- return formattedArgs.length > 0 ? `${message} ${formattedArgs.join(" ")}` : message;
12
- }
13
- function formatWithEmoji(message, emoji, colorFn) {
14
- if (message.trim()) {
15
- return colorFn(`${emoji} ${message}`);
16
- } else {
17
- return "";
18
- }
19
- }
20
- var globalDebugEnabled = false;
21
- var logger = {
22
- info: (message, ...args) => {
23
- const formatted = formatMessage(message, ...args);
24
- const output = formatWithEmoji(formatted, "\u{1F5C2}\uFE0F ", stdoutChalk.blue);
25
- console.log(output);
26
- },
27
- success: (message, ...args) => {
28
- const formatted = formatMessage(message, ...args);
29
- const output = formatWithEmoji(formatted, "\u2705", stdoutChalk.green);
30
- console.log(output);
31
- },
32
- warn: (message, ...args) => {
33
- const formatted = formatMessage(message, ...args);
34
- const output = formatWithEmoji(formatted, "\u26A0\uFE0F ", stderrChalk.yellow);
35
- console.error(output);
36
- },
37
- error: (message, ...args) => {
38
- const formatted = formatMessage(message, ...args);
39
- const output = formatWithEmoji(formatted, "\u274C", stderrChalk.red);
40
- console.error(output);
41
- },
42
- debug: (message, ...args) => {
43
- if (globalDebugEnabled) {
44
- const formatted = formatMessage(message, ...args);
45
- const output = formatWithEmoji(formatted, "\u{1F50D}", stdoutChalk.gray);
46
- console.log(output);
47
- }
48
- },
49
- setDebug: (enabled) => {
50
- globalDebugEnabled = enabled;
51
- },
52
- isDebugEnabled: () => {
53
- return globalDebugEnabled;
54
- }
55
- };
56
- var logger_default = logger;
57
-
58
- export {
59
- logger,
60
- logger_default
61
- };
62
- //# sourceMappingURL=chunk-6SDFJ42P.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/utils/logger.ts"],"sourcesContent":["// Lines 1-5: Imports\nimport chalk, { Chalk } from 'chalk'\n\n// Lines 7-17: Type definitions\nexport interface LoggerOptions {\n prefix?: string\n timestamp?: boolean\n silent?: boolean\n forceColor?: boolean | undefined | null\n debug?: boolean\n}\n\nexport interface Logger {\n info: (message: string, ...args: unknown[]) => void\n success: (message: string, ...args: unknown[]) => void\n warn: (message: string, ...args: unknown[]) => void\n error: (message: string, ...args: unknown[]) => void\n debug: (message: string, ...args: unknown[]) => void\n setDebug: (enabled: boolean) => void\n isDebugEnabled: () => boolean\n}\n\n// Lines 19-29: Stream-specific chalk instances\nconst stdoutChalk = new Chalk({ level: chalk.level })\nconst stderrChalk = new Chalk({ level: chalk.level })\n\n// Lines 31-45: Helper functions\nfunction formatMessage(message: string, ...args: unknown[]): string {\n // Convert args to strings and append to message\n const formattedArgs = args.map(arg =>\n typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)\n )\n return formattedArgs.length > 0 ? `${message} ${formattedArgs.join(' ')}` : message\n}\n\nfunction formatWithEmoji(message: string, emoji: string, colorFn: (str: string) => string): string {\n if (message.trim()) {\n return colorFn(`${emoji} ${message}`)\n } else {\n return ''\n }\n}\n\nlet globalDebugEnabled = false\n\n// Lines 47-96: Main logger implementation\n/* eslint-disable no-console */\nexport const logger: Logger = {\n info: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const output = formatWithEmoji(formatted, '🗂️ ', stdoutChalk.blue)\n console.log(output)\n },\n\n success: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const output = formatWithEmoji(formatted, '✅', stdoutChalk.green)\n console.log(output)\n },\n\n warn: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const output = formatWithEmoji(formatted, '⚠️ ', stderrChalk.yellow)\n console.error(output)\n },\n\n error: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const output = formatWithEmoji(formatted, '❌', stderrChalk.red)\n console.error(output)\n },\n\n debug: (message: string, ...args: unknown[]): void => {\n if (globalDebugEnabled) {\n const formatted = formatMessage(message, ...args)\n const output = formatWithEmoji(formatted, '🔍', stdoutChalk.gray)\n console.log(output)\n }\n },\n\n setDebug: (enabled: boolean): void => {\n globalDebugEnabled = enabled\n },\n\n isDebugEnabled: (): boolean => {\n return globalDebugEnabled\n }\n}\n/* eslint-enable no-console */\n\n// Lines 98-145: Factory function for custom logger instances\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const { prefix = '', timestamp = false, silent = false, forceColor, debug = globalDebugEnabled } = options\n\n // Local debug flag for this logger instance\n let localDebugEnabled = debug\n\n // Create chalk instances with forced color if needed\n const customStdoutChalk = forceColor !== undefined\n ? new Chalk({ level: forceColor ? 3 : 0 })\n : stdoutChalk\n const customStderrChalk = forceColor !== undefined\n ? new Chalk({ level: forceColor ? 3 : 0 })\n : stderrChalk\n\n const prefixStr = prefix ? `[${prefix}] ` : ''\n const getTimestamp = (): string => timestamp ? `[${new Date().toISOString()}] ` : ''\n\n if (silent) {\n // Return no-op logger when silent\n return {\n info: (): void => {},\n success: (): void => {},\n warn: (): void => {},\n error: (): void => {},\n debug: (): void => {},\n setDebug: (): void => {},\n isDebugEnabled: (): boolean => {\n return false\n }\n }\n }\n\n /* eslint-disable no-console */\n return {\n info: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '🗂️ ', customStdoutChalk.blue)\n console.log(output)\n },\n success: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '✅', customStdoutChalk.green)\n console.log(output)\n },\n warn: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '⚠️ ', customStderrChalk.yellow)\n console.error(output)\n },\n error: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '❌', customStderrChalk.red)\n console.error(output)\n },\n debug: (message: string, ...args: unknown[]): void => {\n if (localDebugEnabled) {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '🔍', customStdoutChalk.gray)\n console.log(output)\n }\n },\n setDebug: (enabled: boolean): void => {\n localDebugEnabled = enabled\n },\n isDebugEnabled: (): boolean => {\n return globalDebugEnabled\n }\n }\n /* eslint-enable no-console */\n}\n\n// Lines 147-148: Default export\nexport default logger\n"],"mappings":";;;AACA,OAAO,SAAS,aAAa;AAsB7B,IAAM,cAAc,IAAI,MAAM,EAAE,OAAO,MAAM,MAAM,CAAC;AACpD,IAAM,cAAc,IAAI,MAAM,EAAE,OAAO,MAAM,MAAM,CAAC;AAGpD,SAAS,cAAc,YAAoB,MAAyB;AAElE,QAAM,gBAAgB,KAAK;AAAA,IAAI,SAC7B,OAAO,QAAQ,WAAW,KAAK,UAAU,KAAK,MAAM,CAAC,IAAI,OAAO,GAAG;AAAA,EACrE;AACA,SAAO,cAAc,SAAS,IAAI,GAAG,OAAO,IAAI,cAAc,KAAK,GAAG,CAAC,KAAK;AAC9E;AAEA,SAAS,gBAAgB,SAAiB,OAAe,SAA0C;AACjG,MAAI,QAAQ,KAAK,GAAG;AAClB,WAAO,QAAQ,GAAG,KAAK,IAAI,OAAO,EAAE;AAAA,EACtC,OAAO;AACL,WAAO;AAAA,EACT;AACF;AAEA,IAAI,qBAAqB;AAIlB,IAAM,SAAiB;AAAA,EAC5B,MAAM,CAAC,YAAoB,SAA0B;AACnD,UAAM,YAAY,cAAc,SAAS,GAAG,IAAI;AAChD,UAAM,SAAS,gBAAgB,WAAW,oBAAQ,YAAY,IAAI;AAClE,YAAQ,IAAI,MAAM;AAAA,EACpB;AAAA,EAEA,SAAS,CAAC,YAAoB,SAA0B;AACtD,UAAM,YAAY,cAAc,SAAS,GAAG,IAAI;AAChD,UAAM,SAAS,gBAAgB,WAAW,UAAK,YAAY,KAAK;AAChE,YAAQ,IAAI,MAAM;AAAA,EACpB;AAAA,EAEA,MAAM,CAAC,YAAoB,SAA0B;AACnD,UAAM,YAAY,cAAc,SAAS,GAAG,IAAI;AAChD,UAAM,SAAS,gBAAgB,WAAW,iBAAO,YAAY,MAAM;AACnE,YAAQ,MAAM,MAAM;AAAA,EACtB;AAAA,EAEA,OAAO,CAAC,YAAoB,SAA0B;AACpD,UAAM,YAAY,cAAc,SAAS,GAAG,IAAI;AAChD,UAAM,SAAS,gBAAgB,WAAW,UAAK,YAAY,GAAG;AAC9D,YAAQ,MAAM,MAAM;AAAA,EACtB;AAAA,EAEA,OAAO,CAAC,YAAoB,SAA0B;AACpD,QAAI,oBAAoB;AACtB,YAAM,YAAY,cAAc,SAAS,GAAG,IAAI;AAChD,YAAM,SAAS,gBAAgB,WAAW,aAAM,YAAY,IAAI;AAChE,cAAQ,IAAI,MAAM;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,UAAU,CAAC,YAA2B;AACpC,yBAAqB;AAAA,EACvB;AAAA,EAEA,gBAAgB,MAAe;AAC7B,WAAO;AAAA,EACT;AACF;AAiFA,IAAO,iBAAQ;","names":[]}