@iloom/cli 0.9.2 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +160 -41
- package/dist/{BranchNamingService-K6XNWQ6C.js → BranchNamingService-25KSZAEM.js} +2 -2
- package/dist/ClaudeContextManager-66GR4BGM.js +14 -0
- package/dist/ClaudeService-7KM5NA5Z.js +13 -0
- package/dist/{GitHubService-TGWJN4V4.js → GitHubService-MEHKHUQP.js} +4 -4
- package/dist/IssueTrackerFactory-NG53YX5S.js +14 -0
- package/dist/{LoomLauncher-73NXL2CL.js → LoomLauncher-TDLZSYG2.js} +9 -9
- package/dist/{MetadataManager-W3C54UYT.js → MetadataManager-5QZSTKNN.js} +2 -2
- package/dist/{ProjectCapabilityDetector-N5L7T4IY.js → ProjectCapabilityDetector-5KSYUTBJ.js} +3 -3
- package/dist/{PromptTemplateManager-36YLQRHP.js → PromptTemplateManager-YOE2SIPG.js} +2 -2
- package/dist/README.md +160 -41
- package/dist/{SettingsManager-AW3JTJHD.js → SettingsManager-FNKCOZMQ.js} +4 -2
- package/dist/agents/iloom-artifact-reviewer.md +11 -0
- package/dist/agents/iloom-code-reviewer.md +14 -0
- package/dist/agents/iloom-issue-analyze-and-plan.md +55 -12
- package/dist/agents/iloom-issue-analyzer.md +49 -6
- package/dist/agents/iloom-issue-complexity-evaluator.md +47 -6
- package/dist/agents/iloom-issue-enhancer.md +86 -7
- package/dist/agents/iloom-issue-implementer.md +48 -7
- package/dist/agents/iloom-issue-planner.md +115 -62
- package/dist/{build-THZI572G.js → build-VHGEMXBA.js} +9 -9
- package/dist/chunk-4232AHNQ.js +35 -0
- package/dist/chunk-4232AHNQ.js.map +1 -0
- package/dist/chunk-4E7LCFUG.js +24 -0
- package/dist/chunk-4E7LCFUG.js.map +1 -0
- package/dist/{chunk-AR5QKYNE.js → chunk-4FGEGQW4.js} +4 -4
- package/dist/{chunk-R4YWBGY6.js → chunk-5FJWO4IT.js} +67 -22
- package/dist/chunk-5FJWO4IT.js.map +1 -0
- package/dist/{chunk-VPTAX5TR.js → chunk-5RPBYK5Q.js} +35 -30
- package/dist/chunk-5RPBYK5Q.js.map +1 -0
- package/dist/{chunk-YKFCCV6S.js → chunk-63QWFWH3.js} +7 -7
- package/dist/chunk-63QWFWH3.js.map +1 -0
- package/dist/{chunk-RI2YL6TK.js → chunk-7VHJNVLF.js} +80 -23
- package/dist/chunk-7VHJNVLF.js.map +1 -0
- package/dist/{chunk-B7U6OKUR.js → chunk-C6HNNJIV.js} +11 -3
- package/dist/chunk-C6HNNJIV.js.map +1 -0
- package/dist/{chunk-A7NJF73J.js → chunk-CVCTIDDK.js} +4 -4
- package/dist/{chunk-Z2TWEXR7.js → chunk-E6KOWMKA.js} +6 -6
- package/dist/chunk-E6KOWMKA.js.map +1 -0
- package/dist/{chunk-3I4ONZRT.js → chunk-EVPZFV3K.js} +10 -10
- package/dist/chunk-EVPZFV3K.js.map +1 -0
- package/dist/{chunk-IZIYLYPK.js → chunk-G5V75JD5.js} +2 -2
- package/dist/chunk-GRISNU6G.js +651 -0
- package/dist/chunk-GRISNU6G.js.map +1 -0
- package/dist/chunk-HEXKPKCK.js +1396 -0
- package/dist/chunk-HEXKPKCK.js.map +1 -0
- package/dist/{chunk-TC7APDKU.js → chunk-I5T677EA.js} +2 -2
- package/dist/{chunk-KBEIQP4G.js → chunk-KB64WNBZ.js} +43 -3
- package/dist/chunk-KB64WNBZ.js.map +1 -0
- package/dist/{chunk-NWMORW3U.js → chunk-KIK2ZFAL.js} +2 -2
- package/dist/{chunk-CWRI4JC3.js → chunk-KKV5WH5M.js} +30 -31
- package/dist/chunk-KKV5WH5M.js.map +1 -0
- package/dist/{chunk-DGG2VY7B.js → chunk-KVHIAWVT.js} +9 -9
- package/dist/chunk-KVHIAWVT.js.map +1 -0
- package/dist/{chunk-OFDN5NKS.js → chunk-KXDRI47U.js} +69 -12
- package/dist/chunk-KXDRI47U.js.map +1 -0
- package/dist/{chunk-NUACL52E.js → chunk-LLHXQS3C.js} +2 -2
- package/dist/chunk-LUKXJSRI.js +73 -0
- package/dist/chunk-LUKXJSRI.js.map +1 -0
- package/dist/{chunk-TL72BGP6.js → chunk-MORRVYPT.js} +2 -2
- package/dist/chunk-OTGH2HRS.js +1427 -0
- package/dist/chunk-OTGH2HRS.js.map +1 -0
- package/dist/{chunk-7ZEHSSUP.js → chunk-P4O6EH46.js} +4 -4
- package/dist/{chunk-KAYXR544.js → chunk-QVLPWNE3.js} +2 -2
- package/dist/chunk-QZWEJVWV.js +207 -0
- package/dist/chunk-QZWEJVWV.js.map +1 -0
- package/dist/chunk-RJ3VBUFK.js +781 -0
- package/dist/chunk-RJ3VBUFK.js.map +1 -0
- package/dist/chunk-RSYT7MVI.js +202 -0
- package/dist/chunk-RSYT7MVI.js.map +1 -0
- package/dist/{chunk-6IIL5M2L.js → chunk-S7PZA6IV.js} +10 -8
- package/dist/{chunk-6IIL5M2L.js.map → chunk-S7PZA6IV.js.map} +1 -1
- package/dist/chunk-SKSYYBCU.js +229 -0
- package/dist/chunk-SKSYYBCU.js.map +1 -0
- package/dist/{chunk-ULSWCPQG.js → chunk-SWSJWA2S.js} +476 -5
- package/dist/chunk-SWSJWA2S.js.map +1 -0
- package/dist/{chunk-KXGQYLFZ.js → chunk-UKBAJ2QQ.js} +61 -7
- package/dist/chunk-UKBAJ2QQ.js.map +1 -0
- package/dist/{chunk-FO5GGFOV.js → chunk-UR5DGNUO.js} +71 -9
- package/dist/chunk-UR5DGNUO.js.map +1 -0
- package/dist/{chunk-QN47QVBX.js → chunk-UUEW5KWB.js} +1 -1
- package/dist/chunk-UUEW5KWB.js.map +1 -0
- package/dist/{chunk-4CO6KG5S.js → chunk-VG45TUYK.js} +53 -7
- package/dist/{chunk-4CO6KG5S.js.map → chunk-VG45TUYK.js.map} +1 -1
- package/dist/{chunk-4LKGCFGG.js → chunk-WWKOVDWC.js} +2 -2
- package/dist/{chunk-KJTVU3HZ.js → chunk-WXIM2WS7.js} +8 -8
- package/dist/chunk-WXIM2WS7.js.map +1 -0
- package/dist/{chunk-VOGGLPG5.js → chunk-YQ57ORTV.js} +14 -1
- package/dist/chunk-YQ57ORTV.js.map +1 -0
- package/dist/{chunk-SOSQILHO.js → chunk-ZNMPGMHY.js} +44 -797
- package/dist/chunk-ZNMPGMHY.js.map +1 -0
- package/dist/{claude-TP2QO3BU.js → claude-7GGEWVEM.js} +2 -2
- package/dist/{cleanup-PJRIFFU4.js → cleanup-6PVAC4NI.js} +85 -34
- package/dist/cleanup-6PVAC4NI.js.map +1 -0
- package/dist/cli.js +630 -801
- package/dist/cli.js.map +1 -1
- package/dist/{commit-IVP3M4HG.js → commit-FZR5XDQG.js} +26 -23
- package/dist/commit-FZR5XDQG.js.map +1 -0
- package/dist/{compile-R2J65HBQ.js → compile-7ALJHZ4N.js} +9 -9
- package/dist/{contribute-VDZXHK5Y.js → contribute-5GKLK3BQ.js} +14 -6
- package/dist/contribute-5GKLK3BQ.js.map +1 -0
- package/dist/{dev-server-7F622OEO.js → dev-server-7SMIB7OF.js} +29 -15
- package/dist/dev-server-7SMIB7OF.js.map +1 -0
- package/dist/{feedback-E7VET7CL.js → feedback-G2GJFN2F.js} +18 -16
- package/dist/{feedback-E7VET7CL.js.map → feedback-G2GJFN2F.js.map} +1 -1
- package/dist/{git-2QDQ2X2S.js → git-GTLKAZRJ.js} +4 -4
- package/dist/hooks/iloom-hook.js +15 -0
- package/dist/ignite-H2O5Y5A2.js +34 -0
- package/dist/ignite-H2O5Y5A2.js.map +1 -0
- package/dist/index.d.ts +482 -58
- package/dist/index.js +1340 -44
- package/dist/index.js.map +1 -1
- package/dist/{init-676DHF6R.js → init-32YOKXRL.js} +57 -21
- package/dist/init-32YOKXRL.js.map +1 -0
- package/dist/{issues-PJSOLOBJ.js → issues-4UUAQ5K6.js} +61 -20
- package/dist/issues-4UUAQ5K6.js.map +1 -0
- package/dist/{lint-CJM7BAIM.js → lint-AAN2NZWG.js} +9 -9
- package/dist/mcp/harness-server.js +140 -0
- package/dist/mcp/harness-server.js.map +1 -0
- package/dist/mcp/issue-management-server.js +2599 -262
- package/dist/mcp/issue-management-server.js.map +1 -1
- package/dist/mcp/recap-server.js +144 -21
- package/dist/mcp/recap-server.js.map +1 -1
- package/dist/{neon-helpers-VVFFTLXE.js → neon-helpers-CQN2PB4S.js} +3 -3
- package/dist/neon-helpers-CQN2PB4S.js.map +1 -0
- package/dist/{open-544H7JF5.js → open-FXWW3VI4.js} +15 -15
- package/dist/open-FXWW3VI4.js.map +1 -0
- package/dist/{plan-Q7ELXDLC.js → plan-RQ5FPIGF.js} +358 -40
- package/dist/plan-RQ5FPIGF.js.map +1 -0
- package/dist/{projects-LH362JZQ.js → projects-2UOXFLNZ.js} +4 -4
- package/dist/prompts/CLAUDE.md +62 -0
- package/dist/prompts/init-prompt.txt +430 -34
- package/dist/prompts/issue-prompt.txt +473 -54
- package/dist/prompts/plan-prompt.txt +140 -19
- package/dist/prompts/pr-prompt.txt +44 -1
- package/dist/prompts/regular-prompt.txt +42 -1
- package/dist/prompts/session-summary-prompt.txt +14 -0
- package/dist/prompts/swarm-orchestrator-prompt.txt +464 -0
- package/dist/{rebase-YND35CIE.js → rebase-6NVLX5V7.js} +21 -12
- package/dist/rebase-6NVLX5V7.js.map +1 -0
- package/dist/{recap-3W7COH7D.js → recap-OMBOKJST.js} +47 -19
- package/dist/recap-OMBOKJST.js.map +1 -0
- package/dist/{run-QUXJKDQQ.js → run-BBXLRIZB.js} +15 -15
- package/dist/run-BBXLRIZB.js.map +1 -0
- package/dist/schema/package-iloom.schema.json +58 -0
- package/dist/schema/settings.schema.json +149 -15
- package/dist/{shell-QGECBLST.js → shell-RF7LTND5.js} +14 -7
- package/dist/shell-RF7LTND5.js.map +1 -0
- package/dist/{summary-G2T4452H.js → summary-WTQZ7XG2.js} +27 -25
- package/dist/summary-WTQZ7XG2.js.map +1 -0
- package/dist/{test-EA5NQFDC.js → test-SGO6I5Z7.js} +9 -9
- package/dist/{test-git-M7LSLEFL.js → test-git-XM4TM65W.js} +4 -4
- package/dist/test-jira-LDTOYFSD.js +96 -0
- package/dist/test-jira-LDTOYFSD.js.map +1 -0
- package/dist/{test-prefix-64NAAUON.js → test-prefix-GBO37XCN.js} +4 -4
- package/dist/{test-webserver-OK6Z5FJM.js → test-webserver-NZ3JTVLL.js} +6 -6
- package/dist/{vscode-AR5NNXXI.js → vscode-6XUGHJKL.js} +7 -7
- package/package.json +5 -1
- package/dist/ClaudeContextManager-HR5JQKAI.js +0 -14
- package/dist/ClaudeService-TK7FMC2X.js +0 -13
- package/dist/chunk-3I4ONZRT.js.map +0 -1
- package/dist/chunk-B7U6OKUR.js.map +0 -1
- package/dist/chunk-CWRI4JC3.js.map +0 -1
- package/dist/chunk-DGG2VY7B.js.map +0 -1
- package/dist/chunk-FJDRTVJX.js +0 -520
- package/dist/chunk-FJDRTVJX.js.map +0 -1
- package/dist/chunk-FO5GGFOV.js.map +0 -1
- package/dist/chunk-KBEIQP4G.js.map +0 -1
- package/dist/chunk-KJTVU3HZ.js.map +0 -1
- package/dist/chunk-KXGQYLFZ.js.map +0 -1
- package/dist/chunk-OFDN5NKS.js.map +0 -1
- package/dist/chunk-QN47QVBX.js.map +0 -1
- package/dist/chunk-R4YWBGY6.js.map +0 -1
- package/dist/chunk-RI2YL6TK.js.map +0 -1
- package/dist/chunk-SOSQILHO.js.map +0 -1
- package/dist/chunk-ULSWCPQG.js.map +0 -1
- package/dist/chunk-VOGGLPG5.js.map +0 -1
- package/dist/chunk-VPTAX5TR.js.map +0 -1
- package/dist/chunk-W6DP5RVR.js +0 -101
- package/dist/chunk-W6DP5RVR.js.map +0 -1
- package/dist/chunk-WHI5KEOX.js +0 -121
- package/dist/chunk-WHI5KEOX.js.map +0 -1
- package/dist/chunk-YKFCCV6S.js.map +0 -1
- package/dist/chunk-Z2TWEXR7.js.map +0 -1
- package/dist/cleanup-PJRIFFU4.js.map +0 -1
- package/dist/commit-IVP3M4HG.js.map +0 -1
- package/dist/contribute-VDZXHK5Y.js.map +0 -1
- package/dist/dev-server-7F622OEO.js.map +0 -1
- package/dist/ignite-IW35CDBD.js +0 -784
- package/dist/ignite-IW35CDBD.js.map +0 -1
- package/dist/init-676DHF6R.js.map +0 -1
- package/dist/issues-PJSOLOBJ.js.map +0 -1
- package/dist/open-544H7JF5.js.map +0 -1
- package/dist/plan-Q7ELXDLC.js.map +0 -1
- package/dist/rebase-YND35CIE.js.map +0 -1
- package/dist/recap-3W7COH7D.js.map +0 -1
- package/dist/run-QUXJKDQQ.js.map +0 -1
- package/dist/shell-QGECBLST.js.map +0 -1
- package/dist/summary-G2T4452H.js.map +0 -1
- /package/dist/{BranchNamingService-K6XNWQ6C.js.map → BranchNamingService-25KSZAEM.js.map} +0 -0
- /package/dist/{ClaudeContextManager-HR5JQKAI.js.map → ClaudeContextManager-66GR4BGM.js.map} +0 -0
- /package/dist/{ClaudeService-TK7FMC2X.js.map → ClaudeService-7KM5NA5Z.js.map} +0 -0
- /package/dist/{GitHubService-TGWJN4V4.js.map → GitHubService-MEHKHUQP.js.map} +0 -0
- /package/dist/{MetadataManager-W3C54UYT.js.map → IssueTrackerFactory-NG53YX5S.js.map} +0 -0
- /package/dist/{LoomLauncher-73NXL2CL.js.map → LoomLauncher-TDLZSYG2.js.map} +0 -0
- /package/dist/{ProjectCapabilityDetector-N5L7T4IY.js.map → MetadataManager-5QZSTKNN.js.map} +0 -0
- /package/dist/{PromptTemplateManager-36YLQRHP.js.map → ProjectCapabilityDetector-5KSYUTBJ.js.map} +0 -0
- /package/dist/{SettingsManager-AW3JTJHD.js.map → PromptTemplateManager-YOE2SIPG.js.map} +0 -0
- /package/dist/{claude-TP2QO3BU.js.map → SettingsManager-FNKCOZMQ.js.map} +0 -0
- /package/dist/{build-THZI572G.js.map → build-VHGEMXBA.js.map} +0 -0
- /package/dist/{chunk-AR5QKYNE.js.map → chunk-4FGEGQW4.js.map} +0 -0
- /package/dist/{chunk-A7NJF73J.js.map → chunk-CVCTIDDK.js.map} +0 -0
- /package/dist/{chunk-IZIYLYPK.js.map → chunk-G5V75JD5.js.map} +0 -0
- /package/dist/{chunk-TC7APDKU.js.map → chunk-I5T677EA.js.map} +0 -0
- /package/dist/{chunk-NWMORW3U.js.map → chunk-KIK2ZFAL.js.map} +0 -0
- /package/dist/{chunk-NUACL52E.js.map → chunk-LLHXQS3C.js.map} +0 -0
- /package/dist/{chunk-TL72BGP6.js.map → chunk-MORRVYPT.js.map} +0 -0
- /package/dist/{chunk-7ZEHSSUP.js.map → chunk-P4O6EH46.js.map} +0 -0
- /package/dist/{chunk-KAYXR544.js.map → chunk-QVLPWNE3.js.map} +0 -0
- /package/dist/{chunk-4LKGCFGG.js.map → chunk-WWKOVDWC.js.map} +0 -0
- /package/dist/{git-2QDQ2X2S.js.map → claude-7GGEWVEM.js.map} +0 -0
- /package/dist/{compile-R2J65HBQ.js.map → compile-7ALJHZ4N.js.map} +0 -0
- /package/dist/{neon-helpers-VVFFTLXE.js.map → git-GTLKAZRJ.js.map} +0 -0
- /package/dist/{lint-CJM7BAIM.js.map → lint-AAN2NZWG.js.map} +0 -0
- /package/dist/{projects-LH362JZQ.js.map → projects-2UOXFLNZ.js.map} +0 -0
- /package/dist/{test-EA5NQFDC.js.map → test-SGO6I5Z7.js.map} +0 -0
- /package/dist/{test-git-M7LSLEFL.js.map → test-git-XM4TM65W.js.map} +0 -0
- /package/dist/{test-prefix-64NAAUON.js.map → test-prefix-GBO37XCN.js.map} +0 -0
- /package/dist/{test-webserver-OK6Z5FJM.js.map → test-webserver-NZ3JTVLL.js.map} +0 -0
- /package/dist/{vscode-AR5NNXXI.js.map → vscode-6XUGHJKL.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/LoomManager.ts","../src/lib/VSCodeIntegration.ts","../src/lib/EnvironmentManager.ts","../src/lib/CLIIsolationManager.ts","../src/lib/DatabaseManager.ts"],"sourcesContent":["import path from 'path'\nimport fs from 'fs-extra'\nimport fg from 'fast-glob'\nimport { GitWorktreeManager } from './GitWorktreeManager.js'\nimport type { IssueTracker } from './IssueTracker.js'\nimport type { BranchNamingService } from './BranchNamingService.js'\nimport { EnvironmentManager } from './EnvironmentManager.js'\nimport { ClaudeContextManager } from './ClaudeContextManager.js'\nimport { ProjectCapabilityDetector } from './ProjectCapabilityDetector.js'\nimport { CLIIsolationManager } from './CLIIsolationManager.js'\nimport { VSCodeIntegration } from './VSCodeIntegration.js'\nimport { SettingsManager } from './SettingsManager.js'\nimport { MetadataManager, type WriteMetadataInput } from './MetadataManager.js'\nimport { branchExists, executeGitCommand, ensureRepositoryHasCommits, extractIssueNumber, isFileTrackedByGit, extractPRNumber, PLACEHOLDER_COMMIT_PREFIX, pushBranchToRemote, GitCommandError, fetchOrigin } from '../utils/git.js'\nimport { GitHubService } from './GitHubService.js'\nimport { generateRandomSessionId } from '../utils/claude.js'\nimport { installDependencies } from '../utils/package-manager.js'\nimport { generateColorFromBranchName, selectDistinctColor, hexToRgb, type ColorData } from '../utils/color.js'\nimport { detectDarkMode } from '../utils/terminal.js'\nimport { DatabaseManager } from './DatabaseManager.js'\nimport { loadEnvIntoProcess, findEnvFileForDatabaseUrl, isNoEnvFilesFoundError } from '../utils/env.js'\nimport type { Loom, CreateLoomInput } from '../types/loom.js'\nimport type { GitWorktree } from '../types/worktree.js'\nimport type { Issue, PullRequest } from '../types/index.js'\nimport { getLogger } from '../utils/logger-context.js'\nimport { PRManager } from './PRManager.js'\n\n/**\n * LoomManager orchestrates the creation and management of looms (isolated workspaces)\n * Bridges the gap between input validation and workspace operations\n */\nexport class LoomManager {\n private metadataManager: MetadataManager\n private githubService: GitHubService | undefined\n\n constructor(\n private gitWorktree: GitWorktreeManager,\n private issueTracker: IssueTracker,\n private branchNaming: BranchNamingService,\n private environment: EnvironmentManager,\n _claude: ClaudeContextManager, // Not stored - kept for DI compatibility, LoomLauncher creates its own\n private capabilityDetector: ProjectCapabilityDetector,\n private cliIsolation: CLIIsolationManager,\n private settings: SettingsManager,\n private database?: DatabaseManager,\n githubService?: GitHubService\n ) {\n this.metadataManager = new MetadataManager()\n this.githubService = githubService\n }\n\n /**\n * Get database branch name for a loom by reading its .env file\n * Returns null if database is not configured or branch cannot be determined\n *\n * @param loomPath - Path to the loom worktree\n */\n async getDatabaseBranchForLoom(loomPath: string): Promise<string | null> {\n if (!this.database) {\n return null\n }\n\n try {\n const envFilePath = path.join(loomPath, '.env')\n const settings = await this.settings.loadSettings()\n const databaseUrlVarName = settings.capabilities?.database?.databaseUrlEnvVarName ?? 'DATABASE_URL'\n\n // Get database connection string from loom's .env file\n const connectionString = await this.environment.getEnvVariable(envFilePath, databaseUrlVarName)\n\n if (!connectionString) {\n return null\n }\n\n return await this.database.getBranchNameFromConnectionString(connectionString, loomPath)\n } catch (error) {\n getLogger().debug(`Could not get database branch for loom at ${loomPath}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n return null\n }\n }\n\n /**\n * Create a new loom (isolated workspace)\n * Orchestrates worktree creation, environment setup, and Claude context generation\n * NEW: Checks for existing worktrees and reuses them if found\n */\n async createIloom(input: CreateLoomInput): Promise<Loom> {\n // 1. Fetch issue/PR data if needed\n getLogger().info('Fetching issue data...')\n const issueData = await this.fetchIssueData(input)\n\n // NEW: Check for existing worktree BEFORE generating branch name (for efficiency)\n if (input.type === 'issue' || input.type === 'epic' || input.type === 'pr' || input.type === 'branch') {\n getLogger().info('Checking for existing worktree...')\n const existing = await this.findExistingIloom(input, issueData)\n if (existing) {\n getLogger().success(`Found existing worktree, reusing: ${existing.path}`)\n return await this.reuseIloom(existing, input, issueData)\n }\n getLogger().info('No existing worktree found, creating new one...')\n }\n\n // 2. Generate or validate branch name\n getLogger().info('Preparing branch name...')\n const branchName = await this.prepareBranchName(input, issueData)\n\n // 3. Create git worktree (WITHOUT dependency installation)\n getLogger().info('Creating git worktree...')\n const worktreePath = await this.createWorktreeOnly(input, branchName, issueData)\n\n // 4. Load main .env variables into process.env (like bash script lines 336-339)\n this.loadMainEnvFile()\n\n // 5. Detect project capabilities\n const { capabilities, binEntries } = await this.capabilityDetector.detectCapabilities(worktreePath)\n\n // 6. Copy environment files (.env) - ALWAYS done regardless of capabilities\n await this.copyEnvironmentFiles(worktreePath)\n\n // 7. Copy Loom settings (settings.local.json) - ALWAYS done regardless of capabilities\n await this.copyIloomSettings(worktreePath)\n\n // 7.1. Copy iloom package local config (package.iloom.local.json)\n await this.copyIloomPackageLocal(worktreePath)\n\n // 7.5. Copy Claude settings (.claude/settings.local.json) - ALWAYS done regardless of capabilities\n await this.copyClaudeSettings(worktreePath)\n\n // 7.6. Copy gitignored files matching configured patterns\n await this.copyGitIgnoredFiles(worktreePath)\n\n // 8. Setup PORT environment variable - ONLY for web projects\n // Load base port from settings\n const settingsData = await this.settings.loadSettings()\n const basePort = settingsData.capabilities?.web?.basePort ?? 3000\n\n let port = basePort // default\n if (capabilities.includes('web')) {\n port = await this.setupPortForWeb(worktreePath, input, basePort)\n }\n\n // 9. Install dependencies AFTER environment setup (like bash script line 757-769)\n try {\n await installDependencies(worktreePath, true, true)\n } catch (error) {\n // Log warning but don't fail - matches bash script behavior\n getLogger().warn(`Failed to install dependencies: ${error instanceof Error ? error.message : 'Unknown error'}`, error)\n }\n\n // 10. Setup database branch if configured\n let databaseBranch: string | undefined = undefined\n if (this.database && !input.options?.skipDatabase) {\n try {\n const connectionString = await this.database.createBranchIfConfigured(\n branchName,\n worktreePath, // workspace path - checks all dotenv-flow files\n undefined, // cwd\n input.parentLoom?.databaseBranch // fromBranch - use parent's database branch for child looms\n )\n\n if (connectionString) {\n const varName = this.database.getConfiguredVariableName()\n const targetFile = await findEnvFileForDatabaseUrl(\n worktreePath,\n varName,\n isFileTrackedByGit,\n async (p) => fs.pathExists(p),\n async (p, v) => this.environment.getEnvVariable(p, v)\n )\n await this.environment.setEnvVar(\n path.join(worktreePath, targetFile),\n varName,\n connectionString\n )\n getLogger().success('Database branch configured')\n databaseBranch = branchName\n }\n } catch (error) {\n getLogger().error(\n `Failed to setup database branch: ${error instanceof Error ? error.message : 'Unknown error'}`\n )\n throw error // Database creation failures are fatal\n }\n }\n\n // 10. Setup CLI isolation if project has CLI capability\n // Skip in branch mode - branch mode workspaces don't have a built dist/cli.js\n let cliSymlinks: string[] | undefined = undefined\n if (capabilities.includes('cli') && input.type !== 'branch') {\n try {\n cliSymlinks = await this.cliIsolation.setupCLIIsolation(\n worktreePath,\n input.identifier,\n binEntries\n )\n } catch (error) {\n // Log warning but don't fail - matches dependency installation behavior\n getLogger().warn(\n `Failed to setup CLI isolation: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error\n )\n }\n }\n\n // 10.5. Handle github-draft-pr mode - push branch and create draft PR\n let draftPrNumber: number | undefined = undefined\n let draftPrUrl: string | undefined = undefined\n\n const mergeBehavior = settingsData.mergeBehavior ?? { mode: 'local' }\n\n if (mergeBehavior.mode === 'github-draft-pr' && (input.type === 'issue' || input.type === 'epic' || input.type === 'branch')) {\n const prManager = new PRManager(settingsData)\n\n // Fetch from origin to get latest remote branch state\n getLogger().info('Fetching from origin...')\n await executeGitCommand(['fetch', 'origin'], { cwd: worktreePath })\n\n // Check if remote branch already exists\n let remoteBranchExists = false\n try {\n await executeGitCommand(['rev-parse', '--verify', `origin/${branchName}`], { cwd: worktreePath })\n remoteBranchExists = true\n getLogger().info(`Remote branch origin/${branchName} already exists, resetting local to match...`)\n } catch (error: unknown) {\n // Only treat as \"branch doesn't exist\" if it's a GitCommandError with the expected error patterns\n // Git rev-parse returns exit code 128 for missing refs with messages like:\n // \"fatal: Needed a single revision\" or \"unknown revision\"\n if (error instanceof GitCommandError &&\n (error.stderr.includes('unknown revision') ||\n error.stderr.includes('Needed a single revision') ||\n error.stderr.includes('bad revision'))) {\n // Remote branch doesn't exist - this is the normal case for new branches\n getLogger().debug(`Remote branch origin/${branchName} does not exist`)\n } else {\n // Re-throw unexpected errors (e.g., git crash, permissions, lock file issues)\n throw error\n }\n }\n\n // If remote branch exists, reset local branch to match it (preserves previous work)\n if (remoteBranchExists) {\n await executeGitCommand(['reset', '--hard', `origin/${branchName}`], { cwd: worktreePath })\n await executeGitCommand(['branch', '--set-upstream-to', `origin/${branchName}`], { cwd: worktreePath })\n getLogger().success('Local branch reset to match remote')\n } else {\n // Only create placeholder commit if remote branch didn't exist\n // (if we reset to remote, we already have commits)\n getLogger().info('Creating placeholder commit for draft PR...')\n await executeGitCommand(\n [\n 'commit',\n '--allow-empty',\n '--no-verify',\n '-m',\n `${PLACEHOLDER_COMMIT_PREFIX} Temporary commit for draft PR (will be removed on finish)`\n ],\n { cwd: worktreePath }\n )\n getLogger().debug('Placeholder commit created')\n\n // Push branch to remote (required for draft PR creation)\n getLogger().info('Pushing branch to remote for draft PR...')\n await pushBranchToRemote(branchName, worktreePath, { dryRun: false })\n\n // Remove placeholder from local history - it only needs to exist on remote to keep draft PR open.\n await executeGitCommand(['reset', '--soft', 'HEAD~1'], { cwd: worktreePath })\n getLogger().debug('Placeholder commit removed from local branch (still on remote)')\n }\n\n // Check for existing draft PR before creating a new one\n const existingPR = await prManager.checkForExistingPR(branchName, worktreePath)\n\n if (existingPR) {\n // Reuse existing PR\n draftPrNumber = existingPR.number\n draftPrUrl = existingPR.url\n getLogger().success(`Found existing PR: ${existingPR.url}`)\n } else {\n // Generate PR title and body\n // For issue mode: use issue title and reference issue number\n // For branch mode: use branch name and generic description\n const prTitle = issueData?.title ?? `Work on ${branchName}`\n let prBody: string\n if (input.type === 'issue' || input.type === 'epic') {\n const issueBody = issueData?.body ? `\\n\\n## ${issueData.title}\\n\\n${issueData.body}` : ''\n prBody = `Fixes ${prManager.issuePrefix}${input.identifier}${issueBody}\\n\\n---\\n*This PR was created automatically by iloom.*`\n } else {\n prBody = `Branch: ${branchName}\\n\\n---\\n*This PR was created automatically by iloom.*`\n }\n\n // Create draft PR\n // For child looms, target the parent branch; otherwise use the configured main branch\n const draftBaseBranch = input.parentLoom?.branchName ?? settingsData.mainBranch ?? 'main'\n getLogger().info('Creating draft PR...')\n const prResult = await prManager.createDraftPR(\n branchName,\n prTitle,\n prBody,\n draftBaseBranch,\n worktreePath\n )\n\n draftPrNumber = prResult.number\n draftPrUrl = prResult.url\n getLogger().success(`Draft PR created: ${prResult.url}`)\n }\n }\n\n // 11. Select color with collision avoidance\n // Get hex colors in use from ALL stored looms across all projects (global collision detection)\n // This prevents color reuse across different repositories for the same user\n const allMetadata = await this.metadataManager.listAllMetadata()\n const usedHexColors: string[] = allMetadata\n .filter((metadata) => metadata.colorHex !== null)\n .map((metadata) => metadata.colorHex as string)\n\n // Detect dark mode and select appropriate color palette\n const themeMode = await detectDarkMode()\n\n // Select distinct color using hex-based comparison\n const colorData = selectDistinctColor(branchName, usedHexColors, themeMode)\n getLogger().debug(`Selected color ${colorData.hex} for branch ${branchName} (${usedHexColors.length} colors in use globally)`)\n\n // Apply color synchronization (terminal and VSCode) based on settings\n try {\n await this.applyColorSynchronization(worktreePath, branchName, colorData, settingsData, input.options)\n } catch (error) {\n // Log warning but don't fail - colors are cosmetic\n getLogger().warn(\n `Failed to apply color synchronization: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error\n )\n }\n\n // NEW: Move issue to In Progress (for new worktrees)\n if (input.type === 'issue' || input.type === 'epic') {\n try {\n getLogger().info('Moving issue to In Progress...')\n // Check if provider supports this optional method\n if (this.issueTracker.moveIssueToInProgress) {\n await this.issueTracker.moveIssueToInProgress(input.identifier as number)\n }\n } catch (error) {\n // Warn but don't fail - matches bash script behavior\n getLogger().warn(\n `Failed to move issue to In Progress: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error\n )\n }\n }\n\n // 11.5. Launch workspace components based on individual flags\n const enableClaude = input.options?.enableClaude !== false\n const enableCode = input.options?.enableCode !== false\n const enableDevServer = input.options?.enableDevServer !== false\n const enableTerminal = input.options?.enableTerminal ?? false\n const oneShot = input.options?.oneShot ?? 'default'\n const setArguments = input.options?.setArguments\n const executablePath = input.options?.executablePath\n\n // Only launch if at least one component is enabled\n if (enableClaude || enableCode || enableDevServer || enableTerminal) {\n const { LoomLauncher } = await import('./LoomLauncher.js')\n const { ClaudeContextManager } = await import('./ClaudeContextManager.js')\n\n // Create ClaudeContextManager with shared SettingsManager to ensure CLI overrides work\n const claudeContext = new ClaudeContextManager(undefined, undefined, this.settings)\n const launcher = new LoomLauncher(claudeContext, this.settings)\n\n await launcher.launchLoom({\n enableClaude,\n enableCode,\n enableDevServer,\n enableTerminal,\n worktreePath,\n branchName,\n port,\n capabilities,\n workflowType: input.type === 'branch' ? 'regular' : input.type === 'epic' ? 'issue' : input.type,\n identifier: input.identifier,\n ...(issueData?.title && { title: issueData.title }),\n oneShot,\n ...(setArguments && { setArguments }),\n ...(executablePath && { executablePath }),\n sourceEnvOnStart: settingsData.sourceEnvOnStart ?? false,\n colorTerminal: input.options?.colorTerminal ?? settingsData.colors?.terminal ?? true,\n colorHex: colorData.hex,\n })\n }\n\n // 12. Write loom metadata (spec section 3.1)\n // Derive description from issue/PR title or branch name\n const description = issueData?.title ?? branchName\n\n // Build issue/pr numbers arrays based on type\n // For PR workflows, extract issue number from branch name if present\n let issue_numbers: string[] = []\n let extractedIssueNum: string | null = null\n if (input.type === 'issue' || input.type === 'epic') {\n issue_numbers = [String(input.identifier)]\n } else if (input.type === 'pr') {\n extractedIssueNum = extractIssueNumber(branchName)\n if (extractedIssueNum) {\n issue_numbers = [extractedIssueNum]\n }\n }\n const pr_numbers: string[] = input.type === 'pr' ? [String(input.identifier)] : []\n\n // If a draft PR was created, add its number to pr_numbers\n // This ensures pr_numbers and prUrls are consistent (fixes #555)\n if (draftPrNumber && !pr_numbers.includes(String(draftPrNumber))) {\n pr_numbers.push(String(draftPrNumber))\n }\n\n // Generate random session ID for Claude Code resume support\n // Each loom gets a unique session ID, enabling fresh Claude sessions\n const sessionId = generateRandomSessionId()\n\n // Build issueUrls/prUrls based on workflow type\n // For PR workflows, construct issue URL by replacing /pull/N with /issues/M\n let issueUrls: Record<string, string> = {}\n if ((input.type === 'issue' || input.type === 'epic') && issueData?.url) {\n issueUrls = { [String(input.identifier)]: issueData.url }\n } else if (input.type === 'pr' && extractedIssueNum && issueData?.url) {\n const issueUrl = issueData.url.replace(`/pull/${input.identifier}`, `/issues/${extractedIssueNum}`)\n issueUrls = { [extractedIssueNum]: issueUrl }\n }\n // Include draft PR URL in prUrls if created\n const prUrls: Record<string, string> = draftPrNumber && draftPrUrl\n ? { [String(draftPrNumber)]: draftPrUrl }\n : input.type === 'pr' && issueData?.url\n ? { [String(input.identifier)]: issueData.url }\n : {}\n\n const metadataInput: WriteMetadataInput = {\n description,\n branchName,\n worktreePath,\n issueType: input.type,\n ...((input.type === 'issue' || input.type === 'epic') && { issueKey: this.issueTracker.normalizeIdentifier(input.identifier) }),\n issue_numbers,\n pr_numbers,\n issueTracker: this.issueTracker.providerName,\n colorHex: colorData.hex,\n sessionId,\n projectPath: this.gitWorktree.workingDirectory,\n issueUrls,\n prUrls,\n capabilities,\n ...(draftPrNumber && { draftPrNumber }),\n ...(input.options?.oneShot && { oneShot: input.options.oneShot }),\n ...(input.options?.childIssueNumbers && input.options.childIssueNumbers.length > 0 && { childIssueNumbers: input.options.childIssueNumbers }),\n ...(input.options?.childIssues && input.options.childIssues.length > 0 && { childIssues: input.options.childIssues }),\n ...(input.options?.dependencyMap && Object.keys(input.options.dependencyMap).length > 0 && { dependencyMap: input.options.dependencyMap }),\n ...(input.parentLoom && { parentLoom: input.parentLoom }),\n }\n await this.metadataManager.writeMetadata(worktreePath, metadataInput)\n\n // 13. Create and return loom metadata\n const loom: Loom = {\n id: this.generateLoomId(input),\n path: worktreePath,\n branch: branchName,\n type: input.type,\n identifier: input.identifier,\n port,\n description,\n createdAt: new Date(),\n lastAccessed: new Date(),\n ...(databaseBranch !== undefined && { databaseBranch }),\n ...(capabilities.length > 0 && { capabilities }),\n ...(Object.keys(binEntries).length > 0 && { binEntries }),\n ...(cliSymlinks && cliSymlinks.length > 0 && { cliSymlinks }),\n ...(issueData !== null && {\n issueData: {\n title: issueData.title,\n body: issueData.body,\n url: issueData.url,\n state: issueData.state,\n },\n }),\n }\n\n getLogger().success(`Created loom: ${loom.id} at ${loom.path}`)\n return loom\n }\n\n /**\n * Finish a loom (merge work and cleanup)\n * Not yet implemented - see Issue #7\n */\n async finishIloom(_identifier: string): Promise<void> {\n throw new Error('Not implemented - see Issue #7')\n }\n\n\n /**\n * List all active looms\n */\n async listLooms(): Promise<Loom[]> {\n const worktrees = await this.gitWorktree.listWorktrees()\n if (!worktrees) {\n return []\n }\n return await this.mapWorktreesToLooms(worktrees)\n }\n\n /**\n * Find a specific loom by identifier\n * Case-insensitive matching for Linear IDs (MARK-1 vs mark-1)\n */\n async findIloom(identifier: string): Promise<Loom | null> {\n const looms = await this.listLooms()\n const lowerIdentifier = identifier.toLowerCase()\n return (\n looms.find(\n h =>\n h.id.toLowerCase() === lowerIdentifier ||\n h.identifier.toString().toLowerCase() === lowerIdentifier ||\n h.branch.toLowerCase() === lowerIdentifier\n ) ?? null\n )\n }\n\n /**\n * Find child looms for a given parent loom\n * Child looms are worktrees created with the parent loom as their base\n *\n * @param parentBranchName - The parent loom's branch name\n * @returns Array of child loom worktrees\n */\n async findChildLooms(parentBranchName: string): Promise<GitWorktree[]> {\n try {\n const worktrees = await this.gitWorktree.listWorktrees()\n if (!worktrees) {\n return []\n }\n\n // Sanitize parent branch name the same way as in createWorktreeOnly (lines 361-363)\n const sanitizedBranchName = parentBranchName\n .replace(/\\//g, '-')\n .replace(/[^a-zA-Z0-9-_]/g, '-')\n\n // Child looms are in directory: {sanitizedBranchName}-looms/\n const pattern = `${sanitizedBranchName}-looms/`\n\n return worktrees.filter(wt => wt.path.includes(pattern))\n } catch (error) {\n getLogger().debug(`Failed to find child looms: ${error instanceof Error ? error.message : 'Unknown error'}`)\n return []\n }\n }\n\n /**\n * Check for child looms and warn user if any exist\n * This is useful before finishing or cleaning up a parent loom\n *\n * @param branchName - Optional branch name to check. If not provided, uses current branch.\n * @returns true if child looms were found, false otherwise\n */\n async checkAndWarnChildLooms(branchName?: string): Promise<boolean> {\n // Use provided branch name or get current branch\n let targetBranch: string | null | undefined = branchName\n if (!targetBranch) {\n const { getCurrentBranch } = await import('../utils/git.js')\n targetBranch = await getCurrentBranch()\n }\n\n // Skip if not on a branch\n if (!targetBranch) {\n return false\n }\n\n const childLooms = await this.findChildLooms(targetBranch)\n if (childLooms.length > 0) {\n getLogger().warn(`Found ${childLooms.length} child loom(s) that should be finished first:`)\n for (const child of childLooms) {\n getLogger().warn(` - ${child.path}`)\n }\n getLogger().warn('')\n getLogger().warn('To finish child looms:')\n for (const child of childLooms) {\n // Extract identifier from child branch for finish command\n // Check PR first since PR branches often contain issue numbers too\n const prMatch = child.branch.match(/_pr_(\\d+)/)\n const issueId = extractIssueNumber(child.branch)\n\n const childIdentifier = prMatch\n ? prMatch[1] // PR: use number\n : issueId ?? child.branch // Issue: use extracted ID (alphanumeric or numeric), or branch name\n\n getLogger().warn(` il finish ${childIdentifier}`)\n }\n getLogger().warn('')\n return true\n }\n\n return false\n }\n\n /**\n * Fetch issue/PR data based on input type\n */\n private async fetchIssueData(\n input: CreateLoomInput\n ): Promise<Issue | PullRequest | null> {\n if (input.type === 'issue' || input.type === 'epic') {\n return await this.issueTracker.fetchIssue(input.identifier as number)\n } else if (input.type === 'pr') {\n // Use issue tracker if it supports PRs\n if (this.issueTracker.supportsPullRequests && this.issueTracker.fetchPR) {\n return await this.issueTracker.fetchPR(input.identifier as number)\n }\n // Use injected GitHubService if available\n if (this.githubService) {\n return await this.githubService.fetchPR(input.identifier as number)\n }\n // Create GitHubService on demand for PR fetching\n const github = new GitHubService()\n return await github.fetchPR(input.identifier as number)\n }\n return null\n }\n\n /**\n * Prepare branch name based on input type and issue/PR data\n */\n private async prepareBranchName(\n input: CreateLoomInput,\n issueData: Issue | PullRequest | null\n ): Promise<string> {\n if (input.type === 'branch') {\n return input.identifier as string\n }\n\n if (input.type === 'pr' && issueData && 'branch' in issueData) {\n return issueData.branch\n }\n\n if ((input.type === 'issue' || input.type === 'epic') && issueData) {\n // Use BranchNamingService for AI-powered branch name generation\n const branchName = await this.branchNaming.generateBranchName({\n issueNumber: input.identifier as number,\n title: issueData.title,\n })\n return branchName\n }\n\n // Fallback for edge cases\n if (input.type === 'pr') {\n return `pr-${input.identifier}`\n }\n\n throw new Error(`Unable to determine branch name for input type: ${input.type}`)\n }\n\n /**\n * Create worktree for the loom (without dependency installation)\n */\n private async createWorktreeOnly(\n input: CreateLoomInput,\n branchName: string,\n issueData?: Issue | PullRequest | null\n ): Promise<string> {\n // Ensure repository has at least one commit (needed for worktree creation)\n // This handles the case where the repo is completely empty (post git init, pre-first commit)\n getLogger().info('Ensuring repository has initial commit...')\n await ensureRepositoryHasCommits(this.gitWorktree.workingDirectory)\n\n // Load worktree prefix from settings\n const settingsData = await this.settings.loadSettings()\n let worktreePrefix = settingsData.worktreePrefix\n\n // If this is a child loom, compute dynamic prefix based on parent\n if (input.parentLoom) {\n // Sanitize branch name for directory use\n const sanitizedBranchName = input.parentLoom.branchName\n .replace(/\\//g, '-')\n .replace(/[^a-zA-Z0-9-_]/g, '-')\n worktreePrefix = `${sanitizedBranchName}-looms/`\n getLogger().info(`Creating child loom with prefix: ${worktreePrefix}`)\n }\n\n // Build options object, only including prefix if it's defined\n const pathOptions: { isPR?: boolean; prNumber?: number; prefix?: string } =\n input.type === 'pr'\n ? { isPR: true, prNumber: input.identifier as number }\n : {}\n\n if (worktreePrefix !== undefined) {\n pathOptions.prefix = worktreePrefix\n }\n\n const worktreePath = this.gitWorktree.generateWorktreePath(\n branchName,\n undefined,\n pathOptions\n )\n\n // Detect if this is a fork PR\n const isForkPR = input.type === 'pr' && issueData && 'isFork' in issueData && (issueData as PullRequest).isFork === true\n\n // Fetch all remote branches to ensure we have latest refs (especially for PRs)\n // Ports: bash script lines 667-674\n if (input.type === 'pr') {\n if (isForkPR) {\n // Fork PR: fetch the specific PR ref since the branch doesn't exist on origin\n getLogger().info(`Fetching PR #${input.identifier} ref from origin...`)\n try {\n await executeGitCommand(\n ['fetch', 'origin', `refs/pull/${input.identifier}/head`],\n { cwd: this.gitWorktree.workingDirectory }\n )\n getLogger().success('Successfully fetched PR ref from remote')\n } catch (error) {\n throw new Error(\n `Failed to fetch PR ref: ${error instanceof Error ? error.message : 'Unknown error'}. ` +\n `Make sure you have access to the repository.`\n )\n }\n } else {\n getLogger().info('Fetching all remote branches...')\n try {\n await executeGitCommand(['fetch', 'origin'], { cwd: this.gitWorktree.workingDirectory })\n getLogger().success('Successfully fetched from remote')\n } catch (error) {\n throw new Error(\n `Failed to fetch from remote: ${error instanceof Error ? error.message : 'Unknown error'}. ` +\n `Make sure you have access to the repository.`\n )\n }\n }\n }\n\n // Check if branch exists locally only (used for different purposes depending on type)\n // Pass false for includeRemote to only check local branches - remote branch existence\n // is handled separately in github-draft-pr mode\n const branchExistedLocally = await branchExists(branchName, process.cwd(), false)\n\n // For non-PRs, throw error if branch exists\n // For PRs, we'll use this to determine if we need to reset later\n if (input.type !== 'pr' && branchExistedLocally) {\n throw new Error(\n `Cannot create worktree: branch '${branchName}' already exists. ` +\n `Use 'git branch -D ${branchName}' to delete it first if needed.`\n )\n }\n\n // Determine base branch based on loom type and merge mode:\n // - Child looms: use parent's local branch (parent may not be pushed yet)\n // - PR modes (github-pr, github-draft-pr) for non-child, non-PR type: fetch and use origin/{mainBranch}\n // - Local mode or PR type: use explicit baseBranch or default (main)\n const mergeBehavior = settingsData.mergeBehavior ?? { mode: 'local' }\n const isPRMode = mergeBehavior.mode === 'github-pr' || mergeBehavior.mode === 'github-draft-pr'\n const isChildLoom = !!input.parentLoom\n\n let baseBranch: string | undefined\n\n if (isChildLoom) {\n // Child looms: use parent's local branch (no fetch - parent may not be pushed)\n baseBranch = input.parentLoom?.branchName ?? input.baseBranch\n } else if (isPRMode && input.type !== 'pr') {\n // PR modes (non-child, non-PR type): fetch origin and branch from origin/{mainBranch}\n getLogger().info('Fetching from origin to ensure latest main branch...')\n await fetchOrigin(this.gitWorktree.workingDirectory)\n\n const mainBranch = settingsData.mainBranch ?? 'main'\n baseBranch = `origin/${mainBranch}`\n getLogger().info(`Branching from ${baseBranch}`)\n } else {\n // Local mode or PR type: use explicit baseBranch or default (main)\n baseBranch = input.baseBranch\n }\n\n if (isForkPR) {\n // Fork PR: create a new local branch from FETCH_HEAD (the PR ref we just fetched)\n // If the branch already exists locally (e.g. re-running il start on the same fork PR),\n // delete it first since createBranch (-b) would fail\n if (branchExistedLocally) {\n await executeGitCommand(['branch', '-D', branchName], { cwd: this.gitWorktree.workingDirectory })\n }\n await this.gitWorktree.createWorktree({\n path: worktreePath,\n branch: branchName,\n createBranch: true,\n baseBranch: 'FETCH_HEAD',\n })\n // No reset or upstream tracking needed for fork PRs - there's no remote branch on origin\n } else {\n await this.gitWorktree.createWorktree({\n path: worktreePath,\n branch: branchName,\n createBranch: input.type !== 'pr', // PRs use existing branches\n ...(baseBranch && { baseBranch }),\n })\n\n // Reset PR branch to match remote exactly (if we created a new local branch)\n // Ports: bash script lines 689-713\n if (input.type === 'pr' && !branchExistedLocally) {\n getLogger().info('Resetting new PR branch to match remote exactly...')\n try {\n await executeGitCommand(['reset', '--hard', `origin/${branchName}`], { cwd: worktreePath })\n await executeGitCommand(['branch', '--set-upstream-to', `origin/${branchName}`], { cwd: worktreePath })\n getLogger().success('Successfully reset to match remote')\n } catch (error) {\n getLogger().warn(`Failed to reset to match remote: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n }\n\n return worktreePath\n }\n\n /**\n * Copy user application environment files (.env) from main repo to worktree\n * Copies all dotenv-flow patterns: .env, .env.local, .env.{NODE_ENV}, .env.{NODE_ENV}.local\n * Only copies files that exist and are NOT tracked by git (tracked files exist via worktree)\n * Always called regardless of project capabilities\n */\n private async copyEnvironmentFiles(worktreePath: string): Promise<void> {\n const mainWorkspacePath = this.gitWorktree.workingDirectory\n const nodeEnv = process.env.DOTENV_FLOW_NODE_ENV ?? 'development'\n\n // Define all dotenv-flow patterns to copy\n const envFilePatterns = [\n '.env',\n '.env.local',\n `.env.${nodeEnv}`,\n `.env.${nodeEnv}.local`\n ]\n\n for (const pattern of envFilePatterns) {\n try {\n const mainEnvPath = path.join(mainWorkspacePath, pattern)\n const worktreeEnvPath = path.join(worktreePath, pattern)\n\n // Skip if file doesn't exist in main workspace\n if (!(await fs.pathExists(mainEnvPath))) {\n continue\n }\n\n // Skip if file is tracked by git (it will exist in worktree via git)\n if (await isFileTrackedByGit(pattern, mainWorkspacePath)) {\n getLogger().debug(`Skipping ${pattern} (tracked by git, already in worktree)`)\n continue\n }\n\n // Skip if file already exists in worktree\n if (await fs.pathExists(worktreeEnvPath)) {\n getLogger().warn(`${pattern} already exists in worktree, skipping copy`)\n continue\n }\n\n // Copy the untracked env file\n await this.environment.copyIfExists(mainEnvPath, worktreeEnvPath)\n getLogger().debug(`Copied ${pattern} to worktree`)\n } catch (error) {\n // Handle gracefully if individual file fails to copy\n getLogger().warn(`Warning: Failed to copy ${pattern}: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n }\n\n /**\n * Copy iloom configuration (settings.local.json) from main repo to worktree\n * Always called regardless of project capabilities\n * @param worktreePath Path to the worktree\n */\n private async copyIloomSettings(worktreePath: string): Promise<void> {\n const mainSettingsLocalPath = path.join(process.cwd(), '.iloom', 'settings.local.json')\n\n try {\n const worktreeIloomDir = path.join(worktreePath, '.iloom')\n\n // Ensure .iloom directory exists in worktree\n await fs.ensureDir(worktreeIloomDir)\n\n const worktreeSettingsLocalPath = path.join(worktreeIloomDir, 'settings.local.json')\n\n // Check if settings.local.json already exists in worktree\n if (await fs.pathExists(worktreeSettingsLocalPath)) {\n getLogger().warn('settings.local.json already exists in worktree, skipping copy')\n } else {\n await this.environment.copyIfExists(mainSettingsLocalPath, worktreeSettingsLocalPath)\n }\n } catch (error) {\n getLogger().warn(`Warning: Failed to copy settings.local.json: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Copy iloom package local config (package.iloom.local.json) from main repo to worktree\n * Always called regardless of project capabilities\n * Follows the same pattern as copyIloomSettings()\n * @param worktreePath Path to the worktree\n */\n private async copyIloomPackageLocal(worktreePath: string): Promise<void> {\n const mainPackageLocalPath = path.join(process.cwd(), '.iloom', 'package.iloom.local.json')\n\n try {\n const worktreeIloomDir = path.join(worktreePath, '.iloom')\n\n // Ensure .iloom directory exists in worktree\n await fs.ensureDir(worktreeIloomDir)\n\n const worktreePackageLocalPath = path.join(worktreeIloomDir, 'package.iloom.local.json')\n\n // Check if package.iloom.local.json already exists in worktree\n if (await fs.pathExists(worktreePackageLocalPath)) {\n getLogger().debug('package.iloom.local.json already exists in worktree, skipping copy')\n } else {\n await this.environment.copyIfExists(mainPackageLocalPath, worktreePackageLocalPath)\n }\n } catch (error) {\n getLogger().warn(`Warning: Failed to copy package.iloom.local.json: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Copy Claude settings (settings.local.json) from main repo to worktree\n * Always called regardless of project capabilities\n * Follows the same pattern as copyIloomSettings()\n * @param worktreePath Path to the worktree\n */\n private async copyClaudeSettings(worktreePath: string): Promise<void> {\n const mainClaudeSettingsPath = path.join(process.cwd(), '.claude', 'settings.local.json')\n\n try {\n const worktreeClaudeDir = path.join(worktreePath, '.claude')\n\n // Ensure .claude directory exists in worktree\n await fs.ensureDir(worktreeClaudeDir)\n\n const worktreeClaudeSettingsPath = path.join(worktreeClaudeDir, 'settings.local.json')\n\n // Check if settings.local.json already exists in worktree\n if (await fs.pathExists(worktreeClaudeSettingsPath)) {\n getLogger().debug('.claude/settings.local.json already exists in worktree, skipping copy')\n } else {\n await this.environment.copyIfExists(mainClaudeSettingsPath, worktreeClaudeSettingsPath)\n }\n } catch (error) {\n getLogger().warn(`Warning: Failed to copy .claude/settings.local.json: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Copy gitignored files matching configured patterns from main repo to worktree\n * Uses copyGitIgnoredPatterns from settings to determine which files to copy\n * Only copies files that exist and are NOT tracked by git\n *\n * @param worktreePath Path to the worktree\n */\n private async copyGitIgnoredFiles(worktreePath: string): Promise<void> {\n // Load settings to get patterns\n const settingsData = await this.settings.loadSettings()\n const patterns = settingsData.copyGitIgnoredPatterns\n\n // Exit early if no patterns configured\n if (!patterns || patterns.length === 0) {\n getLogger().debug('No copyGitIgnoredPatterns configured, skipping gitignored file copy')\n return\n }\n\n const mainWorkspacePath = this.gitWorktree.workingDirectory\n\n try {\n // Pass all patterns at once - fast-glob deduplicates automatically\n const allMatches = await fg.glob(patterns, {\n cwd: mainWorkspacePath,\n onlyFiles: true,\n dot: true,\n })\n\n if (allMatches.length === 0) {\n getLogger().debug(`No files matched copyGitIgnoredPatterns: ${patterns.join(', ')}`)\n return\n }\n\n getLogger().info(`Copying ${allMatches.length} gitignored file(s) matching: ${patterns.join(', ')}`)\n\n // Copy each unique file once\n let copiedCount = 0\n for (const relativePath of allMatches) {\n const mainFilePath = path.join(mainWorkspacePath, relativePath)\n const worktreeFilePath = path.join(worktreePath, relativePath)\n\n // Skip if file doesn't exist in main workspace\n if (!(await fs.pathExists(mainFilePath))) {\n continue\n }\n\n // Skip if file is tracked by git (it will exist in worktree via git)\n if (await isFileTrackedByGit(relativePath, mainWorkspacePath)) {\n getLogger().debug(`Skipping ${relativePath} (tracked by git, already in worktree)`)\n continue\n }\n\n // Skip if file already exists in worktree\n if (await fs.pathExists(worktreeFilePath)) {\n getLogger().debug(`Skipping ${relativePath} (already exists in worktree)`)\n continue\n }\n\n // Ensure parent directory exists\n await fs.ensureDir(path.dirname(worktreeFilePath))\n\n // Copy the untracked file\n await this.environment.copyIfExists(mainFilePath, worktreeFilePath)\n getLogger().debug(`Copied gitignored file: ${relativePath}`)\n copiedCount++\n }\n\n if (copiedCount > 0) {\n getLogger().debug(`Copied ${copiedCount} gitignored file(s) to loom`)\n }\n } catch (error) {\n // Warn but don't fail - glob/file failures shouldn't block workflow\n getLogger().warn(`Warning: Failed to copy gitignored files: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Setup PORT environment variable for web projects\n * Only called when project has web capabilities\n */\n private async setupPortForWeb(\n worktreePath: string,\n input: CreateLoomInput,\n basePort: number\n ): Promise<number> {\n const envFilePath = path.join(worktreePath, '.env.local')\n\n // Calculate port based on input type\n const options: { basePort: number; issueNumber?: number; prNumber?: number; branchName?: string } = { basePort }\n\n if (input.type === 'issue' || input.type === 'epic') {\n options.issueNumber = input.identifier as number\n } else if (input.type === 'pr') {\n options.prNumber = input.identifier as number\n } else if (input.type === 'branch') {\n options.branchName = input.identifier as string\n }\n\n const port = this.environment.calculatePort(options)\n\n await this.environment.setEnvVar(envFilePath, 'PORT', String(port))\n return port\n }\n\n /**\n * Load environment variables from main .env file into process.env\n * Uses dotenv-flow to handle various .env file patterns\n */\n private loadMainEnvFile(): void {\n const result = loadEnvIntoProcess({ path: process.cwd() })\n\n if (result.error) {\n // Only log warning for actual errors, not for \"no .env files found\" which is harmless\n if (isNoEnvFilesFoundError(result.error)) {\n getLogger().debug('No .env files found (this is normal for projects without environment files)')\n } else {\n getLogger().warn(`Warning: Could not load .env files: ${result.error.message}`)\n }\n } else {\n getLogger().info('Loaded environment variables using dotenv-flow')\n if (result.parsed && Object.keys(result.parsed).length > 0) {\n getLogger().debug(`Loaded ${Object.keys(result.parsed).length} environment variables`)\n }\n }\n }\n\n /**\n * Generate a unique loom ID\n */\n private generateLoomId(input: CreateLoomInput): string {\n const prefix = input.type\n return `${prefix}-${input.identifier}`\n }\n\n /**\n * Calculate port for the loom\n * Base port: configurable via settings.capabilities.web.basePort (default 3000) + issue/PR number (or deterministic hash for branches)\n */\n private async calculatePort(input: CreateLoomInput): Promise<number> {\n // Load base port from settings\n const settingsData = await this.settings.loadSettings()\n const basePort = settingsData.capabilities?.web?.basePort ?? 3000\n\n if (input.type === 'issue' || input.type === 'epic') {\n if (typeof input.identifier === 'number') {\n return this.environment.calculatePort({ basePort, issueNumber: input.identifier })\n } else if (typeof input.identifier === 'string') {\n // Alphanumeric issue ID (e.g., Linear: ENG-123) - delegate to EnvironmentManager\n return this.environment.calculatePort({ basePort, issueNumber: input.identifier })\n }\n }\n\n if (input.type === 'pr' && typeof input.identifier === 'number') {\n return this.environment.calculatePort({ basePort, prNumber: input.identifier })\n }\n\n if (input.type === 'branch' && typeof input.identifier === 'string') {\n // Use deterministic hash for branch-based ports\n return this.environment.calculatePort({ basePort, branchName: input.identifier })\n }\n\n // Fallback: basePort only (shouldn't reach here with valid input)\n throw new Error(`Unknown input type: ${input.type} with identifier type: ${typeof input.identifier}`)\n }\n\n\n /**\n * Apply color synchronization to both VSCode and terminal\n * Colors are cosmetic - errors are logged but don't block workflow\n * Respects colors settings for independent control\n *\n * DEFAULTS:\n * - terminal: true (always safe, only affects macOS Terminal.app)\n * - vscode: false (safe default, prevents unexpected file modifications)\n *\n * @param colorData - Pre-computed color data (from collision avoidance)\n */\n private async applyColorSynchronization(\n worktreePath: string,\n branchName: string,\n colorData: ColorData,\n settings: import('./SettingsManager.js').IloomSettings,\n options?: CreateLoomInput['options']\n ): Promise<void> {\n // Determine color settings: options override settings, settings override defaults\n // Note: vscode defaults to FALSE for safety\n const colorVscode = options?.colorVscode ?? settings.colors?.vscode ?? false\n const colorTerminal = options?.colorTerminal ?? settings.colors?.terminal ?? true\n\n if (!colorVscode && !colorTerminal) {\n getLogger().debug('Color synchronization disabled for both VSCode and terminal')\n return\n }\n\n // Apply VSCode title bar color if enabled (default: disabled for safety)\n if (colorVscode) {\n const vscode = new VSCodeIntegration()\n await vscode.setTitleBarColor(worktreePath, colorData.hex)\n getLogger().info(`Applied VSCode title bar color: ${colorData.hex} for branch: ${branchName}`)\n } else {\n getLogger().debug('VSCode color sync disabled (default: false for safety)')\n }\n\n // Note: Terminal color is applied during window creation in LoomLauncher\n // The colorTerminal setting is passed through to launch options\n }\n\n /**\n * Map worktrees to loom objects\n * Reads loom metadata from MetadataManager with branch name parsing as fallback\n */\n private async mapWorktreesToLooms(worktrees: GitWorktree[]): Promise<Loom[]> {\n return await Promise.all(worktrees.map(async (wt) => {\n // Read metadata from persistent storage first\n const loomMetadata = await this.metadataManager.readMetadata(wt.path)\n\n // Priority 1: Use metadata as source of truth if available\n let type: 'issue' | 'pr' | 'branch' | 'epic' = 'branch'\n let identifier: string | number = wt.branch\n\n if (loomMetadata?.issueType) {\n type = loomMetadata.issueType\n\n // Extract identifier from metadata based on type\n // Prefer issueKey (canonical case) over issue_numbers (may be lowercase from branch extraction)\n if (type === 'issue' && (loomMetadata.issueKey || loomMetadata.issue_numbers?.[0])) {\n const issueId = loomMetadata.issueKey ?? loomMetadata.issue_numbers[0] ?? ''\n // Try to parse as number, otherwise keep as string (for alphanumeric IDs)\n const numericId = parseInt(issueId, 10)\n identifier = isNaN(numericId) ? issueId : numericId\n } else if (type === 'pr' && loomMetadata.pr_numbers?.[0]) {\n const prId = loomMetadata.pr_numbers[0]\n // PRs are always numeric\n identifier = parseInt(prId, 10)\n } else if (type === 'branch') {\n identifier = wt.branch\n }\n } else {\n // Priority 2: Fall back to branch name parsing if metadata not available\n\n // Check for PR pattern first (higher priority)\n const prNumber = extractPRNumber(wt.branch)\n if (prNumber !== null) {\n type = 'pr'\n identifier = prNumber\n } else {\n // Check for issue pattern\n const issueNumber = extractIssueNumber(wt.branch)\n if (issueNumber !== null) {\n type = 'issue'\n // Try to parse as number, otherwise keep as string (for alphanumeric IDs)\n const numericId = parseInt(issueNumber, 10)\n identifier = isNaN(numericId) ? issueNumber : numericId\n } else {\n // Default to branch type\n type = 'branch'\n identifier = wt.branch\n }\n }\n }\n\n return {\n id: `${type}-${identifier}`,\n path: wt.path,\n branch: wt.branch,\n type,\n identifier,\n port: await this.calculatePort({ type, identifier, originalInput: '' }),\n ...(loomMetadata?.description && { description: loomMetadata.description }),\n createdAt: new Date(),\n lastAccessed: new Date(),\n }\n }))\n }\n\n /**\n * NEW: Find existing loom for the given input\n * Checks for worktrees matching the issue/PR identifier\n */\n private async findExistingIloom(\n input: CreateLoomInput,\n issueData: Issue | PullRequest | null\n ): Promise<GitWorktree | null> {\n if (input.type === 'issue') {\n return await this.gitWorktree.findWorktreeForIssue(input.identifier as number)\n } else if (input.type === 'pr' && issueData && 'branch' in issueData) {\n return await this.gitWorktree.findWorktreeForPR(\n input.identifier as number,\n issueData.branch\n )\n } else if (input.type === 'branch') {\n return await this.gitWorktree.findWorktreeForBranch(input.identifier as string)\n }\n return null\n }\n\n /**\n * NEW: Reuse an existing loom\n * Includes environment setup and database branching for existing worktrees\n * Ports: handle_existing_worktree() from bash script lines 168-215\n */\n private async reuseIloom(\n worktree: GitWorktree,\n input: CreateLoomInput,\n issueData: Issue | PullRequest | null\n ): Promise<Loom> {\n const worktreePath = worktree.path\n const branchName = worktree.branch\n\n // 1. Load main .env variables into process.env\n this.loadMainEnvFile()\n\n // 2. Detect capabilities (quick, no installation)\n const { capabilities, binEntries } = await this.capabilityDetector.detectCapabilities(worktreePath)\n\n // 3. Defensively copy .env and settings.local.json if missing\n await this.copyEnvironmentFiles(worktreePath)\n await this.copyIloomSettings(worktreePath)\n await this.copyIloomPackageLocal(worktreePath)\n await this.copyClaudeSettings(worktreePath)\n\n // 3.5. Copy gitignored files matching configured patterns\n await this.copyGitIgnoredFiles(worktreePath)\n\n // 4. Setup PORT for web projects (ensure it's set even if .env existed)\n // Load base port from settings\n const settingsData = await this.settings.loadSettings()\n const basePort = settingsData.capabilities?.web?.basePort ?? 3000\n\n let port = basePort\n if (capabilities.includes('web')) {\n port = await this.setupPortForWeb(worktreePath, input, basePort)\n }\n\n // 5. Skip database branch creation for existing worktrees\n // The database branch should have been created when the worktree was first created\n // Matches bash script behavior: handle_existing_worktree() skips all setup\n getLogger().info('Database branch assumed to be already configured for existing worktree')\n const databaseBranch: string | undefined = undefined\n\n // 5.5. Read existing metadata to get colorHex (for reusing stored color)\n const existingMetadata = await this.metadataManager.readMetadata(worktreePath)\n\n // Determine colorHex for launch\n let colorHex: string\n if (existingMetadata?.colorHex) {\n // Use stored hex color (already migrated from colorIndex if needed in readMetadata)\n colorHex = existingMetadata.colorHex\n getLogger().debug(`Reusing stored color ${colorHex} for branch ${branchName}`)\n } else {\n // No metadata - fall back to hash-based with dark mode detection\n const themeMode = await detectDarkMode()\n const colorData = generateColorFromBranchName(branchName, themeMode)\n colorHex = colorData.hex\n getLogger().debug(`No stored color, using hash-based color ${colorHex} for branch ${branchName} (${themeMode} mode)`)\n }\n\n // Apply color synchronization (VSCode colors for reused looms)\n // Mirrors createIloom() behavior at lines 205-214\n try {\n const colorData: ColorData = { hex: colorHex, rgb: hexToRgb(colorHex), index: 0 }\n await this.applyColorSynchronization(worktreePath, branchName, colorData, settingsData, input.options)\n } catch (error) {\n // Log warning but don't fail - colors are cosmetic\n getLogger().warn(\n `Failed to apply color synchronization: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error\n )\n }\n\n // 6. Move issue to In Progress (for reused worktrees too)\n if (input.type === 'issue') {\n try {\n getLogger().info('Moving issue to In Progress...')\n // Check if provider supports this optional method\n if (this.issueTracker.moveIssueToInProgress) {\n await this.issueTracker.moveIssueToInProgress(input.identifier as number)\n }\n } catch (error) {\n getLogger().warn(\n `Failed to move issue to In Progress: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error\n )\n }\n }\n\n // 7. Launch components (same as new worktree)\n const enableClaude = input.options?.enableClaude !== false\n const enableCode = input.options?.enableCode !== false\n const enableDevServer = input.options?.enableDevServer !== false\n const enableTerminal = input.options?.enableTerminal ?? false\n const oneShot = input.options?.oneShot ?? 'default'\n const setArguments = input.options?.setArguments\n const executablePath = input.options?.executablePath\n\n if (enableClaude || enableCode || enableDevServer || enableTerminal) {\n getLogger().info('Launching workspace components...')\n const { LoomLauncher } = await import('./LoomLauncher.js')\n const { ClaudeContextManager } = await import('./ClaudeContextManager.js')\n\n // Create ClaudeContextManager with shared SettingsManager to ensure CLI overrides work\n const claudeContext = new ClaudeContextManager(undefined, undefined, this.settings)\n const launcher = new LoomLauncher(claudeContext, this.settings)\n\n await launcher.launchLoom({\n enableClaude,\n enableCode,\n enableDevServer,\n enableTerminal,\n worktreePath,\n branchName,\n port,\n capabilities,\n workflowType: input.type === 'branch' ? 'regular' : input.type === 'epic' ? 'issue' : input.type,\n identifier: input.identifier,\n ...(issueData?.title && { title: issueData.title }),\n oneShot,\n ...(setArguments && { setArguments }),\n ...(executablePath && { executablePath }),\n sourceEnvOnStart: settingsData.sourceEnvOnStart ?? false,\n colorTerminal: input.options?.colorTerminal ?? settingsData.colors?.terminal ?? true,\n colorHex,\n })\n }\n\n // 8. Write loom metadata if missing (spec section 3.1)\n // For reused looms, only write if metadata file doesn't exist\n const description = existingMetadata?.description ?? issueData?.title ?? branchName\n if (!existingMetadata) {\n // Build issue/pr numbers arrays based on type\n // For PR workflows, extract issue number from branch name if present\n let issue_numbers: string[] = []\n let extractedIssueNum: string | null = null\n if (input.type === 'issue') {\n issue_numbers = [String(input.identifier)]\n } else if (input.type === 'pr') {\n extractedIssueNum = extractIssueNumber(branchName)\n if (extractedIssueNum) {\n issue_numbers = [extractedIssueNum]\n }\n }\n const pr_numbers: string[] = input.type === 'pr' ? [String(input.identifier)] : []\n\n // Generate random session ID for Claude Code resume support\n // Each loom gets a unique session ID, enabling fresh Claude sessions\n const sessionId = generateRandomSessionId()\n\n // Build issueUrls/prUrls based on workflow type\n // For PR workflows, construct issue URL by replacing /pull/N with /issues/M\n let issueUrls: Record<string, string> = {}\n if (input.type === 'issue' && issueData?.url) {\n issueUrls = { [String(input.identifier)]: issueData.url }\n } else if (input.type === 'pr' && extractedIssueNum && issueData?.url) {\n const issueUrl = issueData.url.replace(`/pull/${input.identifier}`, `/issues/${extractedIssueNum}`)\n issueUrls = { [extractedIssueNum]: issueUrl }\n }\n const prUrls: Record<string, string> = input.type === 'pr' && issueData?.url\n ? { [String(input.identifier)]: issueData.url }\n : {}\n\n const metadataInput: WriteMetadataInput = {\n description,\n branchName,\n worktreePath,\n issueType: input.type,\n ...(input.type === 'issue' && { issueKey: this.issueTracker.normalizeIdentifier(input.identifier) }),\n issue_numbers,\n pr_numbers,\n issueTracker: this.issueTracker.providerName,\n colorHex,\n sessionId,\n projectPath: this.gitWorktree.workingDirectory,\n issueUrls,\n prUrls,\n capabilities,\n ...(input.options?.oneShot && { oneShot: input.options.oneShot }),\n ...(input.options?.childIssueNumbers && input.options.childIssueNumbers.length > 0 && { childIssueNumbers: input.options.childIssueNumbers }),\n ...(input.parentLoom && { parentLoom: input.parentLoom }),\n }\n await this.metadataManager.writeMetadata(worktreePath, metadataInput)\n }\n\n // 9. Return loom metadata\n const loom: Loom = {\n id: this.generateLoomId(input),\n path: worktreePath,\n branch: branchName,\n type: input.type,\n identifier: input.identifier,\n port,\n description,\n createdAt: new Date(), // We don't have actual creation date, use now\n lastAccessed: new Date(),\n ...(databaseBranch !== undefined && { databaseBranch }),\n ...(capabilities.length > 0 && { capabilities }),\n ...(Object.keys(binEntries).length > 0 && { binEntries }),\n ...(issueData !== null && {\n issueData: {\n title: issueData.title,\n body: issueData.body,\n url: issueData.url,\n state: issueData.state,\n },\n }),\n }\n\n getLogger().success(`Reused existing loom: ${loom.id} at ${loom.path}`)\n return loom\n }\n}\n","import fs from 'fs-extra'\nimport path from 'path'\nimport { parse, modify, applyEdits } from 'jsonc-parser'\nimport { logger } from '../utils/logger.js'\nimport {\n\thexToRgb,\n\trgbToHex,\n\tlightenColor,\n\tcalculateForegroundColor,\n} from '../utils/color.js'\n\n/**\n * VSCode settings structure\n */\ninterface VSCodeSettings {\n\t'workbench.colorCustomizations'?: {\n\t\t// Title Bar\n\t\t'titleBar.activeBackground'?: string\n\t\t'titleBar.inactiveBackground'?: string\n\t\t'titleBar.activeForeground'?: string\n\t\t'titleBar.inactiveForeground'?: string\n\t\t// Status Bar\n\t\t'statusBar.background'?: string\n\t\t'statusBar.foreground'?: string\n\t\t'statusBarItem.hoverBackground'?: string\n\t\t'statusBarItem.remoteBackground'?: string\n\t\t'statusBarItem.remoteForeground'?: string\n\t\t// UI Accents\n\t\t'sash.hoverBorder'?: string\n\t\t'commandCenter.border'?: string\n\t\t[key: string]: string | undefined\n\t}\n\t[key: string]: unknown\n}\n\n/**\n * Manages VSCode settings.json manipulation for workspace color synchronization\n */\nexport class VSCodeIntegration {\n\t/**\n\t * Set VSCode title bar color for a workspace\n\t *\n\t * @param workspacePath - Path to workspace directory\n\t * @param hexColor - Hex color string (e.g., \"#dcebf8\")\n\t */\n\tasync setTitleBarColor(workspacePath: string, hexColor: string): Promise<void> {\n\t\tconst vscodeDir = path.join(workspacePath, '.vscode')\n\t\tconst settingsPath = path.join(vscodeDir, 'settings.json')\n\n\t\ttry {\n\t\t\t// Ensure .vscode directory exists\n\t\t\tawait fs.ensureDir(vscodeDir)\n\n\t\t\t// Read existing settings (or create empty object)\n\t\t\tconst settings = await this.readSettings(settingsPath)\n\n\t\t\t// Merge color settings\n\t\t\tconst updatedSettings = this.mergeColorSettings(settings, hexColor)\n\n\t\t\t// Write settings atomically\n\t\t\tawait this.writeSettings(settingsPath, updatedSettings)\n\n\t\t\tlogger.debug(`Set VSCode title bar color to ${hexColor} for ${workspacePath}`)\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to set VSCode title bar color: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Read VSCode settings from file\n\t * Supports JSONC (JSON with Comments)\n\t *\n\t * @param settingsPath - Path to settings.json file\n\t * @returns Parsed settings object\n\t */\n\tprivate async readSettings(settingsPath: string): Promise<VSCodeSettings> {\n\t\ttry {\n\t\t\t// Check if file exists\n\t\t\tif (!(await fs.pathExists(settingsPath))) {\n\t\t\t\treturn {}\n\t\t\t}\n\n\t\t\t// Read file content\n\t\t\tconst content = await fs.readFile(settingsPath, 'utf8')\n\n\t\t\t// Parse JSONC (handles comments)\n\t\t\tconst errors: import('jsonc-parser').ParseError[] = []\n\t\t\tconst settings = parse(content, errors, { allowTrailingComma: true })\n\n\t\t\t// Check for parse errors\n\t\t\tif (errors.length > 0) {\n\t\t\t\tconst firstError = errors[0]\n\t\t\t\tthrow new Error(`Invalid JSON: ${firstError ? firstError.error : 'Unknown parse error'}`)\n\t\t\t}\n\n\t\t\treturn settings ?? {}\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to parse settings.json: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Write VSCode settings to file atomically\n\t * Preserves comments if present (using JSONC parser)\n\t *\n\t * @param settingsPath - Path to settings.json file\n\t * @param settings - Settings object to write\n\t */\n\tprivate async writeSettings(\n\t\tsettingsPath: string,\n\t\tsettings: VSCodeSettings\n\t): Promise<void> {\n\t\ttry {\n\t\t\tlet content: string\n\n\t\t\t// Check if file exists with comments\n\t\t\tif (await fs.pathExists(settingsPath)) {\n\t\t\t\tconst existingContent = await fs.readFile(settingsPath, 'utf8')\n\n\t\t\t\t// Try to preserve comments by using jsonc-parser's modify function\n\t\t\t\tif (existingContent.includes('//') || existingContent.includes('/*')) {\n\t\t\t\t\t// File has comments - use JSONC modify to preserve them\n\t\t\t\t\tcontent = await this.modifyWithCommentsPreserved(existingContent, settings)\n\t\t\t\t} else {\n\t\t\t\t\t// No comments - use standard JSON.stringify\n\t\t\t\t\tcontent = JSON.stringify(settings, null, 2) + '\\n'\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// New file - use standard JSON.stringify\n\t\t\t\tcontent = JSON.stringify(settings, null, 2) + '\\n'\n\t\t\t}\n\n\t\t\t// Write atomically using temp file + rename\n\t\t\tconst tempPath = `${settingsPath}.tmp`\n\t\t\tawait fs.writeFile(tempPath, content, 'utf8')\n\t\t\tawait fs.rename(tempPath, settingsPath)\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to write settings.json: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Modify JSONC content while preserving comments\n\t *\n\t * @param existingContent - Original JSONC content\n\t * @param newSettings - New settings to apply\n\t * @returns Modified JSONC content with comments preserved\n\t */\n\tprivate async modifyWithCommentsPreserved(\n\t\texistingContent: string,\n\t\tnewSettings: VSCodeSettings\n\t): Promise<string> {\n\t\tlet modifiedContent = existingContent\n\n\t\t// Apply each setting modification\n\t\tfor (const [key, value] of Object.entries(newSettings)) {\n\t\t\tconst edits = modify(modifiedContent, [key], value, {})\n\t\t\tmodifiedContent = applyEdits(modifiedContent, edits)\n\t\t}\n\n\t\treturn modifiedContent\n\t}\n\n\t/**\n\t * Merge color settings into existing settings object\n\t *\n\t * @param existing - Existing settings object\n\t * @param hexColor - Hex color to apply (subtle palette color)\n\t * @returns Updated settings object with color merged\n\t */\n\tprivate mergeColorSettings(existing: VSCodeSettings, hexColor: string): VSCodeSettings {\n\t\t// Clone existing settings\n\t\tconst updated: VSCodeSettings = { ...existing }\n\n\t\t// Initialize workbench.colorCustomizations if needed\n\t\tupdated['workbench.colorCustomizations'] ??= {}\n\n\t\tconst colors = updated['workbench.colorCustomizations']\n\n\t\t// Convert hex to RGB for manipulation\n\t\tconst baseRgb = hexToRgb(hexColor)\n\n\t\t// Calculate foreground color based on background luminance\n\t\tconst foreground = calculateForegroundColor(baseRgb)\n\t\tconst foregroundTransparent = foreground.replace('#', '#') + '99' // Add 60% opacity\n\n\t\t// Create lighter variant for hover states\n\t\tconst lighterRgb = lightenColor(baseRgb, 0.05) // 5% lighter\n\t\tconst lighterHex = rgbToHex(lighterRgb.r, lighterRgb.g, lighterRgb.b)\n\n\t\t// Title Bar - subtle top indicator\n\t\tcolors['titleBar.activeBackground'] = hexColor\n\t\tcolors['titleBar.inactiveBackground'] = hexColor + '99' // Semi-transparent when unfocused\n\t\tcolors['titleBar.activeForeground'] = foreground\n\t\tcolors['titleBar.inactiveForeground'] = foregroundTransparent\n\n\t\t// Status Bar - constant visibility at bottom\n\t\tcolors['statusBar.background'] = hexColor\n\t\tcolors['statusBar.foreground'] = foreground\n\t\tcolors['statusBarItem.hoverBackground'] = lighterHex\n\t\tcolors['statusBarItem.remoteBackground'] = hexColor // When connected to remote\n\t\tcolors['statusBarItem.remoteForeground'] = foreground\n\n\t\t// UI Accents - subtle hints\n\t\tcolors['sash.hoverBorder'] = hexColor // Resize borders\n\t\tcolors['commandCenter.border'] = foregroundTransparent // Search box border\n\n\t\treturn updated\n\t}\n}\n","import fs from 'fs-extra'\nimport { getLogger } from '../utils/logger-context.js'\nimport type {\n PortAssignmentOptions,\n} from '../types/environment.js'\nimport {\n parseEnvFile,\n formatEnvLine,\n validateEnvVariable,\n} from '../utils/env.js'\nimport { calculatePortForBranch, calculatePortFromIdentifier } from '../utils/port.js'\n\nexport class EnvironmentManager {\n private readonly backupSuffix: string = '.backup'\n\n constructor() {\n // No-op - logger now uses AsyncLocalStorage context\n }\n\n /**\n * Set or update an environment variable in a .env file\n * Ports functionality from bash/utils/env-utils.sh:setEnvVar()\n * @returns The backup path if a backup was created\n */\n async setEnvVar(\n filePath: string,\n key: string,\n value: string,\n backup: boolean = false\n ): Promise<string | void> {\n // Validate variable name\n const validation = validateEnvVariable(key, value)\n if (!validation.valid) {\n throw new Error(validation.error ?? 'Invalid variable name')\n }\n\n const fileExists = await fs.pathExists(filePath)\n\n if (!fileExists) {\n // File doesn't exist, create it\n getLogger().info(`Creating ${filePath} with ${key}...`)\n const content = formatEnvLine(key, value)\n await fs.writeFile(filePath, content, 'utf8')\n getLogger().success(`${filePath} created with ${key}`)\n return\n }\n\n // File exists, read and parse it\n const existingContent = await fs.readFile(filePath, 'utf8')\n const envMap = parseEnvFile(existingContent)\n\n // Create backup if requested\n let backupPath: string | undefined\n if (backup) {\n backupPath = await this.createBackup(filePath)\n }\n\n // Update or add the variable\n envMap.set(key, value)\n\n // Rebuild the file content, preserving comments and empty lines\n const lines = existingContent.split('\\n')\n const newLines: string[] = []\n let variableUpdated = false\n\n for (const line of lines) {\n const trimmedLine = line.trim()\n\n // Preserve comments and empty lines\n if (!trimmedLine || trimmedLine.startsWith('#')) {\n newLines.push(line)\n continue\n }\n\n // Remove 'export ' prefix if present\n const cleanLine = trimmedLine.startsWith('export ')\n ? trimmedLine.substring(7)\n : trimmedLine\n\n // Check if this line contains our variable\n const equalsIndex = cleanLine.indexOf('=')\n if (equalsIndex !== -1) {\n const lineKey = cleanLine.substring(0, equalsIndex).trim()\n if (lineKey === key) {\n // Replace this line with the new value\n newLines.push(formatEnvLine(key, value))\n variableUpdated = true\n continue\n }\n }\n\n // Keep other lines as-is\n newLines.push(line)\n }\n\n // If variable wasn't in the file, add it at the end\n if (!variableUpdated) {\n getLogger().info(`Adding ${key} to ${filePath}...`)\n newLines.push(formatEnvLine(key, value))\n getLogger().success(`${key} added successfully`)\n } else {\n getLogger().info(`Updating ${key} in ${filePath}...`)\n getLogger().success(`${key} updated successfully`)\n }\n\n // Write the updated content\n const newContent = newLines.join('\\n')\n await fs.writeFile(filePath, newContent, 'utf8')\n\n return backupPath\n }\n\n /**\n * Read and parse a .env file\n */\n async readEnvFile(filePath: string): Promise<Map<string, string>> {\n try {\n const content = await fs.readFile(filePath, 'utf8')\n return parseEnvFile(content)\n } catch (error) {\n // If file doesn't exist or can't be read, return empty map\n getLogger().debug(\n `Could not read env file ${filePath}: ${error instanceof Error ? error.message : String(error)}`\n )\n return new Map()\n }\n }\n\n /**\n * Get a specific environment variable from a .env file\n * Returns null if file doesn't exist or variable is not found\n */\n async getEnvVariable(filePath: string, variableName: string): Promise<string | null> {\n const envVars = await this.readEnvFile(filePath)\n return envVars.get(variableName) ?? null\n }\n\n /**\n * Generic file copy helper that only copies if source exists\n * Does not throw if source file doesn't exist - just logs and returns\n * @private\n */\n async copyIfExists(\n source: string,\n destination: string\n ): Promise<void> {\n const sourceExists = await fs.pathExists(source)\n if (!sourceExists) {\n getLogger().debug(`Source file ${source} does not exist, skipping copy`)\n return\n }\n\n await fs.copy(source, destination, { overwrite: false })\n getLogger().success(`Copied ${source} to ${destination}`)\n }\n\n /**\n * Calculate unique port for workspace\n * Implements:\n * - Issue/PR: 3000 + issue/PR number\n * - Branch: 3000 + deterministic hash offset (1-999)\n * Delegates to calculatePortFromIdentifier for the core calculation.\n */\n calculatePort(options: PortAssignmentOptions): number {\n const basePort = options.basePort ?? 3000\n\n // Priority: issueNumber > prNumber > branchName > basePort only\n if (options.issueNumber !== undefined) {\n return calculatePortFromIdentifier(options.issueNumber, basePort)\n }\n\n if (options.prNumber !== undefined) {\n return calculatePortFromIdentifier(options.prNumber, basePort)\n }\n\n if (options.branchName !== undefined) {\n // Use deterministic hash for branch-based workspaces\n return calculatePortForBranch(options.branchName, basePort)\n }\n\n // Fallback: basePort only (no offset)\n return basePort\n }\n\n /**\n * Set port environment variable for workspace\n */\n async setPortForWorkspace(\n envFilePath: string,\n issueNumber?: string | number,\n prNumber?: number,\n branchName?: string\n ): Promise<number> {\n const options: PortAssignmentOptions = {}\n if (issueNumber !== undefined) {\n options.issueNumber = issueNumber\n }\n if (prNumber !== undefined) {\n options.prNumber = prNumber\n }\n if (branchName !== undefined) {\n options.branchName = branchName\n }\n const port = this.calculatePort(options)\n await this.setEnvVar(envFilePath, 'PORT', String(port))\n return port\n }\n\n /**\n * Validate environment configuration\n */\n async validateEnvFile(\n filePath: string\n ): Promise<{ valid: boolean; errors: string[] }> {\n try {\n const content = await fs.readFile(filePath, 'utf8')\n const envMap = parseEnvFile(content)\n const errors: string[] = []\n\n // Validate each variable name\n for (const [key, value] of envMap.entries()) {\n const validation = validateEnvVariable(key, value)\n if (!validation.valid) {\n errors.push(`${key}: ${validation.error}`)\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n }\n } catch (error) {\n return {\n valid: false,\n errors: [\n `Failed to read or parse file: ${error instanceof Error ? error.message : String(error)}`,\n ],\n }\n }\n }\n\n /**\n * Create backup of existing file\n */\n private async createBackup(filePath: string): Promise<string> {\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-')\n const backupPath = `${filePath}${this.backupSuffix}-${timestamp}`\n await fs.copy(filePath, backupPath)\n getLogger().debug(`Created backup at ${backupPath}`)\n return backupPath\n }\n}\n","import fs from 'fs-extra'\nimport path from 'path'\nimport os from 'os'\nimport { runScript } from '../utils/package-manager.js'\nimport { getPackageConfig, hasScript } from '../utils/package-json.js'\nimport { getLogger } from '../utils/logger-context.js'\n\nexport class CLIIsolationManager {\n private readonly iloomBinDir: string\n\n constructor() {\n this.iloomBinDir = path.join(os.homedir(), '.iloom', 'bin')\n }\n\n /**\n * Setup CLI isolation for a worktree\n * - Build the project\n * - Create versioned symlinks\n * - Check PATH configuration\n * @param worktreePath Path to the worktree\n * @param identifier Issue/PR number or branch identifier\n * @param binEntries Bin entries from package.json\n * @returns Array of created symlink names\n */\n async setupCLIIsolation(\n worktreePath: string,\n identifier: string | number,\n binEntries: Record<string, string>\n ): Promise<string[]> {\n // 1. Build the project\n await this.buildProject(worktreePath)\n\n // 2. Verify bin targets exist and are executable\n await this.verifyBinTargets(worktreePath, binEntries)\n\n // 3. Create ~/.iloom/bin if needed\n await fs.ensureDir(this.iloomBinDir)\n\n // 4. Create versioned symlinks\n const symlinkNames = await this.createVersionedSymlinks(\n worktreePath,\n identifier,\n binEntries\n )\n\n // 5. Check PATH and provide instructions if needed\n await this.ensureIloomBinInPath()\n\n return symlinkNames\n }\n\n /**\n * Build the project using package.json build script\n * @param worktreePath Path to the worktree\n */\n private async buildProject(worktreePath: string): Promise<void> {\n const pkgJson = await getPackageConfig(worktreePath)\n\n if (!hasScript(pkgJson, 'build')) {\n getLogger().warn('No build script found in package.json - skipping build')\n return\n }\n\n getLogger().info('Building CLI tool...')\n await runScript('build', worktreePath, [], { quiet: true })\n getLogger().success('Build completed')\n }\n\n /**\n * Verify bin targets exist and are executable\n * @param worktreePath Path to the worktree\n * @param binEntries Bin entries from package.json\n */\n private async verifyBinTargets(\n worktreePath: string,\n binEntries: Record<string, string>\n ): Promise<void> {\n for (const binPath of Object.values(binEntries)) {\n const targetPath = path.resolve(worktreePath, binPath)\n\n // Check if file exists\n const exists = await fs.pathExists(targetPath)\n if (!exists) {\n throw new Error(`Bin target does not exist: ${targetPath}`)\n }\n\n // Check if file is executable\n try {\n await fs.access(targetPath, fs.constants.X_OK)\n } catch {\n // File is not executable, but that's okay - symlink will work anyway\n // The shebang in the file will determine how it's executed\n }\n }\n }\n\n /**\n * Create versioned symlinks in ~/.iloom/bin\n * @param worktreePath Path to the worktree\n * @param identifier Issue/PR number or branch identifier\n * @param binEntries Bin entries from package.json\n * @returns Array of created symlink names\n */\n private async createVersionedSymlinks(\n worktreePath: string,\n identifier: string | number,\n binEntries: Record<string, string>\n ): Promise<string[]> {\n const symlinkNames: string[] = []\n\n for (const [binName, binPath] of Object.entries(binEntries)) {\n const versionedName = `${binName}-${identifier}`\n const targetPath = path.resolve(worktreePath, binPath)\n const symlinkPath = path.join(this.iloomBinDir, versionedName)\n\n // Create symlink\n await fs.symlink(targetPath, symlinkPath)\n\n getLogger().success(`CLI available: ${versionedName}`)\n symlinkNames.push(versionedName)\n }\n\n return symlinkNames\n }\n\n /**\n * Check if ~/.iloom/bin is in PATH and provide setup instructions\n */\n private async ensureIloomBinInPath(): Promise<void> {\n const currentPath = process.env.PATH ?? ''\n if (currentPath.includes('.iloom/bin')) {\n return // Already configured\n }\n\n // Detect shell and RC file\n const shell = this.detectShell()\n const rcFile = this.getShellRcFile(shell)\n\n // Print setup instructions\n getLogger().warn('\\n⚠️ One-time PATH setup required:')\n getLogger().warn(` Add to ${rcFile}:`)\n getLogger().warn(` export PATH=\"$HOME/.iloom/bin:$PATH\"`)\n getLogger().warn(` Then run: source ${rcFile}\\n`)\n }\n\n /**\n * Detect current shell\n * @returns Shell name (zsh, bash, fish, etc.)\n */\n private detectShell(): string {\n const shell = process.env.SHELL ?? ''\n return shell.split('/').pop() ?? 'bash'\n }\n\n /**\n * Get RC file path for shell\n * @param shell Shell name\n * @returns RC file path\n */\n private getShellRcFile(shell: string): string {\n const rcFiles: Record<string, string> = {\n zsh: '~/.zshrc',\n bash: '~/.bashrc',\n fish: '~/.config/fish/config.fish'\n }\n return rcFiles[shell] ?? '~/.bashrc'\n }\n\n /**\n * Cleanup versioned CLI executables for a specific identifier\n * Removes all symlinks matching the pattern: {binName}-{identifier}\n *\n * @param identifier - Issue/PR number or branch identifier\n * @returns Array of removed symlink names\n */\n async cleanupVersionedExecutables(identifier: string | number): Promise<string[]> {\n const removed: string[] = []\n\n try {\n const files = await fs.readdir(this.iloomBinDir)\n\n for (const file of files) {\n if (this.matchesIdentifier(file, identifier)) {\n const symlinkPath = path.join(this.iloomBinDir, file)\n\n try {\n await fs.unlink(symlinkPath)\n removed.push(file)\n } catch (error) {\n // Silently skip if symlink already gone (ENOENT)\n const isEnoent = error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT'\n if (isEnoent) {\n removed.push(file)\n continue\n }\n\n // Log warning for other errors but continue cleanup\n getLogger().warn(\n `Failed to remove symlink ${file}: ${error instanceof Error ? error.message : 'Unknown error'}`\n )\n }\n }\n }\n } catch (error) {\n // Handle missing bin directory gracefully\n const isEnoent = error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT'\n if (isEnoent) {\n getLogger().warn('No CLI executables directory found - nothing to cleanup')\n return []\n }\n\n // Re-throw unexpected errors\n throw error\n }\n\n if (removed.length > 0) {\n getLogger().success(`Removed CLI executables: ${removed.join(', ')}`)\n }\n\n return removed\n }\n\n /**\n * Find orphaned symlinks in ~/.iloom/bin\n * Returns symlinks that point to non-existent targets\n *\n * @returns Array of orphaned symlink information\n */\n async findOrphanedSymlinks(): Promise<Array<{ name: string; path: string; brokenTarget: string }>> {\n const orphaned: Array<{ name: string; path: string; brokenTarget: string }> = []\n\n try {\n const files = await fs.readdir(this.iloomBinDir)\n\n for (const file of files) {\n const symlinkPath = path.join(this.iloomBinDir, file)\n\n try {\n const stats = await fs.lstat(symlinkPath)\n\n if (stats.isSymbolicLink()) {\n const target = await fs.readlink(symlinkPath)\n\n // Check if target exists\n try {\n await fs.access(target)\n } catch {\n // Target doesn't exist - this is an orphaned symlink\n orphaned.push({\n name: file,\n path: symlinkPath,\n brokenTarget: target\n })\n }\n }\n } catch (error) {\n // Skip files we can't read\n getLogger().warn(\n `Failed to check symlink ${file}: ${error instanceof Error ? error.message : 'Unknown error'}`\n )\n }\n }\n } catch (error) {\n // Handle missing bin directory\n const isEnoent = error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT'\n if (isEnoent) {\n return []\n }\n\n // Re-throw unexpected errors\n throw error\n }\n\n return orphaned\n }\n\n /**\n * Cleanup all orphaned symlinks\n * Removes symlinks that point to non-existent targets\n *\n * @returns Number of symlinks removed\n */\n async cleanupOrphanedSymlinks(): Promise<number> {\n const orphaned = await this.findOrphanedSymlinks()\n let removedCount = 0\n\n for (const symlink of orphaned) {\n try {\n await fs.unlink(symlink.path)\n removedCount++\n getLogger().success(`Removed orphaned symlink: ${symlink.name}`)\n } catch (error) {\n getLogger().warn(\n `Failed to remove orphaned symlink ${symlink.name}: ${error instanceof Error ? error.message : 'Unknown error'}`\n )\n }\n }\n\n return removedCount\n }\n\n /**\n * Check if a filename matches the versioned pattern for an identifier\n * Pattern: {binName}-{identifier}\n *\n * @param fileName - Name of the file to check\n * @param identifier - Issue/PR number or branch identifier\n * @returns True if the filename matches the pattern\n */\n private matchesIdentifier(fileName: string, identifier: string | number): boolean {\n const suffix = `-${identifier}`\n return fileName.endsWith(suffix)\n }\n}\n","import type { DatabaseProvider } from '../types/index.js'\nimport { EnvironmentManager } from './EnvironmentManager.js'\nimport { getLogger } from '../utils/logger-context.js'\nimport { hasVariableInAnyEnvFile } from '../utils/env.js'\nimport fs from 'fs-extra'\n\n/**\n * Database Manager - orchestrates database operations with conditional execution\n * Ports functionality from bash scripts with guard conditions:\n * 1. Database provider must be properly configured (provider.isConfigured())\n * 2. The worktree's .env file must contain the configured database URL variable (default: DATABASE_URL)\n *\n * This ensures database branching only occurs for projects that actually use databases\n */\nexport class DatabaseManager {\n constructor(\n private provider: DatabaseProvider,\n private environment: EnvironmentManager,\n private databaseUrlEnvVarName: string = 'DATABASE_URL'\n ) {\n // Debug: Show which database URL variable name is configured\n if (databaseUrlEnvVarName !== 'DATABASE_URL') {\n getLogger().debug(`DatabaseManager configured with custom variable: ${databaseUrlEnvVarName}`)\n } else {\n getLogger().debug('DatabaseManager using default variable: DATABASE_URL')\n }\n }\n\n /**\n * Get the configured database URL environment variable name\n */\n getConfiguredVariableName(): string {\n return this.databaseUrlEnvVarName\n }\n\n /**\n * Check if database branching should be used\n * Requires BOTH conditions:\n * 1. Database provider is properly configured (checked via provider.isConfigured())\n * 2. Any dotenv-flow file contains the configured database URL variable\n */\n async shouldUseDatabaseBranching(workspacePath: string): Promise<boolean> {\n // Check for provider configuration\n if (!this.provider.isConfigured()) {\n getLogger().debug('Skipping database branching: Database provider not configured')\n return false\n }\n\n // Check if any dotenv-flow file has the configured database URL variable\n const hasDatabaseUrl = await this.hasDatabaseUrlInEnv(workspacePath)\n if (!hasDatabaseUrl) {\n getLogger().debug(\n 'Skipping database branching: configured database URL variable not found in any env file'\n )\n return false\n }\n\n return true\n }\n\n /**\n * Create database branch only if configured\n * Returns connection string if branch was created, null if skipped\n *\n * @param branchName - Name of the branch to create\n * @param workspacePath - Path to workspace for configuration checks (checks all dotenv-flow files)\n * @param cwd - Optional working directory to run commands from\n * @param fromBranch - Optional parent branch to create from (for child looms)\n */\n async createBranchIfConfigured(\n branchName: string,\n workspacePath: string,\n cwd?: string,\n fromBranch?: string\n ): Promise<string | null> {\n // Guard condition: check if database branching should be used\n if (!(await this.shouldUseDatabaseBranching(workspacePath))) {\n return null\n }\n\n // Check CLI availability and authentication\n if (!(await this.provider.isCliAvailable())) {\n getLogger().warn('Skipping database branch creation: Neon CLI not available')\n getLogger().warn('Install with: npm install -g neonctl')\n return null\n }\n\n try {\n const isAuth = await this.provider.isAuthenticated(cwd)\n if (!isAuth) {\n getLogger().warn('Skipping database branch creation: Not authenticated with Neon CLI')\n getLogger().warn('Run: neon auth')\n return null\n }\n } catch (error) {\n // Authentication check failed with an unexpected error - surface it\n const errorMessage = error instanceof Error ? error.message : String(error)\n getLogger().error(`Database authentication check failed: ${errorMessage}`)\n throw error\n }\n\n try {\n // Create the branch (which checks for preview first)\n // Pass fromBranch if provided (for child looms), otherwise undefined (uses configured parent)\n const connectionString = await this.provider.createBranch(branchName, fromBranch, cwd)\n getLogger().success(`Database branch ready: ${this.provider.sanitizeBranchName(branchName)}`)\n return connectionString\n } catch (error) {\n getLogger().error(\n `Failed to create database branch: ${error instanceof Error ? error.message : String(error)}`\n )\n throw error\n }\n }\n\n /**\n * Delete database branch only if configured\n * Returns result object indicating what happened\n *\n * @param branchName - Name of the branch to delete\n * @param shouldCleanup - Boolean indicating if database cleanup should be performed (pre-fetched config)\n * @param isPreview - Whether this is a preview database branch\n * @param cwd - Optional working directory to run commands from (prevents issues with deleted directories)\n */\n async deleteBranchIfConfigured(\n branchName: string,\n shouldCleanup: boolean,\n isPreview: boolean = false,\n cwd?: string\n ): Promise<import('../types/index.js').DatabaseDeletionResult> {\n // If shouldCleanup is explicitly false, skip immediately\n if (shouldCleanup === false) {\n return {\n success: true,\n deleted: false,\n notFound: true, // Treat \"not configured\" as \"nothing to delete\"\n branchName\n }\n }\n\n // If shouldCleanup is explicitly true, validate provider configuration\n if (!this.provider.isConfigured()) {\n getLogger().debug('Skipping database branch deletion: Database provider not configured')\n return {\n success: true,\n deleted: false,\n notFound: true,\n branchName\n }\n }\n\n // Check CLI availability and authentication\n if (!(await this.provider.isCliAvailable())) {\n getLogger().info('Skipping database branch deletion: CLI tool not available')\n return {\n success: false,\n deleted: false,\n notFound: true,\n error: \"CLI tool not available\",\n branchName\n }\n }\n\n try {\n const isAuth = await this.provider.isAuthenticated(cwd)\n if (!isAuth) {\n getLogger().warn('Skipping database branch deletion: Not authenticated with DB Provider')\n return {\n success: false,\n deleted: false,\n notFound: false,\n error: \"Not authenticated with DB Provider\",\n branchName\n }\n }\n } catch (error) {\n // Authentication check failed with an unexpected error - surface it\n const errorMessage = error instanceof Error ? error.message : String(error)\n getLogger().error(`Database authentication check failed: ${errorMessage}`)\n return {\n success: false,\n deleted: false,\n notFound: false,\n error: `Authentication check failed: ${errorMessage}`,\n branchName\n }\n }\n\n try {\n // Call provider and return its result directly\n const result = await this.provider.deleteBranch(branchName, isPreview, cwd)\n return result\n } catch (error) {\n // Unexpected error (shouldn't happen since provider returns result object)\n getLogger().warn(\n `Unexpected error in database deletion: ${error instanceof Error ? error.message : String(error)}`\n )\n return {\n success: false,\n deleted: false,\n notFound: false,\n error: error instanceof Error ? error.message : String(error),\n branchName\n }\n }\n }\n\n /**\n * Get database branch name from connection string (reverse lookup)\n * Returns branch name if provider supports reverse lookup, null otherwise\n *\n * @param connectionString - Database connection string\n * @param cwd - Optional working directory to run commands from\n */\n async getBranchNameFromConnectionString(connectionString: string, cwd?: string): Promise<string | null> {\n // Check if provider supports reverse lookup (duck typing)\n if (!this.provider.isConfigured()) {\n getLogger().debug('Provider not configured, skipping reverse lookup')\n return null\n }\n\n if ('getBranchNameFromConnectionString' in this.provider &&\n typeof this.provider.getBranchNameFromConnectionString === 'function') {\n return this.provider.getBranchNameFromConnectionString(connectionString, cwd)\n }\n\n getLogger().debug('Provider does not support reverse lookup')\n return null\n }\n\n /**\n * Check if any dotenv-flow file has the configured database URL variable\n * CRITICAL: If user explicitly configured a custom variable name (not default),\n * throw an error if it's missing from all env files\n */\n private async hasDatabaseUrlInEnv(workspacePath: string): Promise<boolean> {\n try {\n // Debug: Show what we're looking for\n if (this.databaseUrlEnvVarName !== 'DATABASE_URL') {\n getLogger().debug(`Looking for custom database URL variable: ${this.databaseUrlEnvVarName}`)\n } else {\n getLogger().debug('Looking for default database URL variable: DATABASE_URL')\n }\n\n // Check all dotenv-flow files for the configured variable\n const hasConfiguredVar = await hasVariableInAnyEnvFile(\n workspacePath,\n this.databaseUrlEnvVarName,\n async (p) => fs.pathExists(p),\n async (p, v) => this.environment.getEnvVariable(p, v)\n )\n\n if (hasConfiguredVar) {\n if (this.databaseUrlEnvVarName !== 'DATABASE_URL') {\n getLogger().debug(`✅ Found custom database URL variable: ${this.databaseUrlEnvVarName}`)\n } else {\n getLogger().debug(`✅ Found default database URL variable: DATABASE_URL`)\n }\n return true\n }\n\n // If user explicitly configured a custom variable name (not the default)\n // and it's missing, throw an error\n if (this.databaseUrlEnvVarName !== 'DATABASE_URL') {\n getLogger().debug(`❌ Custom database URL variable '${this.databaseUrlEnvVarName}' not found in any env file`)\n throw new Error(\n `Configured database URL environment variable '${this.databaseUrlEnvVarName}' not found in any dotenv-flow file. ` +\n `Please add it to an .env file or update your iloom configuration.`\n )\n }\n\n // Fall back to DATABASE_URL when using default configuration\n const hasDefaultVar = await hasVariableInAnyEnvFile(\n workspacePath,\n 'DATABASE_URL',\n async (p) => fs.pathExists(p),\n async (p, v) => this.environment.getEnvVariable(p, v)\n )\n\n if (hasDefaultVar) {\n getLogger().debug('✅ Found fallback DATABASE_URL variable')\n } else {\n getLogger().debug('❌ No DATABASE_URL variable found in any env file')\n }\n return hasDefaultVar\n } catch (error) {\n // Re-throw configuration errors\n if (error instanceof Error && error.message.includes('not found in')) {\n throw error\n }\n // Return false for other errors\n return false\n }\n }\n}\n"],"mappings":"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","names":["path","fs","path","fs","fs","fs","fs","path","path","fs","fs"]}
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
getClaudeVersion,
|
|
8
8
|
launchClaude,
|
|
9
9
|
launchClaudeInNewTerminalWindow
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-UR5DGNUO.js";
|
|
11
11
|
import "./chunk-6MLEBAYZ.js";
|
|
12
12
|
import "./chunk-VT4PDUYT.js";
|
|
13
13
|
export {
|
|
@@ -19,4 +19,4 @@ export {
|
|
|
19
19
|
launchClaude,
|
|
20
20
|
launchClaudeInNewTerminalWindow
|
|
21
21
|
};
|
|
22
|
-
//# sourceMappingURL=claude-
|
|
22
|
+
//# sourceMappingURL=claude-7GGEWVEM.js.map
|
|
@@ -1,51 +1,71 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ResourceCleanup
|
|
4
|
+
} from "./chunk-RJ3VBUFK.js";
|
|
5
|
+
import "./chunk-LUKXJSRI.js";
|
|
2
6
|
import {
|
|
3
7
|
CLIIsolationManager,
|
|
4
8
|
DatabaseManager,
|
|
5
9
|
EnvironmentManager,
|
|
6
|
-
LoomManager
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import "./chunk-
|
|
10
|
+
LoomManager
|
|
11
|
+
} from "./chunk-ZNMPGMHY.js";
|
|
12
|
+
import "./chunk-KVHIAWVT.js";
|
|
13
|
+
import "./chunk-SWSJWA2S.js";
|
|
14
|
+
import "./chunk-4232AHNQ.js";
|
|
10
15
|
import {
|
|
11
16
|
ProcessManager
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
17
|
+
} from "./chunk-G5V75JD5.js";
|
|
18
|
+
import "./chunk-LLHXQS3C.js";
|
|
19
|
+
import "./chunk-WWKOVDWC.js";
|
|
14
20
|
import {
|
|
15
21
|
IdentifierParser
|
|
16
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-63QWFWH3.js";
|
|
17
23
|
import {
|
|
18
24
|
createNeonProviderFromSettings
|
|
19
|
-
} from "./chunk-
|
|
20
|
-
import
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
import "./chunk-4LKGCFGG.js";
|
|
25
|
+
} from "./chunk-P4O6EH46.js";
|
|
26
|
+
import {
|
|
27
|
+
TelemetryService
|
|
28
|
+
} from "./chunk-RSYT7MVI.js";
|
|
24
29
|
import {
|
|
25
30
|
GitWorktreeManager
|
|
26
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-I5T677EA.js";
|
|
32
|
+
import "./chunk-YETJNRQM.js";
|
|
33
|
+
import "./chunk-YQ57ORTV.js";
|
|
27
34
|
import "./chunk-FXDYIV3K.js";
|
|
28
|
-
import "./chunk-
|
|
29
|
-
import "./chunk-
|
|
35
|
+
import "./chunk-UR5DGNUO.js";
|
|
36
|
+
import "./chunk-4FGEGQW4.js";
|
|
30
37
|
import {
|
|
31
38
|
SettingsManager
|
|
32
|
-
} from "./chunk-
|
|
33
|
-
import "./chunk-KBEIQP4G.js";
|
|
34
|
-
import "./chunk-OFDN5NKS.js";
|
|
35
|
-
import "./chunk-4CO6KG5S.js";
|
|
39
|
+
} from "./chunk-7VHJNVLF.js";
|
|
36
40
|
import {
|
|
37
|
-
|
|
38
|
-
} from "./chunk-
|
|
39
|
-
import "./chunk-
|
|
40
|
-
import "./chunk-
|
|
41
|
+
MetadataManager
|
|
42
|
+
} from "./chunk-KB64WNBZ.js";
|
|
43
|
+
import "./chunk-HEXKPKCK.js";
|
|
44
|
+
import "./chunk-KXDRI47U.js";
|
|
45
|
+
import "./chunk-VG45TUYK.js";
|
|
41
46
|
import {
|
|
42
47
|
getLogger
|
|
43
48
|
} from "./chunk-6MLEBAYZ.js";
|
|
49
|
+
import {
|
|
50
|
+
promptConfirmation
|
|
51
|
+
} from "./chunk-7JDMYTFZ.js";
|
|
52
|
+
import "./chunk-433MOLAU.js";
|
|
44
53
|
import {
|
|
45
54
|
loadEnvIntoProcess
|
|
46
55
|
} from "./chunk-VT4PDUYT.js";
|
|
47
56
|
|
|
48
57
|
// src/commands/cleanup.ts
|
|
58
|
+
function trackLoomAbandoned(metadata) {
|
|
59
|
+
try {
|
|
60
|
+
const durationMinutes = metadata.created_at ? Math.round((Date.now() - new Date(metadata.created_at).getTime()) / 6e4) : 0;
|
|
61
|
+
TelemetryService.getInstance().track("loom.abandoned", {
|
|
62
|
+
duration_minutes: isNaN(durationMinutes) ? 0 : durationMinutes,
|
|
63
|
+
phase_reached: metadata.state ?? "unknown"
|
|
64
|
+
});
|
|
65
|
+
} catch (error) {
|
|
66
|
+
getLogger().debug(`Failed to track loom.abandoned telemetry: ${error instanceof Error ? error.message : String(error)}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
49
69
|
var CleanupCommand = class {
|
|
50
70
|
constructor(gitWorktreeManager, resourceCleanup) {
|
|
51
71
|
const envResult = loadEnvIntoProcess();
|
|
@@ -83,13 +103,13 @@ var CleanupCommand = class {
|
|
|
83
103
|
cliIsolationManager
|
|
84
104
|
);
|
|
85
105
|
if (!this.loomManager) {
|
|
86
|
-
const {
|
|
87
|
-
const { ClaudeContextManager } = await import("./ClaudeContextManager-
|
|
88
|
-
const { ProjectCapabilityDetector } = await import("./ProjectCapabilityDetector-
|
|
89
|
-
const { DefaultBranchNamingService } = await import("./BranchNamingService-
|
|
106
|
+
const { IssueTrackerFactory } = await import("./IssueTrackerFactory-NG53YX5S.js");
|
|
107
|
+
const { ClaudeContextManager } = await import("./ClaudeContextManager-66GR4BGM.js");
|
|
108
|
+
const { ProjectCapabilityDetector } = await import("./ProjectCapabilityDetector-5KSYUTBJ.js");
|
|
109
|
+
const { DefaultBranchNamingService } = await import("./BranchNamingService-25KSZAEM.js");
|
|
90
110
|
this.loomManager = new LoomManager(
|
|
91
111
|
this.gitWorktreeManager,
|
|
92
|
-
|
|
112
|
+
IssueTrackerFactory.create(settings),
|
|
93
113
|
new DefaultBranchNamingService({ useClaude: true }),
|
|
94
114
|
environmentManager,
|
|
95
115
|
new ClaudeContextManager(),
|
|
@@ -290,7 +310,7 @@ var CleanupCommand = class {
|
|
|
290
310
|
const { force, dryRun } = parsed.options;
|
|
291
311
|
let parsedInput = await this.identifierParser.parseForPatternDetection(identifier);
|
|
292
312
|
if (parsedInput.type === "branch" && parsedInput.branchName) {
|
|
293
|
-
const { extractIssueNumber } = await import("./git-
|
|
313
|
+
const { extractIssueNumber } = await import("./git-GTLKAZRJ.js");
|
|
294
314
|
const extractedNumber = extractIssueNumber(parsedInput.branchName);
|
|
295
315
|
if (extractedNumber !== null) {
|
|
296
316
|
parsedInput = {
|
|
@@ -315,6 +335,16 @@ var CleanupCommand = class {
|
|
|
315
335
|
};
|
|
316
336
|
}
|
|
317
337
|
}
|
|
338
|
+
let preCleanupMetadata = null;
|
|
339
|
+
try {
|
|
340
|
+
const worktree = parsedInput.type === "branch" && parsedInput.branchName ? await this.gitWorktreeManager.findWorktreeForBranch(parsedInput.branchName) : parsedInput.number !== void 0 ? await this.gitWorktreeManager.findWorktreeForIssue(parsedInput.number) : null;
|
|
341
|
+
if (worktree) {
|
|
342
|
+
const metadataManager = new MetadataManager();
|
|
343
|
+
preCleanupMetadata = await metadataManager.readMetadata(worktree.path);
|
|
344
|
+
}
|
|
345
|
+
} catch (error) {
|
|
346
|
+
getLogger().debug(`Failed to read metadata for telemetry: ${error instanceof Error ? error.message : String(error)}`);
|
|
347
|
+
}
|
|
318
348
|
await this.ensureResourceCleanup();
|
|
319
349
|
if (!this.resourceCleanup) {
|
|
320
350
|
throw new Error("Failed to initialize ResourceCleanup");
|
|
@@ -325,11 +355,15 @@ var CleanupCommand = class {
|
|
|
325
355
|
deleteBranch: true,
|
|
326
356
|
// Always include branch deletion (safety checks run first)
|
|
327
357
|
keepDatabase: false,
|
|
328
|
-
checkMergeSafety: true
|
|
358
|
+
checkMergeSafety: true,
|
|
329
359
|
// Run 5-point safety check BEFORE any deletion
|
|
360
|
+
archive: parsed.options.archive ?? false
|
|
330
361
|
});
|
|
331
362
|
cleanupResult.dryRun = dryRun ?? false;
|
|
332
363
|
this.reportCleanupResults(cleanupResult);
|
|
364
|
+
if (cleanupResult.success && preCleanupMetadata && preCleanupMetadata.status !== "finished") {
|
|
365
|
+
trackLoomAbandoned(preCleanupMetadata);
|
|
366
|
+
}
|
|
333
367
|
if (cleanupResult.success) {
|
|
334
368
|
getLogger().success("Cleanup completed successfully");
|
|
335
369
|
} else {
|
|
@@ -366,7 +400,7 @@ var CleanupCommand = class {
|
|
|
366
400
|
throw new Error("No issue/PR number provided for cleanup");
|
|
367
401
|
}
|
|
368
402
|
const { force, dryRun } = parsed.options;
|
|
369
|
-
getLogger().info(`Finding worktrees related to
|
|
403
|
+
getLogger().info(`Finding worktrees related to issue/PR #${issueNumber}...`);
|
|
370
404
|
const worktrees = await this.gitWorktreeManager.listWorktrees();
|
|
371
405
|
const matchingWorktrees = worktrees.filter((wt) => {
|
|
372
406
|
const path = wt.path.toLowerCase();
|
|
@@ -375,7 +409,7 @@ var CleanupCommand = class {
|
|
|
375
409
|
return pattern.test(path);
|
|
376
410
|
});
|
|
377
411
|
if (matchingWorktrees.length === 0) {
|
|
378
|
-
getLogger().warn(`No worktrees found for
|
|
412
|
+
getLogger().warn(`No worktrees found for issue/PR #${issueNumber}`);
|
|
379
413
|
getLogger().info(`Searched for worktree paths containing: ${issueNumber}, _pr_${issueNumber}, issue-${issueNumber}, etc.`);
|
|
380
414
|
return {
|
|
381
415
|
identifier: String(issueNumber),
|
|
@@ -419,6 +453,15 @@ var CleanupCommand = class {
|
|
|
419
453
|
for (const target of targets) {
|
|
420
454
|
getLogger().info(`Processing worktree: ${target.branchName}`);
|
|
421
455
|
try {
|
|
456
|
+
let targetMetadata = null;
|
|
457
|
+
if (target.worktreePath) {
|
|
458
|
+
try {
|
|
459
|
+
const metadataManager = new MetadataManager();
|
|
460
|
+
targetMetadata = await metadataManager.readMetadata(target.worktreePath);
|
|
461
|
+
} catch (error) {
|
|
462
|
+
getLogger().debug(`Failed to read metadata for telemetry: ${error instanceof Error ? error.message : String(error)}`);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
422
465
|
const parsedInput = {
|
|
423
466
|
type: "issue",
|
|
424
467
|
number: issueNumber,
|
|
@@ -436,8 +479,10 @@ var CleanupCommand = class {
|
|
|
436
479
|
deleteBranch: true,
|
|
437
480
|
// Include branch deletion (with safety checks)
|
|
438
481
|
keepDatabase: false,
|
|
439
|
-
checkMergeSafety: true
|
|
482
|
+
checkMergeSafety: true,
|
|
440
483
|
// Run 5-point safety check BEFORE any deletion
|
|
484
|
+
archive: parsed.options.archive ?? false,
|
|
485
|
+
...target.worktreePath && { worktree: { path: target.worktreePath, branch: target.branchName } }
|
|
441
486
|
});
|
|
442
487
|
if (result.success) {
|
|
443
488
|
worktreesRemoved++;
|
|
@@ -452,9 +497,15 @@ var CleanupCommand = class {
|
|
|
452
497
|
const deletedBranchName = target.branchName;
|
|
453
498
|
databaseBranchesDeletedList.push(deletedBranchName);
|
|
454
499
|
}
|
|
500
|
+
if (targetMetadata && targetMetadata.status !== "finished") {
|
|
501
|
+
trackLoomAbandoned(targetMetadata);
|
|
502
|
+
}
|
|
455
503
|
} else {
|
|
456
504
|
failed++;
|
|
457
505
|
getLogger().error(` Failed to remove worktree: ${target.branchName}`);
|
|
506
|
+
for (const err of result.errors) {
|
|
507
|
+
getLogger().error(` ${err.message}`);
|
|
508
|
+
}
|
|
458
509
|
}
|
|
459
510
|
} catch (error) {
|
|
460
511
|
failed++;
|
|
@@ -489,4 +540,4 @@ var CleanupCommand = class {
|
|
|
489
540
|
export {
|
|
490
541
|
CleanupCommand
|
|
491
542
|
};
|
|
492
|
-
//# sourceMappingURL=cleanup-
|
|
543
|
+
//# sourceMappingURL=cleanup-6PVAC4NI.js.map
|