@iloom/cli 0.12.0 → 0.13.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -2
- package/dist/{ClaudeContextManager-IENAE2CP.js → ClaudeContextManager-RRGREEZQ.js} +4 -4
- package/dist/{ClaudeService-YIJCZUUB.js → ClaudeService-LEPW6QAC.js} +3 -3
- package/dist/{IssueTrackerFactory-2OI7YIN6.js → IssueTrackerFactory-KE2BDCLC.js} +3 -3
- package/dist/{LoomLauncher-3TSFW7QP.js → LoomLauncher-GKQMR5E6.js} +4 -4
- package/dist/README.md +17 -2
- package/dist/{SettingsManager-BMQCAXPP.js → SettingsManager-KQU7OX7G.js} +4 -2
- package/dist/{build-DMWSIME6.js → build-V3KADFMO.js} +6 -6
- package/dist/{chunk-QFDM23CO.js → chunk-3XEXT35Z.js} +2 -2
- package/dist/{chunk-FV4KXBGO.js → chunk-4VQXMEEP.js} +2 -2
- package/dist/{chunk-V5IYLWRA.js → chunk-H3T3EPF3.js} +2 -2
- package/dist/{chunk-QF2DROQR.js → chunk-JDN4SPV3.js} +2 -2
- package/dist/{chunk-M3FBM4T3.js → chunk-KQSV7FOG.js} +2 -2
- package/dist/{chunk-R7DGN73N.js → chunk-NTDY5AMO.js} +2 -2
- package/dist/{chunk-35CBWAJL.js → chunk-NUUFP53X.js} +2 -2
- package/dist/{chunk-IS46GQRA.js → chunk-PD75ZCFT.js} +14 -14
- package/dist/chunk-PD75ZCFT.js.map +1 -0
- package/dist/{chunk-EQIII6GI.js → chunk-Q7VXHJP6.js} +3 -3
- package/dist/{chunk-IHSA7VGI.js → chunk-QED2WB2D.js} +4 -4
- package/dist/{chunk-OPQC4OWM.js → chunk-QNPJXO53.js} +3 -3
- package/dist/{chunk-YWNF5755.js → chunk-QQULYI2S.js} +2 -2
- package/dist/{chunk-HIGWKLQR.js → chunk-QXGM32TO.js} +2 -2
- package/dist/{chunk-PMB6TYV4.js → chunk-RFCAPHL5.js} +2 -2
- package/dist/{chunk-OKB2NEDQ.js → chunk-SA446KA2.js} +5 -5
- package/dist/{chunk-ZM2AYHMO.js → chunk-SN4S5CWL.js} +2 -2
- package/dist/{chunk-XVCGPTEQ.js → chunk-TAEVA4QR.js} +2 -2
- package/dist/chunk-TAEVA4QR.js.map +1 -0
- package/dist/{chunk-PDG74IJT.js → chunk-TN2D2RX7.js} +22 -20
- package/dist/chunk-TN2D2RX7.js.map +1 -0
- package/dist/{chunk-GWJWECZB.js → chunk-VVQQIG64.js} +16 -17
- package/dist/{chunk-GWJWECZB.js.map → chunk-VVQQIG64.js.map} +1 -1
- package/dist/{chunk-653XBU3L.js → chunk-WGUGB54H.js} +10 -1
- package/dist/chunk-WGUGB54H.js.map +1 -0
- package/dist/{chunk-KCZSUJUR.js → chunk-X5DRLONY.js} +4 -4
- package/dist/{chunk-VA6CWUAE.js → chunk-XCP2WDYA.js} +2 -2
- package/dist/{chunk-HKEXRZMU.js → chunk-YUOVWWJX.js} +310 -5
- package/dist/chunk-YUOVWWJX.js.map +1 -0
- package/dist/{chunk-BFF27W3S.js → chunk-ZUIFO7B4.js} +2 -2
- package/dist/{cleanup-RLBLNQZN.js → cleanup-RJKLI47I.js} +19 -19
- package/dist/cleanup-RJKLI47I.js.map +1 -0
- package/dist/cli.js +89 -85
- package/dist/cli.js.map +1 -1
- package/dist/{commit-RILBXFWO.js → commit-SUHRUMDE.js} +6 -6
- package/dist/{compile-QEL5724K.js → compile-2MD346PO.js} +6 -6
- package/dist/{contribute-EHWLYOMZ.js → contribute-P4BMRY7C.js} +3 -3
- package/dist/database-helpers-PRDFNDRO.js +11 -0
- package/dist/{dev-server-2WSWZXJG.js → dev-server-ZNTLWOL5.js} +8 -8
- package/dist/{feedback-I6ZEHEUB.js → feedback-Q6WG2WX4.js} +2 -2
- package/dist/{git-I3PO6FY7.js → git-TX2IEMB3.js} +3 -3
- package/dist/{ignite-XZFYRVRJ.js → ignite-P644W2PK.js} +9 -9
- package/dist/index.d.ts +36 -2
- package/dist/index.js +17 -9
- package/dist/index.js.map +1 -1
- package/dist/{init-A6WRP77L.js → init-5HFY7JG6.js} +5 -5
- package/dist/{install-deps-HXP2TM7G.js → install-deps-J4ALTM27.js} +6 -6
- package/dist/{issues-SUFQJY6O.js → issues-LZMIF22U.js} +4 -4
- package/dist/{lint-FDZC77GL.js → lint-XIXKU22H.js} +6 -6
- package/dist/mcp/issue-management-server.js +8 -0
- package/dist/mcp/issue-management-server.js.map +1 -1
- package/dist/{open-US4XACLW.js → open-KUO35JIJ.js} +8 -8
- package/dist/{plan-PL3ZB32J.js → plan-7CF56OIR.js} +17 -17
- package/dist/prompts/init-prompt.txt +24 -0
- package/dist/prompts/issue-prompt.txt +1 -1
- package/dist/prompts/regular-prompt.txt +1 -1
- package/dist/{rebase-JA3RW2XO.js → rebase-MAMWPA2L.js} +5 -5
- package/dist/{recap-5TO42HN2.js → recap-IDBO3KM5.js} +6 -6
- package/dist/{run-KKCRBRLW.js → run-RGZHCQ6M.js} +8 -8
- package/dist/schema/settings.schema.json +24 -0
- package/dist/{shell-GAB2FCXH.js → shell-7ADCDFIV.js} +5 -5
- package/dist/{summary-P7QE3TNW.js → summary-7J2HORFD.js} +7 -7
- package/dist/{test-6LFB5WOO.js → test-SRB7EWU6.js} +6 -6
- package/dist/{test-git-PYJOYSED.js → test-git-G7ATVIXG.js} +3 -3
- package/dist/{test-jira-SM7IU5HW.js → test-jira-Q2HPA522.js} +3 -3
- package/dist/{test-prefix-HIRZBXTM.js → test-prefix-JMDGXR5A.js} +3 -3
- package/dist/{test-webserver-43PVP2JL.js → test-webserver-GZFVXBGD.js} +5 -5
- package/dist/{vscode-HXIXRZ3A.js → vscode-3I7ISHUU.js} +5 -5
- package/package.json +1 -1
- package/dist/chunk-653XBU3L.js.map +0 -1
- package/dist/chunk-HKEXRZMU.js.map +0 -1
- package/dist/chunk-IS46GQRA.js.map +0 -1
- package/dist/chunk-PDG74IJT.js.map +0 -1
- package/dist/chunk-XVCGPTEQ.js.map +0 -1
- package/dist/cleanup-RLBLNQZN.js.map +0 -1
- package/dist/neon-helpers-LCZAN4U4.js +0 -11
- /package/dist/{ClaudeContextManager-IENAE2CP.js.map → ClaudeContextManager-RRGREEZQ.js.map} +0 -0
- /package/dist/{ClaudeService-YIJCZUUB.js.map → ClaudeService-LEPW6QAC.js.map} +0 -0
- /package/dist/{IssueTrackerFactory-2OI7YIN6.js.map → IssueTrackerFactory-KE2BDCLC.js.map} +0 -0
- /package/dist/{LoomLauncher-3TSFW7QP.js.map → LoomLauncher-GKQMR5E6.js.map} +0 -0
- /package/dist/{SettingsManager-BMQCAXPP.js.map → SettingsManager-KQU7OX7G.js.map} +0 -0
- /package/dist/{build-DMWSIME6.js.map → build-V3KADFMO.js.map} +0 -0
- /package/dist/{chunk-QFDM23CO.js.map → chunk-3XEXT35Z.js.map} +0 -0
- /package/dist/{chunk-FV4KXBGO.js.map → chunk-4VQXMEEP.js.map} +0 -0
- /package/dist/{chunk-V5IYLWRA.js.map → chunk-H3T3EPF3.js.map} +0 -0
- /package/dist/{chunk-QF2DROQR.js.map → chunk-JDN4SPV3.js.map} +0 -0
- /package/dist/{chunk-M3FBM4T3.js.map → chunk-KQSV7FOG.js.map} +0 -0
- /package/dist/{chunk-R7DGN73N.js.map → chunk-NTDY5AMO.js.map} +0 -0
- /package/dist/{chunk-35CBWAJL.js.map → chunk-NUUFP53X.js.map} +0 -0
- /package/dist/{chunk-EQIII6GI.js.map → chunk-Q7VXHJP6.js.map} +0 -0
- /package/dist/{chunk-IHSA7VGI.js.map → chunk-QED2WB2D.js.map} +0 -0
- /package/dist/{chunk-OPQC4OWM.js.map → chunk-QNPJXO53.js.map} +0 -0
- /package/dist/{chunk-YWNF5755.js.map → chunk-QQULYI2S.js.map} +0 -0
- /package/dist/{chunk-HIGWKLQR.js.map → chunk-QXGM32TO.js.map} +0 -0
- /package/dist/{chunk-PMB6TYV4.js.map → chunk-RFCAPHL5.js.map} +0 -0
- /package/dist/{chunk-OKB2NEDQ.js.map → chunk-SA446KA2.js.map} +0 -0
- /package/dist/{chunk-ZM2AYHMO.js.map → chunk-SN4S5CWL.js.map} +0 -0
- /package/dist/{chunk-KCZSUJUR.js.map → chunk-X5DRLONY.js.map} +0 -0
- /package/dist/{chunk-VA6CWUAE.js.map → chunk-XCP2WDYA.js.map} +0 -0
- /package/dist/{chunk-BFF27W3S.js.map → chunk-ZUIFO7B4.js.map} +0 -0
- /package/dist/{commit-RILBXFWO.js.map → commit-SUHRUMDE.js.map} +0 -0
- /package/dist/{compile-QEL5724K.js.map → compile-2MD346PO.js.map} +0 -0
- /package/dist/{contribute-EHWLYOMZ.js.map → contribute-P4BMRY7C.js.map} +0 -0
- /package/dist/{git-I3PO6FY7.js.map → database-helpers-PRDFNDRO.js.map} +0 -0
- /package/dist/{dev-server-2WSWZXJG.js.map → dev-server-ZNTLWOL5.js.map} +0 -0
- /package/dist/{feedback-I6ZEHEUB.js.map → feedback-Q6WG2WX4.js.map} +0 -0
- /package/dist/{ignite-XZFYRVRJ.js.map → git-TX2IEMB3.js.map} +0 -0
- /package/dist/{neon-helpers-LCZAN4U4.js.map → ignite-P644W2PK.js.map} +0 -0
- /package/dist/{init-A6WRP77L.js.map → init-5HFY7JG6.js.map} +0 -0
- /package/dist/{install-deps-HXP2TM7G.js.map → install-deps-J4ALTM27.js.map} +0 -0
- /package/dist/{issues-SUFQJY6O.js.map → issues-LZMIF22U.js.map} +0 -0
- /package/dist/{lint-FDZC77GL.js.map → lint-XIXKU22H.js.map} +0 -0
- /package/dist/{open-US4XACLW.js.map → open-KUO35JIJ.js.map} +0 -0
- /package/dist/{plan-PL3ZB32J.js.map → plan-7CF56OIR.js.map} +0 -0
- /package/dist/{rebase-JA3RW2XO.js.map → rebase-MAMWPA2L.js.map} +0 -0
- /package/dist/{recap-5TO42HN2.js.map → recap-IDBO3KM5.js.map} +0 -0
- /package/dist/{run-KKCRBRLW.js.map → run-RGZHCQ6M.js.map} +0 -0
- /package/dist/{shell-GAB2FCXH.js.map → shell-7ADCDFIV.js.map} +0 -0
- /package/dist/{summary-P7QE3TNW.js.map → summary-7J2HORFD.js.map} +0 -0
- /package/dist/{test-6LFB5WOO.js.map → test-SRB7EWU6.js.map} +0 -0
- /package/dist/{test-git-PYJOYSED.js.map → test-git-G7ATVIXG.js.map} +0 -0
- /package/dist/{test-jira-SM7IU5HW.js.map → test-jira-Q2HPA522.js.map} +0 -0
- /package/dist/{test-prefix-HIRZBXTM.js.map → test-prefix-JMDGXR5A.js.map} +0 -0
- /package/dist/{test-webserver-43PVP2JL.js.map → test-webserver-GZFVXBGD.js.map} +0 -0
- /package/dist/{vscode-HXIXRZ3A.js.map → vscode-3I7ISHUU.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/providers/NeonProvider.ts","../src/lib/providers/SupabaseProvider.ts","../src/utils/database-helpers.ts"],"sourcesContent":["import { execa, type ExecaError } from 'execa'\nimport type { DatabaseProvider } from '../../types/index.js'\nimport { getLogger } from '../../utils/logger-context.js'\nimport { promptConfirmation } from '../../utils/prompt.js'\n\ninterface NeonBranch {\n name: string\n id: string\n [key: string]: unknown\n}\n\nexport interface NeonConfig {\n projectId: string\n parentBranch: string\n}\n\n/**\n * Validate Neon configuration\n * Checks that required configuration values are present\n */\nexport function validateNeonConfig(config: {\n projectId?: string\n parentBranch?: string\n}): { valid: boolean; error?: string } {\n if (!config.projectId) {\n return {\n valid: false,\n error: 'Neon projectId is required. Configure in .iloom/settings.json under databaseProviders.neon',\n }\n }\n\n if (!config.parentBranch) {\n return {\n valid: false,\n error: 'Neon parentBranch is required. Configure in .iloom/settings.json under databaseProviders.neon',\n }\n }\n\n // Basic validation for project ID format (should start with appropriate prefix)\n if (!/^[a-zA-Z0-9-]+$/.test(config.projectId)) {\n return {\n valid: false,\n error: 'Neon projectId contains invalid characters',\n }\n }\n\n return { valid: true }\n}\n\n/**\n * Neon database provider implementation\n * Ports functionality from bash/utils/neon-utils.sh\n */\nexport class NeonProvider implements DatabaseProvider {\n readonly displayName = 'Neon'\n readonly installHint = 'npm install -g neonctl'\n private _isConfigured: boolean = false\n\n constructor(private config: NeonConfig) {\n getLogger().debug('NeonProvider initialized with config:', {\n projectId: config.projectId,\n parentBranch: config.parentBranch,\n hasProjectId: !!config.projectId,\n hasParentBranch: !!config.parentBranch,\n })\n\n // Validate config but don't throw - just mark as not configured\n // This allows the provider to be instantiated even when Neon is not being used\n const validation = validateNeonConfig(config)\n if (!validation.valid) {\n getLogger().debug(`NeonProvider not configured: ${validation.error}`)\n getLogger().debug('Neon database branching will not be used')\n this._isConfigured = false\n } else {\n this._isConfigured = true\n }\n }\n\n /**\n * Check if provider is properly configured\n * Returns true if projectId and parentBranch are valid in settings\n */\n isConfigured(): boolean {\n return this._isConfigured\n }\n\n /**\n * Execute a Neon CLI command and return stdout\n * Throws an error if the command fails\n *\n * @param args - Command arguments to pass to neon CLI\n * @param cwd - Optional working directory to run the command from (defaults to current directory)\n */\n private async executeNeonCommand(args: string[], cwd?: string): Promise<string> {\n // Check if provider is properly configured\n if (!this._isConfigured) {\n throw new Error('NeonProvider is not configured. Check databaseProviders.neon configuration in .iloom/settings.json')\n }\n\n // Log the exact command being executed for debugging\n const command = `neon ${args.join(' ')}`\n getLogger().debug(`Executing Neon CLI command: ${command}`)\n getLogger().debug(`Project ID being used: ${this.config.projectId}`)\n if (cwd) {\n getLogger().debug(`Working directory: ${cwd}`)\n }\n\n const result = await execa('neon', args, {\n timeout: 30000,\n encoding: 'utf8',\n stdio: 'pipe',\n ...(cwd && { cwd }),\n })\n return result.stdout\n }\n\n /**\n * Check if neon CLI is available\n * Ports: check_neon_cli() from bash/utils/neon-utils.sh:18-23\n */\n async isCliAvailable(): Promise<boolean> {\n try {\n await execa('command', ['-v', 'neon'], {\n timeout: 5000,\n shell: true,\n })\n return true\n } catch {\n return false\n }\n }\n\n /**\n * Check if user is authenticated with Neon CLI\n * Ports: check_neon_auth() from bash/utils/neon-utils.sh:25-36\n *\n * @param cwd - Optional working directory to run the command from (prevents issues with deleted directories)\n * @throws Error if authentication check fails for reasons other than not being authenticated\n */\n async isAuthenticated(cwd?: string): Promise<boolean> {\n const cliAvailable = await this.isCliAvailable()\n if (!cliAvailable) {\n return false\n }\n\n try {\n await execa('neon', ['me'], {\n timeout: 10000,\n stdio: 'pipe',\n ...(cwd && { cwd }),\n })\n return true\n } catch (error) {\n const execaError = error as ExecaError\n const stderr = execaError.stderr?.trim() ?? ''\n\n // Check for authentication failure patterns (should return false, not throw)\n const isAuthError =\n stderr.toLowerCase().includes('not authenticated') ||\n stderr.toLowerCase().includes('not logged in') ||\n stderr.toLowerCase().includes('authentication required') ||\n stderr.toLowerCase().includes('login required')\n\n if (isAuthError) {\n return false\n }\n\n // For any other error, let it bubble up\n throw error\n }\n }\n\n /**\n * Sanitize branch name for Neon (replace slashes with underscores)\n * Ports: sanitize_neon_branch_name() from bash/utils/neon-utils.sh:11-15\n */\n sanitizeBranchName(branchName: string): string {\n return branchName.replace(/\\//g, '_')\n }\n\n /**\n * Extract endpoint ID from Neon connection string\n * Pattern matches: ep-abc-123 or ep-abc-123-pooler\n * Returns: ep-abc-123 (without -pooler suffix)\n * Used by: get_neon_branch_name() from bash/utils/neon-utils.sh:294\n */\n private extractEndpointId(connectionString: string): string | null {\n // First, extract the full host part between @ and first dot\n // Examples:\n // @ep-abc123.us-east-1.neon.tech -> ep-abc123\n // @ep-abc123-pooler.us-east-1.neon.tech -> ep-abc123-pooler\n const hostMatch = connectionString.match(/@(ep-[a-z0-9-]+)\\./)\n if (!hostMatch?.[1]) {\n return null\n }\n\n const fullEndpoint = hostMatch[1]\n // Remove -pooler suffix if present\n return fullEndpoint.replace(/-pooler$/, '')\n }\n\n /**\n * List all branches in the Neon project\n * Ports: list_neon_branches() from bash/utils/neon-utils.sh:63-74\n *\n * @param cwd - Optional working directory to run commands from\n */\n async listBranches(cwd?: string): Promise<string[]> {\n const output = await this.executeNeonCommand([\n 'branches',\n 'list',\n '--project-id',\n this.config.projectId,\n '--output',\n 'json',\n ], cwd)\n\n const branches: NeonBranch[] = JSON.parse(output)\n return branches.map(branch => branch.name)\n }\n\n /**\n * Check if a branch exists\n * Ports: check_neon_branch_exists() from bash/utils/neon-utils.sh:38-61\n *\n * @param name - Branch name to check\n * @param cwd - Optional working directory to run commands from\n */\n async branchExists(name: string, cwd?: string): Promise<boolean> {\n const branches = await this.listBranches(cwd)\n return branches.includes(name)\n }\n\n /**\n * Get connection string for a specific branch\n * Ports: get_neon_connection_string() from bash/utils/neon-utils.sh:76-90\n *\n * @param branch - Branch name to get connection string for\n * @param cwd - Optional working directory to run commands from\n */\n async getConnectionString(branch: string, cwd?: string): Promise<string> {\n const connectionString = await this.executeNeonCommand([\n 'connection-string',\n '--branch',\n branch,\n '--project-id',\n this.config.projectId,\n ], cwd)\n return connectionString.trim()\n }\n\n /**\n * Find Vercel preview database branch\n * Checks for both patterns: preview/<branch> and preview_<sanitized-branch>\n * Ports: find_preview_database_branch() from bash/utils/neon-utils.sh:92-124\n *\n * @param branchName - Branch name to find preview for\n * @param cwd - Optional working directory to run commands from\n */\n async findPreviewBranch(branchName: string, cwd?: string): Promise<string | null> {\n // Check for exact preview branch match with slash pattern\n const slashPattern = `preview/${branchName}`\n if (await this.branchExists(slashPattern, cwd)) {\n getLogger().info(`Found Vercel preview database: ${slashPattern}`)\n return slashPattern\n }\n\n // Check for underscore pattern variation\n const sanitized = this.sanitizeBranchName(branchName)\n const underscorePattern = `preview_${sanitized}`\n if (await this.branchExists(underscorePattern, cwd)) {\n getLogger().info(`Found Vercel preview database: ${underscorePattern}`)\n return underscorePattern\n }\n\n return null\n }\n\n /**\n * Remove expiration date from a Neon branch\n * Used when parent branches need to have child branches created\n * Neon limitation: \"Branches with an expiration date cannot have child branches\"\n *\n * @param branchName - Name of the branch to remove expiration from\n * @param cwd - Optional working directory to run commands from\n */\n private async removeExpiration(branchName: string, cwd?: string): Promise<void> {\n getLogger().info(`Removing expiration date from branch: ${branchName}`)\n await this.executeNeonCommand([\n 'branches',\n 'set-expiration',\n branchName,\n '--project-id',\n this.config.projectId,\n ], cwd)\n getLogger().success(`Expiration date removed from ${branchName}`)\n }\n\n /**\n * Create a new database branch\n * ALWAYS checks for Vercel preview database first\n * Handles Neon limitation where parent branches with expiration dates cannot have children\n * Returns connection string for the branch\n * Ports: create_neon_database_branch() from bash/utils/neon-utils.sh:126-187\n *\n * @param name - Name for the new branch\n * @param fromBranch - Parent branch to create from (defaults to config.parentBranch)\n * @param cwd - Optional working directory to run commands from\n */\n async createBranch(name: string, fromBranch?: string, cwd?: string): Promise<string> {\n // Always check for existing Vercel preview database first (lines 149-158)\n const previewBranch = await this.findPreviewBranch(name, cwd)\n if (previewBranch) {\n const connectionString = await this.getConnectionString(previewBranch, cwd)\n getLogger().success(`Using existing Vercel preview database: ${previewBranch}`)\n return connectionString\n }\n\n // Sanitize branch name for Neon (replace slashes with underscores)\n const sanitizedName = this.sanitizeBranchName(name)\n const parentBranch = fromBranch ?? this.config.parentBranch\n\n getLogger().info('Creating Neon database branch...')\n getLogger().info(` Parent branch: ${parentBranch}`)\n getLogger().info(` New branch: ${sanitizedName}`)\n\n try {\n // Create the database branch\n await this.executeNeonCommand([\n 'branches',\n 'create',\n '--name',\n sanitizedName,\n '--parent',\n parentBranch,\n '--project-id',\n this.config.projectId,\n ], cwd)\n } catch (error) {\n // Check if error is about parent branch having an expiration date\n const errorMessage = error instanceof Error ? error.message : String(error)\n if (errorMessage.toLowerCase().includes('expiration') &&\n errorMessage.toLowerCase().includes('child')) {\n getLogger().warn('Parent branch has an expiration date - removing it to allow child branch creation')\n\n // Remove expiration from parent branch\n await this.removeExpiration(parentBranch, cwd)\n\n // Retry branch creation\n getLogger().info('Retrying database branch creation...')\n await this.executeNeonCommand([\n 'branches',\n 'create',\n '--name',\n sanitizedName,\n '--parent',\n parentBranch,\n '--project-id',\n this.config.projectId,\n ], cwd)\n } else {\n // Re-throw if it's a different error\n throw error\n }\n }\n\n getLogger().success('Database branch created successfully')\n\n // Get the connection string for the new branch\n getLogger().info('Getting connection string for new database branch...')\n const connectionString = await this.getConnectionString(sanitizedName, cwd)\n\n return connectionString\n }\n\n /**\n * Delete a database branch\n * Includes preview database protection with user confirmation\n * Ports: delete_neon_database_branch() from bash/utils/neon-utils.sh:204-259\n *\n * @param name - Name of the branch to delete\n * @param isPreview - Whether this is a preview database branch\n * @param cwd - Optional working directory to run commands from (prevents issues with deleted directories)\n */\n async deleteBranch(name: string, isPreview: boolean = false, cwd?: string): Promise<import('../../types/index.js').DatabaseDeletionResult> {\n // Sanitize branch name for Neon\n const sanitizedName = this.sanitizeBranchName(name)\n\n // For preview contexts, check for preview databases first\n if (isPreview) {\n const previewBranch = await this.findPreviewBranch(name, cwd)\n if (previewBranch) {\n getLogger().warn(`Found Vercel preview database: ${previewBranch}`)\n getLogger().warn('Preview databases are managed by Vercel and will be cleaned up automatically')\n getLogger().warn('Manual deletion may interfere with Vercel\\'s preview deployments')\n\n const confirmed = await promptConfirmation(\n 'Delete preview database anyway?',\n false\n )\n\n if (confirmed) {\n // User confirmed - delete preview branch\n try {\n getLogger().info(`Deleting Vercel preview database: ${previewBranch}`)\n await this.executeNeonCommand([\n 'branches',\n 'delete',\n previewBranch,\n '--project-id',\n this.config.projectId,\n ], cwd)\n getLogger().success('Preview database deleted successfully')\n return {\n success: true,\n deleted: true,\n notFound: false,\n branchName: previewBranch\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n getLogger().error(`Failed to delete preview database: ${errorMessage}`)\n return {\n success: false,\n deleted: false,\n notFound: false,\n error: errorMessage,\n branchName: previewBranch\n }\n }\n } else {\n // User declined deletion\n getLogger().info('Skipping preview database deletion')\n return {\n success: true,\n deleted: false,\n notFound: false,\n userDeclined: true,\n branchName: previewBranch\n }\n }\n }\n // If no preview database found, fall through to check regular branch\n }\n\n // Check for regular branch\n getLogger().info(`Checking for Neon database branch: ${sanitizedName}`)\n\n try {\n const exists = await this.branchExists(sanitizedName, cwd)\n\n if (!exists) {\n getLogger().info(`No database branch found for '${name}'`)\n return {\n success: true,\n deleted: false,\n notFound: true,\n branchName: sanitizedName\n }\n }\n\n // Branch exists - delete it\n getLogger().info(`Deleting Neon database branch: ${sanitizedName}`)\n await this.executeNeonCommand([\n 'branches',\n 'delete',\n sanitizedName,\n '--project-id',\n this.config.projectId,\n ], cwd)\n getLogger().success('Database branch deleted successfully')\n\n return {\n success: true,\n deleted: true,\n notFound: false,\n branchName: sanitizedName\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n getLogger().error(`Failed to delete database branch: ${errorMessage}`)\n return {\n success: false,\n deleted: false,\n notFound: false,\n error: errorMessage,\n branchName: sanitizedName\n }\n }\n }\n\n /**\n * Get branch name from endpoint ID (reverse lookup)\n * Searches all branches to find one with matching endpoint\n * Ports: get_neon_branch_name() from bash/utils/neon-utils.sh:262-308\n *\n * @param endpointId - Endpoint ID to search for\n * @param cwd - Optional working directory to run commands from\n */\n async getBranchNameFromEndpoint(endpointId: string, cwd?: string): Promise<string | null> {\n const branches = await this.listBranches(cwd)\n\n for (const branch of branches) {\n try {\n const connectionString = await this.getConnectionString(branch, cwd)\n const branchEndpointId = this.extractEndpointId(connectionString)\n\n if (branchEndpointId === endpointId) {\n return branch\n }\n } catch {\n // Skip branches that fail to get connection string\n continue\n }\n }\n\n return null\n }\n\n /**\n * Get branch name from a connection string (reverse lookup)\n * Extracts endpoint ID from connection string and finds matching branch\n *\n * @param connectionString - Neon connection string (e.g., postgres://...@ep-abc-123.region.neon.tech/...)\n * @param cwd - Optional working directory to run commands from\n */\n async getBranchNameFromConnectionString(connectionString: string, cwd?: string): Promise<string | null> {\n const endpointId = this.extractEndpointId(connectionString)\n if (!endpointId) {\n getLogger().debug('Could not extract endpoint ID from connection string')\n return null\n }\n return this.getBranchNameFromEndpoint(endpointId, cwd)\n }\n}\n","import { execa, type ExecaError } from 'execa'\nimport type { DatabaseProvider, DatabaseDeletionResult } from '../../types/index.js'\nimport { getLogger } from '../../utils/logger-context.js'\n\nexport interface SupabaseConfig {\n projectRef: string\n parentBranch?: string\n withData?: boolean // default: true\n}\n\n/**\n * Validate Supabase configuration\n * Checks that required configuration values are present\n */\nexport function validateSupabaseConfig(config: {\n projectRef?: string\n parentBranch?: string\n}): { valid: boolean; error?: string } {\n if (!config.projectRef) {\n return {\n valid: false,\n error:\n 'Supabase projectRef is required. Configure in .iloom/settings.json under databaseProviders.supabase',\n }\n }\n\n // parentBranch is optional — Supabase currently always branches from the default branch\n\n // Basic validation for project ref format (alphanumeric and hyphens)\n if (!/^[a-zA-Z0-9-]+$/.test(config.projectRef)) {\n return {\n valid: false,\n error: 'Supabase projectRef contains invalid characters',\n }\n }\n\n return { valid: true }\n}\n\n/**\n * Supabase database provider implementation\n * Provides database branching via the Supabase CLI\n */\nexport class SupabaseProvider implements DatabaseProvider {\n private _isConfigured: boolean = false\n\n readonly displayName = 'Supabase CLI'\n readonly installHint = 'Install with: npm install -g supabase'\n\n constructor(private config: SupabaseConfig) {\n getLogger().debug('SupabaseProvider initialized with config:', {\n projectRef: config.projectRef,\n parentBranch: config.parentBranch,\n withData: config.withData,\n hasProjectRef: !!config.projectRef,\n hasParentBranch: !!config.parentBranch,\n })\n\n // Validate config but don't throw - just mark as not configured\n // This allows the provider to be instantiated even when Supabase is not being used\n const validation = validateSupabaseConfig(config)\n if (!validation.valid) {\n getLogger().debug(`SupabaseProvider not configured: ${validation.error}`)\n getLogger().debug('Supabase database branching will not be used')\n this._isConfigured = false\n } else {\n this._isConfigured = true\n }\n\n if (config.parentBranch) {\n getLogger().debug(\n `parentBranch '${config.parentBranch}' is stored but Supabase currently always branches from the default branch`\n )\n }\n }\n\n /**\n * Check if provider is properly configured\n * Returns true if projectRef and parentBranch are valid in settings\n */\n isConfigured(): boolean {\n return this._isConfigured\n }\n\n /**\n * Execute a Supabase CLI command and return stdout\n * Throws an error if the command fails\n *\n * @param args - Command arguments to pass to supabase CLI\n * @param cwd - Optional working directory to run the command from (defaults to current directory)\n */\n private async executeSupabaseCommand(args: string[], cwd?: string, timeout: number = 30000): Promise<string> {\n // Check if provider is properly configured\n if (!this._isConfigured) {\n throw new Error(\n 'SupabaseProvider is not configured. Check databaseProviders.supabase configuration in .iloom/settings.json'\n )\n }\n\n // Log the exact command being executed for debugging\n const command = `supabase ${args.join(' ')}`\n getLogger().debug(`Executing Supabase CLI command: ${command}`)\n getLogger().debug(`Project ref being used: ${this.config.projectRef}`)\n if (cwd) {\n getLogger().debug(`Working directory: ${cwd}`)\n }\n\n const result = await execa('supabase', args, {\n timeout,\n encoding: 'utf8',\n stdio: 'pipe',\n ...(cwd && { cwd }),\n })\n return result.stdout\n }\n\n /**\n * Check if supabase CLI is available\n */\n async isCliAvailable(): Promise<boolean> {\n try {\n await execa('supabase', ['--version'], {\n timeout: 5000,\n stdio: 'pipe',\n })\n return true\n } catch (error) {\n const errorCode = (error as NodeJS.ErrnoException).code\n // ENOENT means the binary was not found on the system\n // EACCES means the binary exists but has no execute permission\n if (errorCode === 'ENOENT' || errorCode === 'EACCES') {\n return false\n }\n // Any other error (e.g., non-zero exit) still means CLI is present\n return true\n }\n }\n\n /**\n * Check if user is authenticated with Supabase CLI\n *\n * @param cwd - Optional working directory to run the command from (prevents issues with deleted directories)\n * @throws Error if authentication check fails for reasons other than not being authenticated\n */\n async isAuthenticated(cwd?: string): Promise<boolean> {\n const cliAvailable = await this.isCliAvailable()\n if (!cliAvailable) {\n return false\n }\n\n try {\n await execa('supabase', ['projects', 'list'], {\n timeout: 10000,\n stdio: 'pipe',\n ...(cwd && { cwd }),\n })\n return true\n } catch (error) {\n const execaError = error as ExecaError\n const stderr = execaError.stderr?.trim() ?? ''\n\n // Check for authentication failure patterns (should return false, not throw)\n const isAuthError =\n stderr.toLowerCase().includes('not authenticated') ||\n stderr.toLowerCase().includes('not logged in') ||\n stderr.toLowerCase().includes('authentication required') ||\n stderr.toLowerCase().includes('login required') ||\n stderr.toLowerCase().includes('access token not provided') ||\n stderr.toLowerCase().includes('you need to be logged in')\n\n if (isAuthError) {\n return false\n }\n\n // For any other error, let it bubble up\n throw error\n }\n }\n\n /**\n * Sanitize branch name for Supabase (replace slashes with hyphens)\n * Supabase uses hyphens as separator (not underscores like Neon)\n */\n sanitizeBranchName(branchName: string): string {\n let sanitized = branchName\n .replace(/\\//g, '-') // replace slashes with hyphens\n .replace(/[^a-zA-Z0-9_-]/g, '') // remove chars that aren't alphanumeric, hyphens, or underscores\n .replace(/^-+/, '') // strip leading hyphens (prevents CLI flag injection)\n return sanitized || 'unnamed-branch'\n }\n\n /**\n * List all branches in the Supabase project\n *\n * @param cwd - Optional working directory to run commands from\n */\n async listBranches(cwd?: string): Promise<string[]> {\n const output = await this.executeSupabaseCommand(\n ['branches', 'list', '--project-ref', this.config.projectRef, '-o', 'json'],\n cwd\n )\n\n interface SupabaseBranch {\n name: string\n [key: string]: unknown\n }\n\n let jsonString = output\n // CLI tools can prepend warnings to stdout; strip non-JSON prefixes\n const firstBracket = output.indexOf('[')\n if (firstBracket > 0) {\n jsonString = output.slice(firstBracket)\n }\n\n let branches: SupabaseBranch[]\n try {\n branches = JSON.parse(jsonString)\n } catch (parseError) {\n throw new Error(\n `Failed to parse Supabase branch list as JSON: ${parseError instanceof Error ? parseError.message : String(parseError)}`\n )\n }\n return branches.map((branch) => branch.name)\n }\n\n /**\n * Check if a branch exists\n * Uses `supabase branches get` for a direct lookup (more efficient than listing all)\n *\n * @param name - Branch name to check\n * @param cwd - Optional working directory to run commands from\n */\n async branchExists(name: string, cwd?: string): Promise<boolean> {\n const sanitizedName = this.sanitizeBranchName(name)\n try {\n await this.executeSupabaseCommand(\n ['branches', 'get', sanitizedName, '--project-ref', this.config.projectRef],\n cwd\n )\n return true\n } catch (error) {\n const execaError = error as ExecaError\n const stderr = execaError.stderr?.toLowerCase() ?? ''\n const stdout = execaError.stdout?.toLowerCase() ?? ''\n const message = (error instanceof Error ? error.message : String(error)).toLowerCase()\n\n // Only return false for explicit \"not found\" error signatures\n // Note: Supabase CLI uses exitCode=1 for \"not found\" and exitCode=2 for auth errors\n const isNotFound =\n stderr.includes('not found') ||\n stderr.includes('does not exist') ||\n stderr.includes('no branch') ||\n stdout.includes('not found') ||\n message.includes('not found') ||\n message.includes('does not exist')\n\n if (isNotFound) {\n return false\n }\n\n // For any other error (auth, network, CLI unavailable), rethrow\n throw error\n }\n }\n\n /**\n * Get connection string for a specific branch\n * Parses POSTGRES_URL_NON_POOLING from `supabase branches get <name> -o env` output\n * Connection strings are never logged at info level or above (security)\n *\n * @param branch - Branch name to get connection string for\n * @param cwd - Optional working directory to run commands from\n */\n async getConnectionString(branch: string, cwd?: string): Promise<string> {\n const sanitizedBranch = this.sanitizeBranchName(branch)\n const output = await this.executeSupabaseCommand(\n ['branches', 'get', sanitizedBranch, '--project-ref', this.config.projectRef, '-o', 'env'],\n cwd\n )\n\n // Parse POSTGRES_URL_NON_POOLING from env output\n const match = output.match(/^POSTGRES_URL_NON_POOLING=(.+)$/m)\n if (!match?.[1]) {\n throw new Error(\n `Could not find POSTGRES_URL_NON_POOLING in branch '${branch}' environment output`\n )\n }\n\n const connectionString = match[1].trim()\n // Log only at debug level - never at info level or above (security)\n getLogger().debug(`Connection string retrieved for branch '${branch}'`)\n return connectionString\n }\n\n /**\n * Create a new database branch\n * Returns connection string for the branch\n *\n * Note: Supabase preview branches always branch from the production database.\n * The fromBranch parameter is accepted for interface compatibility but ignored.\n *\n * @param name - Name for the new branch\n * @param fromBranch - Accepted for interface compatibility but ignored (Supabase always branches from production)\n * @param cwd - Optional working directory to run commands from\n */\n async createBranch(name: string, fromBranch?: string, cwd?: string): Promise<string> {\n void fromBranch // accepted for interface compatibility but ignored - Supabase always branches from production\n\n const sanitizedName = this.sanitizeBranchName(name)\n\n getLogger().info('Creating Supabase database branch...')\n getLogger().info(` New branch: ${sanitizedName}`)\n\n const args = [\n 'branches',\n 'create',\n sanitizedName,\n '--project-ref',\n this.config.projectRef,\n ]\n\n // Add --with-data flag when withData is true (default: true per acceptance criteria)\n if (this.config.withData !== false) {\n args.push('--with-data')\n }\n\n await this.executeSupabaseCommand(args, cwd, 300000)\n\n getLogger().success('Database branch created successfully')\n\n // Get the connection string for the new branch\n getLogger().info('Getting connection string for new database branch...')\n const connectionString = await this.getConnectionString(sanitizedName, cwd)\n\n return connectionString\n }\n\n /**\n * Delete a database branch\n *\n * @param name - Name of the branch to delete\n * @param isPreview - Accepted but ignored (Neon-specific concept for Vercel preview databases)\n * @param cwd - Optional working directory to run commands from (prevents issues with deleted directories)\n */\n async deleteBranch(\n name: string,\n isPreview: boolean = false,\n cwd?: string\n ): Promise<DatabaseDeletionResult> {\n void isPreview // accepted but ignored - Neon-specific concept\n\n const sanitizedName = this.sanitizeBranchName(name)\n\n getLogger().info(`Checking for Supabase database branch: ${sanitizedName}`)\n\n try {\n const exists = await this.branchExists(sanitizedName, cwd)\n\n if (!exists) {\n getLogger().info(`No database branch found for '${name}'`)\n return {\n success: true,\n deleted: false,\n notFound: true,\n branchName: sanitizedName,\n }\n }\n\n // Branch exists - delete it\n getLogger().info(`Deleting Supabase database branch: ${sanitizedName}`)\n await this.executeSupabaseCommand(\n ['branches', 'delete', sanitizedName, '--project-ref', this.config.projectRef],\n cwd\n )\n getLogger().success('Database branch deleted successfully')\n\n return {\n success: true,\n deleted: true,\n notFound: false,\n branchName: sanitizedName,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n getLogger().error(`Failed to delete database branch: ${errorMessage}`)\n return {\n success: false,\n deleted: false,\n notFound: false,\n error: errorMessage,\n branchName: sanitizedName,\n }\n }\n }\n\n}\n","import { NeonProvider } from '../lib/providers/NeonProvider.js'\nimport { SupabaseProvider } from '../lib/providers/SupabaseProvider.js'\nimport type { IloomSettings } from '../lib/SettingsManager.js'\nimport type { DatabaseProvider } from '../types/index.js'\n\n/**\n * Create the appropriate database provider from iloom settings.\n *\n * - Returns a NeonProvider when databaseProviders.neon is configured\n * - Returns a SupabaseProvider when databaseProviders.supabase is configured\n * - Throws if both neon and supabase are configured simultaneously\n * - Returns an unconfigured NeonProvider (isConfigured() = false) when neither is configured\n */\nexport function createDatabaseProviderFromSettings(settings: IloomSettings): DatabaseProvider {\n\tconst neonConfig = settings.databaseProviders?.neon\n\tconst supabaseConfig = settings.databaseProviders?.supabase\n\n\tif (neonConfig && supabaseConfig) {\n\t\tthrow new Error(\n\t\t\t'Cannot configure both Neon and Supabase database providers simultaneously. ' +\n\t\t\t\t'Remove one from databaseProviders in .iloom/settings.json.',\n\t\t)\n\t}\n\n\tif (supabaseConfig) {\n\t\treturn new SupabaseProvider({\n\t\t\tprojectRef: supabaseConfig.projectRef,\n\t\t\t...(supabaseConfig.parentBranch && { parentBranch: supabaseConfig.parentBranch }),\n\t\t\t...(supabaseConfig.withData !== undefined && { withData: supabaseConfig.withData }),\n\t\t})\n\t}\n\n\treturn new NeonProvider({\n\t\tprojectId: neonConfig?.projectId ?? '',\n\t\tparentBranch: neonConfig?.parentBranch ?? '',\n\t})\n}\n"],"mappings":"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","names":["connectionString","execa","execa"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
extractIssueNumber
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QNPJXO53.js";
|
|
5
5
|
import {
|
|
6
6
|
extractPort,
|
|
7
7
|
findEnvFileContainingVariable,
|
|
@@ -108,4 +108,4 @@ export {
|
|
|
108
108
|
calculatePortFromIdentifier,
|
|
109
109
|
getWorkspacePort
|
|
110
110
|
};
|
|
111
|
-
//# sourceMappingURL=chunk-
|
|
111
|
+
//# sourceMappingURL=chunk-ZUIFO7B4.js.map
|
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ResourceCleanup
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-SA446KA2.js";
|
|
5
|
+
import "./chunk-3XEXT35Z.js";
|
|
6
6
|
import {
|
|
7
7
|
CLIIsolationManager,
|
|
8
8
|
DatabaseManager,
|
|
9
9
|
EnvironmentManager,
|
|
10
10
|
LoomManager
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-VVQQIG64.js";
|
|
12
|
+
import "./chunk-KQSV7FOG.js";
|
|
13
13
|
import "./chunk-7UBEHQTP.js";
|
|
14
14
|
import "./chunk-AYLC633W.js";
|
|
15
15
|
import {
|
|
16
16
|
ProcessManager
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import "./chunk-
|
|
17
|
+
} from "./chunk-H3T3EPF3.js";
|
|
18
|
+
import "./chunk-ZUIFO7B4.js";
|
|
19
19
|
import {
|
|
20
20
|
IdentifierParser
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-SN4S5CWL.js";
|
|
22
22
|
import {
|
|
23
|
-
|
|
24
|
-
} from "./chunk-
|
|
23
|
+
createDatabaseProviderFromSettings
|
|
24
|
+
} from "./chunk-YUOVWWJX.js";
|
|
25
25
|
import {
|
|
26
26
|
TelemetryService
|
|
27
27
|
} from "./chunk-MY2Q3FJ3.js";
|
|
28
|
-
import "./chunk-
|
|
28
|
+
import "./chunk-NTDY5AMO.js";
|
|
29
29
|
import "./chunk-4232AHNQ.js";
|
|
30
30
|
import "./chunk-VIQOQ463.js";
|
|
31
31
|
import {
|
|
32
32
|
GitWorktreeManager
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-4VQXMEEP.js";
|
|
34
34
|
import "./chunk-WEBMMJKL.js";
|
|
35
35
|
import "./chunk-K3QGG4O2.js";
|
|
36
36
|
import "./chunk-DMSL5BAP.js";
|
|
@@ -44,10 +44,10 @@ import "./chunk-P5MXXHXQ.js";
|
|
|
44
44
|
import "./chunk-BZ7KTXPB.js";
|
|
45
45
|
import "./chunk-OIVFHJOA.js";
|
|
46
46
|
import "./chunk-DDHWZNGL.js";
|
|
47
|
-
import "./chunk-
|
|
47
|
+
import "./chunk-QNPJXO53.js";
|
|
48
48
|
import {
|
|
49
49
|
SettingsManager
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-WGUGB54H.js";
|
|
51
51
|
import {
|
|
52
52
|
MetadataManager
|
|
53
53
|
} from "./chunk-4JZEQBWV.js";
|
|
@@ -97,8 +97,8 @@ var CleanupCommand = class {
|
|
|
97
97
|
const settings = await settingsManager.loadSettings();
|
|
98
98
|
const databaseUrlEnvVarName = ((_b = (_a = settings.capabilities) == null ? void 0 : _a.database) == null ? void 0 : _b.databaseUrlEnvVarName) ?? "DATABASE_URL";
|
|
99
99
|
const environmentManager = new EnvironmentManager();
|
|
100
|
-
const
|
|
101
|
-
const databaseManager = new DatabaseManager(
|
|
100
|
+
const databaseProvider = createDatabaseProviderFromSettings(settings);
|
|
101
|
+
const databaseManager = new DatabaseManager(databaseProvider, environmentManager, databaseUrlEnvVarName);
|
|
102
102
|
const cliIsolationManager = new CLIIsolationManager();
|
|
103
103
|
this.resourceCleanup ??= new ResourceCleanup(
|
|
104
104
|
this.gitWorktreeManager,
|
|
@@ -107,8 +107,8 @@ var CleanupCommand = class {
|
|
|
107
107
|
cliIsolationManager
|
|
108
108
|
);
|
|
109
109
|
if (!this.loomManager) {
|
|
110
|
-
const { IssueTrackerFactory } = await import("./IssueTrackerFactory-
|
|
111
|
-
const { ClaudeContextManager } = await import("./ClaudeContextManager-
|
|
110
|
+
const { IssueTrackerFactory } = await import("./IssueTrackerFactory-KE2BDCLC.js");
|
|
111
|
+
const { ClaudeContextManager } = await import("./ClaudeContextManager-RRGREEZQ.js");
|
|
112
112
|
const { ProjectCapabilityDetector } = await import("./ProjectCapabilityDetector-I4J66WKF.js");
|
|
113
113
|
const { DefaultBranchNamingService } = await import("./BranchNamingService-MEK2WZUD.js");
|
|
114
114
|
this.loomManager = new LoomManager(
|
|
@@ -314,7 +314,7 @@ var CleanupCommand = class {
|
|
|
314
314
|
const { force, dryRun } = parsed.options;
|
|
315
315
|
let parsedInput = await this.identifierParser.parseForPatternDetection(identifier);
|
|
316
316
|
if (parsedInput.type === "branch" && parsedInput.branchName) {
|
|
317
|
-
const { extractIssueNumber } = await import("./git-
|
|
317
|
+
const { extractIssueNumber } = await import("./git-TX2IEMB3.js");
|
|
318
318
|
const extractedNumber = extractIssueNumber(parsedInput.branchName);
|
|
319
319
|
if (extractedNumber !== null) {
|
|
320
320
|
parsedInput = {
|
|
@@ -544,4 +544,4 @@ var CleanupCommand = class {
|
|
|
544
544
|
export {
|
|
545
545
|
CleanupCommand
|
|
546
546
|
};
|
|
547
|
-
//# sourceMappingURL=cleanup-
|
|
547
|
+
//# sourceMappingURL=cleanup-RJKLI47I.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/cleanup.ts"],"sourcesContent":["import { getLogger } from '../utils/logger-context.js'\nimport { GitWorktreeManager } from '../lib/GitWorktreeManager.js'\nimport { ResourceCleanup } from '../lib/ResourceCleanup.js'\nimport { ProcessManager } from '../lib/process/ProcessManager.js'\nimport { DatabaseManager } from '../lib/DatabaseManager.js'\nimport { EnvironmentManager } from '../lib/EnvironmentManager.js'\nimport { CLIIsolationManager } from '../lib/CLIIsolationManager.js'\nimport { SettingsManager } from '../lib/SettingsManager.js'\nimport { promptConfirmation } from '../utils/prompt.js'\nimport { IdentifierParser } from '../utils/IdentifierParser.js'\nimport { loadEnvIntoProcess } from '../utils/env.js'\nimport { createDatabaseProviderFromSettings } from '../utils/database-helpers.js'\nimport { LoomManager } from '../lib/LoomManager.js'\nimport { TelemetryService } from '../lib/TelemetryService.js'\nimport { MetadataManager } from '../lib/MetadataManager.js'\nimport type { LoomMetadata } from '../lib/MetadataManager.js'\n\nfunction trackLoomAbandoned(metadata: LoomMetadata): void {\n\ttry {\n\t\tconst durationMinutes = metadata.created_at\n\t\t\t? Math.round((Date.now() - new Date(metadata.created_at).getTime()) / 60000)\n\t\t\t: 0\n\t\tTelemetryService.getInstance().track('loom.abandoned', {\n\t\t\tduration_minutes: isNaN(durationMinutes) ? 0 : durationMinutes,\n\t\t\tphase_reached: metadata.state ?? 'unknown',\n\t\t})\n\t} catch (error: unknown) {\n\t\tgetLogger().debug(`Failed to track loom.abandoned telemetry: ${error instanceof Error ? error.message : String(error)}`)\n\t}\n}\nimport type { CleanupOptions } from '../types/index.js'\nimport type { CleanupResult } from '../types/cleanup.js'\nimport type { ParsedInput } from './start.js'\n\n/**\n * Input structure for CleanupCommand.execute()\n */\nexport interface CleanupCommandInput {\n identifier?: string\n options: CleanupOptions\n}\n\n/**\n * Parsed and validated cleanup command input\n * Mode determines which cleanup operation to perform\n */\nexport interface ParsedCleanupInput {\n mode: 'list' | 'single' | 'issue' | 'all'\n identifier?: string\n issueNumber?: string | number\n branchName?: string\n originalInput?: string\n options: CleanupOptions\n}\n\n/**\n * Manages cleanup command execution with option parsing and validation\n * Follows the command pattern established by StartCommand\n *\n * This implementation handles ONLY parsing, validation, and mode determination.\n * Actual cleanup operations are deferred to subsequent sub-issues.\n */\nexport class CleanupCommand {\n private readonly gitWorktreeManager: GitWorktreeManager\n private resourceCleanup?: ResourceCleanup\n private loomManager?: import('../lib/LoomManager.js').LoomManager\n private readonly identifierParser: IdentifierParser\n\n constructor(\n gitWorktreeManager?: GitWorktreeManager,\n resourceCleanup?: ResourceCleanup\n ) {\n // Load environment variables first\n const envResult = loadEnvIntoProcess()\n if (envResult.error) {\n getLogger().debug(`Environment loading warning: ${envResult.error.message}`)\n }\n if (envResult.parsed) {\n getLogger().debug(`Loaded ${Object.keys(envResult.parsed).length} environment variables`)\n }\n\n this.gitWorktreeManager = gitWorktreeManager ?? new GitWorktreeManager()\n\n // Initialize ResourceCleanup with DatabaseManager and CLIIsolationManager\n // ResourceCleanup will be initialized lazily with proper configuration\n if (resourceCleanup) {\n this.resourceCleanup = resourceCleanup\n }\n\n // Initialize IdentifierParser for pattern-based detection\n this.identifierParser = new IdentifierParser(this.gitWorktreeManager)\n }\n\n /**\n * Lazy initialization of ResourceCleanup and LoomManager with properly configured DatabaseManager\n */\n private async ensureResourceCleanup(): Promise<void> {\n if (this.resourceCleanup && this.loomManager) {\n return\n }\n\n const settingsManager = new SettingsManager()\n const settings = await settingsManager.loadSettings()\n const databaseUrlEnvVarName = settings.capabilities?.database?.databaseUrlEnvVarName ?? 'DATABASE_URL'\n\n const environmentManager = new EnvironmentManager()\n const databaseProvider = createDatabaseProviderFromSettings(settings)\n const databaseManager = new DatabaseManager(databaseProvider, environmentManager, databaseUrlEnvVarName)\n const cliIsolationManager = new CLIIsolationManager()\n\n this.resourceCleanup ??= new ResourceCleanup(\n this.gitWorktreeManager,\n new ProcessManager(),\n databaseManager,\n cliIsolationManager\n )\n\n // Initialize LoomManager if not provided (for child loom detection)\n if (!this.loomManager) {\n const { IssueTrackerFactory } = await import('../lib/IssueTrackerFactory.js')\n const { ClaudeContextManager } = await import('../lib/ClaudeContextManager.js')\n const { ProjectCapabilityDetector } = await import('../lib/ProjectCapabilityDetector.js')\n const { DefaultBranchNamingService } = await import('../lib/BranchNamingService.js')\n\n this.loomManager = new LoomManager(\n this.gitWorktreeManager,\n IssueTrackerFactory.create(settings),\n new DefaultBranchNamingService({ useClaude: true }),\n environmentManager,\n new ClaudeContextManager(),\n new ProjectCapabilityDetector(),\n cliIsolationManager,\n settingsManager,\n databaseManager\n )\n }\n }\n\n /**\n * Check for child looms and exit gracefully if any exist\n * Always checks the TARGET loom (the one being cleaned up), not the current directory's loom\n *\n * @param parsed - The parsed input identifying the loom being cleaned up\n */\n private async checkForChildLooms(parsed: ParsedCleanupInput): Promise<void> {\n await this.ensureResourceCleanup()\n if (!this.loomManager) {\n throw new Error('Failed to initialize LoomManager')\n }\n\n // Determine which branch is being cleaned up based on parsed input\n let targetBranch: string | undefined\n\n if (parsed.branchName) {\n targetBranch = parsed.branchName\n } else if (parsed.mode === 'issue' && parsed.issueNumber !== undefined) {\n // For issues, try to find the worktree by issue number to get the branch name\n const worktree = await this.gitWorktreeManager.findWorktreeForIssue(parsed.issueNumber)\n targetBranch = worktree?.branch\n }\n\n // If we can't determine the target branch, skip the check\n if (!targetBranch) {\n getLogger().debug(`Cannot determine target branch for child loom check`)\n return\n }\n\n // Check if the TARGET loom has any child looms\n const hasChildLooms = await this.loomManager.checkAndWarnChildLooms(targetBranch)\n if (hasChildLooms) {\n throw new Error('Cannot cleanup loom while child looms exist. Please \\'finish\\' or \\'cleanup\\' child looms first.')\n }\n }\n\n /**\n * Main entry point for the cleanup command\n * Parses input, validates options, and determines operation mode\n */\n public async execute(input: CleanupCommandInput): Promise<CleanupResult | void> {\n // Step 1: Parse input and determine mode\n const parsed = this.parseInput(input)\n\n // Step 2: Validate option combinations (fail fast before any delay)\n this.validateInput(parsed)\n\n // Note: JSON mode auto-skips routine confirmations (programmatic use can't interact)\n // Safety checks still require --force to bypass (ResourceCleanup.validateWorktreeSafety throws errors)\n\n // Step 3: Check for child looms AFTER parsing input\n // This ensures we only block when cleaning the CURRENT loom (parent), not a child\n await this.checkForChildLooms(parsed)\n\n // Step 4: Handle deferred execution (after all validation passes)\n if (input.options.defer) {\n getLogger().info(`Waiting ${input.options.defer}ms before cleanup...`)\n await new Promise(resolve => globalThis.setTimeout(resolve, input.options.defer))\n }\n\n // Step 5: Execute based on mode\n getLogger().info(`Cleanup mode: ${parsed.mode}`)\n\n if (parsed.mode === 'single') {\n return await this.executeSingleCleanup(parsed)\n } else if (parsed.mode === 'list') {\n getLogger().info('Would list all worktrees') // TODO: Implement in Sub-issue #2\n getLogger().success('Command parsing and validation successful')\n return {\n identifier: 'list',\n success: true,\n dryRun: parsed.options.dryRun ?? false,\n operations: [],\n errors: [],\n rollbackRequired: false,\n }\n } else if (parsed.mode === 'all') {\n getLogger().info('Would remove all worktrees') // TODO: Implement in Sub-issue #5\n getLogger().success('Command parsing and validation successful')\n return {\n identifier: 'all',\n success: true,\n dryRun: parsed.options.dryRun ?? false,\n operations: [],\n errors: [],\n rollbackRequired: false,\n }\n } else if (parsed.mode === 'issue') {\n return await this.executeIssueCleanup(parsed)\n }\n }\n\n /**\n * Parse input to determine cleanup mode and extract relevant data\n * Implements auto-detection: numeric input = issue number, non-numeric = branch name\n *\n * @private\n */\n private parseInput(input: CleanupCommandInput): ParsedCleanupInput {\n const { identifier, options } = input\n\n // Trim identifier if present\n const trimmedIdentifier = identifier?.trim() ?? undefined\n\n // Mode: List (takes priority - it's informational only)\n if (options.list) {\n const result: ParsedCleanupInput = {\n mode: 'list',\n options\n }\n if (trimmedIdentifier) {\n result.identifier = trimmedIdentifier\n }\n return result\n }\n\n // Mode: All (remove everything)\n if (options.all) {\n const result: ParsedCleanupInput = {\n mode: 'all',\n options\n }\n if (trimmedIdentifier) {\n result.identifier = trimmedIdentifier\n }\n if (options.issue !== undefined) {\n result.issueNumber = options.issue\n }\n return result\n }\n\n // Mode: Explicit issue number via --issue flag\n if (options.issue !== undefined) {\n // Need to determine if identifier is branch or numeric to set branchName\n if (trimmedIdentifier) {\n const numericPattern = /^[0-9]+$/\n if (!numericPattern.test(trimmedIdentifier)) {\n // Identifier is a branch name with explicit --issue flag\n return {\n mode: 'issue',\n issueNumber: options.issue,\n branchName: trimmedIdentifier,\n identifier: trimmedIdentifier,\n originalInput: trimmedIdentifier,\n options\n }\n }\n }\n const result: ParsedCleanupInput = {\n mode: 'issue',\n issueNumber: options.issue,\n options\n }\n if (trimmedIdentifier) {\n result.identifier = trimmedIdentifier\n }\n return result\n }\n\n // Mode: Auto-detect from identifier\n if (!trimmedIdentifier) {\n throw new Error('Missing required argument: identifier. Use --all to remove all worktrees or --list to list them.')\n }\n\n // Auto-detection: Check if identifier is purely numeric\n // Pattern from bash script line 364: ^[0-9]+$\n const numericPattern = /^[0-9]+$/\n if (numericPattern.test(trimmedIdentifier)) {\n // Numeric input = issue number\n return {\n mode: 'issue',\n issueNumber: parseInt(trimmedIdentifier, 10),\n identifier: trimmedIdentifier,\n originalInput: trimmedIdentifier,\n options\n }\n } else {\n // Non-numeric = branch name\n return {\n mode: 'single',\n branchName: trimmedIdentifier,\n identifier: trimmedIdentifier,\n originalInput: trimmedIdentifier,\n options\n }\n }\n }\n\n /**\n * Validate parsed input for option conflicts\n * Throws descriptive errors for invalid option combinations\n *\n * @private\n */\n private validateInput(parsed: ParsedCleanupInput): void {\n const { mode, options, branchName } = parsed\n\n // Conflict: --list is informational only, incompatible with destructive operations\n if (mode === 'list') {\n if (options.all) {\n throw new Error('Cannot use --list with --all (list is informational only)')\n }\n if (options.issue !== undefined) {\n throw new Error('Cannot use --list with --issue (list is informational only)')\n }\n if (parsed.identifier) {\n throw new Error('Cannot use --list with a specific identifier (list shows all worktrees)')\n }\n }\n\n // Conflict: --all removes everything, can't combine with specific identifier or --issue\n if (mode === 'all') {\n if (parsed.identifier) {\n throw new Error('Cannot use --all with a specific identifier. Use one or the other.')\n }\n if (parsed.issueNumber !== undefined) {\n throw new Error('Cannot use --all with a specific identifier. Use one or the other.')\n }\n }\n\n // Conflict: explicit --issue flag with branch name identifier\n // (This prevents confusion when user provides both)\n if (options.issue !== undefined && branchName) {\n throw new Error('Cannot use --issue flag with branch name identifier. Use numeric identifier or --issue flag alone.')\n }\n\n // Note: --force and --dry-run are compatible with all modes (no conflicts)\n }\n\n /**\n * Execute cleanup for single worktree\n * Implements two-stage confirmation: worktree removal, then branch deletion\n * Uses IdentifierParser for pattern-based detection without GitHub API calls\n */\n private async executeSingleCleanup(parsed: ParsedCleanupInput): Promise<CleanupResult> {\n const identifier = parsed.branchName ?? parsed.identifier ?? ''\n if (!identifier) {\n throw new Error('No identifier found for cleanup')\n }\n const { force, dryRun } = parsed.options\n\n // Step 1: Parse identifier using pattern-based detection\n let parsedInput: ParsedInput = await this.identifierParser.parseForPatternDetection(identifier)\n\n // If type is 'branch', try to extract issue number for CLI symlink cleanup\n if (parsedInput.type === 'branch' && parsedInput.branchName) {\n const { extractIssueNumber } = await import('../utils/git.js')\n const extractedNumber = extractIssueNumber(parsedInput.branchName)\n if (extractedNumber !== null) {\n parsedInput = {\n ...parsedInput,\n number: extractedNumber // Add number for CLI symlink cleanup\n }\n }\n }\n\n // Step 2: Display worktree details\n getLogger().info(`Preparing to cleanup worktree: ${identifier}`)\n\n // Step 3: Routine confirmation - worktree removal\n // Skip if --force (user explicitly bypasses) or --json (programmatic use can't interact)\n // Note: Safety checks (uncommitted changes, unmerged work) still require --force to bypass\n if (!force && !parsed.options.json) {\n const confirmWorktree = await promptConfirmation('Remove this worktree?', true)\n if (!confirmWorktree) {\n getLogger().info('Cleanup cancelled')\n return {\n identifier,\n success: false,\n dryRun: dryRun ?? false,\n operations: [],\n errors: [],\n rollbackRequired: false,\n }\n }\n }\n\n // Step 3.5: Read metadata BEFORE cleanup (cleanup deletes the worktree)\n let preCleanupMetadata: LoomMetadata | null = null\n try {\n // Find worktree path for metadata lookup\n const worktree = parsedInput.type === 'branch' && parsedInput.branchName\n ? await this.gitWorktreeManager.findWorktreeForBranch(parsedInput.branchName)\n : parsedInput.number !== undefined\n ? await this.gitWorktreeManager.findWorktreeForIssue(parsedInput.number)\n : null\n if (worktree) {\n const metadataManager = new MetadataManager()\n preCleanupMetadata = await metadataManager.readMetadata(worktree.path)\n }\n } catch (error: unknown) {\n getLogger().debug(`Failed to read metadata for telemetry: ${error instanceof Error ? error.message : String(error)}`)\n }\n\n // Step 4: Execute worktree cleanup (includes safety validation)\n // Issue #275 fix: Run 5-point safety check BEFORE any deletion\n // This prevents the scenario where worktree is deleted but branch deletion fails\n await this.ensureResourceCleanup()\n if (!this.resourceCleanup) {\n throw new Error('Failed to initialize ResourceCleanup')\n }\n const cleanupResult = await this.resourceCleanup.cleanupWorktree(parsedInput, {\n dryRun: dryRun ?? false,\n force: force ?? false,\n deleteBranch: true, // Always include branch deletion (safety checks run first)\n keepDatabase: false,\n checkMergeSafety: true, // Run 5-point safety check BEFORE any deletion\n archive: parsed.options.archive ?? false,\n })\n\n // Add dryRun flag to result\n cleanupResult.dryRun = dryRun ?? false\n\n // Step 5: Report cleanup results\n this.reportCleanupResults(cleanupResult)\n\n // Track loom.abandoned telemetry event (only for unfinished looms)\n if (cleanupResult.success && preCleanupMetadata && preCleanupMetadata.status !== 'finished') {\n trackLoomAbandoned(preCleanupMetadata)\n }\n\n // Final success message\n if (cleanupResult.success) {\n getLogger().success('Cleanup completed successfully')\n } else {\n getLogger().warn('Cleanup completed with errors - see details above')\n }\n\n return cleanupResult\n }\n\n /**\n * Report cleanup operation results to user\n */\n private reportCleanupResults(result: CleanupResult): void {\n getLogger().info('Cleanup operations:')\n\n result.operations.forEach(op => {\n const status = op.success ? '✓' : '✗'\n const message = op.error ? `${op.message}: ${op.error}` : op.message\n\n if (op.success) {\n getLogger().info(` ${status} ${message}`)\n } else {\n getLogger().error(` ${status} ${message}`)\n }\n })\n\n if (result.errors.length > 0) {\n getLogger().warn(`${result.errors.length} error(s) occurred during cleanup`)\n }\n }\n\n /**\n * Execute cleanup for all worktrees associated with an issue or PR number\n * Searches for worktrees by their path patterns (e.g., issue-25, pr-25, 25-feature, _pr_25)\n * Implements bash cleanup-worktree.sh remove_worktrees_by_issue() (lines 157-242)\n */\n private async executeIssueCleanup(parsed: ParsedCleanupInput): Promise<CleanupResult> {\n const issueNumber = parsed.issueNumber\n if (issueNumber === undefined) {\n throw new Error('No issue/PR number provided for cleanup')\n }\n\n const { force, dryRun } = parsed.options\n\n getLogger().info(`Finding worktrees related to issue/PR #${issueNumber}...`)\n\n // Step 1: Get all worktrees and filter by path pattern\n const worktrees = await this.gitWorktreeManager.listWorktrees()\n const matchingWorktrees = worktrees.filter(wt => {\n const path = wt.path.toLowerCase()\n // Lowercase for case-insensitive matching (Linear IDs are uppercase like MARK-1)\n const idStr = String(issueNumber).toLowerCase()\n\n // Check if path contains the identifier with proper word boundaries\n // Matches: issue-25, pr-25, 25-feature, _pr_25, issue-mark-1, etc.\n // Uses word boundary or common separators (-, _, /) for alphanumeric IDs\n const pattern = new RegExp(`(?:^|[/_-])${idStr}(?:[/_-]|$)`)\n return pattern.test(path)\n })\n\n if (matchingWorktrees.length === 0) {\n getLogger().warn(`No worktrees found for issue/PR #${issueNumber}`)\n getLogger().info(`Searched for worktree paths containing: ${issueNumber}, _pr_${issueNumber}, issue-${issueNumber}, etc.`)\n return {\n identifier: String(issueNumber),\n success: true,\n dryRun: dryRun ?? false,\n operations: [],\n errors: [],\n rollbackRequired: false,\n }\n }\n\n // Step 2: Build targets list from matching worktrees\n const targets: Array<{ branchName: string; hasWorktree: boolean; worktreePath?: string }> =\n matchingWorktrees.map(wt => ({\n branchName: wt.branch,\n hasWorktree: true,\n worktreePath: wt.path\n }))\n\n // Step 3: Display preview\n getLogger().info(`Found ${targets.length} worktree(s) related to issue/PR #${issueNumber}:`)\n for (const target of targets) {\n getLogger().info(` Branch: ${target.branchName} (${target.worktreePath})`)\n }\n\n // Step 4: Routine batch confirmation\n // Skip if --force (user explicitly bypasses) or --json (programmatic use can't interact)\n // Note: Safety checks per-worktree (uncommitted changes, unmerged work) still require --force to bypass\n if (!force && !parsed.options.json) {\n const confirmCleanup = await promptConfirmation(\n `Remove ${targets.length} worktree(s)?`,\n true\n )\n if (!confirmCleanup) {\n getLogger().info('Cleanup cancelled')\n return {\n identifier: String(issueNumber),\n success: false,\n dryRun: dryRun ?? false,\n operations: [],\n errors: [],\n rollbackRequired: false,\n }\n }\n }\n\n // Step 5: Process each target sequentially\n let worktreesRemoved = 0\n let branchesDeleted = 0\n const databaseBranchesDeletedList: string[] = []\n let failed = 0\n\n for (const target of targets) {\n getLogger().info(`Processing worktree: ${target.branchName}`)\n\n // Cleanup worktree using ResourceCleanup with ParsedInput\n // Now includes branch deletion with 5-point safety check BEFORE any deletion\n try {\n // Read metadata BEFORE cleanup for telemetry\n let targetMetadata: LoomMetadata | null = null\n if (target.worktreePath) {\n try {\n const metadataManager = new MetadataManager()\n targetMetadata = await metadataManager.readMetadata(target.worktreePath)\n } catch (error: unknown) {\n getLogger().debug(`Failed to read metadata for telemetry: ${error instanceof Error ? error.message : String(error)}`)\n }\n }\n\n // Use the known issue number directly instead of parsing from branch name\n // This ensures CLI symlinks (created with issue number) are properly cleaned up\n const parsedInput: ParsedInput = {\n type: 'issue',\n number: issueNumber, // Use the known issue number, not parsed from branch\n branchName: target.branchName,\n originalInput: String(issueNumber)\n }\n\n await this.ensureResourceCleanup()\n if (!this.resourceCleanup) {\n throw new Error('Failed to initialize ResourceCleanup')\n }\n // Issue #275 fix: Run safety checks BEFORE deleting worktree\n // This prevents the scenario where worktree is deleted but branch deletion fails\n const result = await this.resourceCleanup.cleanupWorktree(parsedInput, {\n dryRun: dryRun ?? false,\n force: force ?? false,\n deleteBranch: true, // Include branch deletion (with safety checks)\n keepDatabase: false,\n checkMergeSafety: true, // Run 5-point safety check BEFORE any deletion\n archive: parsed.options.archive ?? false,\n ...(target.worktreePath && { worktree: { path: target.worktreePath, branch: target.branchName } }),\n })\n\n if (result.success) {\n worktreesRemoved++\n getLogger().success(` Worktree removed: ${target.branchName}`)\n\n // Check if branch was deleted\n const branchOperation = result.operations.find(op => op.type === 'branch')\n if (branchOperation?.success) {\n branchesDeleted++\n getLogger().success(` Branch deleted: ${target.branchName}`)\n }\n\n // Check if database branch was actually deleted (use explicit deleted field)\n const dbOperation = result.operations.find(op => op.type === 'database')\n if (dbOperation?.deleted) {\n // Get branch name from result or use the target branch name\n const deletedBranchName = target.branchName\n databaseBranchesDeletedList.push(deletedBranchName)\n }\n\n // Track loom.abandoned telemetry (only for unfinished looms)\n if (targetMetadata && targetMetadata.status !== 'finished') {\n trackLoomAbandoned(targetMetadata)\n }\n } else {\n failed++\n getLogger().error(` Failed to remove worktree: ${target.branchName}`)\n for (const err of result.errors) {\n getLogger().error(` ${err.message}`)\n }\n }\n } catch (error) {\n failed++\n const errMsg = error instanceof Error ? error.message : 'Unknown error'\n getLogger().error(` Failed to cleanup: ${errMsg}`)\n continue // Continue with next worktree even if this one failed\n }\n }\n\n // Step 7: Report statistics\n getLogger().success(`Completed cleanup for issue/PR #${issueNumber}:`)\n getLogger().info(` Worktrees removed: ${worktreesRemoved}`)\n getLogger().info(` Branches deleted: ${branchesDeleted}`)\n if (databaseBranchesDeletedList.length > 0) {\n // Display branch names in the format requested\n getLogger().info(` Database branches deleted: ${databaseBranchesDeletedList.join(', ')}`)\n }\n if (failed > 0) {\n getLogger().warn(` Failed operations: ${failed}`)\n }\n\n // Return aggregated result\n return {\n identifier: String(issueNumber),\n success: failed === 0,\n dryRun: dryRun ?? false,\n operations: [\n { type: 'worktree' as const, success: true, message: `Removed ${worktreesRemoved} worktree(s)` },\n { type: 'branch' as const, success: true, message: `Deleted ${branchesDeleted} branch(es)` },\n ...(databaseBranchesDeletedList.length > 0 ? [{ type: 'database' as const, success: true, message: `Deleted ${databaseBranchesDeletedList.length} database branch(es)`, deleted: true }] : []),\n ],\n errors: [],\n rollbackRequired: false,\n }\n }\n}\n"],"mappings":"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","names":["numericPattern"]}
|