@iloom/cli 0.1.14

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 (161) hide show
  1. package/LICENSE +33 -0
  2. package/README.md +711 -0
  3. package/dist/ClaudeContextManager-XOSXQ67R.js +13 -0
  4. package/dist/ClaudeContextManager-XOSXQ67R.js.map +1 -0
  5. package/dist/ClaudeService-YSZ6EXWP.js +12 -0
  6. package/dist/ClaudeService-YSZ6EXWP.js.map +1 -0
  7. package/dist/GitHubService-F7Z3XJOS.js +11 -0
  8. package/dist/GitHubService-F7Z3XJOS.js.map +1 -0
  9. package/dist/LoomLauncher-MODG2SEM.js +263 -0
  10. package/dist/LoomLauncher-MODG2SEM.js.map +1 -0
  11. package/dist/NeonProvider-PAGPUH7F.js +12 -0
  12. package/dist/NeonProvider-PAGPUH7F.js.map +1 -0
  13. package/dist/PromptTemplateManager-7FINLRDE.js +9 -0
  14. package/dist/PromptTemplateManager-7FINLRDE.js.map +1 -0
  15. package/dist/SettingsManager-VAZF26S2.js +19 -0
  16. package/dist/SettingsManager-VAZF26S2.js.map +1 -0
  17. package/dist/SettingsMigrationManager-MTQIMI54.js +146 -0
  18. package/dist/SettingsMigrationManager-MTQIMI54.js.map +1 -0
  19. package/dist/add-issue-22JBNOML.js +54 -0
  20. package/dist/add-issue-22JBNOML.js.map +1 -0
  21. package/dist/agents/iloom-issue-analyze-and-plan.md +580 -0
  22. package/dist/agents/iloom-issue-analyzer.md +290 -0
  23. package/dist/agents/iloom-issue-complexity-evaluator.md +224 -0
  24. package/dist/agents/iloom-issue-enhancer.md +266 -0
  25. package/dist/agents/iloom-issue-implementer.md +262 -0
  26. package/dist/agents/iloom-issue-planner.md +358 -0
  27. package/dist/agents/iloom-issue-reviewer.md +63 -0
  28. package/dist/chunk-2ZPFJQ3B.js +63 -0
  29. package/dist/chunk-2ZPFJQ3B.js.map +1 -0
  30. package/dist/chunk-37DYYFVK.js +29 -0
  31. package/dist/chunk-37DYYFVK.js.map +1 -0
  32. package/dist/chunk-BLCTGFZN.js +121 -0
  33. package/dist/chunk-BLCTGFZN.js.map +1 -0
  34. package/dist/chunk-CP2NU2JC.js +545 -0
  35. package/dist/chunk-CP2NU2JC.js.map +1 -0
  36. package/dist/chunk-CWR2SANQ.js +39 -0
  37. package/dist/chunk-CWR2SANQ.js.map +1 -0
  38. package/dist/chunk-F3XBU2R7.js +110 -0
  39. package/dist/chunk-F3XBU2R7.js.map +1 -0
  40. package/dist/chunk-GEHQXLEI.js +130 -0
  41. package/dist/chunk-GEHQXLEI.js.map +1 -0
  42. package/dist/chunk-GYCR2LOU.js +143 -0
  43. package/dist/chunk-GYCR2LOU.js.map +1 -0
  44. package/dist/chunk-GZP4UGGM.js +48 -0
  45. package/dist/chunk-GZP4UGGM.js.map +1 -0
  46. package/dist/chunk-H4E4THUZ.js +55 -0
  47. package/dist/chunk-H4E4THUZ.js.map +1 -0
  48. package/dist/chunk-HPJJSYNS.js +644 -0
  49. package/dist/chunk-HPJJSYNS.js.map +1 -0
  50. package/dist/chunk-JBH2ZYYZ.js +220 -0
  51. package/dist/chunk-JBH2ZYYZ.js.map +1 -0
  52. package/dist/chunk-JNKJ7NJV.js +78 -0
  53. package/dist/chunk-JNKJ7NJV.js.map +1 -0
  54. package/dist/chunk-JQ7VOSTC.js +437 -0
  55. package/dist/chunk-JQ7VOSTC.js.map +1 -0
  56. package/dist/chunk-KQDEK2ZW.js +199 -0
  57. package/dist/chunk-KQDEK2ZW.js.map +1 -0
  58. package/dist/chunk-O2QWO64Z.js +179 -0
  59. package/dist/chunk-O2QWO64Z.js.map +1 -0
  60. package/dist/chunk-OC4H6HJD.js +248 -0
  61. package/dist/chunk-OC4H6HJD.js.map +1 -0
  62. package/dist/chunk-PR7FKQBG.js +120 -0
  63. package/dist/chunk-PR7FKQBG.js.map +1 -0
  64. package/dist/chunk-PXZBAC2M.js +250 -0
  65. package/dist/chunk-PXZBAC2M.js.map +1 -0
  66. package/dist/chunk-QEPVTTHD.js +383 -0
  67. package/dist/chunk-QEPVTTHD.js.map +1 -0
  68. package/dist/chunk-RSRO7564.js +203 -0
  69. package/dist/chunk-RSRO7564.js.map +1 -0
  70. package/dist/chunk-SJUQ2NDR.js +146 -0
  71. package/dist/chunk-SJUQ2NDR.js.map +1 -0
  72. package/dist/chunk-SPYPLHMK.js +177 -0
  73. package/dist/chunk-SPYPLHMK.js.map +1 -0
  74. package/dist/chunk-SSCQCCJ7.js +75 -0
  75. package/dist/chunk-SSCQCCJ7.js.map +1 -0
  76. package/dist/chunk-SSR5AVRJ.js +41 -0
  77. package/dist/chunk-SSR5AVRJ.js.map +1 -0
  78. package/dist/chunk-T7QPXANZ.js +315 -0
  79. package/dist/chunk-T7QPXANZ.js.map +1 -0
  80. package/dist/chunk-U3WU5OWO.js +203 -0
  81. package/dist/chunk-U3WU5OWO.js.map +1 -0
  82. package/dist/chunk-W3DQTW63.js +124 -0
  83. package/dist/chunk-W3DQTW63.js.map +1 -0
  84. package/dist/chunk-WKEWRSDB.js +151 -0
  85. package/dist/chunk-WKEWRSDB.js.map +1 -0
  86. package/dist/chunk-Y7SAGNUT.js +66 -0
  87. package/dist/chunk-Y7SAGNUT.js.map +1 -0
  88. package/dist/chunk-YETJNRQM.js +39 -0
  89. package/dist/chunk-YETJNRQM.js.map +1 -0
  90. package/dist/chunk-YYSKGAZT.js +384 -0
  91. package/dist/chunk-YYSKGAZT.js.map +1 -0
  92. package/dist/chunk-ZZZWQGTS.js +169 -0
  93. package/dist/chunk-ZZZWQGTS.js.map +1 -0
  94. package/dist/claude-7LUVDZZ4.js +17 -0
  95. package/dist/claude-7LUVDZZ4.js.map +1 -0
  96. package/dist/cleanup-3LUWPSM7.js +412 -0
  97. package/dist/cleanup-3LUWPSM7.js.map +1 -0
  98. package/dist/cli-overrides-XFZWY7CM.js +16 -0
  99. package/dist/cli-overrides-XFZWY7CM.js.map +1 -0
  100. package/dist/cli.js +603 -0
  101. package/dist/cli.js.map +1 -0
  102. package/dist/color-ZVALX37U.js +21 -0
  103. package/dist/color-ZVALX37U.js.map +1 -0
  104. package/dist/enhance-XJIQHVPD.js +166 -0
  105. package/dist/enhance-XJIQHVPD.js.map +1 -0
  106. package/dist/env-MDFL4ZXL.js +23 -0
  107. package/dist/env-MDFL4ZXL.js.map +1 -0
  108. package/dist/feedback-23CLXKFT.js +158 -0
  109. package/dist/feedback-23CLXKFT.js.map +1 -0
  110. package/dist/finish-CY4CIH6O.js +1608 -0
  111. package/dist/finish-CY4CIH6O.js.map +1 -0
  112. package/dist/git-LVRZ57GJ.js +43 -0
  113. package/dist/git-LVRZ57GJ.js.map +1 -0
  114. package/dist/ignite-WXEF2ID5.js +359 -0
  115. package/dist/ignite-WXEF2ID5.js.map +1 -0
  116. package/dist/index.d.ts +1341 -0
  117. package/dist/index.js +3058 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/init-RHACUR4E.js +123 -0
  120. package/dist/init-RHACUR4E.js.map +1 -0
  121. package/dist/installation-detector-VARGFFRZ.js +11 -0
  122. package/dist/installation-detector-VARGFFRZ.js.map +1 -0
  123. package/dist/logger-MKYH4UDV.js +12 -0
  124. package/dist/logger-MKYH4UDV.js.map +1 -0
  125. package/dist/mcp/chunk-6SDFJ42P.js +62 -0
  126. package/dist/mcp/chunk-6SDFJ42P.js.map +1 -0
  127. package/dist/mcp/claude-YHHHLSXH.js +249 -0
  128. package/dist/mcp/claude-YHHHLSXH.js.map +1 -0
  129. package/dist/mcp/color-QS5BFCNN.js +168 -0
  130. package/dist/mcp/color-QS5BFCNN.js.map +1 -0
  131. package/dist/mcp/github-comment-server.js +165 -0
  132. package/dist/mcp/github-comment-server.js.map +1 -0
  133. package/dist/mcp/terminal-SDCMDVD7.js +202 -0
  134. package/dist/mcp/terminal-SDCMDVD7.js.map +1 -0
  135. package/dist/open-X6BTENPV.js +278 -0
  136. package/dist/open-X6BTENPV.js.map +1 -0
  137. package/dist/prompt-ANTQWHUF.js +13 -0
  138. package/dist/prompt-ANTQWHUF.js.map +1 -0
  139. package/dist/prompts/issue-prompt.txt +230 -0
  140. package/dist/prompts/pr-prompt.txt +35 -0
  141. package/dist/prompts/regular-prompt.txt +14 -0
  142. package/dist/run-2JCPQAX3.js +278 -0
  143. package/dist/run-2JCPQAX3.js.map +1 -0
  144. package/dist/schema/settings.schema.json +221 -0
  145. package/dist/start-LWVRBJ6S.js +982 -0
  146. package/dist/start-LWVRBJ6S.js.map +1 -0
  147. package/dist/terminal-3D6TUAKJ.js +16 -0
  148. package/dist/terminal-3D6TUAKJ.js.map +1 -0
  149. package/dist/test-git-XPF4SZXJ.js +52 -0
  150. package/dist/test-git-XPF4SZXJ.js.map +1 -0
  151. package/dist/test-prefix-XGFXFAYN.js +68 -0
  152. package/dist/test-prefix-XGFXFAYN.js.map +1 -0
  153. package/dist/test-tabs-JRKY3QMM.js +69 -0
  154. package/dist/test-tabs-JRKY3QMM.js.map +1 -0
  155. package/dist/test-webserver-M2I3EV4J.js +62 -0
  156. package/dist/test-webserver-M2I3EV4J.js.map +1 -0
  157. package/dist/update-3ZT2XX2G.js +79 -0
  158. package/dist/update-3ZT2XX2G.js.map +1 -0
  159. package/dist/update-notifier-QSSEB5KC.js +11 -0
  160. package/dist/update-notifier-QSSEB5KC.js.map +1 -0
  161. package/package.json +113 -0
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ShellCompletion
4
+ } from "./chunk-O2QWO64Z.js";
5
+ import "./chunk-QEPVTTHD.js";
6
+ import "./chunk-JQ7VOSTC.js";
7
+ import {
8
+ promptConfirmation
9
+ } from "./chunk-JNKJ7NJV.js";
10
+ import {
11
+ logger
12
+ } from "./chunk-GEHQXLEI.js";
13
+
14
+ // src/commands/init.ts
15
+ import chalk from "chalk";
16
+ import { mkdir, writeFile, readFile } from "fs/promises";
17
+ import { existsSync } from "fs";
18
+ import path from "path";
19
+ var InitCommand = class {
20
+ constructor(shellCompletion) {
21
+ this.shellCompletion = shellCompletion ?? new ShellCompletion();
22
+ }
23
+ /**
24
+ * Main entry point for the init command
25
+ * Prompts user for autocomplete setup and displays instructions
26
+ */
27
+ async execute() {
28
+ try {
29
+ logger.info(chalk.bold("Welcome to iloom CLI Setup"));
30
+ logger.info("");
31
+ const shell = this.shellCompletion.detectShell();
32
+ if (shell === "unknown") {
33
+ logger.warn("Could not detect your shell type.");
34
+ logger.warn("Shell autocomplete is supported for bash, zsh, and fish.");
35
+ logger.warn("Please configure autocomplete manually if needed.");
36
+ logger.info("");
37
+ logger.info("Continuing with project configuration setup...");
38
+ logger.info("");
39
+ logger.info(chalk.bold("Project Configuration Setup"));
40
+ logger.info("");
41
+ await this.setupProjectConfiguration();
42
+ logger.info("");
43
+ logger.info(chalk.green("Setup complete! Enjoy using iloom CLI."));
44
+ return;
45
+ }
46
+ logger.info(`Detected shell: ${chalk.cyan(shell)}`);
47
+ logger.info("");
48
+ const enableAutocomplete = await promptConfirmation(
49
+ "Would you like to enable shell autocomplete?",
50
+ true
51
+ // Default to yes
52
+ );
53
+ if (enableAutocomplete) {
54
+ logger.info("");
55
+ logger.info(chalk.bold("Shell Autocomplete Setup Instructions"));
56
+ logger.info("");
57
+ const instructions = this.shellCompletion.getSetupInstructions(shell);
58
+ logger.info(instructions);
59
+ } else {
60
+ logger.info("Skipping autocomplete setup.");
61
+ logger.info("You can run this command again later to set up autocomplete.");
62
+ }
63
+ logger.info("");
64
+ logger.info(chalk.bold("Project Configuration Setup"));
65
+ logger.info("");
66
+ await this.setupProjectConfiguration();
67
+ logger.info("");
68
+ logger.info(chalk.green("Setup complete! Enjoy using iloom CLI."));
69
+ } catch (error) {
70
+ const message = error instanceof Error ? error.message : "Unknown error";
71
+ logger.error(`Initialization failed: ${message}`);
72
+ throw error;
73
+ }
74
+ }
75
+ /**
76
+ * Setup project configuration files
77
+ * Creates settings.local.json and updates .gitignore
78
+ */
79
+ async setupProjectConfiguration() {
80
+ try {
81
+ const { SettingsMigrationManager } = await import("./SettingsMigrationManager-MTQIMI54.js");
82
+ const migrationManager = new SettingsMigrationManager();
83
+ await migrationManager.migrateSettingsIfNeeded();
84
+ } catch (error) {
85
+ logger.warn(`Settings migration failed: ${error instanceof Error ? error.message : "Unknown"}`);
86
+ }
87
+ const iloomDir = path.join(process.cwd(), ".iloom");
88
+ await mkdir(iloomDir, { recursive: true });
89
+ const settingsLocalPath = path.join(iloomDir, "settings.local.json");
90
+ if (!existsSync(settingsLocalPath)) {
91
+ await writeFile(settingsLocalPath, "{}\n", "utf-8");
92
+ logger.info("Created .iloom/settings.local.json");
93
+ } else {
94
+ logger.info(".iloom/settings.local.json already exists, skipping creation");
95
+ }
96
+ await this.updateGitignore();
97
+ }
98
+ /**
99
+ * Add settings.local.json to .gitignore if not already present
100
+ */
101
+ async updateGitignore() {
102
+ const gitignorePath = path.join(process.cwd(), ".gitignore");
103
+ const entryToAdd = ".iloom/settings.local.json";
104
+ let content = "";
105
+ if (existsSync(gitignorePath)) {
106
+ content = await readFile(gitignorePath, "utf-8");
107
+ }
108
+ const lines = content.split("\n");
109
+ if (lines.some((line) => line.trim() === entryToAdd)) {
110
+ logger.info(".gitignore already contains .iloom/settings.local.json");
111
+ return;
112
+ }
113
+ const commentLine = "\n# Added by iloom CLI";
114
+ const separator = content.endsWith("\n") || content === "" ? "" : "\n";
115
+ const newContent = content + separator + commentLine + "\n" + entryToAdd + "\n";
116
+ await writeFile(gitignorePath, newContent, "utf-8");
117
+ logger.info("Added .iloom/settings.local.json to .gitignore");
118
+ }
119
+ };
120
+ export {
121
+ InitCommand
122
+ };
123
+ //# sourceMappingURL=init-RHACUR4E.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/init.ts"],"sourcesContent":["import { logger } from '../utils/logger.js'\nimport { ShellCompletion } from '../lib/ShellCompletion.js'\nimport { promptConfirmation } from '../utils/prompt.js'\nimport chalk from 'chalk'\nimport { mkdir, writeFile, readFile } from 'fs/promises'\nimport { existsSync } from 'fs'\nimport path from 'path'\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\n constructor(shellCompletion?: ShellCompletion) {\n this.shellCompletion = shellCompletion ?? new ShellCompletion()\n }\n\n /**\n * Main entry point for the init command\n * Prompts user for autocomplete setup and displays instructions\n */\n public async execute(): Promise<void> {\n try {\n logger.info(chalk.bold('Welcome to iloom CLI Setup'))\n logger.info('')\n\n // Detect user's shell\n const shell = this.shellCompletion.detectShell()\n\n if (shell === 'unknown') {\n logger.warn('Could not detect your shell type.')\n logger.warn('Shell autocomplete is supported for bash, zsh, and fish.')\n logger.warn('Please configure autocomplete manually if needed.')\n logger.info('')\n logger.info('Continuing with project configuration setup...')\n logger.info('')\n\n // Skip autocomplete, but still run project configuration\n logger.info(chalk.bold('Project Configuration Setup'))\n logger.info('')\n\n await this.setupProjectConfiguration()\n\n logger.info('')\n logger.info(chalk.green('Setup complete! Enjoy using iloom CLI.'))\n return\n }\n\n logger.info(`Detected shell: ${chalk.cyan(shell)}`)\n logger.info('')\n\n // Ask user if they want to enable autocomplete\n const enableAutocomplete = await promptConfirmation(\n 'Would you like to enable shell autocomplete?',\n true // Default to yes\n )\n\n if (enableAutocomplete) {\n // Display setup instructions\n logger.info('')\n logger.info(chalk.bold('Shell Autocomplete Setup Instructions'))\n logger.info('')\n\n const instructions = this.shellCompletion.getSetupInstructions(shell)\n logger.info(instructions)\n } else {\n logger.info('Skipping autocomplete setup.')\n logger.info('You can run this command again later to set up autocomplete.')\n }\n\n // Setup project configuration (always runs)\n logger.info('')\n logger.info(chalk.bold('Project Configuration Setup'))\n logger.info('')\n\n await this.setupProjectConfiguration()\n\n logger.info('')\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 // Migrate legacy .hatchbox settings to .iloom (BEFORE creating new files)\n try {\n const { SettingsMigrationManager } = await import('../lib/SettingsMigrationManager.js')\n const migrationManager = new SettingsMigrationManager()\n await migrationManager.migrateSettingsIfNeeded()\n } catch (error) {\n // Log warning but don't fail\n logger.warn(`Settings migration failed: ${error instanceof Error ? error.message : 'Unknown'}`)\n }\n\n // Ensure .iloom directory exists\n const iloomDir = path.join(process.cwd(), '.iloom')\n await mkdir(iloomDir, { recursive: true })\n\n // Create settings.local.json if it doesn't exist\n const settingsLocalPath = path.join(iloomDir, 'settings.local.json')\n if (!existsSync(settingsLocalPath)) {\n await writeFile(settingsLocalPath, '{}\\n', 'utf-8')\n logger.info('Created .iloom/settings.local.json')\n } else {\n logger.info('.iloom/settings.local.json already exists, skipping creation')\n }\n\n // Update .gitignore\n await this.updateGitignore()\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 // Read existing .gitignore or create empty\n let content = ''\n if (existsSync(gitignorePath)) {\n content = await readFile(gitignorePath, 'utf-8')\n }\n\n // Check if entry already exists\n const lines = content.split('\\n')\n if (lines.some(line => line.trim() === entryToAdd)) {\n logger.info('.gitignore already contains .iloom/settings.local.json')\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 await writeFile(gitignorePath, newContent, 'utf-8')\n logger.info('Added .iloom/settings.local.json to .gitignore')\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ detectInstallationMethod,
4
+ shouldShowUpdateNotification
5
+ } from "./chunk-SSCQCCJ7.js";
6
+ import "./chunk-GEHQXLEI.js";
7
+ export {
8
+ detectInstallationMethod,
9
+ shouldShowUpdateNotification
10
+ };
11
+ //# sourceMappingURL=installation-detector-VARGFFRZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ createLogger,
4
+ logger,
5
+ logger_default
6
+ } from "./chunk-GEHQXLEI.js";
7
+ export {
8
+ createLogger,
9
+ logger_default as default,
10
+ logger
11
+ };
12
+ //# sourceMappingURL=logger-MKYH4UDV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,62 @@
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
@@ -0,0 +1 @@
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":[]}
@@ -0,0 +1,249 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ logger
4
+ } from "./chunk-6SDFJ42P.js";
5
+
6
+ // src/utils/claude.ts
7
+ import { execa } from "execa";
8
+ import { existsSync } from "fs";
9
+ import { join } from "path";
10
+ async function detectClaudeCli() {
11
+ try {
12
+ await execa("command", ["-v", "claude"], {
13
+ shell: true,
14
+ timeout: 5e3
15
+ });
16
+ return true;
17
+ } catch (error) {
18
+ logger.debug("Claude CLI not available", { error });
19
+ return false;
20
+ }
21
+ }
22
+ async function getClaudeVersion() {
23
+ try {
24
+ const result = await execa("claude", ["--version"], {
25
+ timeout: 5e3
26
+ });
27
+ return result.stdout.trim();
28
+ } catch (error) {
29
+ logger.warn("Failed to get Claude version", { error });
30
+ return null;
31
+ }
32
+ }
33
+ function parseJsonStreamOutput(output) {
34
+ try {
35
+ const lines = output.split("\n").filter((line) => line.trim());
36
+ let lastResult = "";
37
+ for (const line of lines) {
38
+ try {
39
+ const jsonObj = JSON.parse(line);
40
+ if (jsonObj && typeof jsonObj === "object" && jsonObj.type === "result" && "result" in jsonObj) {
41
+ lastResult = jsonObj.result;
42
+ }
43
+ } catch {
44
+ continue;
45
+ }
46
+ }
47
+ return lastResult || output;
48
+ } catch {
49
+ return output;
50
+ }
51
+ }
52
+ async function launchClaude(prompt, options = {}) {
53
+ const { model, permissionMode, addDir, headless = false, appendSystemPrompt, mcpConfig, allowedTools, disallowedTools, agents } = options;
54
+ const args = [];
55
+ if (headless) {
56
+ args.push("-p");
57
+ args.push("--output-format", "stream-json");
58
+ args.push("--verbose");
59
+ }
60
+ if (model) {
61
+ args.push("--model", model);
62
+ }
63
+ if (permissionMode && permissionMode !== "default") {
64
+ args.push("--permission-mode", permissionMode);
65
+ }
66
+ if (addDir) {
67
+ args.push("--add-dir", addDir);
68
+ }
69
+ args.push("--add-dir", "/tmp");
70
+ if (appendSystemPrompt) {
71
+ args.push("--append-system-prompt", appendSystemPrompt);
72
+ }
73
+ if (mcpConfig && mcpConfig.length > 0) {
74
+ for (const config of mcpConfig) {
75
+ args.push("--mcp-config", JSON.stringify(config));
76
+ }
77
+ }
78
+ if (allowedTools && allowedTools.length > 0) {
79
+ args.push("--allowed-tools", ...allowedTools);
80
+ }
81
+ if (disallowedTools && disallowedTools.length > 0) {
82
+ args.push("--disallowed-tools", ...disallowedTools);
83
+ }
84
+ if (agents) {
85
+ args.push("--agents", JSON.stringify(agents));
86
+ }
87
+ try {
88
+ if (headless) {
89
+ const isDebugMode = logger.isDebugEnabled();
90
+ const execaOptions = {
91
+ input: prompt,
92
+ timeout: 0,
93
+ // Disable timeout for long responses
94
+ ...addDir && { cwd: addDir },
95
+ // Run Claude in the worktree directory
96
+ verbose: isDebugMode,
97
+ ...isDebugMode && { stdio: ["pipe", "pipe", "pipe"] }
98
+ // Enable streaming in debug mode
99
+ };
100
+ const subprocess = execa("claude", args, execaOptions);
101
+ const isJsonStreamFormat = args.includes("--output-format") && args.includes("stream-json");
102
+ let outputBuffer = "";
103
+ let isStreaming = false;
104
+ let isFirstProgress = true;
105
+ if (subprocess.stdout && typeof subprocess.stdout.on === "function") {
106
+ isStreaming = true;
107
+ subprocess.stdout.on("data", (chunk) => {
108
+ const text = chunk.toString();
109
+ outputBuffer += text;
110
+ if (isDebugMode) {
111
+ process.stdout.write(text);
112
+ } else {
113
+ if (isFirstProgress) {
114
+ process.stdout.write("\u{1F916} .");
115
+ isFirstProgress = false;
116
+ } else {
117
+ process.stdout.write(".");
118
+ }
119
+ }
120
+ });
121
+ }
122
+ const result = await subprocess;
123
+ if (isStreaming) {
124
+ const rawOutput = outputBuffer.trim();
125
+ if (!isDebugMode) {
126
+ process.stdout.write("\n");
127
+ }
128
+ return isJsonStreamFormat ? parseJsonStreamOutput(rawOutput) : rawOutput;
129
+ } else {
130
+ if (isDebugMode) {
131
+ process.stdout.write(result.stdout);
132
+ if (result.stdout && !result.stdout.endsWith("\n")) {
133
+ process.stdout.write("\n");
134
+ }
135
+ } else {
136
+ process.stdout.write("\u{1F916} .");
137
+ process.stdout.write("\n");
138
+ }
139
+ const rawOutput = result.stdout.trim();
140
+ return isJsonStreamFormat ? parseJsonStreamOutput(rawOutput) : rawOutput;
141
+ }
142
+ } else {
143
+ await execa("claude", [...args, "--", prompt], {
144
+ ...addDir && { cwd: addDir },
145
+ stdio: "inherit",
146
+ // Let user interact directly in current terminal
147
+ timeout: 0,
148
+ // Disable timeout
149
+ verbose: logger.isDebugEnabled()
150
+ });
151
+ return;
152
+ }
153
+ } catch (error) {
154
+ const execaError = error;
155
+ const errorMessage = execaError.stderr ?? execaError.message ?? "Unknown Claude CLI error";
156
+ throw new Error(`Claude CLI error: ${errorMessage}`);
157
+ }
158
+ }
159
+ async function launchClaudeInNewTerminalWindow(_prompt, options) {
160
+ const { workspacePath, branchName, oneShot = "default", port, setArguments, executablePath } = options;
161
+ if (!workspacePath) {
162
+ throw new Error("workspacePath is required for terminal window launch");
163
+ }
164
+ const { openTerminalWindow } = await import("./terminal-SDCMDVD7.js");
165
+ const executable = executablePath ?? "iloom";
166
+ let launchCommand = `${executable} spin`;
167
+ if (oneShot !== "default") {
168
+ launchCommand += ` --one-shot=${oneShot}`;
169
+ }
170
+ if (setArguments && setArguments.length > 0) {
171
+ for (const setArg of setArguments) {
172
+ launchCommand += ` --set ${setArg}`;
173
+ }
174
+ }
175
+ let backgroundColor;
176
+ if (branchName) {
177
+ try {
178
+ const { generateColorFromBranchName } = await import("./color-QS5BFCNN.js");
179
+ const colorData = generateColorFromBranchName(branchName);
180
+ backgroundColor = colorData.rgb;
181
+ } catch (error) {
182
+ logger.warn(
183
+ `Failed to generate terminal color: ${error instanceof Error ? error.message : "Unknown error"}`
184
+ );
185
+ }
186
+ }
187
+ const hasEnvFile = existsSync(join(workspacePath, ".env"));
188
+ await openTerminalWindow({
189
+ workspacePath,
190
+ command: launchCommand,
191
+ ...backgroundColor && { backgroundColor },
192
+ includeEnvSetup: hasEnvFile,
193
+ // source .env only if it exists
194
+ ...port !== void 0 && { port, includePortExport: true }
195
+ });
196
+ }
197
+ async function generateBranchName(issueTitle, issueNumber, model = "haiku") {
198
+ try {
199
+ const isAvailable = await detectClaudeCli();
200
+ if (!isAvailable) {
201
+ logger.warn("Claude CLI not available, using fallback branch name");
202
+ return `feat/issue-${issueNumber}`;
203
+ }
204
+ logger.debug("Generating branch name with Claude", { issueNumber, issueTitle });
205
+ const prompt = `<Task>
206
+ Generate a git branch name for the following issue:
207
+ <Issue>
208
+ <IssueNumber>${issueNumber}</IssueNumber>
209
+ <IssueTitle>${issueTitle}</IssueTitle>
210
+ </Issue>
211
+
212
+ <Requirements>
213
+ <IssueNumber>Must use this exact issue number: ${issueNumber}</IssueNumber>
214
+ <Format>Format must be: {prefix}/issue-${issueNumber}-{description}</Format>
215
+ <Prefix>Prefix must be one of: feat, fix, docs, refactor, test, chore</Prefix>
216
+ <MaxLength>Maximum 50 characters total</MaxLength>
217
+ <Characters>Only lowercase letters, numbers, and hyphens allowed</Characters>
218
+ <Output>Reply with ONLY the branch name, nothing else</Output>
219
+ </Requirements>
220
+ </Task>`;
221
+ logger.debug("Sending prompt to Claude", { prompt });
222
+ const result = await launchClaude(prompt, {
223
+ model,
224
+ headless: true
225
+ });
226
+ const branchName = result.trim();
227
+ logger.debug("Claude returned branch name", { branchName, issueNumber });
228
+ if (!branchName || !isValidBranchName(branchName, issueNumber)) {
229
+ logger.warn("Invalid branch name from Claude, using fallback", { branchName });
230
+ return `feat/issue-${issueNumber}`;
231
+ }
232
+ return branchName;
233
+ } catch (error) {
234
+ logger.warn("Failed to generate branch name with Claude", { error });
235
+ return `feat/issue-${issueNumber}`;
236
+ }
237
+ }
238
+ function isValidBranchName(name, issueNumber) {
239
+ const pattern = new RegExp(`^(feat|fix|docs|refactor|test|chore)/issue-${issueNumber}-[a-z0-9-]+$`);
240
+ return pattern.test(name) && name.length <= 50;
241
+ }
242
+ export {
243
+ detectClaudeCli,
244
+ generateBranchName,
245
+ getClaudeVersion,
246
+ launchClaude,
247
+ launchClaudeInNewTerminalWindow
248
+ };
249
+ //# sourceMappingURL=claude-YHHHLSXH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/claude.ts"],"sourcesContent":["import { execa } from 'execa'\nimport { existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { logger } from './logger.js'\n\nexport interface ClaudeCliOptions {\n\tmodel?: string\n\tpermissionMode?: 'plan' | 'acceptEdits' | 'bypassPermissions' | 'default'\n\taddDir?: string\n\theadless?: boolean\n\tbranchName?: string // Optional branch name for terminal coloring\n\tport?: number // Optional port for terminal window export\n\ttimeout?: number // Timeout in milliseconds\n\tappendSystemPrompt?: string // System instructions to append to system prompt\n\tmcpConfig?: Record<string, unknown>[] // Array of MCP server configurations\n\tallowedTools?: string[] // Tools to allow via --allowed-tools flag\n\tdisallowedTools?: string[] // Tools to disallow via --disallowed-tools flag\n\tagents?: Record<string, unknown> // Agent configurations for --agents flag\n\toneShot?: import('../types/index.js').OneShotMode // One-shot automation mode\n\tsetArguments?: string[] // Raw --set arguments to forward (e.g., ['workflows.issue.startIde=false'])\n\texecutablePath?: string // Executable path to use for spin command (e.g., 'il', 'il-125', or '/path/to/dist/cli.js')\n}\n\n/**\n * Detect if Claude CLI is available on the system\n */\nexport async function detectClaudeCli(): Promise<boolean> {\n\ttry {\n\t\t// Use 'command -v' for cross-platform compatibility (works on macOS/Linux)\n\t\tawait execa('command', ['-v', 'claude'], {\n\t\t\tshell: true,\n\t\t\ttimeout: 5000,\n\t\t})\n\t\treturn true\n\t} catch (error) {\n\t\t// Claude CLI not found\n\t\tlogger.debug('Claude CLI not available', { error })\n\t\treturn false\n\t}\n}\n\n/**\n * Get Claude CLI version\n */\nexport async function getClaudeVersion(): Promise<string | null> {\n\ttry {\n\t\tconst result = await execa('claude', ['--version'], {\n\t\t\ttimeout: 5000,\n\t\t})\n\t\treturn result.stdout.trim()\n\t} catch (error) {\n\t\tlogger.warn('Failed to get Claude version', { error })\n\t\treturn null\n\t}\n}\n\n/**\n * Parse JSON stream output and extract result from last JSON object with type:\"result\"\n */\nfunction parseJsonStreamOutput(output: string): string {\n\ttry {\n\t\t// Split by newlines and filter out empty lines\n\t\tconst lines = output.split('\\n').filter(line => line.trim())\n\n\t\t// Find the last valid JSON object with type:\"result\"\n\t\tlet lastResult = ''\n\t\tfor (const line of lines) {\n\t\t\ttry {\n\t\t\t\tconst jsonObj = JSON.parse(line)\n\t\t\t\tif (jsonObj && typeof jsonObj === 'object' && jsonObj.type === 'result' && 'result' in jsonObj) {\n\t\t\t\t\tlastResult = jsonObj.result\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Skip invalid JSON lines\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\treturn lastResult || output // Fallback to original output if no valid result found\n\t} catch {\n\t\t// If parsing fails completely, return original output\n\t\treturn output\n\t}\n}\n\n/**\n * Launch Claude CLI with specified options\n * In headless mode, returns stdout. In interactive mode, returns void.\n */\nexport async function launchClaude(\n\tprompt: string,\n\toptions: ClaudeCliOptions = {}\n): Promise<string | void> {\n\tconst { model, permissionMode, addDir, headless = false, appendSystemPrompt, mcpConfig, allowedTools, disallowedTools, agents } = options\n\n\t// Build command arguments\n\tconst args: string[] = []\n\n\tif (headless) {\n\t\targs.push('-p')\n\n\t\t// Add JSON streaming output for progress tracking\n\t\targs.push('--output-format', 'stream-json')\n\t\targs.push('--verbose')\n\t}\n\n\tif (model) {\n\t\targs.push('--model', model)\n\t}\n\n\tif (permissionMode && permissionMode !== 'default') {\n\t\targs.push('--permission-mode', permissionMode)\n\t}\n\n\tif (addDir) {\n\t\targs.push('--add-dir', addDir)\n\t}\n\n\targs.push('--add-dir', '/tmp') //TODO: Won't work on Windows\n\n\t// Add --append-system-prompt flag if provided\n\tif (appendSystemPrompt) {\n\t\targs.push('--append-system-prompt', appendSystemPrompt)\n\t}\n\n\t// Add --mcp-config flags for each MCP server configuration\n\tif (mcpConfig && mcpConfig.length > 0) {\n\t\tfor (const config of mcpConfig) {\n\t\t\targs.push('--mcp-config', JSON.stringify(config))\n\t\t}\n\t}\n\n\t// Add --allowed-tools flags if provided\n\tif (allowedTools && allowedTools.length > 0) {\n\t\targs.push('--allowed-tools', ...allowedTools)\n\t}\n\n\t// Add --disallowed-tools flags if provided\n\tif (disallowedTools && disallowedTools.length > 0) {\n\t\targs.push('--disallowed-tools', ...disallowedTools)\n\t}\n\n\t// Add --agents flag if provided\n\tif (agents) {\n\t\targs.push('--agents', JSON.stringify(agents))\n\t}\n\n\ttry {\n\t\tif (headless) {\n\t\t\t// Headless mode: capture and return output\n\t\t\tconst isDebugMode = logger.isDebugEnabled()\n\n\t\t\t// Set up execa options based on debug mode\n\t\t\tconst execaOptions = {\n\t\t\t\tinput: prompt,\n\t\t\t\ttimeout: 0, // Disable timeout for long responses\n\t\t\t\t...(addDir && { cwd: addDir }), // Run Claude in the worktree directory\n\t\t\t\tverbose: isDebugMode,\n\t\t\t\t...(isDebugMode && { stdio: ['pipe', 'pipe', 'pipe'] as const }), // Enable streaming in debug mode\n\t\t\t}\n\n\t\t\tconst subprocess = execa('claude', args, execaOptions)\n\n\t\t\t// Check if JSON streaming format is enabled (always true in headless mode)\n\t\t\tconst isJsonStreamFormat = args.includes('--output-format') && args.includes('stream-json')\n\n\t\t\t// Handle real-time streaming (enabled for progress tracking)\n\t\t\tlet outputBuffer = ''\n\t\t\tlet isStreaming = false\n\t\t\tlet isFirstProgress = true\n\t\t\tif (subprocess.stdout && typeof subprocess.stdout.on === 'function') {\n\t\t\t\tisStreaming = true\n\t\t\t\tsubprocess.stdout.on('data', (chunk: Buffer) => {\n\t\t\t\t\tconst text = chunk.toString()\n\t\t\t\t\toutputBuffer += text\n\n\t\t\t\t\tif (isDebugMode) {\n\t\t\t\t\t\tprocess.stdout.write(text) // Full JSON streaming in debug mode\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Progress dots in non-debug mode with robot emoji prefix\n\t\t\t\t\t\tif (isFirstProgress) {\n\t\t\t\t\t\t\tprocess.stdout.write('🤖 .')\n\t\t\t\t\t\t\tisFirstProgress = false\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tprocess.stdout.write('.')\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tconst result = await subprocess\n\n\t\t\t// Return streamed output if we were streaming, otherwise use result.stdout\n\t\t\tif (isStreaming) {\n\t\t\t\tconst rawOutput = outputBuffer.trim()\n\n\t\t\t\t// Clean up progress dots with newline in non-debug mode\n\t\t\t\tif (!isDebugMode) {\n\t\t\t\t\tprocess.stdout.write('\\n')\n\t\t\t\t}\n\n\t\t\t\treturn isJsonStreamFormat ? parseJsonStreamOutput(rawOutput) : rawOutput\n\t\t\t} else {\n\t\t\t\t// Fallback for mocked tests or when streaming not available\n\t\t\t\tif (isDebugMode) {\n\t\t\t\t\t// In debug mode, write to stdout even if not streaming (old behavior for tests)\n\t\t\t\t\tprocess.stdout.write(result.stdout)\n\t\t\t\t\tif (result.stdout && !result.stdout.endsWith('\\n')) {\n\t\t\t\t\t\tprocess.stdout.write('\\n')\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// In non-debug mode, show a single progress dot even without streaming (for tests)\n\t\t\t\t\tprocess.stdout.write('🤖 .')\n\t\t\t\t\tprocess.stdout.write('\\n')\n\t\t\t\t}\n\t\t\t\tconst rawOutput = result.stdout.trim()\n\t\t\t\treturn isJsonStreamFormat ? parseJsonStreamOutput(rawOutput) : rawOutput\n\t\t\t}\n\t\t} else {\n\t\t\t// Simple interactive mode: run Claude in current terminal with stdio inherit\n\t\t\t// Used for conflict resolution, error fixing, etc.\n\t\t\t// This is the simple approach: claude -- \"prompt\"\n\n\t\t\t// Execute in current terminal (blocking, inherits stdio)\n\t\t\tawait execa('claude', [...args, '--', prompt], {\n\t\t\t\t...(addDir && { cwd: addDir }),\n\t\t\t\tstdio: 'inherit', // Let user interact directly in current terminal\n\t\t\t\ttimeout: 0, // Disable timeout\n\t\t\t\tverbose: logger.isDebugEnabled(),\n\t\t\t})\n\n\t\t\treturn\n\t\t}\n\t} catch (error) {\n\t\t// Check for specific Claude CLI errors\n\t\tconst execaError = error as {\n\t\t\tstderr?: string\n\t\t\tmessage?: string\n\t\t\texitCode?: number\n\t\t}\n\n\t\t// Re-throw with more context\n\t\tconst errorMessage = execaError.stderr ?? execaError.message ?? 'Unknown Claude CLI error'\n\t\tthrow new Error(`Claude CLI error: ${errorMessage}`)\n\t}\n}\n\n/**\n * Launch Claude in a new terminal window with rich context\n * This is specifically for \"end of il start\" workflow\n * Ports the terminal window opening, coloring, and .env sourcing behavior\n */\nexport async function launchClaudeInNewTerminalWindow(\n\t_prompt: string,\n\toptions: ClaudeCliOptions & {\n\t\tworkspacePath: string // Required for terminal window launch\n\t}\n): Promise<void> {\n\tconst { workspacePath, branchName, oneShot = 'default', port, setArguments, executablePath } = options\n\n\t// Verify required parameter\n\tif (!workspacePath) {\n\t\tthrow new Error('workspacePath is required for terminal window launch')\n\t}\n\n\t// Import terminal launcher for new terminal window creation\n\tconst { openTerminalWindow } = await import('./terminal.js')\n\n\t// Build launch command with optional --one-shot flag\n\t// Use provided executable path or fallback to 'il'\n\tconst executable = executablePath ?? 'iloom'\n\tlet launchCommand = `${executable} spin`\n\tif (oneShot !== 'default') {\n\t\tlaunchCommand += ` --one-shot=${oneShot}`\n\t}\n\n\t// Append --set arguments if provided\n\tif (setArguments && setArguments.length > 0) {\n\t\tfor (const setArg of setArguments) {\n\t\t\tlaunchCommand += ` --set ${setArg}`\n\t\t}\n\t}\n\n\t// Apply terminal background color if branch name available\n\tlet backgroundColor: { r: number; g: number; b: number } | undefined\n\tif (branchName) {\n\t\ttry {\n\t\t\tconst { generateColorFromBranchName } = await import('./color.js')\n\t\t\tconst colorData = generateColorFromBranchName(branchName)\n\t\t\tbackgroundColor = colorData.rgb\n\t\t} catch (error) {\n\t\t\tlogger.warn(\n\t\t\t\t`Failed to generate terminal color: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t)\n\t\t}\n\t}\n\n\t// Check if .env file exists in workspace\n\tconst hasEnvFile = existsSync(join(workspacePath, '.env'))\n\n\t// Open new terminal window with Claude\n\tawait openTerminalWindow({\n\t\tworkspacePath,\n\t\tcommand: launchCommand,\n\t\t...(backgroundColor && { backgroundColor }),\n\t\tincludeEnvSetup: hasEnvFile, // source .env only if it exists\n\t\t...(port !== undefined && { port, includePortExport: true }),\n\t})\n}\n\n/**\n * Generate a branch name using Claude with fallback\n * This matches the implementation that was working in ClaudeBranchNameStrategy\n */\nexport async function generateBranchName(\n\tissueTitle: string,\n\tissueNumber: number,\n\tmodel: string = 'haiku'\n): Promise<string> {\n\ttry {\n\t\t// Check if Claude CLI is available\n\t\tconst isAvailable = await detectClaudeCli()\n\t\tif (!isAvailable) {\n\t\t\tlogger.warn('Claude CLI not available, using fallback branch name')\n\t\t\treturn `feat/issue-${issueNumber}`\n\t\t}\n\n\t\tlogger.debug('Generating branch name with Claude', { issueNumber, issueTitle })\n\n\t\t// Use the proven prompt format from ClaudeBranchNameStrategy\n\t\tconst prompt = `<Task>\nGenerate a git branch name for the following issue:\n<Issue>\n<IssueNumber>${issueNumber}</IssueNumber>\n<IssueTitle>${issueTitle}</IssueTitle>\n</Issue>\n\n<Requirements>\n<IssueNumber>Must use this exact issue number: ${issueNumber}</IssueNumber>\n<Format>Format must be: {prefix}/issue-${issueNumber}-{description}</Format>\n<Prefix>Prefix must be one of: feat, fix, docs, refactor, test, chore</Prefix>\n<MaxLength>Maximum 50 characters total</MaxLength>\n<Characters>Only lowercase letters, numbers, and hyphens allowed</Characters>\n<Output>Reply with ONLY the branch name, nothing else</Output>\n</Requirements>\n</Task>`\n\n\t\tlogger.debug('Sending prompt to Claude', { prompt })\n\n\t\tconst result = (await launchClaude(prompt, {\n\t\t\tmodel,\n\t\t\theadless: true,\n\t\t})) as string\n\n\t\tconst branchName = result.trim()\n\t\tlogger.debug('Claude returned branch name', { branchName, issueNumber })\n\n\t\t// Validate generated name using same validation as ClaudeBranchNameStrategy\n\t\tif (!branchName || !isValidBranchName(branchName, issueNumber)) {\n\t\t\tlogger.warn('Invalid branch name from Claude, using fallback', { branchName })\n\t\t\treturn `feat/issue-${issueNumber}`\n\t\t}\n\n\t\treturn branchName\n\t} catch (error) {\n\t\tlogger.warn('Failed to generate branch name with Claude', { error })\n\t\treturn `feat/issue-${issueNumber}`\n\t}\n}\n\n/**\n * Validate branch name format\n * Check format: {prefix}/issue-{number}-{description}\n */\nfunction isValidBranchName(name: string, issueNumber: number): boolean {\n\tconst pattern = new RegExp(`^(feat|fix|docs|refactor|test|chore)/issue-${issueNumber}-[a-z0-9-]+$`)\n\treturn pattern.test(name) && name.length <= 50\n}\n"],"mappings":"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","names":[]}