@iloom/cli 0.10.1 → 0.10.2

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 (60) hide show
  1. package/dist/{BranchNamingService-25KSZAEM.js → BranchNamingService-4OP6LOH6.js} +2 -2
  2. package/dist/{ClaudeContextManager-66GR4BGM.js → ClaudeContextManager-ZKTUVQB2.js} +4 -4
  3. package/dist/{ClaudeService-7KM5NA5Z.js → ClaudeService-TRWOYQ6O.js} +3 -3
  4. package/dist/{LoomLauncher-TDLZSYG2.js → LoomLauncher-FRECYMXS.js} +4 -4
  5. package/dist/{chunk-KVHIAWVT.js → chunk-2VEWSM34.js} +2 -2
  6. package/dist/{chunk-5FJWO4IT.js → chunk-2YZCWAVZ.js} +2 -2
  7. package/dist/{chunk-ZNMPGMHY.js → chunk-3F27M7ZD.js} +7 -7
  8. package/dist/{chunk-GRISNU6G.js → chunk-BFHDVFSK.js} +5 -5
  9. package/dist/{chunk-KKV5WH5M.js → chunk-BFLMCE2U.js} +2 -2
  10. package/dist/{chunk-S7PZA6IV.js → chunk-BU53XIGY.js} +2 -2
  11. package/dist/{chunk-5RPBYK5Q.js → chunk-HYGUPUV5.js} +2 -2
  12. package/dist/{chunk-UR5DGNUO.js → chunk-PZ5WSR5Z.js} +4 -4
  13. package/dist/chunk-PZ5WSR5Z.js.map +1 -0
  14. package/dist/{chunk-QVLPWNE3.js → chunk-QFTDZ5E3.js} +2 -2
  15. package/dist/{chunk-EVPZFV3K.js → chunk-V3SVMFDQ.js} +2 -2
  16. package/dist/{chunk-E6KOWMKA.js → chunk-XE4BDRZD.js} +2 -2
  17. package/dist/{chunk-OTGH2HRS.js → chunk-ZGM2FE2R.js} +2 -4
  18. package/dist/chunk-ZGM2FE2R.js.map +1 -0
  19. package/dist/{claude-7GGEWVEM.js → claude-LN7OWVNI.js} +2 -2
  20. package/dist/{cleanup-6PVAC4NI.js → cleanup-4ZM2AJDC.js} +6 -6
  21. package/dist/cli.js +42 -29
  22. package/dist/cli.js.map +1 -1
  23. package/dist/{commit-FZR5XDQG.js → commit-4CFLXRZ3.js} +3 -3
  24. package/dist/{feedback-G2GJFN2F.js → feedback-EZWF5CAL.js} +3 -3
  25. package/dist/{ignite-H2O5Y5A2.js → ignite-MQETGFNA.js} +3 -3
  26. package/dist/index.js +3 -3
  27. package/dist/index.js.map +1 -1
  28. package/dist/{init-32YOKXRL.js → init-ZB2RITW6.js} +2 -2
  29. package/dist/install-deps-RLSGSHH7.js +43 -0
  30. package/dist/install-deps-RLSGSHH7.js.map +1 -0
  31. package/dist/{plan-RQ5FPIGF.js → plan-D3KSN5MU.js} +10 -10
  32. package/dist/prompts/swarm-orchestrator-prompt.txt +20 -6
  33. package/dist/{rebase-6NVLX5V7.js → rebase-62FDLIH4.js} +3 -3
  34. package/dist/{summary-WTQZ7XG2.js → summary-YZI25KW4.js} +4 -4
  35. package/package.json +1 -1
  36. package/dist/chunk-OTGH2HRS.js.map +0 -1
  37. package/dist/chunk-UR5DGNUO.js.map +0 -1
  38. /package/dist/{BranchNamingService-25KSZAEM.js.map → BranchNamingService-4OP6LOH6.js.map} +0 -0
  39. /package/dist/{ClaudeContextManager-66GR4BGM.js.map → ClaudeContextManager-ZKTUVQB2.js.map} +0 -0
  40. /package/dist/{ClaudeService-7KM5NA5Z.js.map → ClaudeService-TRWOYQ6O.js.map} +0 -0
  41. /package/dist/{LoomLauncher-TDLZSYG2.js.map → LoomLauncher-FRECYMXS.js.map} +0 -0
  42. /package/dist/{chunk-KVHIAWVT.js.map → chunk-2VEWSM34.js.map} +0 -0
  43. /package/dist/{chunk-5FJWO4IT.js.map → chunk-2YZCWAVZ.js.map} +0 -0
  44. /package/dist/{chunk-ZNMPGMHY.js.map → chunk-3F27M7ZD.js.map} +0 -0
  45. /package/dist/{chunk-GRISNU6G.js.map → chunk-BFHDVFSK.js.map} +0 -0
  46. /package/dist/{chunk-KKV5WH5M.js.map → chunk-BFLMCE2U.js.map} +0 -0
  47. /package/dist/{chunk-S7PZA6IV.js.map → chunk-BU53XIGY.js.map} +0 -0
  48. /package/dist/{chunk-5RPBYK5Q.js.map → chunk-HYGUPUV5.js.map} +0 -0
  49. /package/dist/{chunk-QVLPWNE3.js.map → chunk-QFTDZ5E3.js.map} +0 -0
  50. /package/dist/{chunk-EVPZFV3K.js.map → chunk-V3SVMFDQ.js.map} +0 -0
  51. /package/dist/{chunk-E6KOWMKA.js.map → chunk-XE4BDRZD.js.map} +0 -0
  52. /package/dist/{claude-7GGEWVEM.js.map → claude-LN7OWVNI.js.map} +0 -0
  53. /package/dist/{cleanup-6PVAC4NI.js.map → cleanup-4ZM2AJDC.js.map} +0 -0
  54. /package/dist/{commit-FZR5XDQG.js.map → commit-4CFLXRZ3.js.map} +0 -0
  55. /package/dist/{feedback-G2GJFN2F.js.map → feedback-EZWF5CAL.js.map} +0 -0
  56. /package/dist/{ignite-H2O5Y5A2.js.map → ignite-MQETGFNA.js.map} +0 -0
  57. /package/dist/{init-32YOKXRL.js.map → init-ZB2RITW6.js.map} +0 -0
  58. /package/dist/{plan-RQ5FPIGF.js.map → plan-D3KSN5MU.js.map} +0 -0
  59. /package/dist/{rebase-6NVLX5V7.js.map → rebase-62FDLIH4.js.map} +0 -0
  60. /package/dist/{summary-WTQZ7XG2.js.map → summary-YZI25KW4.js.map} +0 -0
@@ -21,7 +21,7 @@ import {
21
21
  import {
22
22
  detectClaudeCli,
23
23
  launchClaude
24
- } from "./chunk-UR5DGNUO.js";
24
+ } from "./chunk-PZ5WSR5Z.js";
25
25
  import {
26
26
  PromptTemplateManager
27
27
  } from "./chunk-UUEW5KWB.js";
@@ -461,4 +461,4 @@ var InitCommand = class {
461
461
  export {
462
462
  InitCommand
463
463
  };
464
- //# sourceMappingURL=init-32YOKXRL.js.map
464
+ //# sourceMappingURL=init-ZB2RITW6.js.map
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ScriptCommandBase
4
+ } from "./chunk-WXIM2WS7.js";
5
+ import {
6
+ installDependencies
7
+ } from "./chunk-WWKOVDWC.js";
8
+ import "./chunk-63QWFWH3.js";
9
+ import "./chunk-I5T677EA.js";
10
+ import "./chunk-YQ57ORTV.js";
11
+ import "./chunk-4FGEGQW4.js";
12
+ import "./chunk-7VHJNVLF.js";
13
+ import "./chunk-KB64WNBZ.js";
14
+ import "./chunk-6MLEBAYZ.js";
15
+ import {
16
+ logger
17
+ } from "./chunk-VT4PDUYT.js";
18
+
19
+ // src/commands/install-deps.ts
20
+ var InstallDepsCommand = class extends ScriptCommandBase {
21
+ getScriptName() {
22
+ return "install";
23
+ }
24
+ getScriptDisplayName() {
25
+ return "Install Dependencies";
26
+ }
27
+ /**
28
+ * Override execute to use installDependencies() instead of runScript()
29
+ * This provides the full install resolution chain including Node.js lockfile fallback
30
+ */
31
+ async execute(input) {
32
+ const parsed = input.identifier ? await this.parseExplicitInput(input.identifier) : await this.autoDetectFromCurrentDirectory();
33
+ logger.debug(`Parsed input: ${JSON.stringify(parsed)}`);
34
+ const worktree = await this.findWorktreeForIdentifier(parsed);
35
+ logger.info(`Found worktree at: ${worktree.path}`);
36
+ const frozen = input.frozen !== false;
37
+ await installDependencies(worktree.path, frozen, false);
38
+ }
39
+ };
40
+ export {
41
+ InstallDepsCommand
42
+ };
43
+ //# sourceMappingURL=install-deps-RLSGSHH7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/install-deps.ts"],"sourcesContent":["import { ScriptCommandBase, ScriptCommandInput } from './script-command-base.js'\nimport { installDependencies } from '../utils/package-manager.js'\nimport { logger } from '../utils/logger.js'\n\nexport interface InstallDepsCommandInput extends ScriptCommandInput {\n\tfrozen?: boolean | undefined\n}\n\n/**\n * InstallDepsCommand - Install dependencies for a workspace\n *\n * Unlike other script commands that use runScript(), this command delegates to\n * installDependencies() which includes Node.js lockfile detection fallback\n * when no explicit install script is defined.\n *\n * Install resolution order:\n * 1. scripts.install in .iloom/package.iloom.local.json (highest priority)\n * 2. scripts.install in .iloom/package.iloom.json\n * 3. scripts.install in package.json\n * 4. Node.js lockfile detection (pnpm/npm/yarn with frozen lockfile)\n * 5. Silently skips if no install mechanism found\n */\nexport class InstallDepsCommand extends ScriptCommandBase {\n\tgetScriptName(): string {\n\t\treturn 'install'\n\t}\n\n\tgetScriptDisplayName(): string {\n\t\treturn 'Install Dependencies'\n\t}\n\n\t/**\n\t * Override execute to use installDependencies() instead of runScript()\n\t * This provides the full install resolution chain including Node.js lockfile fallback\n\t */\n\toverride async execute(input: InstallDepsCommandInput): Promise<void> {\n\t\t// 1. Parse or auto-detect identifier\n\t\tconst parsed = input.identifier\n\t\t\t? await this.parseExplicitInput(input.identifier)\n\t\t\t: await this.autoDetectFromCurrentDirectory()\n\n\t\tlogger.debug(`Parsed input: ${JSON.stringify(parsed)}`)\n\n\t\t// 2. Find worktree path based on identifier\n\t\tconst worktree = await this.findWorktreeForIdentifier(parsed)\n\t\tlogger.info(`Found worktree at: ${worktree.path}`)\n\n\t\t// 3. Run installDependencies (handles iloom config scripts, package.json scripts,\n\t\t// AND Node.js lockfile fallback -- unlike base class which only does runScript)\n\t\tconst frozen = input.frozen !== false // default true\n\t\tawait installDependencies(worktree.path, frozen, false) // quiet=false for CLI\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAsBO,IAAM,qBAAN,cAAiC,kBAAkB;AAAA,EACzD,gBAAwB;AACvB,WAAO;AAAA,EACR;AAAA,EAEA,uBAA+B;AAC9B,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAe,QAAQ,OAA+C;AAErE,UAAM,SAAS,MAAM,aAClB,MAAM,KAAK,mBAAmB,MAAM,UAAU,IAC9C,MAAM,KAAK,+BAA+B;AAE7C,WAAO,MAAM,iBAAiB,KAAK,UAAU,MAAM,CAAC,EAAE;AAGtD,UAAM,WAAW,MAAM,KAAK,0BAA0B,MAAM;AAC5D,WAAO,KAAK,sBAAsB,SAAS,IAAI,EAAE;AAIjD,UAAM,SAAS,MAAM,WAAW;AAChC,UAAM,oBAAoB,SAAS,MAAM,QAAQ,KAAK;AAAA,EACvD;AACD;","names":[]}
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  IgniteCommand
4
- } from "./chunk-OTGH2HRS.js";
4
+ } from "./chunk-ZGM2FE2R.js";
5
5
  import {
6
6
  StartCommand,
7
7
  launchFirstRunSetup,
8
8
  needsFirstRunSetup
9
- } from "./chunk-GRISNU6G.js";
10
- import "./chunk-ZNMPGMHY.js";
11
- import "./chunk-KVHIAWVT.js";
9
+ } from "./chunk-BFHDVFSK.js";
10
+ import "./chunk-3F27M7ZD.js";
11
+ import "./chunk-2VEWSM34.js";
12
12
  import "./chunk-QZWEJVWV.js";
13
13
  import {
14
14
  IssueManagementProviderFactory
@@ -35,17 +35,17 @@ import "./chunk-MORRVYPT.js";
35
35
  import "./chunk-YQ57ORTV.js";
36
36
  import "./chunk-C6HNNJIV.js";
37
37
  import "./chunk-FXDYIV3K.js";
38
- import "./chunk-E6KOWMKA.js";
39
- import "./chunk-S7PZA6IV.js";
38
+ import "./chunk-XE4BDRZD.js";
39
+ import "./chunk-BU53XIGY.js";
40
40
  import {
41
41
  detectClaudeCli,
42
42
  launchClaude
43
- } from "./chunk-UR5DGNUO.js";
43
+ } from "./chunk-PZ5WSR5Z.js";
44
44
  import {
45
45
  PromptTemplateManager
46
46
  } from "./chunk-UUEW5KWB.js";
47
47
  import "./chunk-GYCR2LOU.js";
48
- import "./chunk-QVLPWNE3.js";
48
+ import "./chunk-QFTDZ5E3.js";
49
49
  import "./chunk-4FGEGQW4.js";
50
50
  import {
51
51
  PlanCommandSettingsSchema,
@@ -383,7 +383,7 @@ var PlanCommand = class {
383
383
  );
384
384
  if (shouldRunInit) {
385
385
  logger.info(chalk.bold("Launching iloom init..."));
386
- const { InitCommand } = await import("./init-32YOKXRL.js");
386
+ const { InitCommand } = await import("./init-ZB2RITW6.js");
387
387
  const initCommand = new InitCommand();
388
388
  await initCommand.execute(
389
389
  "Help the user set up a GitHub repository or Linear project for this project so they can use issue management features. When complete tell the user they can exit to continue the planning session."
@@ -718,4 +718,4 @@ ${initialMessage}`;
718
718
  export {
719
719
  PlanCommand
720
720
  };
721
- //# sourceMappingURL=plan-RQ5FPIGF.js.map
721
+ //# sourceMappingURL=plan-D3KSN5MU.js.map
@@ -225,17 +225,31 @@ Rebase and merge child branch `<child-branch-name>` (issue #<child-number>: "<ch
225
225
  git merge --ff-only <child-branch-name>
226
226
  ```
227
227
 
228
- 4. Report back with:
229
- - Status: "success" or "failed"
230
- - If conflicts were resolved, briefly describe what was resolved
231
- - If failed, explain why (e.g., "Rebase conflict could not be resolved" or specific error)
228
+ 4. After the merge succeeds, install dependencies in the epic worktree to ensure subsequent workers have up-to-date dependencies:
229
+ ```bash
230
+ cd {{EPIC_WORKTREE_PATH}}
231
+ il install-deps
232
+ ```
233
+ This handles all install resolution automatically (iloom config scripts, package.json scripts, Node.js lockfile detection). It silently skips if no install mechanism is found.
234
+
235
+ **IMPORTANT**: If the install command fails, do NOT treat the merge as failed. The merge (rebase + fast-forward) already succeeded. Log the install failure as a warning and continue.
236
+
237
+ 5. Report back with two separate statuses:
238
+ - **Merge outcome**: "success" or "failed" (covers rebase + fast-forward merge)
239
+ - If conflicts were resolved, briefly describe what was resolved
240
+ - If merge failed, explain why (e.g., "Rebase conflict could not be resolved" or specific error)
241
+ - **Install outcome**: "success", "failed", or "skipped"
242
+ - If success, state which install mechanism was used (e.g., "pnpm install --frozen-lockfile" or "iloom config install script")
243
+ - If failed, include the error output as a warning (merge is still considered successful)
244
+ - If skipped, state why (e.g., "No install mechanism found")
232
245
 
233
246
  IMPORTANT: Use rebase + fast-forward merge, NOT merge commits. This keeps the epic branch history linear and clean.
234
247
  ```
235
248
 
236
249
  **Handle the subagent result:**
237
- - If the subagent reports `success`: proceed to Step 3.2
238
- - If the subagent reports `failed`:
250
+ - If the subagent reports **Merge outcome: "success"**: proceed to Step 3.2
251
+ (Install outcome is informational only — log it but do not affect merge status)
252
+ - If the subagent reports **Merge outcome: "failed"**:
239
253
  - Ensure the rebase is aborted (spawn another subagent if needed): `cd <child-worktree-path> && git rebase --abort`
240
254
  - Mark the child as `failed` with reason from the subagent's report
241
255
  - Skip to Phase 4 failure handling for this child
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  BuildRunner,
4
4
  MergeManager
5
- } from "./chunk-5FJWO4IT.js";
5
+ } from "./chunk-2YZCWAVZ.js";
6
6
  import {
7
7
  installDependencies
8
8
  } from "./chunk-WWKOVDWC.js";
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-I5T677EA.js";
12
12
  import "./chunk-MORRVYPT.js";
13
13
  import "./chunk-YQ57ORTV.js";
14
- import "./chunk-UR5DGNUO.js";
14
+ import "./chunk-PZ5WSR5Z.js";
15
15
  import {
16
16
  getWorktreeRoot,
17
17
  isValidGitRepo
@@ -148,4 +148,4 @@ export {
148
148
  RebaseCommand,
149
149
  WorktreeValidationError
150
150
  };
151
- //# sourceMappingURL=rebase-6NVLX5V7.js.map
151
+ //# sourceMappingURL=rebase-62FDLIH4.js.map
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SessionSummaryService
4
- } from "./chunk-EVPZFV3K.js";
4
+ } from "./chunk-V3SVMFDQ.js";
5
5
  import "./chunk-NXMDEL3F.js";
6
6
  import {
7
7
  PRManager
8
- } from "./chunk-KVHIAWVT.js";
8
+ } from "./chunk-2VEWSM34.js";
9
9
  import "./chunk-SWSJWA2S.js";
10
10
  import "./chunk-4232AHNQ.js";
11
11
  import {
@@ -13,7 +13,7 @@ import {
13
13
  } from "./chunk-I5T677EA.js";
14
14
  import "./chunk-YETJNRQM.js";
15
15
  import "./chunk-FXDYIV3K.js";
16
- import "./chunk-UR5DGNUO.js";
16
+ import "./chunk-PZ5WSR5Z.js";
17
17
  import "./chunk-UUEW5KWB.js";
18
18
  import {
19
19
  extractIssueNumber
@@ -282,4 +282,4 @@ Please provide an issue number, PR number, or branch name.`
282
282
  export {
283
283
  SummaryCommand
284
284
  };
285
- //# sourceMappingURL=summary-WTQZ7XG2.js.map
285
+ //# sourceMappingURL=summary-YZI25KW4.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iloom/cli",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
4
4
  "description": "Control plane for maintaining alignment between you and Claude Code as you work across multiple issues using isolated environments, visible context, and multi-agent workflows to scale understanding, not just output",
5
5
  "keywords": [
6
6
  "ai",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/ignite.ts","../src/lib/ClaudeHookManager.ts","../src/lib/SwarmSetupService.ts","../src/utils/language-detector.ts"],"sourcesContent":["import path from 'path'\nimport fs from 'fs-extra'\nimport { logger, createStderrLogger } from '../utils/logger.js'\nimport { withLogger } from '../utils/logger-context.js'\nimport { ClaudeWorkflowOptions } from '../lib/ClaudeService.js'\nimport { GitWorktreeManager } from '../lib/GitWorktreeManager.js'\nimport { launchClaude, ClaudeCliOptions } from '../utils/claude.js'\nimport { PromptTemplateManager, TemplateVariables, buildReviewTemplateVariables } from '../lib/PromptTemplateManager.js'\nimport { generateIssueManagementMcpConfig, generateRecapMcpConfig, generateAndWriteMcpConfigFile } from '../utils/mcp.js'\nimport { AgentManager } from '../lib/AgentManager.js'\nimport { IssueTrackerFactory } from '../lib/IssueTrackerFactory.js'\nimport { SettingsManager, type IloomSettings } from '../lib/SettingsManager.js'\nimport { MetadataManager } from '../lib/MetadataManager.js'\nimport { extractSettingsOverrides } from '../utils/cli-overrides.js'\nimport { FirstRunManager } from '../utils/FirstRunManager.js'\nimport { extractIssueNumber, isValidGitRepo, getWorktreeRoot, findMainWorktreePathWithSettings } from '../utils/git.js'\nimport { getWorkspacePort } from '../utils/port.js'\nimport { readFile } from 'fs/promises'\nimport { ClaudeHookManager } from '../lib/ClaudeHookManager.js'\nimport type { OneShotMode } from '../types/index.js'\nimport { fetchChildIssueDetails } from '../utils/list-children.js'\nimport { buildDependencyMap } from '../utils/dependency-map.js'\nimport { SwarmSetupService } from '../lib/SwarmSetupService.js'\nimport type { LoomMetadata } from '../lib/MetadataManager.js'\nimport { TelemetryService } from '../lib/TelemetryService.js'\nimport { detectProjectLanguage } from '../utils/language-detector.js'\n\n/**\n * Error thrown when the spin command is run from an invalid location\n */\nexport class WorktreeValidationError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly suggestion: string\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'WorktreeValidationError'\n\t}\n}\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 hookManager: ClaudeHookManager\n\tprivate settings?: 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\thookManager?: ClaudeHookManager\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\tthis.hookManager = hookManager ?? new ClaudeHookManager()\n\t}\n\n\t/**\n\t * Validate that we're not running from the main worktree\n\t * @param workspacePath - Optional explicit workspace path; defaults to process.cwd()\n\t * @throws WorktreeValidationError if running from main worktree\n\t */\n\tprivate async validateNotMainWorktree(workspacePath?: string): Promise<void> {\n\t\tconst currentDir = workspacePath ?? process.cwd()\n\n\t\t// Step 1: Check if we're in a git repository at all\n\t\tconst isGitRepo = await isValidGitRepo(currentDir)\n\t\tif (!isGitRepo) {\n\t\t\t// Not a git repo - let detectWorkspaceContext handle this gracefully\n\t\t\treturn\n\t\t}\n\n\t\t// Step 2: Get the worktree root (handles subdirectories)\n\t\tconst worktreeRoot = await getWorktreeRoot(currentDir)\n\t\tif (!worktreeRoot) {\n\t\t\t// Could not determine root - let detectWorkspaceContext handle this\n\t\t\treturn\n\t\t}\n\n\t\t// Step 3: Check if this path is a registered git worktree\n\t\tconst worktrees = await this.gitWorktreeManager.listWorktrees()\n\t\tconst currentWorktree = worktrees.find(wt => wt.path === worktreeRoot)\n\n\t\tif (!currentWorktree) {\n\t\t\t// Not a registered worktree - let detectWorkspaceContext handle this\n\t\t\treturn\n\t\t}\n\n\t\t// Step 4: Check if this is the main worktree\n\t\tconst isMain = await this.gitWorktreeManager.isMainWorktree(currentWorktree, this.settingsManager)\n\t\tif (isMain) {\n\t\t\tthrow new WorktreeValidationError(\n\t\t\t\t'You cannot run the command from the main worktree.',\n\t\t\t\t\"Navigate to a feature worktree created by 'il start <issue>' and run 'il spin' from there.\"\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Print mode options for headless/CI execution\n\t */\n\tpublic printOptions: {\n\t\tprint?: boolean\n\t\toutputFormat?: 'json' | 'stream-json' | 'text'\n\t\tverbose?: boolean\n\t\tjson?: boolean // --json flag: output final JSON object\n\t\tjsonStream?: boolean // --json-stream flag: stream JSONL to stdout\n\t} | undefined\n\n\t/**\n\t * Main entry point for spin command\n\t * @param oneShot - One-shot automation mode\n\t * @param printOptions - Print mode options for headless/CI execution\n\t * @param skipCleanup - Skip cleanup after execution\n\t * @param workspacePath - Optional explicit workspace path for programmatic invocation (avoids process.chdir())\n\t */\n\tasync execute(oneShot?: OneShotMode, printOptions?: {\n\t\tprint?: boolean\n\t\toutputFormat?: 'json' | 'stream-json' | 'text'\n\t\tverbose?: boolean\n\t\tjson?: boolean\n\t\tjsonStream?: boolean\n\t}, skipCleanup?: boolean, workspacePath?: string): Promise<void> {\n\t\tthis.printOptions = printOptions\n\n\t\t// Wrap execution in stderr logger for JSON modes to keep stdout clean\n\t\tconst isJsonMode = (this.printOptions?.json ?? false) || (this.printOptions?.jsonStream ?? false)\n\t\tif (isJsonMode) {\n\t\t\tconst jsonLogger = createStderrLogger()\n\t\t\treturn withLogger(jsonLogger, () => this.executeInternal(oneShot, skipCleanup, workspacePath))\n\t\t}\n\n\t\treturn this.executeInternal(oneShot, skipCleanup, workspacePath)\n\t}\n\n\t/**\n\t * Internal execution method (separated for withLogger wrapping)\n\t */\n\tprivate async executeInternal(oneShot?: OneShotMode, skipCleanup?: boolean, workspacePath?: string): Promise<void> {\n\t\t// Set ILOOM=1 so hooks know this is an iloom session\n\t\t// This is inherited by the Claude child process\n\t\tprocess.env.ILOOM = '1'\n\n\t\t// Validate we're not in the main worktree first\n\t\ttry {\n\t\t\tawait this.validateNotMainWorktree(workspacePath)\n\t\t} catch (error) {\n\t\t\tif (error instanceof WorktreeValidationError) {\n\t\t\t\tlogger.error(error.message)\n\t\t\t\tlogger.info(error.suggestion)\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\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 0.6: Install Claude hooks for VSCode integration (idempotent, quick)\n\t\t\tawait this.hookManager.installHooks()\n\n\t\t\t// Step 1: Auto-detect workspace context\n\t\t\tconst context = await this.detectWorkspaceContext(workspacePath)\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: Read metadata early to get draftPrNumber and draftPrUrl for templates and MCP config\n\t\t\tconst metadataManager = new MetadataManager()\n\t\t\tconst metadata = await metadataManager.readMetadata(context.workspacePath)\n\t\t\tconst draftPrNumber = metadata?.draftPrNumber ?? undefined\n\t\t\t// Extract draft PR URL from prUrls map if available\n\t\t\tconst draftPrUrl = draftPrNumber && metadata?.prUrls?.[String(draftPrNumber)]\n\t\t\t\t? metadata.prUrls[String(draftPrNumber)]\n\t\t\t\t: undefined\n\n\t\t\t// Step 2.0.3: Prevent il spin in child worktrees of epic looms\n\t\t\t// Child issues managed by a swarm orchestrator must not launch independent agents.\n\t\t\t// Exception: child epics (issueType === 'epic') need il spin for their own swarm.\n\t\t\tif (metadata?.parentLoom?.type === 'epic' && metadata.issueType !== 'epic') {\n\t\t\t\tthrow new WorktreeValidationError(\n\t\t\t\t\t'Cannot run il spin in a child worktree of an epic loom. The swarm orchestrator manages agent execution for these issues.',\n\t\t\t\t\t'Run il spin from the parent epic worktree instead to launch the swarm orchestrator.'\n\t\t\t\t)\n\t\t\t}\n\n\t\t\t// Step 2.0.4: Determine effective oneShot mode\n\t\t\t// If print mode is enabled, force noReview to skip interactive reviews\n\t\t\t// If oneShot is provided (any value including 'default'), use it\n\t\t\t// If oneShot is undefined (not passed), use metadata or fallback to 'default'\n\t\t\t// Note: metadata?.oneShot can be null (for legacy looms), so we need double nullish coalescing\n\t\t\tconst storedOneShot = metadata?.oneShot ?? 'default'\n\t\t\tconst isHeadlessForOneShot = this.printOptions?.print ?? false\n\t\t\tconst effectiveOneShot: OneShotMode = isHeadlessForOneShot ? 'noReview' : (oneShot ?? storedOneShot)\n\n\t\t\t// Step 2.0.5: Load settings early if not cached (needed for port calculation)\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 2.0.5.1: Track session.started telemetry\n\t\t\ttry {\n\t\t\t\tconst hasNeon = !!this.settings?.databaseProviders?.neon\n\t\t\t\tconst language = await detectProjectLanguage(context.workspacePath)\n\t\t\t\tTelemetryService.getInstance().track('session.started', {\n\t\t\t\t\thas_neon: hasNeon,\n\t\t\t\t\tlanguage,\n\t\t\t\t})\n\t\t\t} catch (error) {\n\t\t\t\tlogger.debug(`Telemetry session.started tracking failed: ${error instanceof Error ? error.message : error}`)\n\t\t\t}\n\n\t\t\t// Step 2.0.6: Calculate port for web-capable looms\n\t\t\tif (metadata?.capabilities?.includes('web') && context.branchName) {\n\t\t\t\tconst basePort = this.settings?.capabilities?.web?.basePort ?? 3000\n\t\t\t\tcontext.port = await getWorkspacePort({\n\t\t\t\t\tbasePort,\n\t\t\t\t\tworktreePath: context.workspacePath,\n\t\t\t\t\tworktreeBranch: context.branchName,\n\t\t\t\t})\n\t\t\t\tlogger.info(`🌐 Development server port: ${context.port}`)\n\t\t\t}\n\n\t\t\t// Step 2.1: Fetch and persist epic child data if this is an epic loom\n\t\t\t// Detection: check for childIssues already stored (re-spin of an epic)\n\t\t\t// or check for 'epic' issueType once issue #624 adds it\n\t\t\tconst isEpicLoom = metadata && metadata.issue_numbers.length > 0\n\t\t\t\t&& ((metadata.childIssues?.length ?? 0) > 0 || metadata.issueType === 'epic')\n\t\t\tif (isEpicLoom && this.settings) {\n\t\t\t\tawait this.fetchAndStoreEpicChildData(metadataManager, metadata, context.workspacePath, this.settings)\n\t\t\t}\n\n\t\t\t// Step 2.1.1: If this is an epic loom, enter swarm mode\n\t\t\tif (isEpicLoom && this.settings) {\n\t\t\t\t// Re-read metadata to get freshly persisted child data\n\t\t\t\tconst freshMetadata = await metadataManager.readMetadata(context.workspacePath)\n\t\t\t\tif (freshMetadata && freshMetadata.childIssues.length > 0) {\n\t\t\t\t\tawait this.executeSwarmMode(\n\t\t\t\t\t\tfreshMetadata,\n\t\t\t\t\t\tcontext.workspacePath,\n\t\t\t\t\t\tcontext.branchName ?? '',\n\t\t\t\t\t\tmetadataManager,\n\t\t\t\t\t\tskipCleanup,\n\t\t\t\t\t)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Step 2.2: Get prompt template with variable substitution\n\t\t\tconst variables = this.buildTemplateVariables(context, effectiveOneShot, draftPrNumber, draftPrUrl)\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(effectiveOneShot)\n\n\t\t\t// Step 3: Determine model and permission mode based on workflow type\n\t\t\tconst model = this.settingsManager.getSpinModel(this.settings)\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 (effectiveOneShot === '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\t// Session ID must come from loom metadata - no fallback generation\n\t\t\tconst sessionId = metadata?.sessionId\n\t\t\tif (!sessionId) {\n\t\t\t\tthrow new Error('No session ID found in loom metadata. This loom may need to be recreated with `il start`.')\n\t\t\t}\n\t\t\tlogger.debug('Using session ID from metadata', { sessionId })\n\n\t\t\t// Determine if we're in print/headless mode\n\t\t\tconst isHeadless = this.printOptions?.print ?? false\n\n\t\t\tconst claudeOptions: ClaudeCliOptions = {\n\t\t\t\theadless: isHeadless,\n\t\t\t\taddDir: context.workspacePath,\n\t\t\t\tsessionId, // Enable Claude Code session resume\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\t// When print mode is enabled, force bypassPermissions for autonomous execution\n\t\t\tif (isHeadless) {\n\t\t\t\tpermissionMode = 'bypassPermissions'\n\t\t\t}\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 output format and verbose options if provided (print mode only)\n\t\t\tif (this.printOptions?.outputFormat !== undefined) {\n\t\t\t\tclaudeOptions.outputFormat = this.printOptions.outputFormat\n\t\t\t}\n\t\t\tif (this.printOptions?.verbose !== undefined) {\n\t\t\t\tclaudeOptions.verbose = this.printOptions.verbose\n\t\t\t}\n\n\t\t\t// Add JSON mode if specified (requires print mode)\n\t\t\tif (this.printOptions?.json) {\n\t\t\t\tclaudeOptions.jsonMode = 'json'\n\t\t\t\tclaudeOptions.outputFormat = 'stream-json' // Force stream-json for parsing\n\t\t\t} else if (this.printOptions?.jsonStream) {\n\t\t\t\tclaudeOptions.jsonMode = 'stream'\n\t\t\t\tclaudeOptions.outputFormat = 'stream-json' // Force stream-json for streaming\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\tconst provider = this.settings ? IssueTrackerFactory.getProviderName(this.settings) : 'github'\n\t\t\t\t\t// Pass draftPrNumber to route comments to PR when in github-draft-pr mode\n\t\t\t\t\tmcpConfig = await generateIssueManagementMcpConfig(context.type, undefined, provider, this.settings, draftPrNumber)\n\t\t\t\t\tlogger.debug('Generated MCP configuration for issue management', { provider, draftPrNumber })\n\n\t\t\t\t\t// Configure tool filtering for issue/PR workflows\n\t\t\t\t\t// Note: set_goal is only allowed for PR workflow (user's purpose unclear)\n\t\t\t\t\t// For issue workflow, the issue title provides context so set_goal is not needed\n\t\t\t\t\tconst baseTools = [\n\t\t\t\t\t\t'mcp__issue_management__get_issue',\n\t\t\t\t\t\t'mcp__issue_management__get_comment',\n\t\t\t\t\t\t'mcp__issue_management__create_comment',\n\t\t\t\t\t\t'mcp__issue_management__update_comment',\n\t\t\t\t\t\t'mcp__issue_management__create_issue',\n\t\t\t\t\t\t'mcp__issue_management__close_issue',\n\t\t\t\t\t\t'mcp__issue_management__reopen_issue',\n\t\t\t\t\t\t'mcp__issue_management__edit_issue',\n\t\t\t\t\t\t'mcp__recap__add_entry',\n\t\t\t\t\t\t'mcp__recap__get_recap',\n\t\t\t\t\t\t'mcp__recap__add_artifact',\n\t\t\t\t\t\t'mcp__recap__set_complexity',\n\t\t\t\t\t\t'mcp__recap__set_loom_state',\n\t\t\t\t\t\t'mcp__recap__get_loom_state'\n\t\t\t\t\t]\n\t\t\t\t\tallowedTools = context.type === 'pr'\n\t\t\t\t\t\t? [...baseTools, 'mcp__issue_management__get_pr', 'mcp__issue_management__get_review_comments', 'mcp__recap__set_goal']\n\t\t\t\t\t\t: baseTools\n\t\t\t\t\tdisallowedTools = ['Bash(gh api:*), Bash(gh issue comment:*)']\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} else {\n\t\t\t\t// Regular/branch workflow - allow recap tools (including set_goal since no issue/PR context)\n\t\t\t\tallowedTools = [\n\t\t\t\t\t'mcp__recap__set_goal',\n\t\t\t\t\t'mcp__recap__add_entry',\n\t\t\t\t\t'mcp__recap__get_recap',\n\t\t\t\t\t'mcp__recap__set_complexity',\n\t\t\t\t\t'mcp__recap__set_loom_state',\n\t\t\t\t\t'mcp__recap__get_loom_state',\n\t\t\t\t]\n\t\t\t\tlogger.debug('Configured tool filtering for regular workflow', { allowedTools })\n\t\t\t}\n\n\t\t\t// Step 4.5.1: Generate recap MCP config (always added for all workflow types)\n\t\t\t// Reuses metadata already read in Step 2\n\t\t\ttry {\n\t\t\t\tif (!metadata) {\n\t\t\t\t\tthrow new Error('No loom metadata found for this workspace')\n\t\t\t\t}\n\t\t\t\tconst recapMcpConfig = generateRecapMcpConfig(context.workspacePath, metadata)\n\t\t\t\tif (mcpConfig) {\n\t\t\t\t\tmcpConfig.push(...recapMcpConfig)\n\t\t\t\t} else {\n\t\t\t\t\tmcpConfig = recapMcpConfig\n\t\t\t\t}\n\t\t\t\tlogger.debug('Generated MCP configuration for recap server')\n\t\t\t} catch (error) {\n\t\t\t\t// Log warning but continue without recap MCP\n\t\t\t\tlogger.warn(`Failed to generate recap MCP config: ${error instanceof Error ? error.message : 'Unknown error'}`)\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 and template variables for substitution\n\t\t\t\t// Exclude init-only agents (e.g., framework-detector which is only for il init)\n\t\t\t\tconst loadedAgents = await this.agentManager.loadAgents(\n\t\t\t\t\tthis.settings,\n\t\t\t\t\tvariables,\n\t\t\t\t\t['*.md', '!iloom-framework-detector.md']\n\t\t\t\t)\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(isHeadless ? '✨ Launching Claude in headless mode...' : '✨ Launching Claude in current terminal...')\n\n\t\t\t// Step 5: Launch Claude with system instructions appended and user prompt\n\t\t\tconst claudeResult = await 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// Output final JSON for --json mode (--json-stream already streamed to stdout)\n\t\t\tif (this.printOptions?.json) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log(JSON.stringify({\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\toutput: claudeResult ?? ''\n\t\t\t\t}))\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\t// Output error as JSON for --json mode\n\t\t\tif (this.printOptions?.json) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.log(JSON.stringify({\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: errorMessage\n\t\t\t\t}))\n\t\t\t} else {\n\t\t\t\tlogger.error(`Failed to launch Claude: ${errorMessage}`)\n\t\t\t}\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(\n\t\tcontext: ClaudeWorkflowOptions,\n\t\toneShot: OneShotMode,\n\t\tdraftPrNumber?: number,\n\t\tdraftPrUrl?: string\n\t): 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 or INTERACTIVE_MODE flag for template conditional sections\n\t\tif (oneShot === 'noReview' || oneShot === 'bypassPermissions') {\n\t\t\tvariables.ONE_SHOT_MODE = true\n\t\t} else {\n\t\t\tvariables.INTERACTIVE_MODE = true\n\t\t}\n\n\t\t// Set review configuration variables (code reviewer + artifact reviewer + per-agent flags)\n\t\tObject.assign(variables, buildReviewTemplateVariables(this.settings?.agents))\n\n\t\t// Set draft PR mode flags (mutually exclusive)\n\t\t// When draftPrNumber is set, we're in github-draft-pr mode\n\t\tif (draftPrNumber !== undefined) {\n\t\t\tvariables.DRAFT_PR_MODE = true\n\t\t\tvariables.DRAFT_PR_NUMBER = draftPrNumber\n\t\t\tif (draftPrUrl) {\n\t\t\t\tvariables.DRAFT_PR_URL = draftPrUrl\n\t\t\t}\n\t\t\t// Set AUTO_COMMIT_PUSH when in draft PR mode and not explicitly disabled\n\t\t\t// Default is true (enabled) for draft PR mode\n\t\t\tconst autoCommitPushEnabled = this.settings?.mergeBehavior?.autoCommitPush !== false\n\t\t\tvariables.AUTO_COMMIT_PUSH = autoCommitPushEnabled\n\t\t\t// Set GIT_REMOTE from settings or default to 'origin'\n\t\t\tconst remote = this.settings?.mergeBehavior?.remote ?? 'origin'\n\t\t\tif (!/^[a-zA-Z0-9_-]+$/.test(remote)) {\n\t\t\t\tthrow new Error(`Invalid git remote name: \"${remote}\". Remote names can only contain alphanumeric characters, underscores, and hyphens.`)\n\t\t\t}\n\t\t\tvariables.GIT_REMOTE = remote\n\t\t} else if (context.type === 'regular') {\n\t\t\t// Branch mode without draft PR\n\t\t\tvariables.STANDARD_BRANCH_MODE = true\n\t\t} else {\n\t\t\t// Issue/PR mode without draft PR\n\t\t\tvariables.STANDARD_ISSUE_MODE = true\n\t\t}\n\n\t\t// Detect VS Code mode\n\t\tconst isVscodeMode = process.env.ILOOM_VSCODE === '1'\n\t\tvariables.IS_VSCODE_MODE = isVscodeMode\n\n\t\treturn variables\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(workspacePath?: string): Promise<ClaudeWorkflowOptions> {\n\t\tconst workspacePath_ = 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\tconst issueNumber = extractIssueNumber(currentDir)\n\n\t\tif (issueNumber !== null) {\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 branchIssueNumber = extractIssueNumber(currentBranch)\n\t\t\t\tif (branchIssueNumber !== null) {\n\t\t\t\t\tlogger.debug(`Auto-detected issue #${branchIssueNumber} from branch: ${currentBranch}`)\n\n\t\t\t\t\treturn this.buildContextForIssue(branchIssueNumber, 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: string | 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 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 (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 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 (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 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 (branchName !== undefined) {\n\t\t\tcontext.branchName = branchName\n\t\t}\n\n\t\treturn context\n\t}\n\n\n\t/**\n\t * Fetch and store epic child issue data and dependency map in metadata\n\t *\n\t * Called during spin setup for epic looms. Fetches child issue details\n\t * and dependency relationships from the issue tracker, then persists\n\t * them in the loom metadata for use by the orchestrator.\n\t */\n\tprivate async fetchAndStoreEpicChildData(\n\t\tmetadataManager: MetadataManager,\n\t\tmetadata: import('../lib/MetadataManager.js').LoomMetadata,\n\t\tworktreePath: string,\n\t\tsettings: import('../lib/SettingsManager.js').IloomSettings,\n\t): Promise<void> {\n\t\tconst parentIssueNumber = metadata.issue_numbers[0]\n\t\tif (!parentIssueNumber) return\n\n\t\tlogger.info('Fetching child issue data for epic...')\n\n\t\ttry {\n\t\t\tconst issueTracker = IssueTrackerFactory.create(settings)\n\n\t\t\t// Fetch child issue details and build dependency map in parallel\n\t\t\tconst childIssueDetails = await fetchChildIssueDetails(\n\t\t\t\tparentIssueNumber, issueTracker\n\t\t\t)\n\n\t\t\tif (childIssueDetails.length === 0) {\n\t\t\t\tlogger.debug('No child issues found for epic')\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Extract raw IDs for dependency map building (strip prefixes)\n\t\t\tconst childIds = childIssueDetails.map((child) => child.number.replace(/^#/, ''))\n\n\t\t\tconst dependencyMap = await buildDependencyMap(childIds, settings)\n\n\t\t\t// Persist to metadata\n\t\t\tawait metadataManager.updateMetadata(worktreePath, {\n\t\t\t\tchildIssues: childIssueDetails,\n\t\t\t\tdependencyMap,\n\t\t\t})\n\n\t\t\tlogger.info(`Stored ${childIssueDetails.length} child issues and dependency map in metadata`)\n\t\t} catch (error) {\n\t\t\t// Non-fatal: epic can still spin without child data\n\t\t\tlogger.warn(`Failed to fetch epic child data: ${error instanceof Error ? error.message : String(error)}`)\n\t\t}\n\t}\n\n\t/**\n\t * Execute swarm mode for an epic loom.\n\t *\n\t * Creates child worktrees, renders swarm agents/skill, builds the\n\t * orchestrator prompt, and launches Claude with agent teams enabled.\n\t */\n\tprivate async executeSwarmMode(\n\t\tmetadata: LoomMetadata,\n\t\tepicWorktreePath: string,\n\t\tepicBranch: string,\n\t\tmetadataManager: MetadataManager,\n\t\tskipCleanup?: boolean,\n\t): Promise<void> {\n\t\tif (!this.settings) {\n\t\t\tthrow new Error('Settings not loaded. Cannot enter swarm mode.')\n\t\t}\n\t\tconst settings = this.settings\n\t\tconst epicIssueNumber = metadata.issue_numbers[0]\n\t\tif (!epicIssueNumber) {\n\t\t\tthrow new Error('Epic loom has no issue number in metadata')\n\t\t}\n\n\t\tlogger.info('Epic loom detected - entering swarm mode...')\n\n\t\t// Determine main worktree path and issue tracker provider\n\t\tconst mainWorktreePath = await findMainWorktreePathWithSettings()\n\t\tconst providerName = IssueTrackerFactory.getProviderName(settings)\n\n\t\t// Create SwarmSetupService\n\t\tconst swarmSetup = new SwarmSetupService(\n\t\t\tthis.gitWorktreeManager,\n\t\t\tmetadataManager,\n\t\t\tthis.agentManager,\n\t\t\tthis.settingsManager,\n\t\t\tthis.templateManager,\n\t\t)\n\n\t\t// Generate and write per-loom MCP config file for the epic worktree\n\t\ttry {\n\t\t\tconst epicMcpConfigPath = await generateAndWriteMcpConfigFile(\n\t\t\t\tepicWorktreePath,\n\t\t\t\tmetadata,\n\t\t\t\tproviderName as 'github' | 'linear' | 'jira',\n\t\t\t\tsettings,\n\t\t\t)\n\t\t\tawait metadataManager.updateMetadata(epicWorktreePath, { mcpConfigPath: epicMcpConfigPath })\n\n\t\t\t// Write MCP config path to .claude/iloom-swarm-mcp-config-path for worker discovery\n\t\t\tconst epicClaudeDir = path.join(epicWorktreePath, '.claude')\n\t\t\tawait fs.ensureDir(epicClaudeDir)\n\t\t\tawait fs.writeFile(\n\t\t\t\tpath.join(epicClaudeDir, 'iloom-swarm-mcp-config-path'),\n\t\t\t\tepicMcpConfigPath,\n\t\t\t\t'utf-8',\n\t\t\t)\n\n\t\t\tlogger.debug('Wrote MCP config for epic loom', { epicMcpConfigPath })\n\t\t} catch (error) {\n\t\t\tlogger.warn(`Failed to write MCP config for epic loom: ${error instanceof Error ? error.message : 'Unknown error'}`)\n\t\t}\n\n\t\t// Build MCP configs for the orchestrator's own launchClaude call\n\t\tconst mcpConfigs: Record<string, unknown>[] = []\n\n\t\t// Issue management MCP\n\t\ttry {\n\t\t\tconst issueMcpConfigs = await generateIssueManagementMcpConfig(\n\t\t\t\t'issue',\n\t\t\t\tundefined,\n\t\t\t\tproviderName as 'github' | 'linear' | 'jira',\n\t\t\t\tsettings,\n\t\t\t)\n\t\t\tmcpConfigs.push(...issueMcpConfigs)\n\t\t} catch (error) {\n\t\t\tlogger.warn(`Failed to generate issue management MCP config: ${error instanceof Error ? error.message : 'Unknown error'}`)\n\t\t}\n\n\t\t// Recap MCP for the epic loom\n\t\ttry {\n\t\t\tconst recapMcpConfigs = generateRecapMcpConfig(epicWorktreePath, metadata)\n\t\t\tmcpConfigs.push(...recapMcpConfigs)\n\t\t} catch (error) {\n\t\t\tlogger.warn(`Failed to generate recap MCP config: ${error instanceof Error ? error.message : 'Unknown error'}`)\n\t\t}\n\n\t\t// Run swarm setup: child worktrees, agents, worker agent\n\t\tconst swarmResult = await swarmSetup.setupSwarm(\n\t\t\tepicIssueNumber,\n\t\t\tepicBranch,\n\t\t\tepicWorktreePath,\n\t\t\tmetadata.childIssues,\n\t\t\tmainWorktreePath,\n\t\t\tproviderName,\n\t\t\tsettings,\n\t\t)\n\n\t\t// Build template variables for orchestrator prompt\n\t\tconst successfulWorktrees = swarmResult.childWorktrees.filter((c) => c.success)\n\t\tconst worktreeMap = new Map(successfulWorktrees.map((cw) => [cw.issueId, cw]))\n\n\t\tconst childIssuesData = metadata.childIssues\n\t\t\t.filter((ci) => worktreeMap.has(ci.number.replace(/^#/, '')))\n\t\t\t.map((ci) => {\n\t\t\t\tconst rawId = ci.number.replace(/^#/, '')\n\t\t\t\tconst wt = worktreeMap.get(rawId)\n\t\t\t\treturn {\n\t\t\t\t\tnumber: rawId,\n\t\t\t\t\ttitle: ci.title,\n\t\t\t\t\tbody: ci.body,\n\t\t\t\t\tworktreePath: wt?.worktreePath ?? '',\n\t\t\t\t\tbranchName: wt?.branch ?? '',\n\t\t\t\t}\n\t\t\t})\n\n\t\t// Get metadata file path for the orchestrator prompt template\n\t\tconst epicMetadataPath = metadataManager.getMetadataFilePath(epicWorktreePath)\n\n\t\t// Determine issue prefix for commit message trailers\n\t\tconst issuePrefix = providerName === 'github' ? '#' : ''\n\n\t\tconst variables: TemplateVariables = {\n\t\t\tEPIC_ISSUE_NUMBER: epicIssueNumber,\n\t\t\tEPIC_WORKTREE_PATH: epicWorktreePath,\n\t\t\tEPIC_METADATA_PATH: epicMetadataPath,\n\t\t\tCHILD_ISSUES: JSON.stringify(childIssuesData, null, 2),\n\t\t\tDEPENDENCY_MAP: JSON.stringify(metadata.dependencyMap, null, 2),\n\t\t\tISSUE_PREFIX: issuePrefix,\n\t\t\t...(skipCleanup && { NO_CLEANUP: true }),\n\t\t}\n\n\t\t// Set draft PR mode flags for swarm orchestrator (same logic as buildTemplateVariables)\n\t\tconst draftPrNumber = metadata.draftPrNumber ?? undefined\n\t\tif (draftPrNumber !== undefined) {\n\t\t\tvariables.DRAFT_PR_MODE = true\n\t\t\tvariables.DRAFT_PR_NUMBER = draftPrNumber\n\t\t\tconst draftPrUrl = metadata.prUrls?.[String(draftPrNumber)]\n\t\t\tif (draftPrUrl) {\n\t\t\t\tvariables.DRAFT_PR_URL = draftPrUrl\n\t\t\t}\n\t\t\tconst autoCommitPushEnabled = settings.mergeBehavior?.autoCommitPush !== false\n\t\t\tvariables.AUTO_COMMIT_PUSH = autoCommitPushEnabled\n\t\t\tconst remote = settings.mergeBehavior?.remote ?? 'origin'\n\t\t\tif (!/^[a-zA-Z0-9_-]+$/.test(remote)) {\n\t\t\t\tthrow new Error(`Invalid git remote name: \"${remote}\". Remote names can only contain alphanumeric characters, underscores, and hyphens.`)\n\t\t\t}\n\t\t\tvariables.GIT_REMOTE = remote\n\t\t}\n\n\t\tconst orchestratorPrompt = await this.templateManager.getPrompt('swarm-orchestrator', variables)\n\n\t\t// Build allowed tools\n\t\tconst allowedTools = [\n\t\t\t'mcp__issue_management__get_issue',\n\t\t\t'mcp__issue_management__get_comment',\n\t\t\t'mcp__issue_management__create_comment',\n\t\t\t'mcp__issue_management__update_comment',\n\t\t\t'mcp__issue_management__create_issue',\n\t\t\t'mcp__issue_management__close_issue',\n\t\t\t'mcp__issue_management__reopen_issue',\n\t\t\t'mcp__issue_management__edit_issue',\n\t\t\t'mcp__recap__add_entry',\n\t\t\t'mcp__recap__get_recap',\n\t\t\t'mcp__recap__add_artifact',\n\t\t\t'mcp__recap__set_complexity',\n\t\t\t'mcp__recap__set_loom_state',\n\t\t\t'mcp__recap__get_loom_state',\n\t\t]\n\n\t\t// Launch Claude with agent teams enabled\n\t\tconst model = this.settingsManager.getSpinModel(settings, 'swarm')\n\n\t\tlogger.info('Launching swarm orchestrator...')\n\t\tlogger.info(` Model: ${model ?? 'default'}`)\n\t\tlogger.info(` Permission mode: bypassPermissions`)\n\t\tlogger.info(` Agent teams: enabled`)\n\t\tlogger.info(` Child worktrees: ${successfulWorktrees.length}`)\n\n\t\t// Load agents for the orchestrator\n\t\tlet agents: Record<string, unknown> | undefined\n\t\ttry {\n\t\t\tconst loadedAgents = await this.agentManager.loadAgents(\n\t\t\t\tsettings,\n\t\t\t\tvariables,\n\t\t\t\t['*.md', '!iloom-framework-detector.md']\n\t\t\t)\n\t\t\tagents = this.agentManager.formatForCli(loadedAgents)\n\t\t} catch (error) {\n\t\t\tlogger.warn(`Failed to load agents: ${error instanceof Error ? error.message : 'Unknown error'}`)\n\t\t}\n\n\t\t// Track swarm.started before launching orchestrator\n\t\tconst swarmStartTime = Date.now()\n\t\ttry {\n\t\t\tTelemetryService.getInstance().track('swarm.started', {\n\t\t\t\tchild_count: successfulWorktrees.length,\n\t\t\t\ttracker: providerName,\n\t\t\t})\n\t\t} catch (error) {\n\t\t\tlogger.debug(`Telemetry swarm.started tracking failed: ${error instanceof Error ? error.message : error}`)\n\t\t}\n\n\t\tawait launchClaude(\n\t\t\t`You are the swarm orchestrator for epic #${epicIssueNumber}. Begin by reading your system prompt instructions and executing the workflow.`,\n\t\t\t{\n\t\t\t\tmodel,\n\t\t\t\tpermissionMode: 'bypassPermissions',\n\t\t\t\taddDir: epicWorktreePath,\n\t\t\t\theadless: false,\n\t\t\t\t...(metadata.sessionId && { sessionId: metadata.sessionId }),\n\t\t\t\tappendSystemPrompt: orchestratorPrompt,\n\t\t\t\tmcpConfig: mcpConfigs,\n\t\t\t\tallowedTools,\n\t\t\t\t...(agents && { agents }),\n\t\t\t\tenv: {\n\t\t\t\t\tCLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: '1',\n\t\t\t\t\tILOOM_SWARM: '1',\n\t\t\t\t\tENABLE_TOOL_SEARCH: 'auto:30',\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\n\t\t// Track swarm child completions and overall completion\n\t\ttry {\n\t\t\tconst swarmEndTime = Date.now()\n\t\t\tlet succeeded = 0\n\t\t\tlet failed = 0\n\n\t\t\tfor (const child of successfulWorktrees) {\n\t\t\t\tconst childMeta = await metadataManager.readMetadata(child.worktreePath)\n\t\t\t\tconst isSuccess = childMeta?.state === 'done'\n\t\t\t\tif (isSuccess) {\n\t\t\t\t\tsucceeded++\n\t\t\t\t} else {\n\t\t\t\t\tfailed++\n\t\t\t\t}\n\n\t\t\t\tconst parsed = childMeta?.created_at ? Date.parse(childMeta.created_at) : NaN\n\t\t\t\tconst childCreatedAt = Number.isNaN(parsed) ? swarmStartTime : parsed\n\t\t\t\tconst childDuration = Math.max(0, Math.round((swarmEndTime - childCreatedAt) / 60000))\n\n\t\t\t\tTelemetryService.getInstance().track('swarm.child_completed', {\n\t\t\t\t\tsuccess: isSuccess,\n\t\t\t\t\tduration_minutes: childDuration,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tTelemetryService.getInstance().track('swarm.completed', {\n\t\t\t\ttotal_children: successfulWorktrees.length,\n\t\t\t\tsucceeded,\n\t\t\t\tfailed,\n\t\t\t\tduration_minutes: Math.round((swarmEndTime - swarmStartTime) / 60000),\n\t\t\t})\n\t\t} catch (error) {\n\t\t\tlogger.debug(`Telemetry swarm completion tracking failed: ${error instanceof Error ? error.message : error}`)\n\t\t}\n\t}\n\n\t/**\n\t * Build user prompt based on one-shot mode\n\t */\n\tprivate buildUserPrompt(oneShot: 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 { parse, modify, applyEdits, ParseError } from 'jsonc-parser'\nimport { fileURLToPath } from 'url'\nimport { accessSync } from 'fs'\nimport { logger } from '../utils/logger.js'\n\n/**\n * Hook configuration for a single event\n */\ninterface HookEntry {\n\ttype: 'command'\n\tcommand: string\n\ttimeout?: number\n}\n\n/**\n * Hook event configuration\n */\ninterface HookEventConfig {\n\tmatcher?: string\n\thooks: HookEntry[]\n}\n\n/**\n * Claude settings.json structure (partial)\n */\ninterface ClaudeSettings {\n\thooks?: Record<string, HookEventConfig[]>\n\t[key: string]: unknown\n}\n\n/**\n * Manages installation of Claude Code hooks to ~/.claude/\n *\n * Hooks enable real-time monitoring of Claude session state\n * via Unix socket communication with the iloom-vscode extension.\n */\nexport class ClaudeHookManager {\n\tprivate claudeDir: string\n\tprivate hooksDir: string\n\tprivate settingsPath: string\n\tprivate templateDir: string\n\n\tconstructor() {\n\t\t// Initialize paths using os.homedir()\n\t\tthis.claudeDir = path.join(os.homedir(), '.claude')\n\t\tthis.hooksDir = path.join(this.claudeDir, 'hooks')\n\t\tthis.settingsPath = path.join(this.claudeDir, 'settings.json')\n\n\t\t// Find templates relative to the package installation\n\t\t// Same pattern as PromptTemplateManager\n\t\tconst currentFileUrl = import.meta.url\n\t\tconst currentFilePath = fileURLToPath(currentFileUrl)\n\t\tconst distDir = path.dirname(currentFilePath)\n\n\t\t// Walk up to find the hooks template directory\n\t\tlet templateDir = path.join(distDir, 'hooks')\n\t\tlet currentDir = distDir\n\n\t\twhile (currentDir !== path.dirname(currentDir)) {\n\t\t\tconst candidatePath = path.join(currentDir, 'hooks')\n\t\t\ttry {\n\t\t\t\taccessSync(candidatePath)\n\t\t\t\ttemplateDir = candidatePath\n\t\t\t\tbreak\n\t\t\t} catch {\n\t\t\t\tcurrentDir = path.dirname(currentDir)\n\t\t\t}\n\t\t}\n\n\t\tthis.templateDir = templateDir\n\t\tlogger.debug('ClaudeHookManager initialized', {\n\t\t\tclaudeDir: this.claudeDir,\n\t\t\thooksDir: this.hooksDir,\n\t\t\tsettingsPath: this.settingsPath,\n\t\t\ttemplateDir: this.templateDir\n\t\t})\n\t}\n\n\t/**\n\t * Install Claude hooks for VSCode integration\n\t *\n\t * This is idempotent - safe to call on every spin.\n\t * Installs hook script to ~/.claude/hooks/ and merges\n\t * hook configuration into ~/.claude/settings.json\n\t */\n\tasync installHooks(): Promise<void> {\n\t\ttry {\n\t\t\t// 1. Create ~/.claude/hooks if missing\n\t\t\tawait fs.ensureDir(this.hooksDir)\n\n\t\t\t// 2. Install hook script from bundled templates\n\t\t\tawait this.installHookScript()\n\n\t\t\t// 3. Merge hook config into settings.json\n\t\t\tawait this.mergeHookConfig()\n\n\t\t\tlogger.debug('Claude hooks installed successfully')\n\t\t} catch (error) {\n\t\t\t// Log warning but don't fail - hooks are optional enhancement\n\t\t\tlogger.warn(\n\t\t\t\t`Failed to install Claude hooks: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Check if hooks are already installed\n\t */\n\tasync isHooksInstalled(): Promise<boolean> {\n\t\ttry {\n\t\t\t// Check if hook script exists\n\t\t\tconst hookScriptPath = path.join(this.hooksDir, 'iloom-hook.js')\n\t\t\tif (!(await fs.pathExists(hookScriptPath))) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Check if settings.json has our hooks\n\t\t\tif (!(await fs.pathExists(this.settingsPath))) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tconst content = await fs.readFile(this.settingsPath, 'utf8')\n\t\t\tconst errors: ParseError[] = []\n\t\t\tconst settings = parse(content, errors, { allowTrailingComma: true }) as ClaudeSettings\n\n\t\t\tif (errors.length > 0 || !settings?.hooks) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Check if our hooks are registered (check for SessionStart as indicator)\n\t\t\treturn Array.isArray(settings.hooks.SessionStart)\n\t\t} catch {\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Install the hook script from bundled templates\n\t * Skips write if destination already has identical content\n\t */\n\tprivate async installHookScript(): Promise<void> {\n\t\tconst sourcePath = path.join(this.templateDir, 'iloom-hook.js')\n\t\tconst destPath = path.join(this.hooksDir, 'iloom-hook.js')\n\n\t\t// Check if source template exists\n\t\tif (!(await fs.pathExists(sourcePath))) {\n\t\t\tthrow new Error(`Hook template not found at ${sourcePath}`)\n\t\t}\n\n\t\t// Skip if destination exists and content matches\n\t\tif (await fs.pathExists(destPath)) {\n\t\t\tconst [sourceContent, destContent] = await Promise.all([\n\t\t\t\tfs.readFile(sourcePath, 'utf8'),\n\t\t\t\tfs.readFile(destPath, 'utf8')\n\t\t\t])\n\t\t\tif (sourceContent === destContent) {\n\t\t\t\tlogger.debug('Hook script already up to date, skipping')\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\t// Copy hook script (only when content differs or doesn't exist)\n\t\tawait fs.copyFile(sourcePath, destPath)\n\t\tlogger.debug('Hook script installed', { sourcePath, destPath })\n\t}\n\n\t/**\n\t * Merge hook configuration into settings.json\n\t * Preserves existing user hooks and comments\n\t */\n\tprivate async mergeHookConfig(): Promise<void> {\n\t\t// Ensure ~/.claude directory exists\n\t\tawait fs.ensureDir(this.claudeDir)\n\n\t\t// Read existing settings (or create empty)\n\t\tlet existingContent = '{}'\n\t\tlet existingSettings: ClaudeSettings = {}\n\n\t\tif (await fs.pathExists(this.settingsPath)) {\n\t\t\texistingContent = await fs.readFile(this.settingsPath, 'utf8')\n\t\t\tconst errors: ParseError[] = []\n\t\t\texistingSettings = parse(existingContent, errors, { allowTrailingComma: true }) as ClaudeSettings\n\n\t\t\tif (errors.length > 0) {\n\t\t\t\tlogger.warn('Existing settings.json has parse errors, will attempt to merge anyway')\n\t\t\t}\n\t\t}\n\n\t\t// Get our hook configuration\n\t\tconst ourHooks = this.getHookConfig()\n\n\t\t// Merge hooks - preserve user's existing hooks on same events\n\t\tconst mergedHooks: Record<string, HookEventConfig[]> = { ...(existingSettings.hooks ?? {}) }\n\t\tlet hooksAdded = false\n\n\t\tfor (const [eventName, eventConfigs] of Object.entries(ourHooks)) {\n\t\t\tconst existing = mergedHooks[eventName] ?? []\n\n\t\t\t// Check if our hook is already registered\n\t\t\tconst ourConfig = eventConfigs[0]\n\t\t\tconst ourCommand = ourConfig?.hooks?.[0]?.command\n\t\t\tconst existingConfigIndex = existing.findIndex(\n\t\t\t\t(config) => config.hooks?.some((h) => h.command === ourCommand)\n\t\t\t)\n\n\t\t\tif (existingConfigIndex === -1) {\n\t\t\t\t// Add our hook config to the event\n\t\t\t\tmergedHooks[eventName] = [...existing, ...eventConfigs]\n\t\t\t\thooksAdded = true\n\t\t\t} else {\n\t\t\t\t// Hook is already registered - check if we need to update the matcher\n\t\t\t\tconst existingConfig = existing[existingConfigIndex]\n\t\t\t\tconst ourMatcher = ourConfig?.matcher\n\n\t\t\t\t// Update matcher if our config has one and existing doesn't match\n\t\t\t\tif (existingConfig && ourMatcher !== undefined && existingConfig.matcher !== ourMatcher) {\n\t\t\t\t\texisting[existingConfigIndex] = {\n\t\t\t\t\t\t...existingConfig,\n\t\t\t\t\t\tmatcher: ourMatcher\n\t\t\t\t\t}\n\t\t\t\t\thooksAdded = true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Skip write if no new hooks were added\n\t\tif (!hooksAdded) {\n\t\t\tlogger.debug('All hooks already registered, skipping settings.json update')\n\t\t\treturn\n\t\t}\n\n\t\t// Write updated settings\n\t\tlet content: string\n\n\t\t// Check if existing content has comments\n\t\tif (existingContent.includes('//') || existingContent.includes('/*')) {\n\t\t\t// Use jsonc-parser to preserve comments\n\t\t\tlet modifiedContent = existingContent\n\t\t\tconst edits = modify(modifiedContent, ['hooks'], mergedHooks, {})\n\t\t\tcontent = applyEdits(modifiedContent, edits)\n\t\t} else {\n\t\t\t// No comments - use JSON.stringify\n\t\t\tconst updatedSettings: ClaudeSettings = {\n\t\t\t\t...existingSettings,\n\t\t\t\thooks: mergedHooks\n\t\t\t}\n\t\t\tcontent = JSON.stringify(updatedSettings, null, 2) + '\\n'\n\t\t}\n\n\t\t// Write atomically using temp file + rename\n\t\tconst tempPath = `${this.settingsPath}.tmp`\n\t\tawait fs.writeFile(tempPath, content, 'utf8')\n\t\tawait fs.rename(tempPath, this.settingsPath)\n\n\t\tlogger.debug('Hook configuration merged into settings.json')\n\t}\n\n\t/**\n\t * Get the hook configuration to register\n\t *\n\t * Each event maps to a hook that runs iloom-hook.js\n\t */\n\tprivate getHookConfig(): Record<string, HookEventConfig[]> {\n\t\tconst hookCommand = `node ${path.join(this.hooksDir, 'iloom-hook.js')}`\n\n\t\treturn {\n\t\t\tNotification: [\n\t\t\t\t{ hooks: [{ type: 'command', command: hookCommand }] }\n\t\t\t],\n\t\t\tStop: [\n\t\t\t\t{ hooks: [{ type: 'command', command: hookCommand }] }\n\t\t\t],\n\t\t\tSubagentStop: [\n\t\t\t\t{ hooks: [{ type: 'command', command: hookCommand }] }\n\t\t\t],\n\t\t\tPermissionRequest: [\n\t\t\t\t{ matcher: '*', hooks: [{ type: 'command', command: hookCommand, timeout: 86400 }] }\n\t\t\t],\n\t\t\tPreToolUse: [\n\t\t\t\t{ matcher: '*', hooks: [{ type: 'command', command: hookCommand }] }\n\t\t\t],\n\t\t\tPostToolUse: [\n\t\t\t\t{ matcher: '*', hooks: [{ type: 'command', command: hookCommand }] }\n\t\t\t],\n\t\t\tSessionStart: [\n\t\t\t\t{ matcher: '*', hooks: [{ type: 'command', command: hookCommand }] }\n\t\t\t],\n\t\t\tSessionEnd: [\n\t\t\t\t{ hooks: [{ type: 'command', command: hookCommand }] }\n\t\t\t],\n\t\t\tUserPromptSubmit: [\n\t\t\t\t{ hooks: [{ type: 'command', command: hookCommand }] }\n\t\t\t]\n\t\t}\n\t}\n}\n","import path from 'path'\nimport fs from 'fs-extra'\nimport { GitWorktreeManager } from './GitWorktreeManager.js'\nimport { MetadataManager, type WriteMetadataInput, type SwarmState } from './MetadataManager.js'\nimport { AgentManager } from './AgentManager.js'\nimport { SettingsManager, type IloomSettings } from './SettingsManager.js'\nimport { PromptTemplateManager, buildReviewTemplateVariables, type TemplateVariables } from './PromptTemplateManager.js'\nimport { IssueTrackerFactory } from './IssueTrackerFactory.js'\nimport { IssueManagementProviderFactory } from '../mcp/IssueManagementProviderFactory.js'\nimport { getLogger } from '../utils/logger-context.js'\nimport { installDependencies } from '../utils/package-manager.js'\nimport { generateWorktreePath } from '../utils/git.js'\nimport { generateAndWriteMcpConfigFile } from '../utils/mcp.js'\n\n/**\n * Result of the swarm setup process\n */\nexport interface SwarmSetupResult {\n\tepicWorktreePath: string\n\tepicBranch: string\n\tchildWorktrees: Array<{\n\t\tissueId: string\n\t\tworktreePath: string\n\t\tbranch: string\n\t\tsuccess: boolean\n\t\terror?: string\n\t}>\n\tagentsRendered: string[]\n\tworkerAgentRendered: boolean\n}\n\n/**\n * Metadata extracted from agent YAML frontmatter for use in claude -p commands.\n * Maps agent file name (without .md) to model and tools info.\n */\nexport interface SwarmAgentMetadata {\n\t[agentFileName: string]: {\n\t\tmodel: string\n\t\ttools?: string[]\n\t}\n}\n\n/**\n * Child issue data as stored in epic metadata\n */\nexport interface SwarmChildIssue {\n\tnumber: string // Prefixed: \"#123\" for GitHub, \"ENG-123\" for Linear\n\ttitle: string\n\tbody: string\n\turl: string\n}\n\n/**\n * SwarmSetupService handles the creation of child worktrees\n * for swarm mode, plus rendering swarm-mode agents and skill files.\n *\n * Called from the spin command (ignite.ts) when an epic loom is detected.\n * The epic worktree already exists (created by `il start`).\n */\nexport class SwarmSetupService {\n\tconstructor(\n\t\tprivate gitWorktree: GitWorktreeManager,\n\t\tprivate metadataManager: MetadataManager,\n\t\tprivate agentManager: AgentManager,\n\t\tprivate settingsManager: SettingsManager,\n\t\tprivate templateManager: PromptTemplateManager,\n\t) {}\n\n\t/**\n\t * Create child worktrees for each child issue, branched off the epic branch.\n\t * Writes iloom-metadata.json for each child with state: 'pending' and parentLoom.\n\t * Generates and writes per-loom MCP config file for each child.\n\t *\n\t * Uses standard iloom naming conventions via generateWorktreePath().\n\t *\n\t * @param childIssues - Array of child issues from epic metadata\n\t * @param epicBranch - The epic branch name (base branch for children)\n\t * @param epicWorktreePath - Path to the epic worktree\n\t * @param mainWorktreePath - Path to the main worktree (project root)\n\t * @param epicIssueNumber - The parent epic issue number\n\t * @param issueTrackerName - The issue tracker provider name (e.g., 'github')\n\t * @param settings - Optional settings for MCP config generation\n\t * @returns Array of results for each child worktree creation\n\t */\n\tasync createChildWorktrees(\n\t\tchildIssues: SwarmChildIssue[],\n\t\tepicBranch: string,\n\t\tepicWorktreePath: string,\n\t\tmainWorktreePath: string,\n\t\tepicIssueNumber: string | number,\n\t\tissueTrackerName: string,\n\t\tsettings?: IloomSettings,\n\t): Promise<SwarmSetupResult['childWorktrees']> {\n\t\treturn Promise.all(childIssues.map(async (child) => {\n\t\t\ttry {\n\t\t\t\t// Strip prefix from child number (e.g., \"#123\" -> \"123\", \"ENG-123\" stays as-is for branch naming)\n\t\t\t\tconst rawId = child.number.replace(/^#/, '')\n\n\t\t\t\t// Sanitize ID for safe git branch naming (replace non-alphanumeric except - and _ with -)\n\t\t\t\tconst safeId = rawId.replace(/[^a-zA-Z0-9-_]/g, '-')\n\n\t\t\t\t// Use standard iloom branch naming: issue/<id> pattern\n\t\t\t\tconst childBranch = `issue/${safeId}`\n\n\t\t\t\t// Use standard iloom worktree path generation\n\t\t\t\tconst childWorktreePath = generateWorktreePath(\n\t\t\t\t\tchildBranch,\n\t\t\t\t\tmainWorktreePath,\n\t\t\t\t)\n\n\t\t\t\tgetLogger().info(`Creating child worktree for ${child.number}: ${childWorktreePath}...`)\n\n\t\t\t\tawait this.gitWorktree.createWorktree({\n\t\t\t\t\tpath: childWorktreePath,\n\t\t\t\t\tbranch: childBranch,\n\t\t\t\t\tcreateBranch: true,\n\t\t\t\t\tbaseBranch: epicBranch,\n\t\t\t\t})\n\n\t\t\t\t// Write metadata with state: 'pending' and parentLoom\n\t\t\t\tconst metadataInput: WriteMetadataInput = {\n\t\t\t\t\tdescription: child.title,\n\t\t\t\t\tbranchName: childBranch,\n\t\t\t\t\tworktreePath: childWorktreePath,\n\t\t\t\t\tissueType: 'issue',\n\t\t\t\t\tissue_numbers: [rawId],\n\t\t\t\t\tpr_numbers: [],\n\t\t\t\t\tissueTracker: issueTrackerName,\n\t\t\t\t\tcolorHex: '#808080',\n\t\t\t\t\tsessionId: '', // No session - not launching Claude directly\n\t\t\t\t\tprojectPath: mainWorktreePath,\n\t\t\t\t\tissueUrls: { [rawId]: child.url },\n\t\t\t\t\tprUrls: {},\n\t\t\t\t\tcapabilities: [],\n\t\t\t\t\tstate: 'pending' as SwarmState,\n\t\t\t\t\tparentLoom: {\n\t\t\t\t\t\ttype: 'epic',\n\t\t\t\t\t\tidentifier: epicIssueNumber,\n\t\t\t\t\t\tbranchName: epicBranch,\n\t\t\t\t\t\tworktreePath: epicWorktreePath,\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tawait this.metadataManager.writeMetadata(childWorktreePath, metadataInput)\n\t\t\t\t} catch (metaError) {\n\t\t\t\t\t// Clean up the worktree to avoid zombie worktrees without metadata\n\t\t\t\t\tgetLogger().warn(`Metadata write failed for ${child.number}, cleaning up worktree...`)\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this.gitWorktree.removeWorktree(childWorktreePath, { force: true })\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tgetLogger().debug(`Could not clean up worktree at ${childWorktreePath}`)\n\t\t\t\t\t}\n\t\t\t\t\tthrow metaError\n\t\t\t\t}\n\n\t\t\t\t// Generate and write per-loom MCP config file\n\t\t\t\ttry {\n\t\t\t\t\tconst childMetadata = await this.metadataManager.readMetadata(childWorktreePath)\n\t\t\t\t\tif (childMetadata) {\n\t\t\t\t\t\tconst providerName = IssueTrackerFactory.getProviderName(\n\t\t\t\t\t\t\tsettings ?? await this.settingsManager.loadSettings(),\n\t\t\t\t\t\t) as 'github' | 'linear' | 'jira'\n\t\t\t\t\t\tconst mcpConfigPath = await generateAndWriteMcpConfigFile(\n\t\t\t\t\t\t\tchildWorktreePath,\n\t\t\t\t\t\t\tchildMetadata,\n\t\t\t\t\t\t\tproviderName,\n\t\t\t\t\t\t\tsettings,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tawait this.metadataManager.updateMetadata(childWorktreePath, { mcpConfigPath })\n\n\t\t\t\t\t\t// Write MCP config path to .claude/iloom-swarm-mcp-config-path for worker discovery\n\t\t\t\t\t\tconst claudeDir = path.join(childWorktreePath, '.claude')\n\t\t\t\t\t\tawait fs.ensureDir(claudeDir)\n\t\t\t\t\t\tawait fs.writeFile(\n\t\t\t\t\t\t\tpath.join(claudeDir, 'iloom-swarm-mcp-config-path'),\n\t\t\t\t\t\t\tmcpConfigPath,\n\t\t\t\t\t\t\t'utf-8',\n\t\t\t\t\t\t)\n\n\t\t\t\t\t\tgetLogger().debug(`Wrote MCP config for ${child.number}: ${mcpConfigPath}`)\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Non-fatal: child can still work without MCP config\n\t\t\t\t\tgetLogger().warn(\n\t\t\t\t\t\t`Failed to write MCP config for child ${child.number}: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t\t\t\t)\n\t\t\t\t}\n\n\t\t\t\t// Install dependencies in the child worktree\n\t\t\t\ttry {\n\t\t\t\t\tawait installDependencies(childWorktreePath, true, true)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tgetLogger().warn(\n\t\t\t\t\t\t`Failed to install dependencies in child worktree ${child.number}: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t\t\t\t)\n\t\t\t\t}\n\n\t\t\t\tgetLogger().success(`Created child worktree for ${child.number}`)\n\t\t\t\treturn {\n\t\t\t\t\tissueId: rawId,\n\t\t\t\t\tworktreePath: childWorktreePath,\n\t\t\t\t\tbranch: childBranch,\n\t\t\t\t\tsuccess: true,\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst rawId = child.number.replace(/^#/, '')\n\t\t\t\tconst errorMessage = error instanceof Error ? error.message : 'Unknown error'\n\t\t\t\tgetLogger().warn(`Failed to create child worktree for ${child.number}: ${errorMessage}`)\n\t\t\t\treturn {\n\t\t\t\t\tissueId: rawId,\n\t\t\t\t\tworktreePath: '',\n\t\t\t\t\tbranch: '',\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: errorMessage,\n\t\t\t\t}\n\t\t\t}\n\t\t}))\n\t}\n\n\t/**\n\t * Render swarm-mode agent templates to the epic worktree's .claude/agents/ directory.\n\t *\n\t * Phase agent files are written WITHOUT frontmatter (prompt body only) because they are\n\t * loaded via `--append-system-prompt-file` which does not parse YAML frontmatter.\n\t * Model and tools metadata is extracted from the agent config and returned separately\n\t * for use as CLI flags in `claude -p` commands.\n\t */\n\tasync renderSwarmAgents(epicWorktreePath: string): Promise<{\n\t\trenderedFiles: string[]\n\t\tmetadata: SwarmAgentMetadata\n\t}> {\n\t\tconst claudeAgentsDir = path.join(epicWorktreePath, '.claude', 'agents')\n\t\tawait fs.ensureDir(claudeAgentsDir)\n\n\t\tconst settings = await this.settingsManager.loadSettings()\n\n\t\tconst templateVariables: TemplateVariables = {\n\t\t\tSWARM_MODE: true,\n\t\t}\n\n\t\tconst agents = await this.agentManager.loadAgents(settings, templateVariables)\n\n\t\t// Default swarmModel map for \"Balanced\" mode. All swarm phase agents are\n\t\t// listed explicitly so that swarm mode never accidentally inherits a\n\t\t// non-swarm model override. User-configured swarmModel values always\n\t\t// take precedence.\n\t\tconst defaultSwarmModels: Record<string, 'sonnet' | 'opus' | 'haiku'> = {\n\t\t\t'iloom-issue-analyzer': 'opus',\n\t\t\t'iloom-issue-analyze-and-plan': 'opus',\n\t\t\t'iloom-issue-planner': 'sonnet',\n\t\t\t'iloom-issue-implementer': 'sonnet',\n\t\t\t'iloom-issue-enhancer': 'sonnet',\n\t\t\t'iloom-code-reviewer': 'sonnet',\n\t\t\t'iloom-issue-complexity-evaluator': 'haiku',\n\t\t}\n\n\t\t// Apply per-agent swarmModel overrides (user-configured takes precedence over defaults)\n\t\tfor (const [agentName, agentConfig] of Object.entries(agents)) {\n\t\t\tconst userSwarmModel = settings?.agents?.[agentName]?.swarmModel\n\t\t\tif (userSwarmModel) {\n\t\t\t\tagents[agentName] = { ...agentConfig, model: userSwarmModel }\n\t\t\t} else if (defaultSwarmModels[agentName]) {\n\t\t\t\tagents[agentName] = { ...agentConfig, model: defaultSwarmModels[agentName] }\n\t\t\t}\n\t\t}\n\n\t\tconst renderedFiles: string[] = []\n\t\tconst metadata: SwarmAgentMetadata = {}\n\n\t\tfor (const [agentName, agentConfig] of Object.entries(agents)) {\n\t\t\tconst swarmFileName = agentName.startsWith('iloom-')\n\t\t\t\t? `iloom-swarm-${agentName.slice('iloom-'.length)}.md`\n\t\t\t\t: `iloom-swarm-${agentName}.md`\n\n\t\t\tconst agentKey = swarmFileName.replace('.md', '')\n\n\t\t\t// Extract metadata from agent config for use in claude -p CLI flags\n\t\t\tmetadata[agentKey] = {\n\t\t\t\tmodel: agentConfig.model,\n\t\t\t\t...(agentConfig.tools && { tools: agentConfig.tools }),\n\t\t\t}\n\n\t\t\t// Write file WITHOUT frontmatter - prompt body only\n\t\t\t// Phase agents are loaded via --append-system-prompt-file which does not parse YAML frontmatter\n\t\t\tconst outputPath = path.join(claudeAgentsDir, swarmFileName)\n\t\t\tawait fs.writeFile(outputPath, agentConfig.prompt + '\\n', 'utf-8')\n\t\t\trenderedFiles.push(swarmFileName)\n\t\t\tgetLogger().debug(`Rendered swarm agent: ${swarmFileName}`)\n\t\t}\n\n\t\tgetLogger().success(`Rendered ${renderedFiles.length} swarm agents to ${claudeAgentsDir}`)\n\t\treturn { renderedFiles, metadata }\n\t}\n\n\t/**\n\t * Render the swarm worker agent file to the epic worktree's .claude/agents/ directory.\n\t *\n\t * This creates an agent file at `.claude/agents/iloom-swarm-worker.md` containing\n\t * the full iloom workflow instructions (rendered from issue-prompt.txt with SWARM_MODE=true).\n\t * The orchestrator spawns children with `subagent_type: \"iloom-swarm-worker\"` so these\n\t * instructions become the agent's system prompt (high authority), rather than arriving\n\t * as a skill invocation (low authority user message).\n\t *\n\t * The agent file is shared across all children. Issue-specific context (number, title,\n\t * worktree path, body) is provided per-child via the Task prompt from the orchestrator.\n\t */\n\tasync renderSwarmWorkerAgent(\n\t\tepicWorktreePath: string,\n\t\tagentMetadata?: SwarmAgentMetadata,\n\t): Promise<boolean> {\n\t\tconst agentsDir = path.join(epicWorktreePath, '.claude', 'agents')\n\t\tconst agentOutputPath = path.join(agentsDir, 'iloom-swarm-worker.md')\n\n\t\tawait fs.ensureDir(agentsDir)\n\n\t\ttry {\n\t\t\t// Load settings for review configuration and issue prefix\n\t\t\tconst settings = await this.settingsManager.loadSettings()\n\t\t\tconst providerType = settings?.issueManagement?.provider ?? 'github'\n\t\t\tconst issuePrefix = IssueManagementProviderFactory.create(providerType, settings ?? undefined).issuePrefix\n\n\t\t\t// Compute sub-agent timeout in milliseconds (default: 10 minutes)\n\t\t\tconst subAgentTimeoutMinutes = settings?.agents?.['iloom-swarm-worker']?.subAgentTimeout ?? 10\n\t\t\tconst subAgentTimeoutMs = subAgentTimeoutMinutes * 60 * 1000\n\n\t\t\t// Build template variables for swarm worker agent rendering\n\t\t\tconst variables: TemplateVariables = {\n\t\t\t\tSWARM_MODE: true,\n\t\t\t\tONE_SHOT_MODE: true,\n\t\t\t\tEPIC_WORKTREE_PATH: epicWorktreePath,\n\t\t\t\tISSUE_PREFIX: issuePrefix,\n\t\t\t\tSWARM_SUB_AGENT_TIMEOUT_MS: subAgentTimeoutMs,\n\t\t\t\t...(agentMetadata && { SWARM_AGENT_METADATA: JSON.stringify(agentMetadata) }),\n\t\t\t\t...buildReviewTemplateVariables(settings?.agents),\n\t\t\t}\n\n\t\t\t// Render issue prompt template with swarm variables\n\t\t\tconst agentBody = await this.templateManager.getPrompt('issue', variables)\n\n\t\t\t// Build the agent file with frontmatter\n\t\t\tconst workerModel = settings?.agents?.['iloom-swarm-worker']?.model ?? 'opus'\n\n\t\t\tconst frontmatter = [\n\t\t\t\t'---',\n\t\t\t\t'name: iloom-swarm-worker',\n\t\t\t\t'description: Swarm worker agent that implements a child issue following the full iloom workflow.',\n\t\t\t\t`model: ${workerModel}`,\n\t\t\t\t'---',\n\t\t\t].join('\\n')\n\n\t\t\tconst content = `${frontmatter}\\n\\n${agentBody}\\n`\n\n\t\t\tawait fs.writeFile(agentOutputPath, content, 'utf-8')\n\t\t\tgetLogger().success(`Rendered swarm worker agent to ${agentOutputPath}`)\n\t\t\treturn true\n\t\t} catch (error) {\n\t\t\t// Intentional graceful degradation: setupSwarm reports workerAgentRendered=false\n\t\t\t// in its result rather than aborting the entire swarm setup.\n\t\t\tgetLogger().warn(\n\t\t\t\t`Failed to render swarm worker agent: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t\t)\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Copy .claude/agents/ from the epic worktree to each child worktree.\n\t *\n\t * Child workers need local access to agent files (used via --append-system-prompt-file).\n\t * Without this copy, child worktrees lack the rendered agent files since they only\n\t * exist in the epic worktree after renderSwarmAgents/renderSwarmWorkerAgent.\n\t */\n\tasync copyAgentsToChildWorktrees(\n\t\tepicWorktreePath: string,\n\t\tchildWorktrees: SwarmSetupResult['childWorktrees'],\n\t): Promise<void> {\n\t\tconst sourceDir = path.join(epicWorktreePath, '.claude', 'agents')\n\n\t\tif (!await fs.pathExists(sourceDir)) {\n\t\t\tgetLogger().warn('No .claude/agents/ directory in epic worktree to copy')\n\t\t\treturn\n\t\t}\n\n\t\tconst successfulChildren = childWorktrees.filter((c) => c.success)\n\n\t\tawait Promise.all(successfulChildren.map(async (child) => {\n\t\t\ttry {\n\t\t\t\tconst targetDir = path.join(child.worktreePath, '.claude', 'agents')\n\t\t\t\tawait fs.copy(sourceDir, targetDir, { overwrite: true })\n\t\t\t\tgetLogger().debug(`Copied .claude/agents/ to ${child.worktreePath}`)\n\t\t\t} catch (error) {\n\t\t\t\t// Non-fatal: worker can fall back to epic worktree path\n\t\t\t\tgetLogger().warn(\n\t\t\t\t\t`Failed to copy agents to child worktree ${child.issueId}: ${error instanceof Error ? error.message : 'Unknown error'}`,\n\t\t\t\t)\n\t\t\t}\n\t\t}))\n\n\t\tgetLogger().success(`Copied agents to ${successfulChildren.length} child worktrees`)\n\t}\n\n\t/**\n\t * Run the full swarm setup: child worktrees, agents, and worker agent.\n\t *\n\t * The epic worktree already exists (created by `il start`).\n\t */\n\tasync setupSwarm(\n\t\tepicIssueNumber: string | number,\n\t\tepicBranch: string,\n\t\tepicWorktreePath: string,\n\t\tchildIssues: SwarmChildIssue[],\n\t\tmainWorktreePath: string,\n\t\tissueTrackerName: string,\n\t\tsettings?: IloomSettings,\n\t): Promise<SwarmSetupResult> {\n\t\t// 1. Create child worktrees (with per-loom MCP config generation)\n\t\tconst childWorktrees = await this.createChildWorktrees(\n\t\t\tchildIssues,\n\t\t\tepicBranch,\n\t\t\tepicWorktreePath,\n\t\t\tmainWorktreePath,\n\t\t\tepicIssueNumber,\n\t\t\tissueTrackerName,\n\t\t\tsettings,\n\t\t)\n\n\t\t// 2. Render swarm agents to epic worktree's .claude/ directory (returns metadata)\n\t\tconst { renderedFiles: agentsRendered, metadata: agentMetadata } =\n\t\t\tawait this.renderSwarmAgents(epicWorktreePath)\n\n\t\t// 3. Render the swarm worker agent file with agent metadata\n\t\tconst workerAgentRendered = await this.renderSwarmWorkerAgent(\n\t\t\tepicWorktreePath,\n\t\t\tagentMetadata,\n\t\t)\n\n\t\t// 4. Copy .claude/agents/ from epic worktree to each child worktree\n\t\tawait this.copyAgentsToChildWorktrees(epicWorktreePath, childWorktrees)\n\n\t\tconst successCount = childWorktrees.filter((c) => c.success).length\n\t\tconst failCount = childWorktrees.filter((c) => !c.success).length\n\n\t\tgetLogger().success(\n\t\t\t`Swarm setup complete: ${successCount} child worktrees` +\n\t\t\t\t(failCount > 0 ? ` (${failCount} failed)` : ''),\n\t\t)\n\n\t\treturn {\n\t\t\tepicWorktreePath,\n\t\t\tepicBranch,\n\t\t\tchildWorktrees,\n\t\t\tagentsRendered,\n\t\t\tworkerAgentRendered,\n\t\t}\n\t}\n}\n","import fs from 'fs-extra'\nimport path from 'path'\nimport fg from 'fast-glob'\n\n/**\n * Detect the primary programming language of a project by checking for common project files.\n * Checks are performed in priority order; the first match wins.\n * All errors are caught and return 'unknown' — this function is non-blocking.\n */\nexport async function detectProjectLanguage(projectPath: string): Promise<string> {\n try {\n // 1. package.json → check for 'typescript' in deps/devDeps → 'typescript' or 'javascript'\n const packageJsonPath = path.join(projectPath, 'package.json')\n if (await fs.pathExists(packageJsonPath)) {\n try {\n const pkg = await fs.readJson(packageJsonPath) as {\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n }\n const allDeps = { ...pkg.dependencies, ...pkg.devDependencies }\n return 'typescript' in allDeps ? 'typescript' : 'javascript'\n } catch {\n return 'javascript'\n }\n }\n\n // 2. Cargo.toml → 'rust'\n if (await fs.pathExists(path.join(projectPath, 'Cargo.toml'))) {\n return 'rust'\n }\n\n // 3. go.mod → 'go'\n if (await fs.pathExists(path.join(projectPath, 'go.mod'))) {\n return 'go'\n }\n\n // 4. pyproject.toml | setup.py | requirements.txt → 'python'\n for (const file of ['pyproject.toml', 'setup.py', 'requirements.txt']) {\n if (await fs.pathExists(path.join(projectPath, file))) {\n return 'python'\n }\n }\n\n // 5. Gemfile → 'ruby'\n if (await fs.pathExists(path.join(projectPath, 'Gemfile'))) {\n return 'ruby'\n }\n\n // 6. pom.xml | build.gradle | build.gradle.kts → 'java'\n for (const file of ['pom.xml', 'build.gradle', 'build.gradle.kts']) {\n if (await fs.pathExists(path.join(projectPath, file))) {\n return 'java'\n }\n }\n\n // 7. *.csproj via glob → 'csharp'\n const csprojFiles = await fg('*.csproj', { cwd: projectPath, dot: false })\n if (csprojFiles.length > 0) {\n return 'csharp'\n }\n\n // 8. Default\n return 'unknown'\n } catch {\n return 'unknown'\n }\n}\n"],"mappings":"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","names":["path","fs","_a","path","fs","path","fs","fs","path","path","fs"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/claude.ts"],"sourcesContent":["/* global AbortSignal */\nimport { execa, type ExecaChildProcess } from 'execa'\nimport { existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { createHash, randomUUID } from 'node:crypto'\nimport { logger } from './logger.js'\nimport { getLogger } from './logger-context.js'\nimport { openTerminalWindow } from './terminal.js'\n\n/**\n * Generate a deterministic UUID v5 from a worktree path\n * Uses SHA1 hash with URL namespace to create a consistent session ID\n * that can be used to resume Claude Code sessions\n */\nexport function generateDeterministicSessionId(worktreePath: string): string {\n\t// UUID v5 namespace for URLs (RFC 4122)\n\tconst URL_NAMESPACE = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'\n\n\t// Create SHA1 hash of namespace + path\n\tconst hash = createHash('sha1')\n\n\t// Convert namespace UUID to bytes\n\tconst namespaceBytes = Buffer.from(URL_NAMESPACE.replace(/-/g, ''), 'hex')\n\thash.update(namespaceBytes)\n\thash.update(worktreePath)\n\n\tconst digest = hash.digest()\n\n\t// Format as UUID v5:\n\t// - Set version (bits 12-15 of time_hi_and_version) to 5\n\t// - Set variant (bits 6-7 of clock_seq_hi_and_reserved) to binary 10\n\tconst bytes = Array.from(digest.subarray(0, 16))\n\n\t// Set version to 5 (byte 6, high nibble)\n\tconst byte6 = bytes[6] ?? 0\n\tbytes[6] = (byte6 & 0x0f) | 0x50\n\n\t// Set variant to RFC 4122 (byte 8, high 2 bits = 10)\n\tconst byte8 = bytes[8] ?? 0\n\tbytes[8] = (byte8 & 0x3f) | 0x80\n\n\t// Format as UUID string\n\tconst hex = Buffer.from(bytes).toString('hex')\n\treturn `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`\n}\n\n/**\n * Generate a random UUID v4 for session ID\n * Uses crypto.randomUUID() for cryptographically secure random UUID generation\n * Used to create unique session IDs for each loom, enabling fresh Claude sessions\n */\nexport function generateRandomSessionId(): string {\n\treturn randomUUID()\n}\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\tsessionId?: string // Session ID for Claude Code resume support (must be valid UUID)\n\tnoSessionPersistence?: boolean // Prevent session data from being saved to disk (for utility operations)\n\toutputFormat?: 'json' | 'stream-json' | 'text' // Output format for Claude CLI (headless mode)\n\tverbose?: boolean // Enable verbose output (headless mode) - defaults to true when headless\n\tjsonMode?: 'json' | 'stream' // JSON output mode: 'json' for final object, 'stream' for real-time JSONL\n\tpassthroughStdout?: boolean // In headless mode, pipe stdout to process.stdout instead of capturing\n\tenv?: Record<string, string> // Additional environment variables to pass to the Claude process\n\tsignal?: AbortSignal // Optional AbortSignal for graceful termination of the Claude process\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, sessionId, noSessionPersistence, outputFormat, verbose, jsonMode, passthroughStdout, env: extraEnv, signal } = options\n\tconst log = getLogger()\n\n\t// Build command arguments\n\tconst args: string[] = []\n\n\tif (headless) {\n\t\targs.push('-p')\n\n\t\t// Use user-provided outputFormat or default to stream-json for progress tracking\n\t\tconst effectiveOutputFormat = outputFormat ?? 'stream-json'\n\t\targs.push('--output-format', effectiveOutputFormat)\n\n\t\t// Use user-provided verbose setting or default to true\n\t\tif (verbose !== false) {\n\t\t\targs.push('--verbose')\n\t\t}\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\t// Add --session-id flag if provided (enables Claude Code session resume)\n\tif (sessionId) {\n\t\targs.push('--session-id', sessionId)\n\t}\n\n\t// Add --no-session-persistence flag if requested (for utility operations that don't need session persistence)\n\t// Note: --no-session-persistence can only be used with --print mode (-p), which is only added in headless mode\n\tif (noSessionPersistence && headless) {\n\t\targs.push('--no-session-persistence')\n\t}\n\n\t// Set CLAUDECODE=0 to prevent Claude from detecting it's running inside Claude Code\n\tconst claudeEnv = { ...process.env, CLAUDECODE: '0' }\n\n\t// Helper to attach AbortSignal to a subprocess for graceful termination\n\tfunction attachAbortSignal(subprocess: ExecaChildProcess): void {\n\t\tif (!signal) return\n\t\tconst onAbort = (): void => {\n\t\t\tsubprocess.kill('SIGTERM')\n\t\t}\n\t\tsignal.addEventListener('abort', onAbort, { once: true })\n\t\tsubprocess.on('exit', (): void => {\n\t\t\tsignal.removeEventListener('abort', onAbort)\n\t\t})\n\t}\n\n\ttry {\n\t\tif (headless && passthroughStdout) {\n\t\t\t// Headless + passthrough: Claude's stdout goes directly to process.stdout\n\t\t\t// Used for --json-stream where JSONL must reach the caller's stdout\n\t\t\tconst subprocess = execa('claude', args, {\n\t\t\t\tinput: prompt,\n\t\t\t\ttimeout: 0,\n\t\t\t\t...(addDir && { cwd: addDir }),\n\t\t\t\tenv: { ...claudeEnv, ...extraEnv }, // CLAUDECODE=0 + any extra env vars\n\t\t\t\tstdio: ['pipe', 'inherit', 'pipe'], // stdin: pipe (for prompt), stdout: inherit (passthrough), stderr: pipe (capture errors)\n\t\t\t})\n\n\t\t\tattachAbortSignal(subprocess)\n\t\t\ttry {\n\t\t\t\tawait subprocess\n\t\t\t} catch (err) {\n\t\t\t\tif (signal?.aborted) return\n\t\t\t\tthrow err\n\t\t\t}\n\t\t\treturn // No output to return - it went directly to stdout\n\t\t}\n\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\tenv: { ...claudeEnv, ...extraEnv }, // CLAUDECODE=0 + any extra env vars\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\t\t\tattachAbortSignal(subprocess)\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 (jsonMode === 'stream') {\n\t\t\t\t\t\t// --json-stream: Output raw JSONL to stdout immediately\n\t\t\t\t\t\tprocess.stdout.write(text)\n\t\t\t\t\t} else if (jsonMode === 'json') {\n\t\t\t\t\t\t// --json: Suppress all progress output (will return final JSON)\n\t\t\t\t\t\t// Do nothing - just accumulate in buffer\n\t\t\t\t\t} else if (isDebugMode) {\n\t\t\t\t\t\tlog.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\tlog.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\tlog.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\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\tlet result: any\n\t\t\ttry {\n\t\t\t\tresult = await subprocess\n\t\t\t} catch (subprocessError) {\n\t\t\t\t// If aborted intentionally, do not treat as an error\n\t\t\t\tif (signal?.aborted) return\n\t\t\t\tthrow subprocessError\n\t\t\t}\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 (skip for json modes)\n\t\t\t\tif (!isDebugMode && !jsonMode) {\n\t\t\t\t\tlog.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\tlog.stdout.write(result.stdout)\n\t\t\t\t\tif (result.stdout && !result.stdout.endsWith('\\n')) {\n\t\t\t\t\t\tlog.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\tlog.stdout.write('🤖 .')\n\t\t\t\t\tlog.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// First attempt: capture stderr to detect session ID conflicts\n\t\t\t// stdin/stdout inherit for interactivity, stderr captured for error detection\n\t\t\ttry {\n\t\t\t\tconst interactiveSubprocess = execa('claude', [...args, '--', prompt], {\n\t\t\t\t\t...(addDir && { cwd: addDir }),\n\t\t\t\t\tstdio: ['inherit', 'inherit', 'pipe'], // Capture stderr to detect session conflicts\n\t\t\t\t\ttimeout: 0, // Disable timeout\n\t\t\t\t\tverbose: logger.isDebugEnabled(),\n\t\t\t\t\tenv: { ...claudeEnv, ...extraEnv }, // CLAUDECODE=0 + any extra env vars\n\t\t\t\t})\n\t\t\t\tattachAbortSignal(interactiveSubprocess)\n\t\t\t\ttry {\n\t\t\t\t\tawait interactiveSubprocess\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (signal?.aborted) return\n\t\t\t\t\tthrow err\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t} catch (interactiveError) {\n\t\t\t\tif (signal?.aborted) return\n\t\t\t\tconst interactiveExecaError = interactiveError as { stderr?: string; message?: string }\n\t\t\t\tconst interactiveErrorMessage = interactiveExecaError.stderr ?? interactiveExecaError.message ?? ''\n\n\t\t\t\t// Check for session ID conflict\n\t\t\t\tconst sessionMatch = interactiveErrorMessage.match(/Session ID ([0-9a-f-]+) is already in use/i)\n\t\t\t\tconst conflictSessionId = sessionMatch?.[1]\n\t\t\t\tif (sessionMatch && sessionId && conflictSessionId) {\n\t\t\t\t\tlog.debug(`Session ID ${conflictSessionId} already in use, retrying with --resume`)\n\n\t\t\t\t\t// Rebuild args with --resume instead of --session-id\n\t\t\t\t\tconst resumeArgs = args.filter((arg, idx) => {\n\t\t\t\t\t\tif (arg === '--session-id') return false\n\t\t\t\t\t\tif (idx > 0 && args[idx - 1] === '--session-id') return false\n\t\t\t\t\t\treturn true\n\t\t\t\t\t})\n\t\t\t\t\tresumeArgs.push('--resume', conflictSessionId)\n\n\t\t\t\t\t// Retry with full stdio inherit for proper interactive experience\n\t\t\t\t\t// Note: When using --resume, we omit the prompt since the session already has context\n\t\t\t\t\tconst resumeSubprocess = execa('claude', resumeArgs, {\n\t\t\t\t\t\t...(addDir && { cwd: addDir }),\n\t\t\t\t\t\tstdio: 'inherit',\n\t\t\t\t\t\ttimeout: 0,\n\t\t\t\t\t\tverbose: logger.isDebugEnabled(),\n\t\t\t\t\t\tenv: claudeEnv,\n\t\t\t\t\t})\n\t\t\t\t\tattachAbortSignal(resumeSubprocess)\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait resumeSubprocess\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tif (signal?.aborted) return\n\t\t\t\t\t\tthrow err\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// Not a session conflict, re-throw\n\t\t\t\tthrow interactiveError\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\t// If aborted intentionally, do not treat as an error\n\t\tif (signal?.aborted) return\n\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\tconst errorMessage = execaError.stderr ?? execaError.message ?? 'Unknown Claude CLI error'\n\n\t\t// Check for \"Session ID ... is already in use\" error and retry with --resume\n\t\tconst sessionInUseMatch = errorMessage.match(/Session ID ([0-9a-f-]+) is already in use/i)\n\t\tconst extractedSessionId = sessionInUseMatch?.[1]\n\t\tif (sessionInUseMatch && sessionId && extractedSessionId) {\n\t\t\tlog.debug(`Session ID ${extractedSessionId} already in use, retrying with --resume`)\n\n\t\t\t// Rebuild args with --resume instead of --session-id\n\t\t\tconst resumeArgs = args.filter((arg, idx) => {\n\t\t\t\t// Filter out --session-id and its value\n\t\t\t\tif (arg === '--session-id') return false\n\t\t\t\tif (idx > 0 && args[idx - 1] === '--session-id') return false\n\t\t\t\treturn true\n\t\t\t})\n\t\t\tresumeArgs.push('--resume', extractedSessionId)\n\n\t\t\ttry {\n\t\t\t\tif (headless) {\n\t\t\t\t\tconst isDebugMode = logger.isDebugEnabled()\n\t\t\t\t\t// Note: In headless mode, we still need to pass the prompt even with --resume\n\t\t\t\t\t// because there's no interactive input mechanism\n\t\t\t\t\tconst execaOptions = {\n\t\t\t\t\t\tinput: prompt,\n\t\t\t\t\t\ttimeout: 0,\n\t\t\t\t\t\t...(addDir && { cwd: addDir }),\n\t\t\t\t\t\tverbose: isDebugMode,\n\t\t\t\t\t\tenv: claudeEnv,\n\t\t\t\t\t\t...(isDebugMode && { stdio: ['pipe', 'pipe', 'pipe'] as const }),\n\t\t\t\t\t}\n\n\t\t\t\t\tconst subprocess = execa('claude', resumeArgs, execaOptions)\n\t\t\t\t\tconst isJsonStreamFormat = resumeArgs.includes('--output-format') && resumeArgs.includes('stream-json')\n\n\t\t\t\t\tlet outputBuffer = ''\n\t\t\t\t\tlet isStreaming = false\n\t\t\t\t\tlet isFirstProgress = true\n\t\t\t\t\tif (subprocess.stdout && typeof subprocess.stdout.on === 'function') {\n\t\t\t\t\t\tisStreaming = true\n\t\t\t\t\t\tsubprocess.stdout.on('data', (chunk: Buffer) => {\n\t\t\t\t\t\t\tconst text = chunk.toString()\n\t\t\t\t\t\t\toutputBuffer += text\n\t\t\t\t\t\t\tif (jsonMode === 'stream') {\n\t\t\t\t\t\t\t\tprocess.stdout.write(text)\n\t\t\t\t\t\t\t} else if (jsonMode === 'json') {\n\t\t\t\t\t\t\t\t// Suppress progress output for json mode\n\t\t\t\t\t\t\t} else if (isDebugMode) {\n\t\t\t\t\t\t\t\tlog.stdout.write(text)\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tif (isFirstProgress) {\n\t\t\t\t\t\t\t\t\tlog.stdout.write('🤖 .')\n\t\t\t\t\t\t\t\t\tisFirstProgress = false\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tlog.stdout.write('.')\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\n\t\t\t\t\tconst result = await subprocess\n\n\t\t\t\t\tif (isStreaming) {\n\t\t\t\t\t\tconst rawOutput = outputBuffer.trim()\n\t\t\t\t\t\tif (!isDebugMode && !jsonMode) {\n\t\t\t\t\t\t\tlog.stdout.write('\\n')\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn isJsonStreamFormat ? parseJsonStreamOutput(rawOutput) : rawOutput\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (isDebugMode) {\n\t\t\t\t\t\t\tlog.stdout.write(result.stdout)\n\t\t\t\t\t\t\tif (result.stdout && !result.stdout.endsWith('\\n')) {\n\t\t\t\t\t\t\t\tlog.stdout.write('\\n')\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlog.stdout.write('🤖 .')\n\t\t\t\t\t\t\tlog.stdout.write('\\n')\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst rawOutput = result.stdout.trim()\n\t\t\t\t\t\treturn isJsonStreamFormat ? parseJsonStreamOutput(rawOutput) : rawOutput\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Note: When using --resume, we omit the prompt since the session already has context\n\t\t\t\t\tawait execa('claude', resumeArgs, {\n\t\t\t\t\t\t...(addDir && { cwd: addDir }),\n\t\t\t\t\t\tstdio: 'inherit',\n\t\t\t\t\t\ttimeout: 0,\n\t\t\t\t\t\tverbose: logger.isDebugEnabled(),\n\t\t\t\t\t\tenv: claudeEnv,\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} catch (retryError) {\n\t\t\t\tconst retryExecaError = retryError as { stderr?: string; message?: string }\n\t\t\t\tconst retryErrorMessage = retryExecaError.stderr ?? retryExecaError.message ?? 'Unknown Claude CLI error'\n\t\t\t\tthrow new Error(`Claude CLI error: ${retryErrorMessage}`)\n\t\t\t}\n\t\t}\n\n\t\t// Re-throw with more context\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// 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: string | 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\tnoSessionPersistence: true, // Utility operation - don't persist session\n\t\t\tenv: { CLAUDE_CODE_SIMPLE: '1' }, // Minimal mode - no MCP, hooks, or CLAUDE.md loading\n\t\t})) as string\n\n\t\t// Normalize to lowercase for consistency (Linear IDs are uppercase but branches should be lowercase)\n\t\tconst branchName = result.trim().toLowerCase()\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}`.toLowerCase()\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}`.toLowerCase()\n\t}\n}\n\n/**\n * Validate branch name format\n * Check format: {prefix}/issue-{number}__{description}\n * Uses case-insensitive matching for issue number (Linear uses uppercase like MARK-1)\n */\nfunction isValidBranchName(name: string, issueNumber: string | number): boolean {\n\tconst pattern = new RegExp(`^(feat|fix|docs|refactor|test|chore)/issue-${issueNumber}__[a-z0-9-]+$`, 'i')\n\treturn pattern.test(name) && name.length <= 50\n}\n"],"mappings":"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","names":[]}