@iloom/cli 0.1.17 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +14 -0
  2. package/dist/ClaudeContextManager-LD3VB6EM.js +13 -0
  3. package/dist/ClaudeService-CFFI7DD5.js +12 -0
  4. package/dist/{GitHubService-F7Z3XJOS.js → GitHubService-SH4H6VS5.js} +3 -3
  5. package/dist/{LoomLauncher-MODG2SEM.js → LoomLauncher-FB2MV2ZI.js} +7 -7
  6. package/dist/{PromptTemplateManager-7FINLRDE.js → PromptTemplateManager-WM5GIPEF.js} +2 -2
  7. package/dist/{SettingsManager-VAZF26S2.js → SettingsManager-SKLUVE3K.js} +6 -2
  8. package/dist/{add-issue-22JBNOML.js → add-issue-L5HX6LEV.js} +23 -8
  9. package/dist/add-issue-L5HX6LEV.js.map +1 -0
  10. package/dist/{chunk-SSR5AVRJ.js → chunk-6OTVPRXH.js} +21 -8
  11. package/dist/chunk-6OTVPRXH.js.map +1 -0
  12. package/dist/{chunk-KQDEK2ZW.js → chunk-DGEKUT7Q.js} +9 -5
  13. package/dist/chunk-DGEKUT7Q.js.map +1 -0
  14. package/dist/chunk-FXV24OYZ.js +83 -0
  15. package/dist/chunk-FXV24OYZ.js.map +1 -0
  16. package/dist/{chunk-HPJJSYNS.js → chunk-H5LDRGVK.js} +6 -8
  17. package/dist/{chunk-HPJJSYNS.js.map → chunk-H5LDRGVK.js.map} +1 -1
  18. package/dist/{chunk-WKEWRSDB.js → chunk-HURVAQRK.js} +3 -3
  19. package/dist/{chunk-T7QPXANZ.js → chunk-IIPTBZQW.js} +17 -17
  20. package/dist/chunk-IIPTBZQW.js.map +1 -0
  21. package/dist/{chunk-QEPVTTHD.js → chunk-IO4WFTL2.js} +17 -11
  22. package/dist/chunk-IO4WFTL2.js.map +1 -0
  23. package/dist/{chunk-JQ7VOSTC.js → chunk-KOCQAD2E.js} +3 -3
  24. package/dist/{chunk-F3XBU2R7.js → chunk-L4QGC27H.js} +68 -2
  25. package/dist/chunk-L4QGC27H.js.map +1 -0
  26. package/dist/{chunk-YYSKGAZT.js → chunk-LAPY6NAE.js} +17 -8
  27. package/dist/chunk-LAPY6NAE.js.map +1 -0
  28. package/dist/{chunk-O2QWO64Z.js → chunk-PV3GAXQO.js} +56 -3
  29. package/dist/chunk-PV3GAXQO.js.map +1 -0
  30. package/dist/{chunk-CP2NU2JC.js → chunk-Q2KYPAH2.js} +7 -7
  31. package/dist/{chunk-CP2NU2JC.js.map → chunk-Q2KYPAH2.js.map} +1 -1
  32. package/dist/{chunk-Y7SAGNUT.js → chunk-SLIMABFA.js} +2 -2
  33. package/dist/{chunk-W3DQTW63.js → chunk-USVVV3FP.js} +4 -4
  34. package/dist/chunk-VVH3ANF2.js +307 -0
  35. package/dist/chunk-VVH3ANF2.js.map +1 -0
  36. package/dist/{chunk-JBH2ZYYZ.js → chunk-VYQLLHZ7.js} +22 -3
  37. package/dist/chunk-VYQLLHZ7.js.map +1 -0
  38. package/dist/{chunk-SJUQ2NDR.js → chunk-ZMNQBJUI.js} +24 -19
  39. package/dist/chunk-ZMNQBJUI.js.map +1 -0
  40. package/dist/{cleanup-3LUWPSM7.js → cleanup-ZHROIBSQ.js} +12 -16
  41. package/dist/cleanup-ZHROIBSQ.js.map +1 -0
  42. package/dist/cli.js +96 -48
  43. package/dist/cli.js.map +1 -1
  44. package/dist/{enhance-XJIQHVPD.js → enhance-VVMAKMVZ.js} +18 -8
  45. package/dist/enhance-VVMAKMVZ.js.map +1 -0
  46. package/dist/{feedback-23CLXKFT.js → feedback-AKHD7QIM.js} +8 -8
  47. package/dist/{finish-3CQZIULO.js → finish-WGPISUEH.js} +36 -313
  48. package/dist/finish-WGPISUEH.js.map +1 -0
  49. package/dist/{git-LVRZ57GJ.js → git-OUYMVYJX.js} +2 -2
  50. package/dist/{ignite-WXEF2ID5.js → ignite-JEN3K3OT.js} +7 -7
  51. package/dist/index.d.ts +791 -712
  52. package/dist/index.js +126 -32
  53. package/dist/index.js.map +1 -1
  54. package/dist/init-EVUT4ZQJ.js +339 -0
  55. package/dist/init-EVUT4ZQJ.js.map +1 -0
  56. package/dist/mcp/github-comment-server.js +12 -9
  57. package/dist/mcp/github-comment-server.js.map +1 -1
  58. package/dist/neon-helpers-ZVIRPKCI.js +10 -0
  59. package/dist/{open-X6BTENPV.js → open-ETZUFSE4.js} +15 -17
  60. package/dist/{open-X6BTENPV.js.map → open-ETZUFSE4.js.map} +1 -1
  61. package/dist/prompts/init-prompt.txt +746 -0
  62. package/dist/rebase-KBWFDZCN.js +95 -0
  63. package/dist/rebase-KBWFDZCN.js.map +1 -0
  64. package/dist/remote-GJEZWRCC.js +14 -0
  65. package/dist/{run-2JCPQAX3.js → run-4SVQ3WEU.js} +15 -17
  66. package/dist/{run-2JCPQAX3.js.map → run-4SVQ3WEU.js.map} +1 -1
  67. package/dist/schema/settings.schema.json +51 -1
  68. package/dist/{start-LWVRBJ6S.js → start-2NEZU7SE.js} +54 -53
  69. package/dist/{start-LWVRBJ6S.js.map → start-2NEZU7SE.js.map} +1 -1
  70. package/dist/{test-git-XPF4SZXJ.js → test-git-MKZATGZN.js} +3 -3
  71. package/dist/{test-prefix-XGFXFAYN.js → test-prefix-ZNLWDI3K.js} +3 -3
  72. package/dist/{update-DN3FSNKY.js → update-4TDDUR5K.js} +10 -4
  73. package/dist/{update-DN3FSNKY.js.map → update-4TDDUR5K.js.map} +1 -1
  74. package/package.json +1 -1
  75. package/dist/ClaudeContextManager-XOSXQ67R.js +0 -13
  76. package/dist/ClaudeService-YSZ6EXWP.js +0 -12
  77. package/dist/NeonProvider-PAGPUH7F.js +0 -12
  78. package/dist/add-issue-22JBNOML.js.map +0 -1
  79. package/dist/chunk-37DYYFVK.js +0 -29
  80. package/dist/chunk-37DYYFVK.js.map +0 -1
  81. package/dist/chunk-F3XBU2R7.js.map +0 -1
  82. package/dist/chunk-JBH2ZYYZ.js.map +0 -1
  83. package/dist/chunk-KQDEK2ZW.js.map +0 -1
  84. package/dist/chunk-O2QWO64Z.js.map +0 -1
  85. package/dist/chunk-QEPVTTHD.js.map +0 -1
  86. package/dist/chunk-SJUQ2NDR.js.map +0 -1
  87. package/dist/chunk-SSR5AVRJ.js.map +0 -1
  88. package/dist/chunk-T7QPXANZ.js.map +0 -1
  89. package/dist/chunk-YYSKGAZT.js.map +0 -1
  90. package/dist/cleanup-3LUWPSM7.js.map +0 -1
  91. package/dist/enhance-XJIQHVPD.js.map +0 -1
  92. package/dist/env-MDFL4ZXL.js +0 -23
  93. package/dist/finish-3CQZIULO.js.map +0 -1
  94. package/dist/init-RHACUR4E.js +0 -123
  95. package/dist/init-RHACUR4E.js.map +0 -1
  96. /package/dist/{ClaudeContextManager-XOSXQ67R.js.map → ClaudeContextManager-LD3VB6EM.js.map} +0 -0
  97. /package/dist/{ClaudeService-YSZ6EXWP.js.map → ClaudeService-CFFI7DD5.js.map} +0 -0
  98. /package/dist/{GitHubService-F7Z3XJOS.js.map → GitHubService-SH4H6VS5.js.map} +0 -0
  99. /package/dist/{LoomLauncher-MODG2SEM.js.map → LoomLauncher-FB2MV2ZI.js.map} +0 -0
  100. /package/dist/{NeonProvider-PAGPUH7F.js.map → PromptTemplateManager-WM5GIPEF.js.map} +0 -0
  101. /package/dist/{PromptTemplateManager-7FINLRDE.js.map → SettingsManager-SKLUVE3K.js.map} +0 -0
  102. /package/dist/{chunk-WKEWRSDB.js.map → chunk-HURVAQRK.js.map} +0 -0
  103. /package/dist/{chunk-JQ7VOSTC.js.map → chunk-KOCQAD2E.js.map} +0 -0
  104. /package/dist/{chunk-Y7SAGNUT.js.map → chunk-SLIMABFA.js.map} +0 -0
  105. /package/dist/{chunk-W3DQTW63.js.map → chunk-USVVV3FP.js.map} +0 -0
  106. /package/dist/{feedback-23CLXKFT.js.map → feedback-AKHD7QIM.js.map} +0 -0
  107. /package/dist/{SettingsManager-VAZF26S2.js.map → git-OUYMVYJX.js.map} +0 -0
  108. /package/dist/{ignite-WXEF2ID5.js.map → ignite-JEN3K3OT.js.map} +0 -0
  109. /package/dist/{env-MDFL4ZXL.js.map → neon-helpers-ZVIRPKCI.js.map} +0 -0
  110. /package/dist/{git-LVRZ57GJ.js.map → remote-GJEZWRCC.js.map} +0 -0
  111. /package/dist/{test-git-XPF4SZXJ.js.map → test-git-MKZATGZN.js.map} +0 -0
  112. /package/dist/{test-prefix-XGFXFAYN.js.map → test-prefix-ZNLWDI3K.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/LoomManager.ts","../src/lib/VSCodeIntegration.ts","../src/commands/start.ts"],"sourcesContent":["import path from 'path'\nimport fs from 'fs-extra'\nimport { GitWorktreeManager } from './GitWorktreeManager.js'\nimport { GitHubService } from './GitHubService.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 { branchExists, executeGitCommand, ensureRepositoryHasCommits } from '../utils/git.js'\nimport { installDependencies } from '../utils/package-manager.js'\nimport { generateColorFromBranchName } from '../utils/color.js'\nimport { DatabaseManager } from './DatabaseManager.js'\nimport { loadEnvIntoProcess } 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 { logger } from '../utils/logger.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 constructor(\n private gitWorktree: GitWorktreeManager,\n private github: GitHubService,\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 ) {}\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 GitHub data if needed\n logger.info('Fetching GitHub data...')\n const githubData = await this.fetchGitHubData(input)\n\n // NEW: Check for existing worktree BEFORE generating branch name (for efficiency)\n if (input.type === 'issue' || input.type === 'pr') {\n logger.info('Checking for existing worktree...')\n const existing = await this.findExistingIloom(input, githubData)\n if (existing) {\n logger.success(`Found existing worktree, reusing: ${existing.path}`)\n return await this.reuseIloom(existing, input, githubData)\n }\n logger.info('No existing worktree found, creating new one...')\n }\n\n // 2. Generate or validate branch name\n logger.info('Preparing branch name...')\n const branchName = await this.prepareBranchName(input, githubData)\n\n // 3. Create git worktree (WITHOUT dependency installation)\n logger.info('Creating git worktree...')\n const worktreePath = await this.createWorktreeOnly(input, branchName)\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 // 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)\n } catch (error) {\n // Log warning but don't fail - matches bash script behavior\n logger.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 path.join(worktreePath, '.env')\n )\n\n if (connectionString) {\n await this.environment.setEnvVar(\n path.join(worktreePath, '.env'),\n this.database.getConfiguredVariableName(),\n connectionString\n )\n logger.success('Database branch configured')\n databaseBranch = branchName\n }\n } catch (error) {\n logger.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 let cliSymlinks: string[] | undefined = undefined\n if (capabilities.includes('cli')) {\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 logger.warn(\n `Failed to setup CLI isolation: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error\n )\n }\n }\n\n // 11. Apply color synchronization (terminal and VSCode)\n if (!input.options?.skipColorSync) {\n try {\n await this.applyColorSynchronization(worktreePath, branchName)\n } catch (error) {\n // Log warning but don't fail - colors are cosmetic\n logger.warn(\n `Failed to apply color synchronization: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error\n )\n }\n }\n\n // NEW: Move issue to In Progress (for new worktrees)\n if (input.type === 'issue') {\n try {\n logger.info('Moving issue to In Progress...')\n await this.github.moveIssueToInProgress(input.identifier as number)\n } catch (error) {\n // Warn but don't fail - matches bash script behavior\n logger.warn(\n `Failed to move issue to In Progress: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error\n )\n }\n }\n\n // 8. 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)\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,\n identifier: input.identifier,\n ...(githubData?.title && { title: githubData.title }),\n oneShot,\n ...(setArguments && { setArguments }),\n ...(executablePath && { executablePath }),\n })\n }\n\n // 9. 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 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 ...(githubData !== null && {\n githubData: {\n title: githubData.title,\n body: githubData.body,\n url: githubData.url,\n state: githubData.state,\n },\n }),\n }\n\n logger.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 return await this.mapWorktreesToLooms(worktrees)\n }\n\n /**\n * Find a specific loom by identifier\n */\n async findIloom(identifier: string): Promise<Loom | null> {\n const looms = await this.listLooms()\n return (\n looms.find(\n h =>\n h.id === identifier ||\n h.identifier.toString() === identifier ||\n h.branch === identifier\n ) ?? null\n )\n }\n\n /**\n * Fetch GitHub data based on input type\n */\n private async fetchGitHubData(\n input: CreateLoomInput\n ): Promise<Issue | PullRequest | null> {\n if (input.type === 'issue') {\n return await this.github.fetchIssue(input.identifier as number)\n } else if (input.type === 'pr') {\n return await this.github.fetchPR(input.identifier as number)\n }\n return null\n }\n\n /**\n * Prepare branch name based on input type and GitHub data\n */\n private async prepareBranchName(\n input: CreateLoomInput,\n githubData: Issue | PullRequest | null\n ): Promise<string> {\n if (input.type === 'branch') {\n return input.identifier as string\n }\n\n if (input.type === 'pr' && githubData && 'branch' in githubData) {\n return githubData.branch\n }\n\n if (input.type === 'issue' && githubData) {\n // Use Claude AI-powered branch name generation\n const branchName = await this.github.generateBranchName({\n issueNumber: input.identifier as number,\n title: githubData.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 ): 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 logger.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 const worktreePrefix = settingsData.worktreePrefix\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 // 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 logger.info('Fetching all remote branches...')\n try {\n await executeGitCommand(['fetch', 'origin'], { cwd: this.gitWorktree.workingDirectory })\n logger.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 // Check if branch exists locally (used for different purposes depending on type)\n const branchExistedLocally = await branchExists(branchName)\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 await this.gitWorktree.createWorktree({\n path: worktreePath,\n branch: branchName,\n createBranch: input.type !== 'pr', // PRs use existing branches\n ...(input.baseBranch && { baseBranch: input.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 logger.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 logger.success('Successfully reset to match remote')\n } catch (error) {\n logger.warn(`Failed to reset to match remote: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n return worktreePath\n }\n\n /**\n * Copy user application environment files (.env) from main repo to worktree\n * Always called regardless of project capabilities\n */\n private async copyEnvironmentFiles(worktreePath: string): Promise<void> {\n const envFilePath = path.join(worktreePath, '.env')\n\n try {\n const mainEnvPath = path.join(process.cwd(), '.env')\n if (await fs.pathExists(envFilePath)) {\n logger.warn('.env file already exists in worktree, skipping copy')\n } else {\n //TODO: Update this to handle .env.local, .env.development and .env.development.local as well.\n await this.environment.copyIfExists(mainEnvPath, envFilePath)\n }\n } catch (error) {\n // Handle gracefully if main .env fails to copy\n logger.warn(`Warning: Failed to copy main .env file: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Copy iloom configuration (settings.local.json) from main repo to worktree\n * Always called regardless of project capabilities\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 // Check if settings.local.json already exists in worktree\n if (await fs.pathExists(worktreeSettingsLocalPath)) {\n logger.warn('settings.local.json already exists in worktree, skipping copy')\n } else {\n await this.environment.copyIfExists(mainSettingsLocalPath, worktreeSettingsLocalPath)\n }\n } catch (error) {\n logger.warn(`Warning: Failed to copy settings.local.json: ${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')\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') {\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 // Handle gracefully if .env files don't exist\n logger.warn(`Warning: Could not load .env files: ${result.error.message}`)\n } else {\n logger.info('Loaded environment variables using dotenv-flow')\n if (result.parsed && Object.keys(result.parsed).length > 0) {\n logger.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' && typeof input.identifier === 'number') {\n return this.environment.calculatePort({ basePort, issueNumber: input.identifier })\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}`)\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 */\n private async applyColorSynchronization(\n worktreePath: string,\n branchName: string\n ): Promise<void> {\n const colorData = generateColorFromBranchName(branchName)\n\n // Apply VSCode title bar color\n const vscode = new VSCodeIntegration()\n await vscode.setTitleBarColor(worktreePath, colorData.hex)\n\n logger.info(`Applied VSCode title bar color: ${colorData.hex} for branch: ${branchName}`)\n\n // Note: Terminal color is applied during window creation in ClaudeContextManager\n // This ensures the color is set when the new terminal window is opened\n }\n\n /**\n * Map worktrees to loom objects\n * This is a simplified conversion - in production we'd store loom metadata\n */\n private async mapWorktreesToLooms(worktrees: GitWorktree[]): Promise<Loom[]> {\n return await Promise.all(worktrees.map(async (wt) => {\n // Extract identifier from branch name\n let type: 'issue' | 'pr' | 'branch' = 'branch'\n let identifier: string | number = wt.branch\n\n if (wt.branch.startsWith('issue-')) {\n type = 'issue'\n identifier = parseInt(wt.branch.replace('issue-', ''), 10)\n } else if (wt.branch.startsWith('pr-')) {\n type = 'pr'\n identifier = parseInt(wt.branch.replace('pr-', ''), 10)\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 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 githubData: 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' && githubData && 'branch' in githubData) {\n return await this.gitWorktree.findWorktreeForPR(\n input.identifier as number,\n githubData.branch\n )\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 githubData: 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\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 logger.info('Database branch assumed to be already configured for existing worktree')\n const databaseBranch: string | undefined = undefined\n\n // 6. Move issue to In Progress (for reused worktrees too)\n if (input.type === 'issue') {\n try {\n logger.info('Moving issue to In Progress...')\n await this.github.moveIssueToInProgress(input.identifier as number)\n } catch (error) {\n logger.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 logger.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)\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,\n identifier: input.identifier,\n ...(githubData?.title && { title: githubData.title }),\n oneShot,\n ...(setArguments && { setArguments }),\n ...(executablePath && { executablePath }),\n })\n }\n\n // 8. 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 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 ...(githubData !== null && {\n githubData: {\n title: githubData.title,\n body: githubData.body,\n url: githubData.url,\n state: githubData.state,\n },\n }),\n }\n\n logger.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 { logger } from '../utils/logger.js'\nimport { GitHubService } from '../lib/GitHubService.js'\nimport { LoomManager } from '../lib/LoomManager.js'\nimport { GitWorktreeManager } from '../lib/GitWorktreeManager.js'\nimport { EnvironmentManager } from '../lib/EnvironmentManager.js'\nimport { ClaudeContextManager } from '../lib/ClaudeContextManager.js'\nimport { ProjectCapabilityDetector } from '../lib/ProjectCapabilityDetector.js'\nimport { CLIIsolationManager } from '../lib/CLIIsolationManager.js'\nimport { SettingsManager } from '../lib/SettingsManager.js'\nimport { AgentManager } from '../lib/AgentManager.js'\nimport { DatabaseManager } from '../lib/DatabaseManager.js'\nimport { NeonProvider } from '../lib/providers/NeonProvider.js'\nimport { IssueEnhancementService } from '../lib/IssueEnhancementService.js'\nimport { branchExists, findMainWorktreePathWithSettings } from '../utils/git.js'\nimport { loadEnvIntoProcess } from '../utils/env.js'\nimport { extractSettingsOverrides } from '../utils/cli-overrides.js'\nimport type { StartOptions } from '../types/index.js'\n\nexport interface StartCommandInput {\n\tidentifier: string\n\toptions: StartOptions\n}\n\nexport interface ParsedInput {\n\ttype: 'issue' | 'pr' | 'branch' | 'description'\n\tnumber?: number\n\tbranchName?: string\n\toriginalInput: string\n}\n\nexport class StartCommand {\n\tprivate gitHubService: GitHubService\n\tprivate loomManager: LoomManager | null = null\n\tprivate agentManager: AgentManager\n\tprivate settingsManager: SettingsManager\n\tprivate enhancementService: IssueEnhancementService\n\tprivate providedLoomManager: LoomManager | undefined\n\n\tconstructor(\n\t\tgitHubService?: GitHubService,\n\t\tloomManager?: LoomManager,\n\t\tagentManager?: AgentManager,\n\t\tsettingsManager?: SettingsManager\n\t) {\n\t\tthis.gitHubService = gitHubService ?? new GitHubService()\n\t\tthis.agentManager = agentManager ?? new AgentManager()\n\t\tthis.settingsManager = settingsManager ?? new SettingsManager()\n\t\tthis.enhancementService = new IssueEnhancementService(\n\t\t\tthis.gitHubService,\n\t\t\tthis.agentManager,\n\t\t\tthis.settingsManager\n\t\t)\n\t\t// Store provided LoomManager for testing, but don't initialize yet\n\t\tthis.providedLoomManager = loomManager\n\n\t\t// Load environment variables first\n\t\tconst envResult = loadEnvIntoProcess()\n\t\tif (envResult.error) {\n\t\t\tlogger.debug(`Environment loading warning: ${envResult.error.message}`)\n\t\t}\n\t\tif (envResult.parsed) {\n\t\t\tlogger.debug(`Loaded ${Object.keys(envResult.parsed).length} environment variables`)\n\t\t}\n\t}\n\n\t/**\n\t * Initialize LoomManager with the main worktree path\n\t * Uses lazy initialization to ensure we have the correct path\n\t */\n\tprivate async initializeLoomManager(): Promise<LoomManager> {\n\t\tif (this.loomManager) {\n\t\t\treturn this.loomManager\n\t\t}\n\n\t\tif (this.providedLoomManager) {\n\t\t\tthis.loomManager = this.providedLoomManager\n\t\t\treturn this.loomManager\n\t\t}\n\n\t\t// Find main worktree path\n\t\tconst mainWorktreePath = await findMainWorktreePathWithSettings()\n\n\t\t// Create DatabaseManager with NeonProvider and EnvironmentManager\n\t\tconst environmentManager = new EnvironmentManager()\n\n\t\t// Debug environment variables\n\t\tlogger.debug('Environment variables for Neon:', {\n\t\t\tNEON_PROJECT_ID: process.env.NEON_PROJECT_ID,\n\t\t\tNEON_PARENT_BRANCH: process.env.NEON_PARENT_BRANCH,\n\t\t\thasNeonProjectId: !!process.env.NEON_PROJECT_ID,\n\t\t\thasNeonParentBranch: !!process.env.NEON_PARENT_BRANCH,\n\t\t\tneonProjectIdLength: process.env.NEON_PROJECT_ID?.length ?? 0,\n\t\t})\n\n\t\tconst neonProvider = new NeonProvider({\n\t\t\tprojectId: process.env.NEON_PROJECT_ID ?? '',\n\t\t\tparentBranch: process.env.NEON_PARENT_BRANCH ?? '',\n\t\t})\n\n\t\t// Load settings to get database URL environment variable name\n\t\tconst settings = await this.settingsManager.loadSettings()\n\t\tconst databaseUrlEnvVarName = settings.capabilities?.database?.databaseUrlEnvVarName ?? 'DATABASE_URL'\n\n\t\tconst databaseManager = new DatabaseManager(neonProvider, environmentManager, databaseUrlEnvVarName)\n\n\t\tthis.loomManager = new LoomManager(\n\t\t\tnew GitWorktreeManager(mainWorktreePath),\n\t\t\tthis.gitHubService,\n\t\t\tenvironmentManager, // Reuse same instance\n\t\t\tnew ClaudeContextManager(),\n\t\t\tnew ProjectCapabilityDetector(),\n\t\t\tnew CLIIsolationManager(),\n\t\t\tthis.settingsManager, // Use same instance with CLI overrides\n\t\t\tdatabaseManager // Add database manager\n\t\t)\n\n\t\treturn this.loomManager\n\t}\n\n\t/**\n\t * Main entry point for the start command\n\t */\n\tpublic async execute(input: StartCommandInput): Promise<void> {\n\t\ttry {\n\t\t\t// Step 0: Initialize LoomManager with main worktree path\n\t\t\tconst loomManager = await this.initializeLoomManager()\n\n\t\t\t// Step 1: Parse and validate input\n\t\t\tconst parsed = await this.parseInput(input.identifier)\n\n\t\t\t// Step 2: Validate based on type\n\t\t\tawait this.validateInput(parsed)\n\n\t\t\t// Step 2.5: Handle description input - create GitHub issue\n\t\t\tif (parsed.type === 'description') {\n\t\t\t\tconst issueNumber = await this.enhanceAndCreateIssue(parsed.originalInput)\n\t\t\t\t// Update parsed to be an issue type with the new number\n\t\t\t\tparsed.type = 'issue'\n\t\t\t\tparsed.number = issueNumber\n\t\t\t}\n\n\t\t\t// Step 2.7: Confirm bypassPermissions mode if applicable\n\t\t\tif (input.options.oneShot === 'bypassPermissions') {\n\t\t\t\tconst { promptConfirmation } = await import('../utils/prompt.js')\n\t\t\t\tconst confirmed = await promptConfirmation(\n\t\t\t\t\t'⚠️ WARNING: bypassPermissions mode will allow Claude to execute all tool calls without confirmation. ' +\n\t\t\t\t\t'This can be dangerous. Do you want to proceed?'\n\t\t\t\t)\n\t\t\t\tif (!confirmed) {\n\t\t\t\t\tlogger.info('Operation cancelled by user')\n\t\t\t\t\tprocess.exit(0)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Step 2.8: Load workflow-specific settings with CLI overrides\n\t\t\tconst cliOverrides = extractSettingsOverrides()\n\t\t\tconst settings = await this.settingsManager.loadSettings(undefined, cliOverrides)\n\t\t\tconst workflowType = parsed.type === 'branch' ? 'regular' : parsed.type\n\t\t\tconst workflowConfig = settings.workflows?.[workflowType]\n\n\t\t\t// Step 2.9: Extract raw --set arguments and executable path for forwarding to spin\n\t\t\tconst { extractRawSetArguments, getExecutablePath } = await import('../utils/cli-overrides.js')\n\t\t\tconst setArguments = extractRawSetArguments()\n\t\t\tconst executablePath = getExecutablePath()\n\n\t\t\t// Step 3: Log success and create loom\n\t\t\tlogger.info(`✅ Validated input: ${this.formatParsedInput(parsed)}`)\n\n\t\t\t// Step 4: Create loom using LoomManager\n\t\t\tconst identifier =\n\t\t\t\tparsed.type === 'branch'\n\t\t\t\t\t? parsed.branchName ?? ''\n\t\t\t\t\t: parsed.number ?? 0\n\n\t\t\t// Apply configuration precedence: CLI flags > workflow config > defaults (true)\n\t\t\tconst enableClaude = input.options.claude ?? workflowConfig?.startAiAgent ?? true\n\t\t\tconst enableCode = input.options.code ?? workflowConfig?.startIde ?? true\n\t\t\tconst enableDevServer = input.options.devServer ?? workflowConfig?.startDevServer ?? true\n\t\t\tconst enableTerminal = input.options.terminal ?? workflowConfig?.startTerminal ?? false\n\n\t\t\tlogger.debug('Final workflow config values:', {\n\t\t\t\tenableClaude,\n\t\t\t\tenableCode,\n\t\t\t\tenableDevServer,\n\t\t\t\tenableTerminal,\n\t\t\t})\n\n\t\t\tconst loom = await loomManager.createIloom({\n\t\t\t\ttype: parsed.type,\n\t\t\t\tidentifier,\n\t\t\t\toriginalInput: parsed.originalInput,\n\t\t\t\toptions: {\n\t\t\t\t\tenableClaude,\n\t\t\t\t\tenableCode,\n\t\t\t\t\tenableDevServer,\n\t\t\t\t\tenableTerminal,\n\t\t\t\t\t...(input.options.oneShot && { oneShot: input.options.oneShot }),\n\t\t\t\t\t...(setArguments.length > 0 && { setArguments }),\n\t\t\t\t\t...(executablePath && { executablePath }),\n\t\t\t\t},\n\t\t\t})\n\n\t\t\tlogger.success(`✅ Created loom: ${loom.id} at ${loom.path}`)\n\t\t\tlogger.info(` Branch: ${loom.branch}`)\n\t\t\t// Only show port for web projects\n\t\t\tif (loom.capabilities?.includes('web')) {\n\t\t\t\tlogger.info(` Port: ${loom.port}`)\n\t\t\t}\n\t\t\tif (loom.githubData?.title) {\n\t\t\t\tlogger.info(` Title: ${loom.githubData.title}`)\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) {\n\t\t\t\tlogger.error(`❌ ${error.message}`)\n\t\t\t} else {\n\t\t\t\tlogger.error('❌ An unknown error occurred')\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Parse input to determine type and extract relevant data\n\t */\n\tprivate async parseInput(identifier: string): Promise<ParsedInput> {\n\t\t// Handle empty input\n\t\tconst trimmedIdentifier = identifier.trim()\n\t\tif (!trimmedIdentifier) {\n\t\t\tthrow new Error('Missing required argument: identifier')\n\t\t}\n\n\t\t// Check for description: >25 chars AND >2 spaces\n\t\tconst spaceCount = (trimmedIdentifier.match(/ /g) ?? []).length\n\t\tif (trimmedIdentifier.length > 25 && spaceCount > 2) {\n\t\t\treturn {\n\t\t\t\ttype: 'description',\n\t\t\t\toriginalInput: trimmedIdentifier,\n\t\t\t}\n\t\t}\n\n\t\t// Check for PR-specific formats: pr/123, PR-123, PR/123\n\t\tconst prPattern = /^(?:pr|PR)[/-](\\d+)$/\n\t\tconst prMatch = trimmedIdentifier.match(prPattern)\n\t\tif (prMatch?.[1]) {\n\t\t\treturn {\n\t\t\t\ttype: 'pr',\n\t\t\t\tnumber: parseInt(prMatch[1], 10),\n\t\t\t\toriginalInput: trimmedIdentifier,\n\t\t\t}\n\t\t}\n\n\t\t// Check for numeric pattern (could be issue or PR)\n\t\tconst numericPattern = /^#?(\\d+)$/\n\t\tconst numericMatch = trimmedIdentifier.match(numericPattern)\n\t\tif (numericMatch?.[1]) {\n\t\t\tconst number = parseInt(numericMatch[1], 10)\n\n\t\t\t// Use GitHubService to detect if it's a PR or issue\n\t\t\tconst detection = await this.gitHubService.detectInputType(\n\t\t\t\ttrimmedIdentifier\n\t\t\t)\n\n\t\t\tif (detection.type === 'pr') {\n\t\t\t\treturn {\n\t\t\t\t\ttype: 'pr',\n\t\t\t\t\tnumber: detection.number ?? number,\n\t\t\t\t\toriginalInput: trimmedIdentifier,\n\t\t\t\t}\n\t\t\t} else if (detection.type === 'issue') {\n\t\t\t\treturn {\n\t\t\t\t\ttype: 'issue',\n\t\t\t\t\tnumber: detection.number ?? number,\n\t\t\t\t\toriginalInput: trimmedIdentifier,\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Could not find issue or PR #${number}`)\n\t\t\t}\n\t\t}\n\n\t\t// Treat as branch name\n\t\treturn {\n\t\t\ttype: 'branch',\n\t\t\tbranchName: trimmedIdentifier,\n\t\t\toriginalInput: trimmedIdentifier,\n\t\t}\n\t}\n\n\t/**\n\t * Validate the parsed input based on its type\n\t */\n\tprivate async validateInput(parsed: ParsedInput): Promise<void> {\n\t\tswitch (parsed.type) {\n\t\t\tcase 'pr': {\n\t\t\t\tif (!parsed.number) {\n\t\t\t\t\tthrow new Error('Invalid PR number')\n\t\t\t\t}\n\t\t\t\t// Fetch and validate PR state\n\t\t\t\tconst pr = await this.gitHubService.fetchPR(parsed.number)\n\t\t\t\tawait this.gitHubService.validatePRState(pr)\n\t\t\t\tlogger.debug(`Validated PR #${parsed.number}`)\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcase 'issue': {\n\t\t\t\tif (!parsed.number) {\n\t\t\t\t\tthrow new Error('Invalid issue number')\n\t\t\t\t}\n\t\t\t\t// Fetch and validate issue state\n\t\t\t\tconst issue = await this.gitHubService.fetchIssue(parsed.number)\n\t\t\t\tawait this.gitHubService.validateIssueState(issue)\n\t\t\t\tlogger.debug(`Validated issue #${parsed.number}`)\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcase 'branch': {\n\t\t\t\tif (!parsed.branchName) {\n\t\t\t\t\tthrow new Error('Invalid branch name')\n\t\t\t\t}\n\t\t\t\t// Validate branch name characters (from bash script line 586)\n\t\t\t\tif (!this.isValidBranchName(parsed.branchName)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t'Invalid branch name. Use only letters, numbers, hyphens, underscores, and slashes'\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\t// Check if branch already exists\n\t\t\t\tconst exists = await branchExists(parsed.branchName)\n\t\t\t\tif (exists) {\n\t\t\t\t\tthrow new Error(`Branch '${parsed.branchName}' already exists`)\n\t\t\t\t}\n\t\t\t\tlogger.debug(`Validated branch name: ${parsed.branchName}`)\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcase 'description': {\n\t\t\t\t// Description inputs are valid - they will be converted to issues\n\t\t\t\tlogger.debug('Detected description input', {\n\t\t\t\t\tlength: parsed.originalInput.length\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tconst unknownType = parsed as { type: string }\n\t\t\t\tthrow new Error(`Unknown input type: ${unknownType.type}`)\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Validate branch name format\n\t */\n\tprivate isValidBranchName(branch: string): boolean {\n\t\t// Pattern from bash script line 586\n\t\treturn /^[a-zA-Z0-9/_-]+$/.test(branch)\n\t}\n\n\t/**\n\t * Format parsed input for display\n\t */\n\tprivate formatParsedInput(parsed: ParsedInput): string {\n\t\tswitch (parsed.type) {\n\t\t\tcase 'pr':\n\t\t\t\treturn `PR #${parsed.number}`\n\t\t\tcase 'issue':\n\t\t\t\treturn `Issue #${parsed.number}`\n\t\t\tcase 'branch':\n\t\t\t\treturn `Branch '${parsed.branchName}'`\n\t\t\tcase 'description':\n\t\t\t\treturn `Description: ${parsed.originalInput.slice(0, 50)}...`\n\t\t\tdefault:\n\t\t\t\treturn 'Unknown input'\n\t\t}\n\t}\n\n\t/**\n\t * Enhance description using Claude AI and create GitHub issue\n\t * Returns the new issue number\n\t */\n\tprivate async enhanceAndCreateIssue(description: string): Promise<number> {\n\t\t// Use IssueEnhancementService for the workflow\n\t\tconst enhancedDescription = await this.enhancementService.enhanceDescription(description)\n\t\tconst result = await this.enhancementService.createEnhancedIssue(description, enhancedDescription)\n\t\tawait this.enhancementService.waitForReviewAndOpen(result.number, true)\n\n\t\treturn result.number\n\t}\n\n}\n"],"mappings":"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","names":["path","fs","path","ClaudeContextManager","fs"]}
1
+ {"version":3,"sources":["../src/lib/LoomManager.ts","../src/lib/VSCodeIntegration.ts","../src/commands/start.ts"],"sourcesContent":["import path from 'path'\nimport fs from 'fs-extra'\nimport { GitWorktreeManager } from './GitWorktreeManager.js'\nimport { GitHubService } from './GitHubService.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 { branchExists, executeGitCommand, ensureRepositoryHasCommits } from '../utils/git.js'\nimport { installDependencies } from '../utils/package-manager.js'\nimport { generateColorFromBranchName } from '../utils/color.js'\nimport { DatabaseManager } from './DatabaseManager.js'\nimport { loadEnvIntoProcess } 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 { logger } from '../utils/logger.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 constructor(\n private gitWorktree: GitWorktreeManager,\n private github: GitHubService,\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 ) {}\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 GitHub data if needed\n logger.info('Fetching GitHub data...')\n const githubData = await this.fetchGitHubData(input)\n\n // NEW: Check for existing worktree BEFORE generating branch name (for efficiency)\n if (input.type === 'issue' || input.type === 'pr') {\n logger.info('Checking for existing worktree...')\n const existing = await this.findExistingIloom(input, githubData)\n if (existing) {\n logger.success(`Found existing worktree, reusing: ${existing.path}`)\n return await this.reuseIloom(existing, input, githubData)\n }\n logger.info('No existing worktree found, creating new one...')\n }\n\n // 2. Generate or validate branch name\n logger.info('Preparing branch name...')\n const branchName = await this.prepareBranchName(input, githubData)\n\n // 3. Create git worktree (WITHOUT dependency installation)\n logger.info('Creating git worktree...')\n const worktreePath = await this.createWorktreeOnly(input, branchName)\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 // 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)\n } catch (error) {\n // Log warning but don't fail - matches bash script behavior\n logger.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 path.join(worktreePath, '.env')\n )\n\n if (connectionString) {\n await this.environment.setEnvVar(\n path.join(worktreePath, '.env'),\n this.database.getConfiguredVariableName(),\n connectionString\n )\n logger.success('Database branch configured')\n databaseBranch = branchName\n }\n } catch (error) {\n logger.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 let cliSymlinks: string[] | undefined = undefined\n if (capabilities.includes('cli')) {\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 logger.warn(\n `Failed to setup CLI isolation: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error\n )\n }\n }\n\n // 11. Apply color synchronization (terminal and VSCode)\n if (!input.options?.skipColorSync) {\n try {\n await this.applyColorSynchronization(worktreePath, branchName)\n } catch (error) {\n // Log warning but don't fail - colors are cosmetic\n logger.warn(\n `Failed to apply color synchronization: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error\n )\n }\n }\n\n // NEW: Move issue to In Progress (for new worktrees)\n if (input.type === 'issue') {\n try {\n logger.info('Moving issue to In Progress...')\n await this.github.moveIssueToInProgress(input.identifier as number)\n } catch (error) {\n // Warn but don't fail - matches bash script behavior\n logger.warn(\n `Failed to move issue to In Progress: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error\n )\n }\n }\n\n // 8. 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)\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,\n identifier: input.identifier,\n ...(githubData?.title && { title: githubData.title }),\n oneShot,\n ...(setArguments && { setArguments }),\n ...(executablePath && { executablePath }),\n })\n }\n\n // 9. 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 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 ...(githubData !== null && {\n githubData: {\n title: githubData.title,\n body: githubData.body,\n url: githubData.url,\n state: githubData.state,\n },\n }),\n }\n\n logger.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 return await this.mapWorktreesToLooms(worktrees)\n }\n\n /**\n * Find a specific loom by identifier\n */\n async findIloom(identifier: string): Promise<Loom | null> {\n const looms = await this.listLooms()\n return (\n looms.find(\n h =>\n h.id === identifier ||\n h.identifier.toString() === identifier ||\n h.branch === identifier\n ) ?? null\n )\n }\n\n /**\n * Fetch GitHub data based on input type\n */\n private async fetchGitHubData(\n input: CreateLoomInput\n ): Promise<Issue | PullRequest | null> {\n if (input.type === 'issue') {\n return await this.github.fetchIssue(input.identifier as number)\n } else if (input.type === 'pr') {\n return await this.github.fetchPR(input.identifier as number)\n }\n return null\n }\n\n /**\n * Prepare branch name based on input type and GitHub data\n */\n private async prepareBranchName(\n input: CreateLoomInput,\n githubData: Issue | PullRequest | null\n ): Promise<string> {\n if (input.type === 'branch') {\n return input.identifier as string\n }\n\n if (input.type === 'pr' && githubData && 'branch' in githubData) {\n return githubData.branch\n }\n\n if (input.type === 'issue' && githubData) {\n // Use Claude AI-powered branch name generation\n const branchName = await this.github.generateBranchName({\n issueNumber: input.identifier as number,\n title: githubData.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 ): 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 logger.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 const worktreePrefix = settingsData.worktreePrefix\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 // 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 logger.info('Fetching all remote branches...')\n try {\n await executeGitCommand(['fetch', 'origin'], { cwd: this.gitWorktree.workingDirectory })\n logger.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 // Check if branch exists locally (used for different purposes depending on type)\n const branchExistedLocally = await branchExists(branchName)\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 await this.gitWorktree.createWorktree({\n path: worktreePath,\n branch: branchName,\n createBranch: input.type !== 'pr', // PRs use existing branches\n ...(input.baseBranch && { baseBranch: input.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 logger.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 logger.success('Successfully reset to match remote')\n } catch (error) {\n logger.warn(`Failed to reset to match remote: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n return worktreePath\n }\n\n /**\n * Copy user application environment files (.env) from main repo to worktree\n * Always called regardless of project capabilities\n */\n private async copyEnvironmentFiles(worktreePath: string): Promise<void> {\n const envFilePath = path.join(worktreePath, '.env')\n\n try {\n const mainEnvPath = path.join(process.cwd(), '.env')\n if (await fs.pathExists(envFilePath)) {\n logger.warn('.env file already exists in worktree, skipping copy')\n } else {\n //TODO: Update this to handle .env.local, .env.development and .env.development.local as well.\n await this.environment.copyIfExists(mainEnvPath, envFilePath)\n }\n } catch (error) {\n // Handle gracefully if main .env fails to copy\n logger.warn(`Warning: Failed to copy main .env file: ${error instanceof Error ? error.message : 'Unknown error'}`)\n }\n }\n\n /**\n * Copy iloom configuration (settings.local.json) from main repo to worktree\n * Always called regardless of project capabilities\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 // Check if settings.local.json already exists in worktree\n if (await fs.pathExists(worktreeSettingsLocalPath)) {\n logger.warn('settings.local.json already exists in worktree, skipping copy')\n } else {\n await this.environment.copyIfExists(mainSettingsLocalPath, worktreeSettingsLocalPath)\n }\n } catch (error) {\n logger.warn(`Warning: Failed to copy settings.local.json: ${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')\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') {\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 // Handle gracefully if .env files don't exist\n logger.warn(`Warning: Could not load .env files: ${result.error.message}`)\n } else {\n logger.info('Loaded environment variables using dotenv-flow')\n if (result.parsed && Object.keys(result.parsed).length > 0) {\n logger.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' && typeof input.identifier === 'number') {\n return this.environment.calculatePort({ basePort, issueNumber: input.identifier })\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}`)\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 */\n private async applyColorSynchronization(\n worktreePath: string,\n branchName: string\n ): Promise<void> {\n const colorData = generateColorFromBranchName(branchName)\n\n // Apply VSCode title bar color\n const vscode = new VSCodeIntegration()\n await vscode.setTitleBarColor(worktreePath, colorData.hex)\n\n logger.info(`Applied VSCode title bar color: ${colorData.hex} for branch: ${branchName}`)\n\n // Note: Terminal color is applied during window creation in ClaudeContextManager\n // This ensures the color is set when the new terminal window is opened\n }\n\n /**\n * Map worktrees to loom objects\n * This is a simplified conversion - in production we'd store loom metadata\n */\n private async mapWorktreesToLooms(worktrees: GitWorktree[]): Promise<Loom[]> {\n return await Promise.all(worktrees.map(async (wt) => {\n // Extract identifier from branch name\n let type: 'issue' | 'pr' | 'branch' = 'branch'\n let identifier: string | number = wt.branch\n\n if (wt.branch.startsWith('issue-')) {\n type = 'issue'\n identifier = parseInt(wt.branch.replace('issue-', ''), 10)\n } else if (wt.branch.startsWith('pr-')) {\n type = 'pr'\n identifier = parseInt(wt.branch.replace('pr-', ''), 10)\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 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 githubData: 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' && githubData && 'branch' in githubData) {\n return await this.gitWorktree.findWorktreeForPR(\n input.identifier as number,\n githubData.branch\n )\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 githubData: 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\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 logger.info('Database branch assumed to be already configured for existing worktree')\n const databaseBranch: string | undefined = undefined\n\n // 6. Move issue to In Progress (for reused worktrees too)\n if (input.type === 'issue') {\n try {\n logger.info('Moving issue to In Progress...')\n await this.github.moveIssueToInProgress(input.identifier as number)\n } catch (error) {\n logger.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 logger.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)\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,\n identifier: input.identifier,\n ...(githubData?.title && { title: githubData.title }),\n oneShot,\n ...(setArguments && { setArguments }),\n ...(executablePath && { executablePath }),\n })\n }\n\n // 8. 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 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 ...(githubData !== null && {\n githubData: {\n title: githubData.title,\n body: githubData.body,\n url: githubData.url,\n state: githubData.state,\n },\n }),\n }\n\n logger.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 { logger } from '../utils/logger.js'\nimport { GitHubService } from '../lib/GitHubService.js'\nimport { LoomManager } from '../lib/LoomManager.js'\nimport { GitWorktreeManager } from '../lib/GitWorktreeManager.js'\nimport { EnvironmentManager } from '../lib/EnvironmentManager.js'\nimport { ClaudeContextManager } from '../lib/ClaudeContextManager.js'\nimport { ProjectCapabilityDetector } from '../lib/ProjectCapabilityDetector.js'\nimport { CLIIsolationManager } from '../lib/CLIIsolationManager.js'\nimport { SettingsManager } from '../lib/SettingsManager.js'\nimport { AgentManager } from '../lib/AgentManager.js'\nimport { DatabaseManager } from '../lib/DatabaseManager.js'\nimport { IssueEnhancementService } from '../lib/IssueEnhancementService.js'\nimport { branchExists, findMainWorktreePathWithSettings } from '../utils/git.js'\nimport { loadEnvIntoProcess } from '../utils/env.js'\nimport { extractSettingsOverrides } from '../utils/cli-overrides.js'\nimport { createNeonProviderFromSettings } from '../utils/neon-helpers.js'\nimport { getConfiguredRepoFromSettings, hasMultipleRemotes } from '../utils/remote.js'\nimport type { StartOptions } from '../types/index.js'\n\nexport interface StartCommandInput {\n\tidentifier: string\n\toptions: StartOptions\n}\n\nexport interface ParsedInput {\n\ttype: 'issue' | 'pr' | 'branch' | 'description'\n\tnumber?: number\n\tbranchName?: string\n\toriginalInput: string\n}\n\nexport class StartCommand {\n\tprivate gitHubService: GitHubService\n\tprivate loomManager: LoomManager | null = null\n\tprivate agentManager: AgentManager\n\tprivate settingsManager: SettingsManager\n\tprivate enhancementService: IssueEnhancementService\n\tprivate providedLoomManager: LoomManager | undefined\n\n\tconstructor(\n\t\tgitHubService?: GitHubService,\n\t\tloomManager?: LoomManager,\n\t\tagentManager?: AgentManager,\n\t\tsettingsManager?: SettingsManager\n\t) {\n\t\tthis.gitHubService = gitHubService ?? new GitHubService()\n\t\tthis.agentManager = agentManager ?? new AgentManager()\n\t\tthis.settingsManager = settingsManager ?? new SettingsManager()\n\t\tthis.enhancementService = new IssueEnhancementService(\n\t\t\tthis.gitHubService,\n\t\t\tthis.agentManager,\n\t\t\tthis.settingsManager\n\t\t)\n\t\t// Store provided LoomManager for testing, but don't initialize yet\n\t\tthis.providedLoomManager = loomManager\n\n\t\t// Load environment variables first\n\t\tconst envResult = loadEnvIntoProcess()\n\t\tif (envResult.error) {\n\t\t\tlogger.debug(`Environment loading warning: ${envResult.error.message}`)\n\t\t}\n\t\tif (envResult.parsed) {\n\t\t\tlogger.debug(`Loaded ${Object.keys(envResult.parsed).length} environment variables`)\n\t\t}\n\t}\n\n\t/**\n\t * Initialize LoomManager with the main worktree path\n\t * Uses lazy initialization to ensure we have the correct path\n\t */\n\tprivate async initializeLoomManager(): Promise<LoomManager> {\n\t\tif (this.loomManager) {\n\t\t\treturn this.loomManager\n\t\t}\n\n\t\tif (this.providedLoomManager) {\n\t\t\tthis.loomManager = this.providedLoomManager\n\t\t\treturn this.loomManager\n\t\t}\n\n\t\t// Find main worktree path\n\t\tconst mainWorktreePath = await findMainWorktreePathWithSettings()\n\n\t\t// Load settings to get database configuration\n\t\tconst settings = await this.settingsManager.loadSettings()\n\n\t\t// Create DatabaseManager with NeonProvider and EnvironmentManager\n\t\tconst environmentManager = new EnvironmentManager()\n\t\tconst neonProvider = createNeonProviderFromSettings(settings)\n\t\tconst databaseUrlEnvVarName = settings.capabilities?.database?.databaseUrlEnvVarName ?? 'DATABASE_URL'\n\n\t\tconst databaseManager = new DatabaseManager(neonProvider, environmentManager, databaseUrlEnvVarName)\n\n\t\tthis.loomManager = new LoomManager(\n\t\t\tnew GitWorktreeManager(mainWorktreePath),\n\t\t\tthis.gitHubService,\n\t\t\tenvironmentManager, // Reuse same instance\n\t\t\tnew ClaudeContextManager(),\n\t\t\tnew ProjectCapabilityDetector(),\n\t\t\tnew CLIIsolationManager(),\n\t\t\tthis.settingsManager, // Use same instance with CLI overrides\n\t\t\tdatabaseManager // Add database manager\n\t\t)\n\n\t\treturn this.loomManager\n\t}\n\n\t/**\n\t * Main entry point for the start command\n\t */\n\tpublic async execute(input: StartCommandInput): Promise<void> {\n\t\ttry {\n\t\t\t// Step 0: Load settings and get configured repo for GitHub operations\n\t\t\tconst initialSettings = await this.settingsManager.loadSettings()\n\t\t\tlet repo: string | undefined\n\n\t\t\t// Only get repo if we have multiple remotes (prehook already validated config)\n\t\t\tconst multipleRemotes = await hasMultipleRemotes()\n\t\t\tif (multipleRemotes) {\n\t\t\t\trepo = await getConfiguredRepoFromSettings(initialSettings)\n\t\t\t\tlogger.info(`Using GitHub repository: ${repo}`)\n\t\t\t}\n\n\t\t\t// Step 0.5: Initialize LoomManager with main worktree path\n\t\t\tconst loomManager = await this.initializeLoomManager()\n\n\t\t\t// Step 1: Parse and validate input (pass repo to methods)\n\t\t\tconst parsed = await this.parseInput(input.identifier, repo)\n\n\t\t\t// Step 2: Validate based on type\n\t\t\tawait this.validateInput(parsed, repo)\n\n\t\t\t// Step 2.5: Handle description input - create GitHub issue\n\t\t\tif (parsed.type === 'description') {\n\t\t\t\tconst issueNumber = await this.enhanceAndCreateIssue(parsed.originalInput)\n\t\t\t\t// Update parsed to be an issue type with the new number\n\t\t\t\tparsed.type = 'issue'\n\t\t\t\tparsed.number = issueNumber\n\t\t\t}\n\n\t\t\t// Step 2.7: Confirm bypassPermissions mode if applicable\n\t\t\tif (input.options.oneShot === 'bypassPermissions') {\n\t\t\t\tconst { promptConfirmation } = await import('../utils/prompt.js')\n\t\t\t\tconst confirmed = await promptConfirmation(\n\t\t\t\t\t'⚠️ WARNING: bypassPermissions mode will allow Claude to execute all tool calls without confirmation. ' +\n\t\t\t\t\t'This can be dangerous. Do you want to proceed?'\n\t\t\t\t)\n\t\t\t\tif (!confirmed) {\n\t\t\t\t\tlogger.info('Operation cancelled by user')\n\t\t\t\t\tprocess.exit(0)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Step 2.8: Load workflow-specific settings with CLI overrides\n\t\t\tconst cliOverrides = extractSettingsOverrides()\n\t\t\tconst settings = await this.settingsManager.loadSettings(undefined, cliOverrides)\n\t\t\tconst workflowType = parsed.type === 'branch' ? 'regular' : parsed.type\n\t\t\tconst workflowConfig = settings.workflows?.[workflowType]\n\n\t\t\t// Step 2.9: Extract raw --set arguments and executable path for forwarding to spin\n\t\t\tconst { extractRawSetArguments, getExecutablePath } = await import('../utils/cli-overrides.js')\n\t\t\tconst setArguments = extractRawSetArguments()\n\t\t\tconst executablePath = getExecutablePath()\n\n\t\t\t// Step 3: Log success and create loom\n\t\t\tlogger.info(`✅ Validated input: ${this.formatParsedInput(parsed)}`)\n\n\t\t\t// Step 4: Create loom using LoomManager\n\t\t\tconst identifier =\n\t\t\t\tparsed.type === 'branch'\n\t\t\t\t\t? parsed.branchName ?? ''\n\t\t\t\t\t: parsed.number ?? 0\n\n\t\t\t// Apply configuration precedence: CLI flags > workflow config > defaults (true)\n\t\t\tconst enableClaude = input.options.claude ?? workflowConfig?.startAiAgent ?? true\n\t\t\tconst enableCode = input.options.code ?? workflowConfig?.startIde ?? true\n\t\t\tconst enableDevServer = input.options.devServer ?? workflowConfig?.startDevServer ?? true\n\t\t\tconst enableTerminal = input.options.terminal ?? workflowConfig?.startTerminal ?? false\n\n\t\t\tlogger.debug('Final workflow config values:', {\n\t\t\t\tenableClaude,\n\t\t\t\tenableCode,\n\t\t\t\tenableDevServer,\n\t\t\t\tenableTerminal,\n\t\t\t})\n\n\t\t\tconst loom = await loomManager.createIloom({\n\t\t\t\ttype: parsed.type,\n\t\t\t\tidentifier,\n\t\t\t\toriginalInput: parsed.originalInput,\n\t\t\t\toptions: {\n\t\t\t\t\tenableClaude,\n\t\t\t\t\tenableCode,\n\t\t\t\t\tenableDevServer,\n\t\t\t\t\tenableTerminal,\n\t\t\t\t\t...(input.options.oneShot && { oneShot: input.options.oneShot }),\n\t\t\t\t\t...(setArguments.length > 0 && { setArguments }),\n\t\t\t\t\t...(executablePath && { executablePath }),\n\t\t\t\t},\n\t\t\t})\n\n\t\t\tlogger.success(`✅ Created loom: ${loom.id} at ${loom.path}`)\n\t\t\tlogger.info(` Branch: ${loom.branch}`)\n\t\t\t// Only show port for web projects\n\t\t\tif (loom.capabilities?.includes('web')) {\n\t\t\t\tlogger.info(` Port: ${loom.port}`)\n\t\t\t}\n\t\t\tif (loom.githubData?.title) {\n\t\t\t\tlogger.info(` Title: ${loom.githubData.title}`)\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) {\n\t\t\t\tlogger.error(`❌ ${error.message}`)\n\t\t\t} else {\n\t\t\t\tlogger.error('❌ An unknown error occurred')\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Parse input to determine type and extract relevant data\n\t */\n\tprivate async parseInput(identifier: string, repo?: string): Promise<ParsedInput> {\n\t\t// Handle empty input\n\t\tconst trimmedIdentifier = identifier.trim()\n\t\tif (!trimmedIdentifier) {\n\t\t\tthrow new Error('Missing required argument: identifier')\n\t\t}\n\n\t\t// Check for description: >25 chars AND >2 spaces\n\t\tconst spaceCount = (trimmedIdentifier.match(/ /g) ?? []).length\n\t\tif (trimmedIdentifier.length > 25 && spaceCount > 2) {\n\t\t\treturn {\n\t\t\t\ttype: 'description',\n\t\t\t\toriginalInput: trimmedIdentifier,\n\t\t\t}\n\t\t}\n\n\t\t// Check for PR-specific formats: pr/123, PR-123, PR/123\n\t\tconst prPattern = /^(?:pr|PR)[/-](\\d+)$/\n\t\tconst prMatch = trimmedIdentifier.match(prPattern)\n\t\tif (prMatch?.[1]) {\n\t\t\treturn {\n\t\t\t\ttype: 'pr',\n\t\t\t\tnumber: parseInt(prMatch[1], 10),\n\t\t\t\toriginalInput: trimmedIdentifier,\n\t\t\t}\n\t\t}\n\n\t\t// Check for numeric pattern (could be issue or PR)\n\t\tconst numericPattern = /^#?(\\d+)$/\n\t\tconst numericMatch = trimmedIdentifier.match(numericPattern)\n\t\tif (numericMatch?.[1]) {\n\t\t\tconst number = parseInt(numericMatch[1], 10)\n\n\t\t\t// Use GitHubService to detect if it's a PR or issue\n\t\t\tconst detection = await this.gitHubService.detectInputType(\n\t\t\t\ttrimmedIdentifier,\n\t\t\t\trepo\n\t\t\t)\n\n\t\t\tif (detection.type === 'pr') {\n\t\t\t\treturn {\n\t\t\t\t\ttype: 'pr',\n\t\t\t\t\tnumber: detection.number ?? number,\n\t\t\t\t\toriginalInput: trimmedIdentifier,\n\t\t\t\t}\n\t\t\t} else if (detection.type === 'issue') {\n\t\t\t\treturn {\n\t\t\t\t\ttype: 'issue',\n\t\t\t\t\tnumber: detection.number ?? number,\n\t\t\t\t\toriginalInput: trimmedIdentifier,\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Could not find issue or PR #${number}`)\n\t\t\t}\n\t\t}\n\n\t\t// Treat as branch name\n\t\treturn {\n\t\t\ttype: 'branch',\n\t\t\tbranchName: trimmedIdentifier,\n\t\t\toriginalInput: trimmedIdentifier,\n\t\t}\n\t}\n\n\t/**\n\t * Validate the parsed input based on its type\n\t */\n\tprivate async validateInput(parsed: ParsedInput, repo?: string): Promise<void> {\n\t\tswitch (parsed.type) {\n\t\t\tcase 'pr': {\n\t\t\t\tif (!parsed.number) {\n\t\t\t\t\tthrow new Error('Invalid PR number')\n\t\t\t\t}\n\t\t\t\t// Fetch and validate PR state\n\t\t\t\tconst pr = await this.gitHubService.fetchPR(parsed.number, repo)\n\t\t\t\tawait this.gitHubService.validatePRState(pr)\n\t\t\t\tlogger.debug(`Validated PR #${parsed.number}`)\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcase 'issue': {\n\t\t\t\tif (!parsed.number) {\n\t\t\t\t\tthrow new Error('Invalid issue number')\n\t\t\t\t}\n\t\t\t\t// Fetch and validate issue state\n\t\t\t\tconst issue = await this.gitHubService.fetchIssue(parsed.number, repo)\n\t\t\t\tawait this.gitHubService.validateIssueState(issue)\n\t\t\t\tlogger.debug(`Validated issue #${parsed.number}`)\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcase 'branch': {\n\t\t\t\tif (!parsed.branchName) {\n\t\t\t\t\tthrow new Error('Invalid branch name')\n\t\t\t\t}\n\t\t\t\t// Validate branch name characters (from bash script line 586)\n\t\t\t\tif (!this.isValidBranchName(parsed.branchName)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t'Invalid branch name. Use only letters, numbers, hyphens, underscores, and slashes'\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\t// Check if branch already exists\n\t\t\t\tconst exists = await branchExists(parsed.branchName)\n\t\t\t\tif (exists) {\n\t\t\t\t\tthrow new Error(`Branch '${parsed.branchName}' already exists`)\n\t\t\t\t}\n\t\t\t\tlogger.debug(`Validated branch name: ${parsed.branchName}`)\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcase 'description': {\n\t\t\t\t// Description inputs are valid - they will be converted to issues\n\t\t\t\tlogger.debug('Detected description input', {\n\t\t\t\t\tlength: parsed.originalInput.length\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tconst unknownType = parsed as { type: string }\n\t\t\t\tthrow new Error(`Unknown input type: ${unknownType.type}`)\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Validate branch name format\n\t */\n\tprivate isValidBranchName(branch: string): boolean {\n\t\t// Pattern from bash script line 586\n\t\treturn /^[a-zA-Z0-9/_-]+$/.test(branch)\n\t}\n\n\t/**\n\t * Format parsed input for display\n\t */\n\tprivate formatParsedInput(parsed: ParsedInput): string {\n\t\tswitch (parsed.type) {\n\t\t\tcase 'pr':\n\t\t\t\treturn `PR #${parsed.number}`\n\t\t\tcase 'issue':\n\t\t\t\treturn `Issue #${parsed.number}`\n\t\t\tcase 'branch':\n\t\t\t\treturn `Branch '${parsed.branchName}'`\n\t\t\tcase 'description':\n\t\t\t\treturn `Description: ${parsed.originalInput.slice(0, 50)}...`\n\t\t\tdefault:\n\t\t\t\treturn 'Unknown input'\n\t\t}\n\t}\n\n\t/**\n\t * Enhance description using Claude AI and create GitHub issue\n\t * Returns the new issue number\n\t */\n\tprivate async enhanceAndCreateIssue(description: string): Promise<number> {\n\t\t// Use IssueEnhancementService for the workflow\n\t\tconst enhancedDescription = await this.enhancementService.enhanceDescription(description)\n\t\tconst result = await this.enhancementService.createEnhancedIssue(description, enhancedDescription)\n\t\tawait this.enhancementService.waitForReviewAndOpen(result.number, true)\n\n\t\treturn result.number\n\t}\n\n}\n"],"mappings":"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","names":["path","fs","path","ClaudeContextManager","fs"]}
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SettingsManager
4
- } from "./chunk-JBH2ZYYZ.js";
4
+ } from "./chunk-VYQLLHZ7.js";
5
5
  import {
6
6
  findMainWorktreePath
7
- } from "./chunk-JQ7VOSTC.js";
7
+ } from "./chunk-KOCQAD2E.js";
8
8
  import {
9
9
  logger
10
10
  } from "./chunk-GEHQXLEI.js";
@@ -49,4 +49,4 @@ var TestGitCommand = class {
49
49
  export {
50
50
  TestGitCommand
51
51
  };
52
- //# sourceMappingURL=test-git-XPF4SZXJ.js.map
52
+ //# sourceMappingURL=test-git-MKZATGZN.js.map
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SettingsManager
4
- } from "./chunk-JBH2ZYYZ.js";
4
+ } from "./chunk-VYQLLHZ7.js";
5
5
  import {
6
6
  generateWorktreePath
7
- } from "./chunk-JQ7VOSTC.js";
7
+ } from "./chunk-KOCQAD2E.js";
8
8
  import {
9
9
  logger
10
10
  } from "./chunk-GEHQXLEI.js";
@@ -65,4 +65,4 @@ var TestPrefixCommand = class {
65
65
  export {
66
66
  TestPrefixCommand
67
67
  };
68
- //# sourceMappingURL=test-prefix-XGFXFAYN.js.map
68
+ //# sourceMappingURL=test-prefix-ZNLWDI3K.js.map
@@ -66,14 +66,20 @@ var UpdateCommand = class {
66
66
  return;
67
67
  }
68
68
  logger.info("\u{1F504} Starting update...");
69
- spawn("npm", ["install", "-g", `${packageName}@latest`], {
70
- detached: true,
69
+ const child = spawn("npm", ["install", "-g", `${packageName}@latest`], {
71
70
  stdio: "inherit"
72
71
  });
73
- process.exit(0);
72
+ child.on("close", (code) => {
73
+ if (code === 0) {
74
+ logger.success("Update complete!");
75
+ } else {
76
+ logger.error(`Update failed with exit code ${code}`);
77
+ }
78
+ process.exit(code ?? 0);
79
+ });
74
80
  }
75
81
  };
76
82
  export {
77
83
  UpdateCommand
78
84
  };
79
- //# sourceMappingURL=update-DN3FSNKY.js.map
85
+ //# sourceMappingURL=update-4TDDUR5K.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/update.ts"],"sourcesContent":["import { spawn } from 'child_process'\nimport { fileURLToPath } from 'url'\nimport { dirname, join } from 'path'\nimport fs from 'fs-extra'\nimport { logger } from '../utils/logger.js'\nimport { detectInstallationMethod } from '../utils/installation-detector.js'\nimport { UpdateNotifier } from '../utils/update-notifier.js'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\nexport class UpdateCommand {\n async execute(options: { dryRun?: boolean } = {}): Promise<void> {\n // Check installation method - only allow updates for global installations\n const installMethod = detectInstallationMethod(__filename)\n logger.debug(`[update] Installation method detected: ${installMethod}`)\n\n if (installMethod !== 'global') {\n logger.error('Update command only works for globally installed iloom-cli')\n\n switch (installMethod) {\n case 'local':\n logger.info('You appear to be running from local development.')\n logger.info('To update: git pull origin main && pnpm install && pnpm build')\n break\n case 'linked':\n logger.info('You appear to be running from npm link.')\n logger.info('To update: cd to your local iloom repo and run git pull')\n break\n default:\n logger.info('Unable to determine installation method.')\n logger.info('If globally installed, try: npm install -g @iloom/cli@latest')\n break\n }\n\n process.exit(1)\n }\n\n // Get current version from package.json\n const packageJsonPath = join(__dirname, '..', 'package.json')\n logger.debug(`[update] Reading package.json from: ${packageJsonPath}`)\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'))\n const currentVersion = packageJson.version\n const packageName = packageJson.name\n logger.debug(`[update] Current version: ${currentVersion}, package: ${packageName}`)\n\n // Check for available updates\n logger.info('🔍 Checking for updates...')\n const notifier = new UpdateNotifier(currentVersion, packageName)\n const updateResult = await notifier.checkForUpdates()\n logger.debug(`[update] Update check result: ${JSON.stringify(updateResult)}`)\n\n if (!updateResult) {\n logger.error('Failed to check for updates. Please try again later.')\n process.exit(1)\n }\n\n if (!updateResult.updateAvailable) {\n logger.success(`Already up to date! Current version: ${currentVersion}`)\n return\n }\n\n // Show update info and proceed\n logger.info(`Update available: ${updateResult.currentVersion} → ${updateResult.latestVersion}`)\n\n if (options.dryRun) {\n logger.info('🔍 DRY RUN - showing what would be done:')\n logger.info(` Would run: npm install -g ${packageName}@latest`)\n logger.info(` Current version: ${currentVersion}`)\n logger.info(` Target version: ${updateResult.latestVersion}`)\n logger.debug(`[update] Dry run complete, skipping actual update`)\n return\n }\n\n logger.info('🔄 Starting update...')\n\n // Start npm update in background and exit immediately\n spawn('npm', ['install', '-g', `${packageName}@latest`], {\n detached: true,\n stdio: 'inherit'\n })\n\n // Exit before npm tries to replace files (avoids file locking issues)\n process.exit(0)\n }\n}"],"mappings":";;;;;;;;;;;;AAAA,SAAS,aAAa;AACtB,SAAS,qBAAqB;AAC9B,SAAS,SAAS,YAAY;AAC9B,OAAO,QAAQ;AAKf,IAAM,aAAa,cAAc,YAAY,GAAG;AAChD,IAAM,YAAY,QAAQ,UAAU;AAE7B,IAAM,gBAAN,MAAoB;AAAA,EACzB,MAAM,QAAQ,UAAgC,CAAC,GAAkB;AAE/D,UAAM,gBAAgB,yBAAyB,UAAU;AACzD,WAAO,MAAM,0CAA0C,aAAa,EAAE;AAEtE,QAAI,kBAAkB,UAAU;AAC9B,aAAO,MAAM,4DAA4D;AAEzE,cAAQ,eAAe;AAAA,QACrB,KAAK;AACH,iBAAO,KAAK,kDAAkD;AAC9D,iBAAO,KAAK,+DAA+D;AAC3E;AAAA,QACF,KAAK;AACH,iBAAO,KAAK,yCAAyC;AACrD,iBAAO,KAAK,yDAAyD;AACrE;AAAA,QACF;AACE,iBAAO,KAAK,0CAA0C;AACtD,iBAAO,KAAK,8DAA8D;AAC1E;AAAA,MACJ;AAEA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAGA,UAAM,kBAAkB,KAAK,WAAW,MAAM,cAAc;AAC5D,WAAO,MAAM,uCAAuC,eAAe,EAAE;AACrE,UAAM,cAAc,KAAK,MAAM,MAAM,GAAG,SAAS,iBAAiB,MAAM,CAAC;AACzE,UAAM,iBAAiB,YAAY;AACnC,UAAM,cAAc,YAAY;AAChC,WAAO,MAAM,6BAA6B,cAAc,cAAc,WAAW,EAAE;AAGnF,WAAO,KAAK,mCAA4B;AACxC,UAAM,WAAW,IAAI,eAAe,gBAAgB,WAAW;AAC/D,UAAM,eAAe,MAAM,SAAS,gBAAgB;AACpD,WAAO,MAAM,iCAAiC,KAAK,UAAU,YAAY,CAAC,EAAE;AAE5E,QAAI,CAAC,cAAc;AACjB,aAAO,MAAM,sDAAsD;AACnE,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,QAAI,CAAC,aAAa,iBAAiB;AACjC,aAAO,QAAQ,wCAAwC,cAAc,EAAE;AACvE;AAAA,IACF;AAGA,WAAO,KAAK,qBAAqB,aAAa,cAAc,WAAM,aAAa,aAAa,EAAE;AAE9F,QAAI,QAAQ,QAAQ;AAClB,aAAO,KAAK,iDAA0C;AACtD,aAAO,KAAK,gCAAgC,WAAW,SAAS;AAChE,aAAO,KAAK,uBAAuB,cAAc,EAAE;AACnD,aAAO,KAAK,sBAAsB,aAAa,aAAa,EAAE;AAC9D,aAAO,MAAM,mDAAmD;AAChE;AAAA,IACF;AAEA,WAAO,KAAK,8BAAuB;AAGnC,UAAM,OAAO,CAAC,WAAW,MAAM,GAAG,WAAW,SAAS,GAAG;AAAA,MACvD,UAAU;AAAA,MACV,OAAO;AAAA,IACT,CAAC;AAGD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/commands/update.ts"],"sourcesContent":["import { spawn } from 'child_process'\nimport { fileURLToPath } from 'url'\nimport { dirname, join } from 'path'\nimport fs from 'fs-extra'\nimport { logger } from '../utils/logger.js'\nimport { detectInstallationMethod } from '../utils/installation-detector.js'\nimport { UpdateNotifier } from '../utils/update-notifier.js'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\nexport class UpdateCommand {\n async execute(options: { dryRun?: boolean } = {}): Promise<void> {\n // Check installation method - only allow updates for global installations\n const installMethod = detectInstallationMethod(__filename)\n logger.debug(`[update] Installation method detected: ${installMethod}`)\n\n if (installMethod !== 'global') {\n logger.error('Update command only works for globally installed iloom-cli')\n\n switch (installMethod) {\n case 'local':\n logger.info('You appear to be running from local development.')\n logger.info('To update: git pull origin main && pnpm install && pnpm build')\n break\n case 'linked':\n logger.info('You appear to be running from npm link.')\n logger.info('To update: cd to your local iloom repo and run git pull')\n break\n default:\n logger.info('Unable to determine installation method.')\n logger.info('If globally installed, try: npm install -g @iloom/cli@latest')\n break\n }\n\n process.exit(1)\n }\n\n // Get current version from package.json\n const packageJsonPath = join(__dirname, '..', 'package.json')\n logger.debug(`[update] Reading package.json from: ${packageJsonPath}`)\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'))\n const currentVersion = packageJson.version\n const packageName = packageJson.name\n logger.debug(`[update] Current version: ${currentVersion}, package: ${packageName}`)\n\n // Check for available updates\n logger.info('🔍 Checking for updates...')\n const notifier = new UpdateNotifier(currentVersion, packageName)\n const updateResult = await notifier.checkForUpdates()\n logger.debug(`[update] Update check result: ${JSON.stringify(updateResult)}`)\n\n if (!updateResult) {\n logger.error('Failed to check for updates. Please try again later.')\n process.exit(1)\n }\n\n if (!updateResult.updateAvailable) {\n logger.success(`Already up to date! Current version: ${currentVersion}`)\n return\n }\n\n // Show update info and proceed\n logger.info(`Update available: ${updateResult.currentVersion} → ${updateResult.latestVersion}`)\n\n if (options.dryRun) {\n logger.info('🔍 DRY RUN - showing what would be done:')\n logger.info(` Would run: npm install -g ${packageName}@latest`)\n logger.info(` Current version: ${currentVersion}`)\n logger.info(` Target version: ${updateResult.latestVersion}`)\n logger.debug(`[update] Dry run complete, skipping actual update`)\n return\n }\n\n logger.info('🔄 Starting update...')\n\n const child = spawn('npm', ['install', '-g', `${packageName}@latest`], {\n stdio: 'inherit'\n })\n\n child.on('close', (code) => {\n if (code === 0) {\n logger.success('Update complete!')\n } else {\n logger.error(`Update failed with exit code ${code}`)\n }\n process.exit(code ?? 0)\n })\n }\n}"],"mappings":";;;;;;;;;;;;AAAA,SAAS,aAAa;AACtB,SAAS,qBAAqB;AAC9B,SAAS,SAAS,YAAY;AAC9B,OAAO,QAAQ;AAKf,IAAM,aAAa,cAAc,YAAY,GAAG;AAChD,IAAM,YAAY,QAAQ,UAAU;AAE7B,IAAM,gBAAN,MAAoB;AAAA,EACzB,MAAM,QAAQ,UAAgC,CAAC,GAAkB;AAE/D,UAAM,gBAAgB,yBAAyB,UAAU;AACzD,WAAO,MAAM,0CAA0C,aAAa,EAAE;AAEtE,QAAI,kBAAkB,UAAU;AAC9B,aAAO,MAAM,4DAA4D;AAEzE,cAAQ,eAAe;AAAA,QACrB,KAAK;AACH,iBAAO,KAAK,kDAAkD;AAC9D,iBAAO,KAAK,+DAA+D;AAC3E;AAAA,QACF,KAAK;AACH,iBAAO,KAAK,yCAAyC;AACrD,iBAAO,KAAK,yDAAyD;AACrE;AAAA,QACF;AACE,iBAAO,KAAK,0CAA0C;AACtD,iBAAO,KAAK,8DAA8D;AAC1E;AAAA,MACJ;AAEA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAGA,UAAM,kBAAkB,KAAK,WAAW,MAAM,cAAc;AAC5D,WAAO,MAAM,uCAAuC,eAAe,EAAE;AACrE,UAAM,cAAc,KAAK,MAAM,MAAM,GAAG,SAAS,iBAAiB,MAAM,CAAC;AACzE,UAAM,iBAAiB,YAAY;AACnC,UAAM,cAAc,YAAY;AAChC,WAAO,MAAM,6BAA6B,cAAc,cAAc,WAAW,EAAE;AAGnF,WAAO,KAAK,mCAA4B;AACxC,UAAM,WAAW,IAAI,eAAe,gBAAgB,WAAW;AAC/D,UAAM,eAAe,MAAM,SAAS,gBAAgB;AACpD,WAAO,MAAM,iCAAiC,KAAK,UAAU,YAAY,CAAC,EAAE;AAE5E,QAAI,CAAC,cAAc;AACjB,aAAO,MAAM,sDAAsD;AACnE,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,QAAI,CAAC,aAAa,iBAAiB;AACjC,aAAO,QAAQ,wCAAwC,cAAc,EAAE;AACvE;AAAA,IACF;AAGA,WAAO,KAAK,qBAAqB,aAAa,cAAc,WAAM,aAAa,aAAa,EAAE;AAE9F,QAAI,QAAQ,QAAQ;AAClB,aAAO,KAAK,iDAA0C;AACtD,aAAO,KAAK,gCAAgC,WAAW,SAAS;AAChE,aAAO,KAAK,uBAAuB,cAAc,EAAE;AACnD,aAAO,KAAK,sBAAsB,aAAa,aAAa,EAAE;AAC9D,aAAO,MAAM,mDAAmD;AAChE;AAAA,IACF;AAEA,WAAO,KAAK,8BAAuB;AAEnC,UAAM,QAAQ,MAAM,OAAO,CAAC,WAAW,MAAM,GAAG,WAAW,SAAS,GAAG;AAAA,MACrE,OAAO;AAAA,IACT,CAAC;AAED,UAAM,GAAG,SAAS,CAAC,SAAS;AAC1B,UAAI,SAAS,GAAG;AACd,eAAO,QAAQ,kBAAkB;AAAA,MACnC,OAAO;AACL,eAAO,MAAM,gCAAgC,IAAI,EAAE;AAAA,MACrD;AACA,cAAQ,KAAK,QAAQ,CAAC;AAAA,IACxB,CAAC;AAAA,EACH;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iloom/cli",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "description": "Control plane for maintaining alignment between you and Claude AI as you work across multiple issues using isolated environments, visible context, and multi-agent workflows to scale understanding, not just output",
5
5
  "keywords": [
6
6
  "ai",
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- ClaudeContextManager
4
- } from "./chunk-Y7SAGNUT.js";
5
- import "./chunk-WKEWRSDB.js";
6
- import "./chunk-PXZBAC2M.js";
7
- import "./chunk-F3XBU2R7.js";
8
- import "./chunk-JBH2ZYYZ.js";
9
- import "./chunk-GEHQXLEI.js";
10
- export {
11
- ClaudeContextManager
12
- };
13
- //# sourceMappingURL=ClaudeContextManager-XOSXQ67R.js.map
@@ -1,12 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- ClaudeService
4
- } from "./chunk-WKEWRSDB.js";
5
- import "./chunk-PXZBAC2M.js";
6
- import "./chunk-F3XBU2R7.js";
7
- import "./chunk-JBH2ZYYZ.js";
8
- import "./chunk-GEHQXLEI.js";
9
- export {
10
- ClaudeService
11
- };
12
- //# sourceMappingURL=ClaudeService-YSZ6EXWP.js.map
@@ -1,12 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- NeonProvider,
4
- validateNeonConfig
5
- } from "./chunk-YYSKGAZT.js";
6
- import "./chunk-JNKJ7NJV.js";
7
- import "./chunk-GEHQXLEI.js";
8
- export {
9
- NeonProvider,
10
- validateNeonConfig
11
- };
12
- //# sourceMappingURL=NeonProvider-PAGPUH7F.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/add-issue.ts"],"sourcesContent":["import type { AddIssueOptions } from '../types/index.js'\nimport { IssueEnhancementService } from '../lib/IssueEnhancementService.js'\nimport { GitHubService } from '../lib/GitHubService.js'\nimport { AgentManager } from '../lib/AgentManager.js'\nimport { SettingsManager } from '../lib/SettingsManager.js'\n\n/**\n * Input structure for AddIssueCommand\n */\nexport interface AddIssueCommandInput {\n\tdescription: string\n\toptions: AddIssueOptions\n}\n\n/**\n * Command to create and enhance GitHub issues without creating workspaces.\n * This separates the \"document the work\" step from the \"start the work\" step.\n */\nexport class AddIssueCommand {\n\tprivate enhancementService: IssueEnhancementService\n\n\tconstructor(enhancementService?: IssueEnhancementService) {\n\t\t// Use provided service or create default\n\t\tthis.enhancementService = enhancementService ?? new IssueEnhancementService(\n\t\t\tnew GitHubService(),\n\t\t\tnew AgentManager(),\n\t\t\tnew SettingsManager()\n\t\t)\n\t}\n\n\t/**\n\t * Execute the add-issue command workflow:\n\t * 1. Validate description format\n\t * 2. Enhance description with Claude AI\n\t * 3. Create GitHub issue\n\t * 4. Wait for keypress and open browser for review\n\t * 5. Return issue number\n\t */\n\tpublic async execute(input: AddIssueCommandInput): Promise<number> {\n\t\tconst { description } = input\n\n\t\t// Step 1: Validate description format\n\t\tif (!description || !this.enhancementService.validateDescription(description)) {\n\t\t\tthrow new Error('Description is required and must be more than 30 characters with at least 3 words')\n\t\t}\n\n\t\t// Step 2: Enhance description using Claude AI\n\t\tconst enhancedDescription = await this.enhancementService.enhanceDescription(description)\n\n\t\t// Step 3: Create GitHub issue with original as title, enhanced as body\n\t\tconst result = await this.enhancementService.createEnhancedIssue(\n\t\t\tdescription,\n\t\t\tenhancedDescription\n\t\t)\n\n\t\t// Step 4: Wait for keypress and open issue in browser for review\n\t\tawait this.enhancementService.waitForReviewAndOpen(result.number)\n\n\t\t// Step 5: Return issue number for reference\n\t\treturn result.number\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAkBO,IAAM,kBAAN,MAAsB;AAAA,EAG5B,YAAY,oBAA8C;AAEzD,SAAK,qBAAqB,sBAAsB,IAAI;AAAA,MACnD,IAAI,cAAc;AAAA,MAClB,IAAI,aAAa;AAAA,MACjB,IAAI,gBAAgB;AAAA,IACrB;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAa,QAAQ,OAA8C;AAClE,UAAM,EAAE,YAAY,IAAI;AAGxB,QAAI,CAAC,eAAe,CAAC,KAAK,mBAAmB,oBAAoB,WAAW,GAAG;AAC9E,YAAM,IAAI,MAAM,mFAAmF;AAAA,IACpG;AAGA,UAAM,sBAAsB,MAAM,KAAK,mBAAmB,mBAAmB,WAAW;AAGxF,UAAM,SAAS,MAAM,KAAK,mBAAmB;AAAA,MAC5C;AAAA,MACA;AAAA,IACD;AAGA,UAAM,KAAK,mBAAmB,qBAAqB,OAAO,MAAM;AAGhE,WAAO,OAAO;AAAA,EACf;AACD;","names":[]}
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/utils/port.ts
4
- import { createHash } from "crypto";
5
- function generatePortOffsetFromBranchName(branchName) {
6
- if (!branchName || branchName.trim().length === 0) {
7
- throw new Error("Branch name cannot be empty");
8
- }
9
- const hash = createHash("sha256").update(branchName).digest("hex");
10
- const hashPrefix = hash.slice(0, 8);
11
- const hashAsInt = parseInt(hashPrefix, 16);
12
- const portOffset = hashAsInt % 999 + 1;
13
- return portOffset;
14
- }
15
- function calculatePortForBranch(branchName, basePort = 3e3) {
16
- const offset = generatePortOffsetFromBranchName(branchName);
17
- const port = basePort + offset;
18
- if (port > 65535) {
19
- throw new Error(
20
- `Calculated port ${port} exceeds maximum (65535). Use a lower base port (current: ${basePort}).`
21
- );
22
- }
23
- return port;
24
- }
25
-
26
- export {
27
- calculatePortForBranch
28
- };
29
- //# sourceMappingURL=chunk-37DYYFVK.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/port.ts"],"sourcesContent":["import { createHash } from 'crypto'\n\n/**\n * Generate deterministic port offset from branch name using SHA256 hash\n * Range: 1-999 (matches existing random range for branches)\n *\n * @param branchName - Branch name to generate port offset from\n * @returns Port offset in range [1, 999]\n * @throws Error if branchName is empty\n */\nexport function generatePortOffsetFromBranchName(branchName: string): number {\n\t// Validate input\n\tif (!branchName || branchName.trim().length === 0) {\n\t\tthrow new Error('Branch name cannot be empty')\n\t}\n\n\t// Generate SHA256 hash of branch name (same pattern as color.ts)\n\tconst hash = createHash('sha256').update(branchName).digest('hex')\n\n\t// Take first 8 hex characters and convert to port offset (1-999)\n\tconst hashPrefix = hash.slice(0, 8)\n\tconst hashAsInt = parseInt(hashPrefix, 16)\n\tconst portOffset = (hashAsInt % 999) + 1 // +1 ensures range is 1-999, not 0-998\n\n\treturn portOffset\n}\n\n/**\n * Calculate deterministic port for branch-based workspace\n *\n * @param branchName - Branch name\n * @param basePort - Base port (default: 3000)\n * @returns Port number\n * @throws Error if calculated port exceeds 65535 or branchName is empty\n */\nexport function calculatePortForBranch(branchName: string, basePort: number = 3000): number {\n\tconst offset = generatePortOffsetFromBranchName(branchName)\n\tconst port = basePort + offset\n\n\t// Validate port range (same as EnvironmentManager.calculatePort)\n\tif (port > 65535) {\n\t\tthrow new Error(\n\t\t\t`Calculated port ${port} exceeds maximum (65535). Use a lower base port (current: ${basePort}).`\n\t\t)\n\t}\n\n\treturn port\n}\n"],"mappings":";;;AAAA,SAAS,kBAAkB;AAUpB,SAAS,iCAAiC,YAA4B;AAE5E,MAAI,CAAC,cAAc,WAAW,KAAK,EAAE,WAAW,GAAG;AAClD,UAAM,IAAI,MAAM,6BAA6B;AAAA,EAC9C;AAGA,QAAM,OAAO,WAAW,QAAQ,EAAE,OAAO,UAAU,EAAE,OAAO,KAAK;AAGjE,QAAM,aAAa,KAAK,MAAM,GAAG,CAAC;AAClC,QAAM,YAAY,SAAS,YAAY,EAAE;AACzC,QAAM,aAAc,YAAY,MAAO;AAEvC,SAAO;AACR;AAUO,SAAS,uBAAuB,YAAoB,WAAmB,KAAc;AAC3F,QAAM,SAAS,iCAAiC,UAAU;AAC1D,QAAM,OAAO,WAAW;AAGxB,MAAI,OAAO,OAAO;AACjB,UAAM,IAAI;AAAA,MACT,mBAAmB,IAAI,6DAA6D,QAAQ;AAAA,IAC7F;AAAA,EACD;AAEA,SAAO;AACR;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/PromptTemplateManager.ts"],"sourcesContent":["import { readFile } from 'fs/promises'\nimport { accessSync } from 'fs'\nimport path from 'path'\nimport { fileURLToPath } from 'url'\nimport { logger } from '../utils/logger.js'\n\nexport interface TemplateVariables {\n\tISSUE_NUMBER?: number\n\tPR_NUMBER?: number\n\tISSUE_TITLE?: string\n\tPR_TITLE?: string\n\tWORKSPACE_PATH?: string\n\tPORT?: number\n\tONE_SHOT_MODE?: boolean\n}\n\nexport class PromptTemplateManager {\n\tprivate templateDir: string\n\n\tconstructor(templateDir?: string) {\n\t\tif (templateDir) {\n\t\t\tthis.templateDir = templateDir\n\t\t} else {\n\t\t\t// Find templates relative to the package installation\n\t\t\t// When running from dist/, templates are copied to dist/prompts/\n\t\t\tconst currentFileUrl = import.meta.url\n\t\t\tconst currentFilePath = fileURLToPath(currentFileUrl)\n\t\t\tconst distDir = path.dirname(currentFilePath) // dist directory (may be chunked file location)\n\n\t\t\t// Walk up to find the dist directory (in case of chunked files)\n\t\t\tlet templateDir = path.join(distDir, 'prompts')\n\t\t\tlet currentDir = distDir\n\n\t\t\t// Try to find the prompts directory by walking up\n\t\t\twhile (currentDir !== path.dirname(currentDir)) {\n\t\t\t\tconst candidatePath = path.join(currentDir, 'prompts')\n\t\t\t\ttry {\n\t\t\t\t\t// Check if this directory exists (sync check for constructor)\n\t\t\t\t\taccessSync(candidatePath)\n\t\t\t\t\ttemplateDir = candidatePath\n\t\t\t\t\tbreak\n\t\t\t\t} catch {\n\t\t\t\t\tcurrentDir = path.dirname(currentDir)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.templateDir = templateDir\n\t\t\tlogger.debug('PromptTemplateManager initialized', {\n\t\t\t\tcurrentFilePath,\n\t\t\t\tdistDir,\n\t\t\t\ttemplateDir: this.templateDir\n\t\t\t})\n\t\t}\n\t}\n\n\t/**\n\t * Load a template file by name\n\t */\n\tasync loadTemplate(templateName: 'issue' | 'pr' | 'regular'): Promise<string> {\n\t\tconst templatePath = path.join(this.templateDir, `${templateName}-prompt.txt`)\n\n\t\tlogger.debug('Loading template', {\n\t\t\ttemplateName,\n\t\t\ttemplateDir: this.templateDir,\n\t\t\ttemplatePath\n\t\t})\n\n\t\ttry {\n\t\t\treturn await readFile(templatePath, 'utf-8')\n\t\t} catch (error) {\n\t\t\tlogger.error('Failed to load template', { templateName, templatePath, error })\n\t\t\tthrow new Error(`Template not found: ${templatePath}`)\n\t\t}\n\t}\n\n\t/**\n\t * Substitute variables in a template string\n\t */\n\tsubstituteVariables(template: string, variables: TemplateVariables): string {\n\t\tlet result = template\n\n\t\t// Process conditional sections first\n\t\tresult = this.processConditionalSections(result, variables)\n\n\t\t// Replace each variable if it exists\n\t\tif (variables.ISSUE_NUMBER !== undefined) {\n\t\t\tresult = result.replace(/ISSUE_NUMBER/g, String(variables.ISSUE_NUMBER))\n\t\t}\n\n\t\tif (variables.PR_NUMBER !== undefined) {\n\t\t\tresult = result.replace(/PR_NUMBER/g, String(variables.PR_NUMBER))\n\t\t}\n\n\t\tif (variables.ISSUE_TITLE !== undefined) {\n\t\t\tresult = result.replace(/ISSUE_TITLE/g, variables.ISSUE_TITLE)\n\t\t}\n\n\t\tif (variables.PR_TITLE !== undefined) {\n\t\t\tresult = result.replace(/PR_TITLE/g, variables.PR_TITLE)\n\t\t}\n\n\t\tif (variables.WORKSPACE_PATH !== undefined) {\n\t\t\tresult = result.replace(/WORKSPACE_PATH/g, variables.WORKSPACE_PATH)\n\t\t}\n\n\t\tif (variables.PORT !== undefined) {\n\t\t\tresult = result.replace(/PORT/g, String(variables.PORT))\n\t\t}\n\n\t\treturn result\n\t}\n\n\t/**\n\t * Process conditional sections in template\n\t * Format: {{#IF ONE_SHOT_MODE}}content{{/IF ONE_SHOT_MODE}}\n\t * \n\t * Note: /s flag allows . to match newlines\n\t */\n\tprivate processConditionalSections(template: string, variables: TemplateVariables): string {\n\t\tlet result = template\n\n\t\t// Process ONE_SHOT_MODE conditionals\n\t\tconst oneShotRegex = /\\{\\{#IF ONE_SHOT_MODE\\}\\}(.*?)\\{\\{\\/IF ONE_SHOT_MODE\\}\\}/gs\n\n\t\tif (variables.ONE_SHOT_MODE === true) {\n\t\t\t// Include the content, remove the conditional markers\n\t\t\tresult = result.replace(oneShotRegex, '$1')\n\t\t} else {\n\t\t\t// Remove the entire conditional block\n\t\t\tresult = result.replace(oneShotRegex, '')\n\t\t}\n\n\t\treturn result\n\t}\n\n\t/**\n\t * Get a fully processed prompt for a workflow type\n\t */\n\tasync getPrompt(\n\t\ttype: 'issue' | 'pr' | 'regular',\n\t\tvariables: TemplateVariables\n\t): Promise<string> {\n\t\tconst template = await this.loadTemplate(type)\n\t\treturn this.substituteVariables(template, variables)\n\t}\n}\n"],"mappings":";;;;;;AAAA,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAC3B,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAavB,IAAM,wBAAN,MAA4B;AAAA,EAGlC,YAAY,aAAsB;AACjC,QAAI,aAAa;AAChB,WAAK,cAAc;AAAA,IACpB,OAAO;AAGN,YAAM,iBAAiB,YAAY;AACnC,YAAM,kBAAkB,cAAc,cAAc;AACpD,YAAM,UAAU,KAAK,QAAQ,eAAe;AAG5C,UAAIA,eAAc,KAAK,KAAK,SAAS,SAAS;AAC9C,UAAI,aAAa;AAGjB,aAAO,eAAe,KAAK,QAAQ,UAAU,GAAG;AAC/C,cAAM,gBAAgB,KAAK,KAAK,YAAY,SAAS;AACrD,YAAI;AAEH,qBAAW,aAAa;AACxB,UAAAA,eAAc;AACd;AAAA,QACD,QAAQ;AACP,uBAAa,KAAK,QAAQ,UAAU;AAAA,QACrC;AAAA,MACD;AAEA,WAAK,cAAcA;AACnB,aAAO,MAAM,qCAAqC;AAAA,QACjD;AAAA,QACA;AAAA,QACA,aAAa,KAAK;AAAA,MACnB,CAAC;AAAA,IACF;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,cAA2D;AAC7E,UAAM,eAAe,KAAK,KAAK,KAAK,aAAa,GAAG,YAAY,aAAa;AAE7E,WAAO,MAAM,oBAAoB;AAAA,MAChC;AAAA,MACA,aAAa,KAAK;AAAA,MAClB;AAAA,IACD,CAAC;AAED,QAAI;AACH,aAAO,MAAM,SAAS,cAAc,OAAO;AAAA,IAC5C,SAAS,OAAO;AACf,aAAO,MAAM,2BAA2B,EAAE,cAAc,cAAc,MAAM,CAAC;AAC7E,YAAM,IAAI,MAAM,uBAAuB,YAAY,EAAE;AAAA,IACtD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoB,UAAkB,WAAsC;AAC3E,QAAI,SAAS;AAGb,aAAS,KAAK,2BAA2B,QAAQ,SAAS;AAG1D,QAAI,UAAU,iBAAiB,QAAW;AACzC,eAAS,OAAO,QAAQ,iBAAiB,OAAO,UAAU,YAAY,CAAC;AAAA,IACxE;AAEA,QAAI,UAAU,cAAc,QAAW;AACtC,eAAS,OAAO,QAAQ,cAAc,OAAO,UAAU,SAAS,CAAC;AAAA,IAClE;AAEA,QAAI,UAAU,gBAAgB,QAAW;AACxC,eAAS,OAAO,QAAQ,gBAAgB,UAAU,WAAW;AAAA,IAC9D;AAEA,QAAI,UAAU,aAAa,QAAW;AACrC,eAAS,OAAO,QAAQ,aAAa,UAAU,QAAQ;AAAA,IACxD;AAEA,QAAI,UAAU,mBAAmB,QAAW;AAC3C,eAAS,OAAO,QAAQ,mBAAmB,UAAU,cAAc;AAAA,IACpE;AAEA,QAAI,UAAU,SAAS,QAAW;AACjC,eAAS,OAAO,QAAQ,SAAS,OAAO,UAAU,IAAI,CAAC;AAAA,IACxD;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,2BAA2B,UAAkB,WAAsC;AAC1F,QAAI,SAAS;AAGb,UAAM,eAAe;AAErB,QAAI,UAAU,kBAAkB,MAAM;AAErC,eAAS,OAAO,QAAQ,cAAc,IAAI;AAAA,IAC3C,OAAO;AAEN,eAAS,OAAO,QAAQ,cAAc,EAAE;AAAA,IACzC;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UACL,MACA,WACkB;AAClB,UAAM,WAAW,MAAM,KAAK,aAAa,IAAI;AAC7C,WAAO,KAAK,oBAAoB,UAAU,SAAS;AAAA,EACpD;AACD;","names":["templateDir"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/SettingsManager.ts"],"sourcesContent":["import { readFile } from 'fs/promises'\nimport path from 'path'\nimport { z } from 'zod'\nimport deepmerge from 'deepmerge'\nimport { logger } from '../utils/logger.js'\n\n/**\n * Zod schema for agent settings\n */\nexport const AgentSettingsSchema = z.object({\n\tmodel: z\n\t\t.enum(['sonnet', 'opus', 'haiku'])\n\t\t.optional()\n\t\t.describe('Claude model shorthand: sonnet, opus, or haiku'),\n\t// Future: could add other per-agent overrides\n})\n\n/**\n * Zod schema for workflow permission configuration\n */\nexport const WorkflowPermissionSchema = z.object({\n\tpermissionMode: z\n\t\t.enum(['plan', 'acceptEdits', 'bypassPermissions', 'default'])\n\t\t.optional()\n\t\t.describe('Permission mode for Claude CLI in this workflow type'),\n\tnoVerify: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe('Skip pre-commit hooks (--no-verify) when committing during finish workflow'),\n\tstartIde: z\n\t\t.boolean()\n\t\t.default(true)\n\t\t.describe('Launch IDE (code) when starting this workflow type'),\n\tstartDevServer: z\n\t\t.boolean()\n\t\t.default(true)\n\t\t.describe('Launch development server when starting this workflow type'),\n\tstartAiAgent: z\n\t\t.boolean()\n\t\t.default(true)\n\t\t.describe('Launch Claude AI agent when starting this workflow type'),\n\tstartTerminal: z\n\t\t.boolean()\n\t\t.default(false)\n\t\t.describe('Launch terminal window without dev server when starting this workflow type'),\n})\n\n/**\n * Zod schema for workflows settings\n */\nexport const WorkflowsSettingsSchema = z\n\t.object({\n\t\tissue: WorkflowPermissionSchema.optional(),\n\t\tpr: WorkflowPermissionSchema.optional(),\n\t\tregular: WorkflowPermissionSchema.optional(),\n\t})\n\t.optional()\n\n/**\n * Zod schema for capabilities settings\n */\nexport const CapabilitiesSettingsSchema = z\n\t.object({\n\t\tweb: z\n\t\t\t.object({\n\t\t\t\tbasePort: z\n\t\t\t\t\t.number()\n\t\t\t\t\t.min(1, 'Base port must be >= 1')\n\t\t\t\t\t.max(65535, 'Base port must be <= 65535')\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe('Base port for web workspace port calculations (default: 3000)'),\n\t\t\t})\n\t\t\t.optional(),\n\t\tdatabase: z\n\t\t\t.object({\n\t\t\t\tdatabaseUrlEnvVarName: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.min(1, 'Database URL variable name cannot be empty')\n\t\t\t\t\t.regex(/^[A-Z_][A-Z0-9_]*$/, 'Must be valid env var name (uppercase, underscores)')\n\t\t\t\t\t.optional()\n\t\t\t\t\t.default('DATABASE_URL')\n\t\t\t\t\t.describe('Name of environment variable for database connection URL'),\n\t\t\t})\n\t\t\t.optional(),\n\t})\n\t.optional()\n\n/**\n * Zod schema for iloom settings\n */\nexport const IloomSettingsSchema = z.object({\n\tmainBranch: z\n\t\t.string()\n\t\t.min(1, \"Settings 'mainBranch' cannot be empty\")\n\t\t.optional()\n\t\t.describe('Name of the main/primary branch for the repository'),\n\tworktreePrefix: z\n\t\t.string()\n\t\t.optional()\n\t\t.refine(\n\t\t\t(val) => {\n\t\t\t\tif (val === undefined) return true // undefined = use default calculation\n\t\t\t\tif (val === '') return true // empty string = no prefix mode\n\n\t\t\t\t// Allowlist: only alphanumeric, hyphens, underscores, and forward slashes\n\t\t\t\tconst allowedChars = /^[a-zA-Z0-9\\-_/]+$/\n\t\t\t\tif (!allowedChars.test(val)) return false\n\n\t\t\t\t// Reject if only special characters (no alphanumeric content)\n\t\t\t\tif (/^[-_/]+$/.test(val)) return false\n\n\t\t\t\t// Check each segment (split by /) contains at least one alphanumeric character\n\t\t\t\tconst segments = val.split('/')\n\t\t\t\tfor (const segment of segments) {\n\t\t\t\t\tif (segment && /^[-_]+$/.test(segment)) {\n\t\t\t\t\t\t// Segment exists but contains only hyphens/underscores\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn true\n\t\t\t},\n\t\t\t{\n\t\t\t\tmessage:\n\t\t\t\t\t\"worktreePrefix contains invalid characters. Only alphanumeric characters, hyphens (-), underscores (_), and forward slashes (/) are allowed. Use forward slashes for nested directories.\",\n\t\t\t},\n\t\t)\n\t\t.describe(\n\t\t\t'Prefix for worktree directories. Empty string disables prefix. Defaults to <repo-name>-looms if not set.',\n\t\t),\n\tprotectedBranches: z\n\t\t.array(z.string().min(1, 'Protected branch name cannot be empty'))\n\t\t.optional()\n\t\t.describe('List of branches that cannot be deleted (defaults to [mainBranch, \"main\", \"master\", \"develop\"])'),\n\tworkflows: WorkflowsSettingsSchema.describe('Per-workflow-type permission configurations'),\n\tagents: z\n\t\t.record(z.string(), AgentSettingsSchema)\n\t\t.optional()\n\t\t.nullable()\n\t\t.describe('Per-agent configuration overrides'),\n\tcapabilities: CapabilitiesSettingsSchema.describe('Project capability configurations'),\n})\n\n/**\n * TypeScript type for agent settings derived from Zod schema\n */\nexport type AgentSettings = z.infer<typeof AgentSettingsSchema>\n\n/**\n * TypeScript type for workflow permission configuration derived from Zod schema\n */\nexport type WorkflowPermission = z.infer<typeof WorkflowPermissionSchema>\n\n/**\n * TypeScript type for workflows settings derived from Zod schema\n */\nexport type WorkflowsSettings = z.infer<typeof WorkflowsSettingsSchema>\n\n/**\n * TypeScript type for capabilities settings derived from Zod schema\n */\nexport type CapabilitiesSettings = z.infer<typeof CapabilitiesSettingsSchema>\n\n/**\n * TypeScript type for iloom settings derived from Zod schema\n */\nexport type IloomSettings = z.infer<typeof IloomSettingsSchema>\n\n/**\n * Manages project-level settings from .iloom/settings.json\n */\nexport class SettingsManager {\n\t/**\n\t * Load settings from <PROJECT_ROOT>/.iloom/settings.json and settings.local.json\n\t * Merges settings.local.json over settings.json with priority\n\t * CLI overrides have highest priority if provided\n\t * Returns empty object if both files don't exist (not an error)\n\t */\n\tasync loadSettings(\n\t\tprojectRoot?: string,\n\t\tcliOverrides?: Partial<IloomSettings>,\n\t): Promise<IloomSettings> {\n\t\tconst root = this.getProjectRoot(projectRoot)\n\n\t\t// Load base settings from settings.json\n\t\tconst baseSettings = await this.loadSettingsFile(root, 'settings.json')\n\t\tconst baseSettingsPath = path.join(root, '.iloom', 'settings.json')\n\t\tlogger.debug(`📄 Base settings from ${baseSettingsPath}:`, JSON.stringify(baseSettings, null, 2))\n\n\t\t// Load local overrides from settings.local.json\n\t\tconst localSettings = await this.loadSettingsFile(root, 'settings.local.json')\n\t\tconst localSettingsPath = path.join(root, '.iloom', 'settings.local.json')\n\t\tlogger.debug(`📄 Local settings from ${localSettingsPath}:`, JSON.stringify(localSettings, null, 2))\n\n\t\t// Deep merge with priority: cliOverrides > localSettings > baseSettings\n\t\tlet merged = this.mergeSettings(baseSettings, localSettings)\n\t\tlogger.debug('🔄 After merging base + local settings:', JSON.stringify(merged, null, 2))\n\n\t\tif (cliOverrides && Object.keys(cliOverrides).length > 0) {\n\t\t\tlogger.debug('⚙️ CLI overrides to apply:', JSON.stringify(cliOverrides, null, 2))\n\t\t\tmerged = this.mergeSettings(merged, cliOverrides)\n\t\t\tlogger.debug('🔄 After applying CLI overrides:', JSON.stringify(merged, null, 2))\n\t\t}\n\n\t\t// Validate merged result\n\t\ttry {\n\t\t\tconst finalSettings = IloomSettingsSchema.parse(merged)\n\n\t\t\t// Debug: Log final merged configuration\n\t\t\tthis.logFinalConfiguration(finalSettings)\n\n\t\t\treturn finalSettings\n\t\t} catch (error) {\n\t\t\t// Show all Zod validation errors\n\t\t\tif (error instanceof z.ZodError) {\n\t\t\t\tconst errorMsg = this.formatAllZodErrors(error, '<merged settings>')\n\t\t\t\t// Enhance error message if CLI overrides were applied\n\t\t\t\tif (cliOverrides && Object.keys(cliOverrides).length > 0) {\n\t\t\t\t\tthrow new Error(`${errorMsg.message}\\n\\nNote: CLI overrides were applied. Check your --set arguments.`)\n\t\t\t\t}\n\t\t\t\tthrow errorMsg\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Log the final merged configuration for debugging\n\t */\n\tprivate logFinalConfiguration(settings: IloomSettings): void {\n\t\tlogger.debug('📋 Final merged configuration:', JSON.stringify(settings, null, 2))\n\t}\n\n\t/**\n\t * Load and parse a single settings file\n\t * Returns empty object if file doesn't exist (not an error)\n\t */\n\tprivate async loadSettingsFile(\n\t\tprojectRoot: string,\n\t\tfilename: string,\n\t): Promise<Partial<IloomSettings>> {\n\t\tconst settingsPath = path.join(projectRoot, '.iloom', filename)\n\n\t\ttry {\n\t\t\tconst content = await readFile(settingsPath, 'utf-8')\n\t\t\tlet parsed: unknown\n\n\t\t\ttry {\n\t\t\t\tparsed = JSON.parse(content)\n\t\t\t} catch (error) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to parse settings file at ${settingsPath}: ${error instanceof Error ? error.message : 'Invalid JSON'}`,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\t// Validate individual file with strict mode to catch unknown keys\n\t\t\t// Note: Schema already has all fields as optional, so no need for .partial()\n\t\t\ttry {\n\t\t\t\tconst validated = IloomSettingsSchema.strict().parse(parsed)\n\t\t\t\treturn validated\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof z.ZodError) {\n\t\t\t\t\tconst errorMsg = this.formatAllZodErrors(error, filename)\n\t\t\t\t\tthrow errorMsg\n\t\t\t\t}\n\t\t\t\tthrow error\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// File not found is not an error - return empty settings\n\t\t\tif ((error as { code?: string }).code === 'ENOENT') {\n\t\t\t\tlogger.debug(`No settings file found at ${settingsPath}, using defaults`)\n\t\t\t\treturn {}\n\t\t\t}\n\n\t\t\t// Re-throw parsing errors\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Deep merge two settings objects with priority to override\n\t * Uses deepmerge library with array replacement strategy\n\t */\n\tprivate mergeSettings(\n\t\tbase: Partial<IloomSettings>,\n\t\toverride: Partial<IloomSettings>,\n\t): IloomSettings {\n\t\t// Use deepmerge with array replacement (not concatenation)\n\t\treturn deepmerge(base, override, {\n\t\t\t// Replace arrays instead of concatenating them\n\t\t\tarrayMerge: (_destinationArray, sourceArray) => sourceArray,\n\t\t}) as IloomSettings\n\t}\n\n\t/**\n\t * Format all Zod validation errors into a single error message\n\t */\n\tprivate formatAllZodErrors(error: z.ZodError, settingsPath: string): Error {\n\t\tconst errorMessages = error.issues.map(issue => {\n\t\t\tconst path = issue.path.length > 0 ? issue.path.join('.') : 'root'\n\t\t\treturn ` - ${path}: ${issue.message}`\n\t\t})\n\n\t\treturn new Error(\n\t\t\t`Settings validation failed at ${settingsPath}:\\n${errorMessages.join('\\n')}`,\n\t\t)\n\t}\n\n\t/**\n\t * Validate settings structure and model names using Zod schema\n\t * This method is kept for testing purposes but uses Zod internally\n\t * @internal - Only used in tests via bracket notation\n\t */\n\t// @ts-expect-error - Used in tests via bracket notation, TypeScript can't detect this usage\n\tprivate validateSettings(settings: IloomSettings): void {\n\t\ttry {\n\t\t\tIloomSettingsSchema.parse(settings)\n\t\t} catch (error) {\n\t\t\tif (error instanceof z.ZodError) {\n\t\t\t\tthrow this.formatAllZodErrors(error, '<validation>')\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Get project root (defaults to process.cwd())\n\t */\n\tprivate getProjectRoot(projectRoot?: string): string {\n\t\treturn projectRoot ?? process.cwd()\n\t}\n\n\t/**\n\t * Get effective protected branches list with mainBranch always included\n\t *\n\t * This method provides a single source of truth for protected branches logic:\n\t * 1. Use configured protectedBranches if provided\n\t * 2. Otherwise use defaults: [mainBranch, 'main', 'master', 'develop']\n\t * 3. ALWAYS ensure mainBranch is included even if user configured custom list\n\t *\n\t * @param projectRoot - Optional project root directory (defaults to process.cwd())\n\t * @returns Array of protected branch names with mainBranch guaranteed to be included\n\t */\n\tasync getProtectedBranches(projectRoot?: string): Promise<string[]> {\n\t\tconst settings = await this.loadSettings(projectRoot)\n\t\tconst mainBranch = settings.mainBranch ?? 'main'\n\n\t\t// Build protected branches list:\n\t\t// 1. Use configured protectedBranches if provided\n\t\t// 2. Otherwise use defaults: [mainBranch, 'main', 'master', 'develop']\n\t\t// 3. ALWAYS ensure mainBranch is included even if user configured custom list\n\t\tlet protectedBranches: string[]\n\t\tif (settings.protectedBranches) {\n\t\t\t// Use configured list but ensure mainBranch is always included\n\t\t\tprotectedBranches = settings.protectedBranches.includes(mainBranch)\n\t\t\t\t? settings.protectedBranches\n\t\t\t\t: [mainBranch, ...settings.protectedBranches]\n\t\t} else {\n\t\t\t// Use defaults with current mainBranch\n\t\t\tprotectedBranches = [mainBranch, 'main', 'master', 'develop']\n\t\t}\n\n\t\treturn protectedBranches\n\t}\n}\n"],"mappings":"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","names":["path"]}