@iloom/cli 0.5.3 → 0.5.5
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 +41 -0
- package/dist/{ClaudeContextManager-PQ46VILL.js → ClaudeContextManager-7WX7DUNI.js} +4 -4
- package/dist/{ClaudeService-6OMO552H.js → ClaudeService-LQLN2GP4.js} +3 -3
- package/dist/{LoomLauncher-ZHDTPKED.js → LoomLauncher-5QU42LOM.js} +4 -4
- package/dist/README.md +41 -0
- package/dist/{SettingsManager-CNYBGXDT.js → SettingsManager-35F5RUJH.js} +2 -2
- package/dist/{chunk-Z5BM4JWB.js → chunk-46JVEGUW.js} +65 -9
- package/dist/chunk-46JVEGUW.js.map +1 -0
- package/dist/{chunk-66BMJ25W.js → chunk-6YSFTPKW.js} +8 -192
- package/dist/chunk-6YSFTPKW.js.map +1 -0
- package/dist/{chunk-HMMO2LDS.js → chunk-EK3XCAAS.js} +2 -2
- package/dist/{chunk-IDUICCZY.js → chunk-F6WVM437.js} +3 -1
- package/dist/chunk-F6WVM437.js.map +1 -0
- package/dist/{chunk-FXJKNVZW.js → chunk-FO2H3YXI.js} +2 -2
- package/dist/{chunk-53OMUNUN.js → chunk-GEXP5IOF.js} +9 -4
- package/dist/chunk-GEXP5IOF.js.map +1 -0
- package/dist/chunk-NKRQNER7.js +197 -0
- package/dist/chunk-NKRQNER7.js.map +1 -0
- package/dist/{chunk-J7GHNTYK.js → chunk-SJIMVKK7.js} +2 -2
- package/dist/{chunk-YU5HVI6B.js → chunk-UQIXZ3BA.js} +2 -2
- package/dist/{chunk-QPS6TZUW.js → chunk-VXMY22TP.js} +2 -2
- package/dist/{chunk-XNNXAAZT.js → chunk-WIJWIKAN.js} +3 -3
- package/dist/{chunk-VV66DH6T.js → chunk-WZHBRKLN.js} +26 -7
- package/dist/chunk-WZHBRKLN.js.map +1 -0
- package/dist/{cleanup-Y5W3CNUV.js → cleanup-WTZZ74VS.js} +8 -8
- package/dist/cli.js +39 -39
- package/dist/cli.js.map +1 -1
- package/dist/{contribute-SMIPMWCH.js → contribute-T7ENST5N.js} +3 -3
- package/dist/{dev-server-HNBRWGCD.js → dev-server-S5QG5SBZ.js} +5 -5
- package/dist/{feedback-567ZH2O7.js → feedback-PDMCKYOT.js} +2 -2
- package/dist/{git-OV6ADVO7.js → git-FVMGBHC2.js} +3 -3
- package/dist/{ignite-3HB3ZBEW.js → ignite-YF4Q5RA7.js} +8 -6
- package/dist/{ignite-3HB3ZBEW.js.map → ignite-YF4Q5RA7.js.map} +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/{init-CMIRHFSR.js → init-XQQGC6DN.js} +6 -5
- package/dist/{open-AXE225Z5.js → open-AIZG5756.js} +5 -5
- package/dist/{projects-GVEMCN5R.js → projects-SA76I4TZ.js} +14 -7
- package/dist/projects-SA76I4TZ.js.map +1 -0
- package/dist/prompts/init-prompt.txt +8 -0
- package/dist/prompts/issue-prompt.txt +12 -6
- package/dist/{rebase-6UIHMUWS.js → rebase-5EY3Q6XP.js} +5 -5
- package/dist/{recap-XTBNMEMO.js → recap-VOOUXOGP.js} +5 -5
- package/dist/{run-H375EYRB.js → run-CMZUYZVG.js} +5 -5
- package/dist/schema/settings.schema.json +8 -0
- package/dist/{shell-33FJCWJQ.js → shell-SBLXVOVJ.js} +5 -5
- package/dist/{summary-JUMOCNLR.js → summary-5YXUGPRN.js} +5 -5
- package/dist/{test-git-CO3BA4BV.js → test-git-ZB6AGGRW.js} +3 -3
- package/dist/{test-prefix-HZYSDQYT.js → test-prefix-FBGXKMPA.js} +3 -3
- package/package.json +2 -1
- package/dist/chunk-53OMUNUN.js.map +0 -1
- package/dist/chunk-66BMJ25W.js.map +0 -1
- package/dist/chunk-IDUICCZY.js.map +0 -1
- package/dist/chunk-VV66DH6T.js.map +0 -1
- package/dist/chunk-Z5BM4JWB.js.map +0 -1
- package/dist/projects-GVEMCN5R.js.map +0 -1
- /package/dist/{ClaudeContextManager-PQ46VILL.js.map → ClaudeContextManager-7WX7DUNI.js.map} +0 -0
- /package/dist/{ClaudeService-6OMO552H.js.map → ClaudeService-LQLN2GP4.js.map} +0 -0
- /package/dist/{LoomLauncher-ZHDTPKED.js.map → LoomLauncher-5QU42LOM.js.map} +0 -0
- /package/dist/{SettingsManager-CNYBGXDT.js.map → SettingsManager-35F5RUJH.js.map} +0 -0
- /package/dist/{chunk-HMMO2LDS.js.map → chunk-EK3XCAAS.js.map} +0 -0
- /package/dist/{chunk-FXJKNVZW.js.map → chunk-FO2H3YXI.js.map} +0 -0
- /package/dist/{chunk-J7GHNTYK.js.map → chunk-SJIMVKK7.js.map} +0 -0
- /package/dist/{chunk-YU5HVI6B.js.map → chunk-UQIXZ3BA.js.map} +0 -0
- /package/dist/{chunk-QPS6TZUW.js.map → chunk-VXMY22TP.js.map} +0 -0
- /package/dist/{chunk-XNNXAAZT.js.map → chunk-WIJWIKAN.js.map} +0 -0
- /package/dist/{cleanup-Y5W3CNUV.js.map → cleanup-WTZZ74VS.js.map} +0 -0
- /package/dist/{contribute-SMIPMWCH.js.map → contribute-T7ENST5N.js.map} +0 -0
- /package/dist/{dev-server-HNBRWGCD.js.map → dev-server-S5QG5SBZ.js.map} +0 -0
- /package/dist/{feedback-567ZH2O7.js.map → feedback-PDMCKYOT.js.map} +0 -0
- /package/dist/{git-OV6ADVO7.js.map → git-FVMGBHC2.js.map} +0 -0
- /package/dist/{init-CMIRHFSR.js.map → init-XQQGC6DN.js.map} +0 -0
- /package/dist/{open-AXE225Z5.js.map → open-AIZG5756.js.map} +0 -0
- /package/dist/{rebase-6UIHMUWS.js.map → rebase-5EY3Q6XP.js.map} +0 -0
- /package/dist/{recap-XTBNMEMO.js.map → recap-VOOUXOGP.js.map} +0 -0
- /package/dist/{run-H375EYRB.js.map → run-CMZUYZVG.js.map} +0 -0
- /package/dist/{shell-33FJCWJQ.js.map → shell-SBLXVOVJ.js.map} +0 -0
- /package/dist/{summary-JUMOCNLR.js.map → summary-5YXUGPRN.js.map} +0 -0
- /package/dist/{test-git-CO3BA4BV.js.map → test-git-ZB6AGGRW.js.map} +0 -0
- /package/dist/{test-prefix-HZYSDQYT.js.map → test-prefix-FBGXKMPA.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/LinearService.ts","../src/lib/IssueTrackerFactory.ts","../src/utils/FirstRunManager.ts","../src/utils/mcp.ts"],"sourcesContent":["/**\n * LinearService - IssueTracker implementation for Linear\n * Implements issue tracking operations using the @linear/sdk\n */\n\nimport type { Issue, PullRequest, IssueTrackerInputDetection } from '../types/index.js'\nimport type { LinearIssue } from '../types/linear.js'\nimport { LinearServiceError } from '../types/linear.js'\nimport {\n fetchLinearIssue,\n createLinearIssue,\n updateLinearIssueState,\n} from '../utils/linear.js'\nimport { promptConfirmation } from '../utils/prompt.js'\nimport type { IssueTracker } from './IssueTracker.js'\nimport { logger } from '../utils/logger.js'\n\n/**\n * Linear service configuration options\n */\nexport interface LinearServiceConfig {\n /** Linear team key (e.g., \"ENG\", \"PLAT\") */\n teamId?: string\n /** Branch naming template (e.g., \"feat/{{key}}__{{title}}\") */\n branchFormat?: string\n /** Linear API token (lin_api_...). If provided, sets process.env.LINEAR_API_TOKEN */\n apiToken?: string\n}\n\n/**\n * Linear implementation of IssueTracker interface\n */\nexport class LinearService implements IssueTracker {\n // IssueTracker interface implementation\n readonly providerName = 'linear'\n readonly supportsPullRequests = false // Linear doesn't have pull requests\n\n private config: LinearServiceConfig\n private prompter: (message: string) => Promise<boolean>\n\n constructor(\n config?: LinearServiceConfig,\n options?: { prompter?: (message: string) => Promise<boolean> },\n ) {\n this.config = config ?? {}\n this.prompter = options?.prompter ?? promptConfirmation\n\n // Set API token from config if provided (follows mcp.ts pattern)\n if (this.config.apiToken) {\n process.env.LINEAR_API_TOKEN = this.config.apiToken\n }\n }\n\n /**\n * Detect if input matches Linear identifier format (TEAM-NUMBER)\n * @param input - User input string\n * @param _repo - Repository (unused for Linear)\n * @returns Detection result with type and identifier\n */\n public async detectInputType(\n input: string,\n _repo?: string,\n ): Promise<IssueTrackerInputDetection> {\n logger.debug(`LinearService.detectInputType called with input: \"${input}\"`)\n\n // Pattern: TEAM-NUMBER (e.g., ENG-123, PLAT-456)\n // Requires at least 2 letters before dash to avoid conflict with PR-123 format\n const linearPattern = /^([A-Z]{2,}-\\d+)$/i\n const match = input.match(linearPattern)\n\n if (!match?.[1]) {\n logger.debug(`LinearService: Input \"${input}\" does not match Linear pattern`)\n return { type: 'unknown', identifier: null, rawInput: input }\n }\n\n const identifier = match[1].toUpperCase()\n logger.debug(`LinearService: Matched Linear identifier: ${identifier}`)\n\n // Validate the issue exists in Linear\n logger.debug(`LinearService: Checking if ${identifier} is a valid Linear issue via SDK`)\n const issue = await this.isValidIssue(identifier)\n\n if (issue) {\n logger.debug(`LinearService: Issue ${identifier} found: \"${issue.title}\"`)\n return { type: 'issue', identifier, rawInput: input }\n }\n\n // Not found\n logger.debug(`LinearService: Issue ${identifier} NOT found by SDK`)\n return { type: 'unknown', identifier: null, rawInput: input }\n }\n\n /**\n * Fetch a Linear issue by identifier\n * @param identifier - Linear issue identifier (string or number)\n * @param _repo - Repository (unused for Linear)\n * @returns Generic Issue type\n * @throws LinearServiceError if issue not found\n */\n public async fetchIssue(identifier: string | number, _repo?: string): Promise<Issue> {\n const linearIssue = await fetchLinearIssue(String(identifier))\n return this.mapLinearIssueToIssue(linearIssue)\n }\n\n /**\n * Check if an issue identifier is valid (silent validation)\n * @param identifier - Linear issue identifier\n * @param _repo - Repository (unused for Linear)\n * @returns Issue if valid, false if not found\n */\n public async isValidIssue(identifier: string | number, _repo?: string): Promise<Issue | false> {\n try {\n return await this.fetchIssue(identifier)\n } catch (error) {\n // Return false for NOT_FOUND errors (expected during detection)\n if (error instanceof LinearServiceError && error.code === 'NOT_FOUND') {\n return false\n }\n // Re-throw unexpected errors\n throw error\n }\n }\n\n /**\n * Validate issue state and prompt user if closed\n * @param issue - Issue to validate\n * @throws LinearServiceError if user cancels due to closed issue\n */\n public async validateIssueState(issue: Issue): Promise<void> {\n if (issue.state === 'closed') {\n const shouldContinue = await this.prompter(\n `Issue ${issue.number} is closed. Continue anyway?`,\n )\n\n if (!shouldContinue) {\n throw new LinearServiceError('INVALID_STATE', 'User cancelled due to closed issue')\n }\n }\n }\n\n /**\n * Create a new Linear issue\n * @param title - Issue title\n * @param body - Issue description (markdown)\n * @param _repository - Repository (unused for Linear)\n * @param labels - Optional label names\n * @returns Created issue identifier and URL\n * @throws LinearServiceError if teamId not configured or creation fails\n */\n public async createIssue(\n title: string,\n body: string,\n _repository?: string,\n labels?: string[],\n ): Promise<{ number: string | number; url: string }> {\n // Require teamId configuration\n if (!this.config.teamId) {\n throw new LinearServiceError(\n 'INVALID_STATE',\n 'Linear teamId not configured. Run `il init` to configure Linear settings.',\n )\n }\n\n logger.info(`Creating Linear issue in team ${this.config.teamId}: ${title}`)\n\n const result = await createLinearIssue(title, body, this.config.teamId, labels)\n\n return {\n number: result.identifier,\n url: result.url,\n }\n }\n\n /**\n * Get the web URL for a Linear issue\n * @param identifier - Linear issue identifier\n * @param _repo - Repository (unused for Linear)\n * @returns Issue URL\n */\n public async getIssueUrl(identifier: string | number, _repo?: string): Promise<string> {\n const issue = await this.fetchIssue(identifier)\n return issue.url\n }\n\n /**\n * Move a Linear issue to \"In Progress\" state\n * @param identifier - Linear issue identifier\n * @throws LinearServiceError if state update fails\n */\n public async moveIssueToInProgress(identifier: string | number): Promise<void> {\n logger.info(`Moving Linear issue ${identifier} to In Progress`)\n await updateLinearIssueState(String(identifier), 'In Progress')\n }\n\n /**\n * Extract issue context for AI prompts\n * @param entity - Issue (Linear doesn't have PRs)\n * @returns Formatted context string\n */\n public extractContext(entity: Issue | PullRequest): string {\n // Linear doesn't have PRs, always an issue\n const issue = entity as Issue\n return `Linear Issue ${issue.number}: ${issue.title}\\nState: ${issue.state}\\n\\n${issue.body}`\n }\n\n /**\n * Map Linear API issue to generic Issue type\n * @param linear - Linear issue from SDK\n * @returns Generic Issue type\n */\n private mapLinearIssueToIssue(linear: LinearIssue): Issue {\n return {\n number: linear.identifier, // Keep as string (e.g., \"ENG-123\")\n title: linear.title,\n body: linear.description ?? '',\n state: linear.state ? (linear.state.toLowerCase().includes('done') || linear.state.toLowerCase().includes('completed') || linear.state.toLowerCase().includes('canceled') ? 'closed' : 'open') : 'open',\n labels: [],\n assignees: [],\n url: linear.url,\n }\n }\n}\n","// IssueTrackerFactory - creates appropriate IssueTracker based on settings\n// Follows pattern from database provider instantiation\n\nimport type { IssueTracker } from './IssueTracker.js'\nimport { GitHubService } from './GitHubService.js'\nimport { LinearService, type LinearServiceConfig } from './LinearService.js'\nimport type { IloomSettings } from './SettingsManager.js'\nimport { getLogger } from '../utils/logger-context.js'\n\nexport type IssueTrackerProviderType = 'github' | 'linear'\n\n/**\n * Factory for creating IssueTracker instances based on settings\n * Provides a single point of provider instantiation\n *\n * Usage:\n * const tracker = IssueTrackerFactory.create(settings, { useClaude: true })\n * const issue = await tracker.fetchIssue(123)\n */\nexport class IssueTrackerFactory {\n\t/**\n\t * Create an IssueTracker instance based on settings configuration\n\t * Defaults to GitHub if no provider specified\n\t *\n\t * @param settings - iloom settings containing issueManagement.provider\n\t * @returns IssueTracker instance configured for the specified provider\n\t * @throws Error if provider type is not supported\n\t */\n\tstatic create(settings: IloomSettings): IssueTracker {\n\t\tconst provider = settings.issueManagement?.provider ?? 'github'\n\n\t\tgetLogger().debug(`IssueTrackerFactory: Creating tracker for provider \"${provider}\"`)\n\t\tgetLogger().debug(`IssueTrackerFactory: issueManagement settings:`, JSON.stringify(settings.issueManagement, null, 2))\n\n\t\tswitch (provider) {\n\t\t\tcase 'github':\n\t\t\t\tgetLogger().debug('IssueTrackerFactory: Creating GitHubService')\n\t\t\t\treturn new GitHubService()\n\t\t\tcase 'linear': {\n\t\t\t\tconst linearSettings = settings.issueManagement?.linear\n\t\t\t\tconst linearConfig: LinearServiceConfig = {}\n\n\t\t\t\tif (linearSettings?.teamId) {\n\t\t\t\t\tlinearConfig.teamId = linearSettings.teamId\n\t\t\t\t}\n\t\t\t\tif (linearSettings?.branchFormat) {\n\t\t\t\t\tlinearConfig.branchFormat = linearSettings.branchFormat\n\t\t\t\t}\n\t\t\t\tif (linearSettings?.apiToken) {\n\t\t\t\t\tlinearConfig.apiToken = linearSettings.apiToken\n\t\t\t\t}\n\n\t\t\t\tgetLogger().debug(`IssueTrackerFactory: Creating LinearService with config:`, JSON.stringify(linearConfig, null, 2))\n\t\t\t\treturn new LinearService(linearConfig)\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unsupported issue tracker provider: ${provider}`)\n\t\t}\n\t}\n\n\t/**\n\t * Get the configured provider name from settings\n\t * Defaults to 'github' if not configured\n\t *\n\t * @param settings - iloom settings\n\t * @returns Provider type string\n\t */\n\tstatic getProviderName(settings: IloomSettings): IssueTrackerProviderType {\n\t\treturn (settings.issueManagement?.provider ?? 'github') as IssueTrackerProviderType\n\t}\n}\n","import os from 'os'\nimport path from 'path'\nimport fs from 'fs-extra'\nimport { logger } from './logger.js'\n\n/**\n * FirstRunManager: Detect and track first-time spin usage via marker file\n *\n * Follows the same pattern as UpdateNotifier for file-based state tracking\n * in ~/.config/iloom-ai/ directory.\n *\n * Also supports project-level tracking for config wizard completion using\n * individual marker files per project in ~/.config/iloom-ai/projects/\n */\nexport class FirstRunManager {\n\tprivate markerFilePath: string\n\tprivate configDir: string\n\n\tconstructor(feature: string = 'spin') {\n\t\tthis.configDir = path.join(os.homedir(), '.config', 'iloom-ai')\n\t\tthis.markerFilePath = path.join(this.configDir, `${feature}-first-run`)\n\t\tlogger.debug('FirstRunManager initialized', {\n\t\t\tfeature,\n\t\t\tmarkerFilePath: this.markerFilePath\n\t\t})\n\t}\n\n\t/**\n\t * Get the directory for project marker files\n\t */\n\tprivate getProjectsDir(): string {\n\t\treturn path.join(this.configDir, 'projects')\n\t}\n\n\t/**\n\t * Resolve symlinks in project path to get canonical path\n\t * Falls back to original path on errors (broken symlinks, permissions, etc.)\n\t */\n\tprivate async resolveProjectPath(projectPath: string): Promise<string> {\n\t\ttry {\n\t\t\treturn await fs.realpath(projectPath)\n\t\t} catch {\n\t\t\tlogger.debug('resolveProjectPath: Failed to resolve symlink, using original path', { projectPath })\n\t\t\treturn projectPath\n\t\t}\n\t}\n\n\t/**\n\t * Convert a project path to a readable filename\n\t * /Users/adam/Projects/my-app -> Users__adam__Projects__my-app\n\t */\n\tprivate projectPathToFileName(projectPath: string): string {\n\t\tconst normalized = path.normalize(projectPath)\n\t\treturn normalized.replace(/^[/\\\\]+/, '').replace(/[/\\\\]+/g, '__')\n\t}\n\n\t/**\n\t * Get full path to a project's marker file\n\t */\n\tprivate getProjectMarkerPath(projectPath: string): string {\n\t\treturn path.join(this.getProjectsDir(), this.projectPathToFileName(projectPath))\n\t}\n\n\t/**\n\t * Extract project name from path\n\t */\n\tprivate getProjectName(projectPath: string): string {\n\t\treturn path.basename(projectPath)\n\t}\n\n\t/**\n\t * Check if a project has been configured\n\t * Returns true if project marker file exists\n\t */\n\tasync isProjectConfigured(projectPath?: string): Promise<boolean> {\n\t\tconst inputPath = projectPath ?? process.cwd()\n\t\tconst resolvedPath = await this.resolveProjectPath(inputPath)\n\t\tconst markerPath = this.getProjectMarkerPath(resolvedPath)\n\t\tlogger.debug('isProjectConfigured: Checking for marker file', { markerPath })\n\t\ttry {\n\t\t\tconst exists = await fs.pathExists(markerPath)\n\t\t\tlogger.debug(`isProjectConfigured: Marker file exists=${exists}`)\n\t\t\treturn exists\n\t\t} catch (error) {\n\t\t\t// On error, treat as not configured to allow wizard to run\n\t\t\tlogger.debug(`isProjectConfigured: Error checking marker file, treating as not configured: ${error}`)\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Check if a project has local .iloom settings files\n\t * Returns true if .iloom/settings.json or .iloom/settings.local.json exists with content\n\t */\n\tprivate async hasLocalSettings(projectPath: string): Promise<boolean> {\n\t\tconst iloomDir = path.join(projectPath, '.iloom')\n\t\tconst settingsPath = path.join(iloomDir, 'settings.json')\n\t\tconst settingsLocalPath = path.join(iloomDir, 'settings.local.json')\n\n\t\tconst hasSettings = await this.hasNonEmptySettingsFile(settingsPath)\n\t\tconst hasLocalSettings = await this.hasNonEmptySettingsFile(settingsLocalPath)\n\n\t\treturn hasSettings || hasLocalSettings\n\t}\n\n\t/**\n\t * Check if a settings file exists and has non-empty content\n\t */\n\tprivate async hasNonEmptySettingsFile(filePath: string): Promise<boolean> {\n\t\ttry {\n\t\t\tconst exists = await fs.pathExists(filePath)\n\t\t\tif (!exists) return false\n\t\t\tconst content = await fs.readFile(filePath, 'utf8')\n\t\t\tconst parsed = JSON.parse(content)\n\t\t\treturn Object.keys(parsed).length > 0\n\t\t} catch {\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Fixup legacy projects that have local config but lack the global marker file\n\t * This handles projects configured before global project tracking was implemented\n\t *\n\t * Returns object with:\n\t * - isConfigured: true if project is configured (either already had marker or fixup created one)\n\t * - wasFixedUp: true if fixup was performed (marker was created by this call)\n\t *\n\t * This combined return avoids duplicate isProjectConfigured() calls in needsFirstRunSetup()\n\t */\n\tasync fixupLegacyProject(projectPath?: string): Promise<{ isConfigured: boolean; wasFixedUp: boolean }> {\n\t\tconst inputPath = projectPath ?? process.cwd()\n\t\tconst resolvedPath = await this.resolveProjectPath(inputPath)\n\t\tlogger.debug('fixupLegacyProject: Checking for legacy project', { projectPath: resolvedPath })\n\n\t\t// Check if already has global marker - no fixup needed, but project IS configured\n\t\tconst hasMarker = await this.isProjectConfigured(resolvedPath)\n\t\tif (hasMarker) {\n\t\t\tlogger.debug('fixupLegacyProject: Project already has global marker')\n\t\t\treturn { isConfigured: true, wasFixedUp: false }\n\t\t}\n\n\t\t// Check if has local settings files - this indicates a legacy configured project\n\t\tconst hasLocal = await this.hasLocalSettings(resolvedPath)\n\t\tif (!hasLocal) {\n\t\t\tlogger.debug('fixupLegacyProject: No local settings found, not a legacy project')\n\t\t\treturn { isConfigured: false, wasFixedUp: false }\n\t\t}\n\n\t\t// Legacy project found - create the missing global marker\n\t\tlogger.debug('fixupLegacyProject: Legacy project detected, creating global marker')\n\t\tawait this.markProjectAsConfigured(resolvedPath)\n\t\treturn { isConfigured: true, wasFixedUp: true }\n\t}\n\n\t/**\n\t * Mark a project as configured\n\t * Creates a marker file with project metadata\n\t */\n\tasync markProjectAsConfigured(projectPath?: string): Promise<void> {\n\t\tconst inputPath = projectPath ?? process.cwd()\n\t\tconst resolvedPath = await this.resolveProjectPath(inputPath)\n\t\tconst markerPath = this.getProjectMarkerPath(resolvedPath)\n\t\tlogger.debug('markProjectAsConfigured: Creating marker file', { markerPath })\n\t\ttry {\n\t\t\tawait fs.ensureDir(this.getProjectsDir())\n\t\t\tconst markerContent = {\n\t\t\t\tconfiguredAt: new Date().toISOString(),\n\t\t\t\tprojectPath: resolvedPath,\n\t\t\t\tprojectName: this.getProjectName(resolvedPath)\n\t\t\t}\n\t\t\tawait fs.writeFile(markerPath, JSON.stringify(markerContent, null, 2), 'utf8')\n\t\t\tlogger.debug('markProjectAsConfigured: Marker file created successfully')\n\t\t} catch (error) {\n\t\t\t// Don't throw on errors - just log debug message\n\t\t\tlogger.debug(`markProjectAsConfigured: Failed to create marker file: ${error}`)\n\t\t}\n\t}\n\n\t/**\n\t * Check if this is the first run of the feature\n\t * Returns true if marker file doesn't exist\n\t * Handles errors gracefully by returning true (treat as first-run on error)\n\t */\n\tasync isFirstRun(): Promise<boolean> {\n\t\tlogger.debug('isFirstRun: Checking for marker file', { markerFilePath: this.markerFilePath })\n\t\ttry {\n\t\t\tconst exists = await fs.pathExists(this.markerFilePath)\n\t\t\tlogger.debug(`isFirstRun: Marker file exists=${exists}`)\n\t\t\treturn !exists\n\t\t} catch (error) {\n\t\t\t// On error, gracefully degrade by treating as first-run\n\t\t\tlogger.debug(`isFirstRun: Error checking marker file, treating as first-run: ${error}`)\n\t\t\treturn true\n\t\t}\n\t}\n\n\t/**\n\t * Mark the feature as having been run\n\t * Creates the marker file in config directory\n\t * Handles errors gracefully without throwing\n\t */\n\tasync markAsRun(): Promise<void> {\n\t\tlogger.debug('markAsRun: Attempting to create marker file', { markerFilePath: this.markerFilePath })\n\t\ttry {\n\t\t\t// Ensure directory exists\n\t\t\tconst configDir = path.dirname(this.markerFilePath)\n\t\t\tlogger.debug(`markAsRun: Ensuring config directory exists: ${configDir}`)\n\t\t\tawait fs.ensureDir(configDir)\n\n\t\t\t// Write marker file with timestamp for debugging\n\t\t\tconst markerContent = {\n\t\t\t\tfirstRun: new Date().toISOString(),\n\t\t\t}\n\t\t\tawait fs.writeFile(this.markerFilePath, JSON.stringify(markerContent, null, 2), 'utf8')\n\t\t\tlogger.debug('markAsRun: Marker file created successfully')\n\t\t} catch (error) {\n\t\t\t// Don't throw on errors - just log debug message\n\t\t\t// Failing to write marker shouldn't break the workflow\n\t\t\tlogger.debug(`markAsRun: Failed to create marker file: ${error}`)\n\t\t}\n\t}\n}\n","import path from 'path'\nimport os from 'os'\nimport { getRepoInfo } from './github.js'\nimport { logger } from './logger.js'\nimport type { IloomSettings } from '../lib/SettingsManager.js'\nimport type { LoomMetadata } from '../lib/MetadataManager.js'\n\n/**\n * Generate MCP configuration for issue management\n * Uses a single server that can handle both issues and pull requests\n * Returns array of MCP server config objects\n * @param contextType - Optional context type (issue or pr)\n * @param repo - Optional repo in \"owner/repo\" format. If not provided, will auto-detect from git.\n * @param provider - Issue management provider (default: 'github')\n * @param settings - Optional settings to extract Linear API token from\n * @param draftPrNumber - Optional draft PR number for github-draft-pr mode (routes comments to PR)\n */\nexport async function generateIssueManagementMcpConfig(\n\tcontextType?: 'issue' | 'pr',\n\trepo?: string,\n\tprovider: 'github' | 'linear' = 'github',\n\tsettings?: IloomSettings,\n\tdraftPrNumber?: number\n): Promise<Record<string, unknown>[]> {\n\t// When draftPrNumber is provided (github-draft-pr mode), force contextType to 'pr'\n\t// This ensures agents route comments to the draft PR instead of the issue\n\tconst effectiveContextType = draftPrNumber ? 'pr' : contextType\n\n\t// Build provider-specific environment variables\n\tlet envVars: Record<string, string> = {\n\t\tISSUE_PROVIDER: provider,\n\t}\n\n\t// Add draft PR number to env vars if provided\n\tif (draftPrNumber) {\n\t\tenvVars.DRAFT_PR_NUMBER = String(draftPrNumber)\n\t}\n\n\tif (provider === 'github') {\n\t\t// Get repository information for GitHub - either from provided repo string or auto-detect\n\t\tlet owner: string\n\t\tlet name: string\n\n\t\tif (repo) {\n\t\t\tconst parts = repo.split('/')\n\t\t\tif (parts.length !== 2 || !parts[0] || !parts[1]) {\n\t\t\t\tthrow new Error(`Invalid repo format: ${repo}. Expected \"owner/repo\"`)\n\t\t\t}\n\t\t\towner = parts[0]\n\t\t\tname = parts[1]\n\t\t} else {\n\t\t\tconst repoInfo = await getRepoInfo()\n\t\t\towner = repoInfo.owner\n\t\t\tname = repoInfo.name\n\t\t}\n\n\t\t// Map logical types to GitHub's webhook event names (handle GitHub's naming quirk here)\n\t\t// Use effectiveContextType which may be overridden by draftPrNumber\n\t\tconst githubEventName = effectiveContextType === 'issue' ? 'issues' : effectiveContextType === 'pr' ? 'pull_request' : undefined\n\n\t\tenvVars = {\n\t\t\t...envVars,\n\t\t\tREPO_OWNER: owner,\n\t\t\tREPO_NAME: name,\n\t\t\tGITHUB_API_URL: 'https://api.github.com/',\n\t\t\t...(githubEventName && { GITHUB_EVENT_NAME: githubEventName }),\n\t\t}\n\n\t\tlogger.debug('Generated MCP config for GitHub issue management', {\n\t\t\tprovider,\n\t\t\trepoOwner: owner,\n\t\t\trepoName: name,\n\t\t\tcontextType: effectiveContextType ?? 'auto-detect',\n\t\t\tgithubEventName: githubEventName ?? 'auto-detect',\n\t\t\tdraftPrNumber: draftPrNumber ?? undefined,\n\t\t})\n\t} else {\n\t\t// Linear needs API token passed through\n\t\tconst apiToken = settings?.issueManagement?.linear?.apiToken ?? process.env.LINEAR_API_TOKEN\n\n\t\tif (apiToken) {\n\t\t\tenvVars.LINEAR_API_TOKEN = apiToken\n\t\t}\n\n\t\tlogger.debug('Generated MCP config for Linear issue management', {\n\t\t\tprovider,\n\t\t\thasApiToken: !!apiToken,\n\t\t\tcontextType: contextType ?? 'auto-detect',\n\t\t})\n\t}\n\n\t// Generate single MCP server config\n\tconst mcpServerConfig = {\n\t\tmcpServers: {\n\t\t\tissue_management: {\n\t\t\t\ttransport: 'stdio',\n\t\t\t\tcommand: 'node',\n\t\t\t\targs: [path.join(path.dirname(new globalThis.URL(import.meta.url).pathname), '../dist/mcp/issue-management-server.js')],\n\t\t\t\tenv: envVars,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn [mcpServerConfig]\n}\n\n/**\n * Reuse MetadataManager.slugifyPath() algorithm for recap file naming\n *\n * Algorithm:\n * 1. Trim trailing slashes\n * 2. Replace all path separators (/ or \\) with ___ (triple underscore)\n * 3. Replace any other non-alphanumeric characters (except _ and -) with -\n * 4. Append .json\n */\nfunction slugifyPath(loomPath: string): string {\n\tlet slug = loomPath.replace(/[/\\\\]+$/, '')\n\tslug = slug.replace(/[/\\\\]/g, '___')\n\tslug = slug.replace(/[^a-zA-Z0-9_-]/g, '-')\n\treturn `${slug}.json`\n}\n\n/**\n * Generate MCP configuration for recap server\n *\n * The recap server captures session context (goal, decisions, insights, risks, assumptions)\n * for the VS Code Loom Context Panel.\n *\n * @param loomPath - Absolute path to the loom workspace\n * @param loomMetadata - The loom metadata object (will be stringified as JSON)\n */\nexport function generateRecapMcpConfig(\n\tloomPath: string,\n\tloomMetadata: LoomMetadata\n): Record<string, unknown>[] {\n\t// Compute recap file path using slugifyPath algorithm (same as MetadataManager)\n\tconst recapsDir = path.join(os.homedir(), '.config', 'iloom-ai', 'recaps')\n\tconst recapFilePath = path.join(recapsDir, slugifyPath(loomPath))\n\n\t// Pass both env vars:\n\t// - RECAP_FILE_PATH: where to read/write recap data\n\t// - LOOM_METADATA_JSON: stringified loom metadata (parsed by MCP using LoomMetadata type)\n\tconst envVars = {\n\t\tRECAP_FILE_PATH: recapFilePath,\n\t\tLOOM_METADATA_JSON: JSON.stringify(loomMetadata),\n\t}\n\n\tlogger.debug('Generated MCP config for recap server', {\n\t\tloomPath,\n\t\trecapFilePath,\n\t\tloomMetadataDescription: loomMetadata.description,\n\t})\n\n\treturn [\n\t\t{\n\t\t\tmcpServers: {\n\t\t\t\trecap: {\n\t\t\t\t\ttransport: 'stdio',\n\t\t\t\t\tcommand: 'node',\n\t\t\t\t\targs: [\n\t\t\t\t\t\tpath.join(\n\t\t\t\t\t\t\tpath.dirname(new globalThis.URL(import.meta.url).pathname),\n\t\t\t\t\t\t\t'../dist/mcp/recap-server.js'\n\t\t\t\t\t\t),\n\t\t\t\t\t],\n\t\t\t\t\tenv: envVars,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t]\n}"],"mappings":"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","names":["path","os","path","os"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/SettingsManager.ts"],"sourcesContent":["import { readFile } from 'fs/promises'\nimport path from 'path'\nimport os from 'os'\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 spin agent settings with default model\n * Used for the spin orchestrator configuration\n */\nexport const SpinAgentSettingsSchema = z.object({\n\tmodel: z\n\t\t.enum(['sonnet', 'opus', 'haiku'])\n\t\t.default('opus')\n\t\t.describe('Claude model shorthand for spin orchestrator'),\n})\n\n/**\n * Zod schema for summary settings with default model\n * Used for session summary generation configuration\n */\nexport const SummarySettingsSchema = z.object({\n\tmodel: z\n\t\t.enum(['sonnet', 'opus', 'haiku'])\n\t\t.default('sonnet')\n\t\t.describe('Claude model shorthand for session summary generation'),\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 Code 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\tgenerateSummary: z\n\t\t.boolean()\n\t\t.default(true)\n\t\t.describe('Generate and post Claude session summary when finishing this workflow type'),\n})\n\n/**\n * Non-defaulting variant for pre-merge validation\n * This prevents Zod from polluting partial settings with default values before merge\n */\nexport const WorkflowPermissionSchemaNoDefaults = 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.optional()\n\t\t.describe('Launch IDE (code) when starting this workflow type'),\n\tstartDevServer: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe('Launch development server when starting this workflow type'),\n\tstartAiAgent: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe('Launch Claude Code agent when starting this workflow type'),\n\tstartTerminal: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe('Launch terminal window without dev server when starting this workflow type'),\n\tgenerateSummary: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe('Generate and post Claude session summary when finishing 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 * Non-defaulting variant for pre-merge validation\n */\nexport const WorkflowsSettingsSchemaNoDefaults = z\n\t.object({\n\t\tissue: WorkflowPermissionSchemaNoDefaults.optional(),\n\t\tpr: WorkflowPermissionSchemaNoDefaults.optional(),\n\t\tregular: WorkflowPermissionSchemaNoDefaults.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 * Non-defaulting variant for pre-merge validation\n */\nexport const CapabilitiesSettingsSchemaNoDefaults = 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.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 Neon database provider settings\n */\nexport const NeonSettingsSchema = z.object({\n\tprojectId: z\n\t\t.string()\n\t\t.min(1)\n\t\t.regex(/^[a-zA-Z0-9-]+$/, 'Neon project ID must contain only letters, numbers, and hyphens')\n\t\t.describe('Neon project ID found in your project URL (e.g., \"fantastic-fox-3566354\")'),\n\tparentBranch: z\n\t\t.string()\n\t\t.min(1)\n\t\t.describe('Branch from which new database branches are created'),\n})\n\n/**\n * Zod schema for database provider settings\n */\nexport const DatabaseProvidersSettingsSchema = z\n\t.object({\n\t\tneon: NeonSettingsSchema.optional().describe(\n\t\t\t'Neon database configuration. Requires Neon CLI installed and authenticated for database branching.',\n\t\t),\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\tsourceEnvOnStart: z\n\t\t.boolean()\n\t\t.default(false)\n\t\t.describe(\n\t\t\t'Source all dotenv-flow files (.env, .env.local, .env.development, .env.development.local) when launching terminal processes (Claude, dev server, terminal). ' +\n\t\t\t\t'Files are sourced in precedence order so later files override earlier ones. ' +\n\t\t\t\t'NOTE TO AI AGENTS: Before making changes to settings files, YOU MUST OFFER to check .env file compatibility. ' +\n\t\t\t\t'WARNING: Unquoted values in .env files may break sourcing in bash/zsh shells. ' +\n\t\t\t\t'Before enabling, verify ALL your .env.* files do not contain unquoted special characters ' +\n\t\t\t\t'(e.g., database URLs with ?, &, or other shell metacharacters). ' +\n\t\t\t\t'Shell compatibility issues may cause processes to fail or behave unexpectedly.',\n\t\t),\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(\n\t\t\t'Per-agent configuration overrides. Available agents: ' +\n\t\t\t\t'iloom-issue-analyzer (analyzes issues), ' +\n\t\t\t\t'iloom-issue-planner (creates implementation plans), ' +\n\t\t\t\t'iloom-issue-analyze-and-plan (combined analysis and planning), ' +\n\t\t\t\t'iloom-issue-complexity-evaluator (evaluates complexity), ' +\n\t\t\t\t'iloom-issue-enhancer (enhances issue descriptions), ' +\n\t\t\t\t'iloom-issue-implementer (implements code changes), ' +\n\t\t\t\t'iloom-issue-reviewer (reviews code changes against requirements)',\n\t\t),\n\tspin: SpinAgentSettingsSchema.optional().describe(\n\t\t'Spin orchestrator configuration. Model defaults to opus when not configured.',\n\t),\n\tsummary: SummarySettingsSchema.optional().describe(\n\t\t'Session summary generation configuration. Model defaults to sonnet when not configured.',\n\t),\n\tcapabilities: CapabilitiesSettingsSchema.describe('Project capability configurations'),\n\tdatabaseProviders: DatabaseProvidersSettingsSchema.describe('Database provider configurations'),\n\tissueManagement: z\n\t\t.object({\n\t\t\tprovider: z.enum(['github', 'linear']).optional().default('github').describe('Issue tracker provider (github, linear)'),\n\t\t\tgithub: z\n\t\t\t\t.object({\n\t\t\t\t\tremote: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1, 'Remote name cannot be empty')\n\t\t\t\t\t\t.describe('Git remote name to use for GitHub operations'),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\tlinear: z\n\t\t\t\t.object({\n\t\t\t\t\tteamId: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1, 'Team ID cannot be empty')\n\t\t\t\t\t\t.describe('Linear team identifier (e.g., \"ENG\", \"PLAT\")'),\n\t\t\t\t\tbranchFormat: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Branch naming template for Linear issues'),\n\t\t\t\t\tapiToken: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Linear API token (lin_api_...). SECURITY: Store in settings.local.json only, never commit to source control.'),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t})\n\t\t.optional()\n\t\t.describe('Issue management configuration'),\n\tmergeBehavior: z\n\t\t.object({\n\t\t\tmode: z.enum(['local', 'github-pr', 'github-draft-pr']).default('local'),\n\t\t\tremote: z.string().optional(),\n\t\t})\n\t\t.optional()\n\t\t.describe('Merge behavior configuration: local (merge locally), github-pr (create PR), or github-draft-pr (create draft PR at start, mark ready on finish)'),\n\tide: z\n\t\t.object({\n\t\t\ttype: z\n\t\t\t\t.enum(['vscode', 'cursor', 'webstorm', 'sublime', 'intellij', 'windsurf', 'antigravity'])\n\t\t\t\t.default('vscode')\n\t\t\t\t.describe(\n\t\t\t\t\t'IDE to launch when starting a loom. Options: vscode (Visual Studio Code), cursor (Cursor AI editor), ' +\n\t\t\t\t\t\t'webstorm (JetBrains WebStorm), sublime (Sublime Text), intellij (JetBrains IntelliJ IDEA), ' +\n\t\t\t\t\t\t'windsurf (Windsurf editor), antigravity (Antigravity IDE).'\n\t\t\t\t),\n\t\t})\n\t\t.optional()\n\t\t.describe(\n\t\t\t'IDE configuration for workspace launches. Controls which editor opens when you start a loom. ' +\n\t\t\t\t'Supports VSCode, Cursor, WebStorm, Sublime Text, IntelliJ, Windsurf, and Antigravity. ' +\n\t\t\t\t'Note: Color synchronization (title bar colors) only works with VSCode-compatible editors (vscode, cursor, windsurf, antigravity).'\n\t\t),\n\tcolors: z\n\t\t.object({\n\t\t\tterminal: z\n\t\t\t\t.boolean()\n\t\t\t\t.default(true)\n\t\t\t\t.describe('Apply terminal background colors based on branch name (macOS only)'),\n\t\t\tvscode: z\n\t\t\t\t.boolean()\n\t\t\t\t.default(false)\n\t\t\t\t.describe(\n\t\t\t\t\t'Apply VSCode/Cursor title bar colors based on branch name. ' +\n\t\t\t\t\t\t'Note: This modifies .vscode/settings.json which may be in source control. ' +\n\t\t\t\t\t\t'Default is false for safety; enable via init or explicitly if .vscode is gitignored.'\n\t\t\t\t),\n\t\t})\n\t\t.optional()\n\t\t.describe('Color synchronization settings for workspace identification'),\n\tattribution: z\n\t\t.enum(['off', 'upstreamOnly', 'on'])\n\t\t.default('upstreamOnly')\n\t\t.describe(\n\t\t\t'Controls when iloom attribution appears in session summaries. ' +\n\t\t\t\t'\"off\" - never show attribution. ' +\n\t\t\t\t'\"upstreamOnly\" - only show for contributions to external repositories (e.g., open source). ' +\n\t\t\t\t'\"on\" - always show attribution.'\n\t\t),\n})\n\n/**\n * Non-defaulting variant for pre-merge validation\n * This prevents Zod from polluting partial settings with default values before merge\n */\nexport const IloomSettingsSchemaNoDefaults = 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\tsourceEnvOnStart: z\n\t\t.boolean()\n\t\t.optional()\n\t\t.describe(\n\t\t\t'Source all dotenv-flow files (.env, .env.local, .env.development, .env.development.local) when launching terminal processes (Claude, dev server, terminal). ' +\n\t\t\t\t'Files are sourced in precedence order so later files override earlier ones. ' +\n\t\t\t\t'NOTE TO AI AGENTS: Before making changes to settings files, YOU MUST OFFER to check .env compatibility. ' +\n\t\t\t\t'WARNING: Unquoted values in .env files may break sourcing in bash/zsh shells. ' +\n\t\t\t\t'Before enabling, verify ALL your .env.* files do not contain unquoted special characters ' +\n\t\t\t\t'(e.g., database URLs with ?, &, or other shell metacharacters). ' +\n\t\t\t\t'Shell compatibility issues may cause processes to fail or behave unexpectedly.',\n\t\t),\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: WorkflowsSettingsSchemaNoDefaults.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(\n\t\t\t'Per-agent configuration overrides. Available agents: ' +\n\t\t\t\t'iloom-issue-analyzer (analyzes issues), ' +\n\t\t\t\t'iloom-issue-planner (creates implementation plans), ' +\n\t\t\t\t'iloom-issue-analyze-and-plan (combined analysis and planning), ' +\n\t\t\t\t'iloom-issue-complexity-evaluator (evaluates complexity), ' +\n\t\t\t\t'iloom-issue-enhancer (enhances issue descriptions), ' +\n\t\t\t\t'iloom-issue-implementer (implements code changes), ' +\n\t\t\t\t'iloom-issue-reviewer (reviews code changes against requirements)',\n\t\t),\n\tspin: z\n\t\t.object({\n\t\t\tmodel: z.enum(['sonnet', 'opus', 'haiku']).optional(),\n\t\t})\n\t\t.optional()\n\t\t.describe('Spin orchestrator configuration'),\n\tsummary: z\n\t\t.object({\n\t\t\tmodel: z.enum(['sonnet', 'opus', 'haiku']).optional(),\n\t\t})\n\t\t.optional()\n\t\t.describe('Session summary generation configuration'),\n\tcapabilities: CapabilitiesSettingsSchemaNoDefaults.describe('Project capability configurations'),\n\tdatabaseProviders: DatabaseProvidersSettingsSchema.describe('Database provider configurations'),\n\tissueManagement: z\n\t\t.object({\n\t\t\tprovider: z.enum(['github', 'linear']).optional().describe('Issue tracker provider (github, linear)'),\n\t\t\tgithub: z\n\t\t\t\t.object({\n\t\t\t\t\tremote: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1, 'Remote name cannot be empty')\n\t\t\t\t\t\t.describe('Git remote name to use for GitHub operations'),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\tlinear: z\n\t\t\t\t.object({\n\t\t\t\t\tteamId: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.min(1, 'Team ID cannot be empty')\n\t\t\t\t\t\t.describe('Linear team identifier (e.g., \"ENG\", \"PLAT\")'),\n\t\t\t\t\tbranchFormat: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Branch naming template for Linear issues'),\n\t\t\t\t\tapiToken: z\n\t\t\t\t\t\t.string()\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.describe('Linear API token (lin_api_...). SECURITY: Store in settings.local.json only, never commit to source control.'),\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t})\n\t\t.optional()\n\t\t.describe('Issue management configuration'),\n\tmergeBehavior: z\n\t\t.object({\n\t\t\tmode: z.enum(['local', 'github-pr', 'github-draft-pr']).optional(),\n\t\t\tremote: z.string().optional(),\n\t\t})\n\t\t.optional()\n\t\t.describe('Merge behavior configuration: local (merge locally), github-pr (create PR), or github-draft-pr (create draft PR at start, mark ready on finish)'),\n\tide: z\n\t\t.object({\n\t\t\ttype: z\n\t\t\t\t.enum(['vscode', 'cursor', 'webstorm', 'sublime', 'intellij', 'windsurf', 'antigravity'])\n\t\t\t\t.optional()\n\t\t\t\t.describe(\n\t\t\t\t\t'IDE to launch when starting a loom. Options: vscode (Visual Studio Code), cursor (Cursor AI editor), ' +\n\t\t\t\t\t\t'webstorm (JetBrains WebStorm), sublime (Sublime Text), intellij (JetBrains IntelliJ IDEA), ' +\n\t\t\t\t\t\t'windsurf (Windsurf editor), antigravity (Antigravity IDE).'\n\t\t\t\t),\n\t\t})\n\t\t.optional()\n\t\t.describe(\n\t\t\t'IDE configuration for workspace launches. Controls which editor opens when you start a loom. ' +\n\t\t\t\t'Supports VSCode, Cursor, WebStorm, Sublime Text, IntelliJ, Windsurf, and Antigravity. ' +\n\t\t\t\t'Note: Color synchronization (title bar colors) only works with VSCode-compatible editors (vscode, cursor, windsurf, antigravity).'\n\t\t),\n\tcolors: z\n\t\t.object({\n\t\t\tterminal: z\n\t\t\t\t.boolean()\n\t\t\t\t.optional()\n\t\t\t\t.describe('Apply terminal background colors based on branch name (macOS only)'),\n\t\t\tvscode: z\n\t\t\t\t.boolean()\n\t\t\t\t.optional()\n\t\t\t\t.describe(\n\t\t\t\t\t'Apply VSCode/Cursor title bar colors based on branch name. ' +\n\t\t\t\t\t\t'Note: This modifies .vscode/settings.json which may be in source control.'\n\t\t\t\t),\n\t\t})\n\t\t.optional()\n\t\t.describe('Color synchronization settings for workspace identification'),\n\tattribution: z\n\t\t.enum(['off', 'upstreamOnly', 'on'])\n\t\t.optional()\n\t\t.describe(\n\t\t\t'Controls when iloom attribution appears in session summaries. ' +\n\t\t\t\t'\"off\" - never show attribution. ' +\n\t\t\t\t'\"upstreamOnly\" - only show for contributions to external repositories (e.g., open source). ' +\n\t\t\t\t'\"on\" - always show attribution.'\n\t\t),\n})\n\n/**\n * TypeScript type for Neon settings derived from Zod schema\n */\nexport type NeonSettings = z.infer<typeof NeonSettingsSchema>\n\n/**\n * TypeScript type for database providers settings derived from Zod schema\n */\nexport type DatabaseProvidersSettings = z.infer<typeof DatabaseProvidersSettingsSchema>\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 spin agent settings derived from Zod schema\n */\nexport type SpinAgentSettings = z.infer<typeof SpinAgentSettingsSchema>\n\n/**\n * TypeScript type for summary settings derived from Zod schema\n */\nexport type SummarySettings = z.infer<typeof SummarySettingsSchema>\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 IDE settings derived from Zod schema\n */\nexport type IdeSettings = z.infer<typeof IloomSettingsSchema>['ide']\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 global, project, and local sources with proper precedence\n\t * Merge hierarchy (lowest to highest priority):\n\t * 1. Global settings (~/.config/iloom-ai/settings.json)\n\t * 2. Project settings (<PROJECT_ROOT>/.iloom/settings.json)\n\t * 3. Local settings (<PROJECT_ROOT>/.iloom/settings.local.json)\n\t * 4. CLI overrides (--set flags)\n\t * Returns empty object if all 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 global settings (lowest priority)\n\t\tconst globalSettings = await this.loadGlobalSettingsFile()\n\t\tconst globalSettingsPath = this.getGlobalSettingsPath()\n\t\tlogger.debug(`🌍 Global settings from ${globalSettingsPath}:`, JSON.stringify(globalSettings, null, 2))\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 > globalSettings\n\t\tlet merged = this.mergeSettings(this.mergeSettings(globalSettings, baseSettings), localSettings)\n\t\tlogger.debug('🔄 After merging global + 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 * Uses non-defaulting schema to prevent polluting partial settings with defaults before merge\n\t */\n\tprivate async loadSettingsFile(\n\t\tprojectRoot: string,\n\t\tfilename: string,\n\t): Promise<z.infer<typeof IloomSettingsSchemaNoDefaults>> {\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// Basic type checking - ensure it's an object, but don't validate schema completeness\n\t\t\t// Individual files may be incomplete (e.g., Linear config split between files)\n\t\t\t// Final validation will happen on the merged result in loadSettings()\n\t\t\tif (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Settings validation failed at ${filename}:\\n - root: Expected object, received ${typeof parsed}`\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn parsed as z.infer<typeof IloomSettingsSchemaNoDefaults>\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> | z.infer<typeof IloomSettingsSchemaNoDefaults>,\n\t\toverride: Partial<IloomSettings> | z.infer<typeof IloomSettingsSchemaNoDefaults>,\n\t): IloomSettings {\n\t\t// Use deepmerge with array replacement (not concatenation)\n\t\t// Type assertion is safe because the merged result will be validated with IloomSettingsSchema\n\t\t// which applies all the defaults after merging\n\t\treturn deepmerge(base as Record<string, unknown>, override as Record<string, unknown>, {\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 global config directory path (~/.config/iloom-ai)\n\t */\n\tprivate getGlobalConfigDir(): string {\n\t\treturn path.join(os.homedir(), '.config', 'iloom-ai')\n\t}\n\n\t/**\n\t * Get global settings file path (~/.config/iloom-ai/settings.json)\n\t */\n\tprivate getGlobalSettingsPath(): string {\n\t\treturn path.join(this.getGlobalConfigDir(), 'settings.json')\n\t}\n\n\t/**\n\t * Load and parse global settings file\n\t * Returns empty object if file doesn't exist (not an error)\n\t * Warns but returns empty object on validation/parse errors (graceful degradation)\n\t */\n\tprivate async loadGlobalSettingsFile(): Promise<z.infer<typeof IloomSettingsSchemaNoDefaults>> {\n\t\tconst settingsPath = this.getGlobalSettingsPath()\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\tlogger.warn(\n\t\t\t\t\t`Failed to parse global settings file at ${settingsPath}: ${error instanceof Error ? error.message : 'Invalid JSON'}. Ignoring global settings.`,\n\t\t\t\t)\n\t\t\t\treturn {}\n\t\t\t}\n\n\t\t\t// Validate with non-defaulting schema\n\t\t\ttry {\n\t\t\t\tconst validated = IloomSettingsSchemaNoDefaults.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, 'global settings')\n\t\t\t\t\tlogger.warn(`${errorMsg.message}. Ignoring global settings.`)\n\t\t\t\t} else {\n\t\t\t\t\tlogger.warn(`Validation error in global settings: ${error instanceof Error ? error.message : 'Unknown error'}. Ignoring global settings.`)\n\t\t\t\t}\n\t\t\t\treturn {}\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 global settings file found at ${settingsPath}`)\n\t\t\t\treturn {}\n\t\t\t}\n\n\t\t\t// Other file system errors - warn and continue\n\t\t\tlogger.warn(`Error reading global settings file at ${settingsPath}: ${error instanceof Error ? error.message : 'Unknown error'}. Ignoring global settings.`)\n\t\t\treturn {}\n\t\t}\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\t/**\n\t * Get the spin orchestrator model with default applied\n\t * Default is defined in SpinAgentSettingsSchema\n\t *\n\t * @param settings - Pre-loaded settings object\n\t * @returns Model shorthand ('opus', 'sonnet', or 'haiku')\n\t */\n\tgetSpinModel(settings?: IloomSettings): 'sonnet' | 'opus' | 'haiku' {\n\t\treturn settings?.spin?.model ?? SpinAgentSettingsSchema.parse({}).model\n\t}\n\n\t/**\n\t * Get the session summary model with default applied\n\t * Default is defined in SummarySettingsSchema\n\t *\n\t * @param settings - Pre-loaded settings object\n\t * @returns Model shorthand ('opus', 'sonnet', or 'haiku')\n\t */\n\tgetSummaryModel(settings?: IloomSettings): 'sonnet' | 'opus' | 'haiku' {\n\t\treturn settings?.summary?.model ?? SummarySettingsSchema.parse({}).model\n\t}\n}\n"],"mappings":"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","names":["path"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/ShellCompletion.ts","../src/commands/init.ts"],"sourcesContent":["import omelette from 'omelette'\nimport { GitWorktreeManager } from './GitWorktreeManager.js'\nimport { logger } from '../utils/logger.js'\nimport { readFile } from 'fs/promises'\nimport { existsSync } from 'fs'\nimport path from 'path'\nimport os from 'os'\n\nexport type ShellType = 'bash' | 'zsh' | 'fish' | 'unknown'\n\n/**\n * Manages shell autocomplete functionality for the iloom CLI\n * Uses omelette to provide tab-completion for commands in bash/zsh/fish\n */\nexport class ShellCompletion {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private completion: any // omelette instance - no types available\n private readonly COMPLETION_TIMEOUT = 1000 // ms - prevent blocking\n private readonly commandName: string\n\n constructor(commandName?: string) {\n // Detect command name from process.argv[1] if not provided\n this.commandName = commandName ?? this.detectCommandName()\n\n // Initialize omelette with both command names using pipe syntax\n // This registers completion for both 'iloom' and 'il' aliases\n // Template covers: <commandName> <command> <arg>\n // This allows for two-level completion: command completion + argument completion\n this.completion = omelette('iloom|il <command> <arg>')\n this.setupHandlers()\n }\n\n private detectCommandName(): string {\n // Get the actual command name used to invoke this script\n const scriptPath = process.argv[1] ?? 'il'\n const baseName = scriptPath.split('/').pop() ?? 'il'\n\n // Remove .js extension if present\n return baseName.replace(/\\.js$/, '')\n }\n\n private setupHandlers(): void {\n // Handler for command-level completion\n // When user types: il <TAB>\n this.completion.on('command', ({ reply }: { reply: (suggestions: string[]) => void }) => {\n reply([\n 'start',\n 'finish',\n 'spin',\n 'ignite',\n 'open',\n 'run',\n 'cleanup',\n 'list',\n 'init',\n // Intentionally exclude test-* commands from autocomplete\n ])\n })\n\n // Handler for argument-level completion\n // When user types: il <command> <TAB>\n this.completion.on('arg', async ({ line, reply }: { line: string; reply: (suggestions: string[]) => void }) => {\n // Check if the command is 'cleanup' to provide dynamic branch suggestions\n if (line.includes('cleanup')) {\n // Use timeout to prevent blocking if worktree listing is slow\n const suggestions = await this.getBranchSuggestionsWithTimeout()\n reply(suggestions)\n } else {\n // For other commands, no argument suggestions\n reply([])\n }\n })\n }\n\n /**\n * Get branch suggestions with timeout to prevent blocking\n */\n private async getBranchSuggestionsWithTimeout(): Promise<string[]> {\n try {\n return await Promise.race([\n this.getBranchSuggestions(),\n this.timeout(this.COMPLETION_TIMEOUT, []),\n ])\n } catch (error) {\n logger.debug(`Autocomplete branch suggestions failed: ${error}`)\n return []\n }\n }\n\n private async timeout<T>(ms: number, defaultValue: T): Promise<T> {\n return new Promise((resolve) => {\n // eslint-disable-next-line no-undef\n setTimeout(() => resolve(defaultValue), ms)\n })\n }\n\n async getBranchSuggestions(): Promise<string[]> {\n // Retrieve worktree branches for dynamic completion\n // Used by cleanup command autocomplete\n try {\n const manager = new GitWorktreeManager()\n const worktrees = await manager.listWorktrees({ porcelain: true })\n const repoInfo = await manager.getRepoInfo()\n\n // Filter out:\n // 1. Main worktree (at repo root) - can't be cleaned up\n // 2. Current worktree (where we're working) - shouldn't clean up current location\n const repoRoot = repoInfo.root\n const currentBranch = repoInfo.currentBranch\n\n return worktrees\n .filter((wt) => wt.path !== repoRoot) // Not the main worktree\n .filter((wt) => wt.branch !== currentBranch) // Not current worktree\n .map((wt) => wt.branch)\n } catch (error) {\n // Silently fail - autocomplete should never break the CLI\n logger.debug(`Failed to get branch suggestions: ${error}`)\n return []\n }\n }\n\n /**\n * Initialize completion - must be called before program.parseAsync()\n */\n init(): void {\n this.completion.init()\n }\n\n /**\n * Detect user's current shell\n */\n detectShell(): ShellType {\n const shell = process.env.SHELL ?? ''\n\n if (shell.includes('bash')) return 'bash'\n if (shell.includes('zsh')) return 'zsh'\n if (shell.includes('fish')) return 'fish'\n\n return 'unknown'\n }\n\n /**\n * Get completion script for a specific shell\n */\n getCompletionScript(shell: ShellType): string {\n switch (shell) {\n case 'bash':\n return this.completion.setupShellInitFile('bash')\n case 'zsh':\n return this.completion.setupShellInitFile('zsh')\n case 'fish':\n return this.completion.setupShellInitFile('fish')\n default:\n throw new Error(`Unsupported shell type: ${shell}`)\n }\n }\n\n /**\n * Get setup instructions for manual installation\n */\n getSetupInstructions(shell: ShellType): string {\n const binaryName = this.commandName\n\n switch (shell) {\n case 'bash':\n return `\nAdd the following to your ~/.bashrc or ~/.bash_profile:\n\n eval \"$(${binaryName} --completion)\"\n\nThen reload your shell:\n\n source ~/.bashrc\n`\n case 'zsh':\n return `\nAdd the following to your ~/.zshrc:\n\n eval \"$(${binaryName} --completion)\"\n\nThen reload your shell:\n\n source ~/.zshrc\n`\n case 'fish':\n return `\nAdd the following to your ~/.config/fish/config.fish:\n\n ${binaryName} --completion | source\n\nThen reload your shell:\n\n source ~/.config/fish/config.fish\n`\n default:\n return `\nShell autocomplete is supported for bash, zsh, and fish.\nYour current shell (${shell}) may not be supported.\n\nPlease consult your shell's documentation for setting up custom completions.\n`\n }\n }\n\n /**\n * Generate completion script and print to stdout\n * Used by: il --completion\n */\n printCompletionScript(shell?: ShellType): void {\n const detectedShell = shell ?? this.detectShell()\n\n if (detectedShell === 'unknown') {\n logger.error('Could not detect shell type. Please specify --shell bash|zsh|fish')\n process.exit(1)\n }\n\n try {\n const script = this.getCompletionScript(detectedShell)\n // eslint-disable-next-line no-console\n console.log(script)\n } catch (error) {\n logger.error(`Failed to generate completion script: ${error}`)\n process.exit(1)\n }\n }\n\n /**\n * Get the shell configuration file path for the given shell type\n */\n getShellConfigPath(shell: ShellType): string | null {\n const homeDir = os.homedir()\n\n switch (shell) {\n case 'bash': {\n // Prefer .bashrc, fall back to .bash_profile\n const bashrcPath = path.join(homeDir, '.bashrc')\n const bashProfilePath = path.join(homeDir, '.bash_profile')\n\n if (existsSync(bashrcPath)) {\n return bashrcPath\n } else if (existsSync(bashProfilePath)) {\n return bashProfilePath\n }\n // Return .bashrc path even if it doesn't exist (for creation)\n return bashrcPath\n }\n\n case 'zsh':\n return path.join(homeDir, '.zshrc')\n\n case 'fish':\n return path.join(homeDir, '.config', 'fish', 'config.fish')\n\n default:\n return null\n }\n }\n\n /**\n * Read the shell configuration file contents\n */\n async readShellConfig(shell: ShellType): Promise<{ path: string; content: string } | null> {\n const configPath = this.getShellConfigPath(shell)\n\n if (!configPath) {\n return null\n }\n\n try {\n let content = ''\n if (existsSync(configPath)) {\n content = await readFile(configPath, 'utf-8')\n }\n // Return the path and content (empty string if file doesn't exist)\n return {\n path: configPath,\n content\n }\n } catch (error) {\n logger.debug(`Failed to read shell config file ${configPath}: ${error}`)\n return {\n path: configPath,\n content: ''\n }\n }\n }\n\n /**\n * Grep for completion-related content in shell configuration file\n * Returns only lines containing '--completion' with 2 lines of context before and after\n * Properly handles overlapping matches\n */\n async grepCompletionConfig(shell: ShellType): Promise<{ path: string; content: string } | null> {\n const configPath = this.getShellConfigPath(shell)\n\n if (!configPath) {\n return null\n }\n\n try {\n let content = ''\n if (existsSync(configPath)) {\n const fullContent = await readFile(configPath, 'utf-8')\n const lines = fullContent.split(/\\r?\\n/)\n\n // Find all matching line indices\n const matchingIndices: number[] = []\n lines.forEach((line, index) => {\n if (line.includes('--completion')) {\n matchingIndices.push(index)\n }\n })\n\n if (matchingIndices.length === 0) {\n content = ''\n } else {\n // Create ranges with context, handling overlaps\n const ranges: { start: number; end: number }[] = []\n\n matchingIndices.forEach(matchIndex => {\n const start = Math.max(0, matchIndex - 2)\n const end = Math.min(lines.length - 1, matchIndex + 2)\n ranges.push({ start, end })\n })\n\n // Merge overlapping ranges\n const mergedRanges = this.mergeOverlappingRanges(ranges)\n\n // Extract lines for each merged range\n const resultSections = mergedRanges.map(range =>\n lines.slice(range.start, range.end + 1).join('\\n')\n )\n\n content = resultSections.join('\\n--\\n')\n }\n }\n\n return {\n path: configPath,\n content\n }\n } catch (error) {\n logger.debug(`Failed to grep shell config file ${configPath}: ${error}`)\n return {\n path: configPath,\n content: ''\n }\n }\n }\n\n /**\n * Merge overlapping ranges to avoid duplicate lines\n */\n private mergeOverlappingRanges(ranges: { start: number; end: number }[]): { start: number; end: number }[] {\n if (ranges.length === 0) return []\n\n // Sort ranges by start position\n const sorted = [...ranges].sort((a, b) => a.start - b.start)\n const firstRange = sorted[0]\n if (!firstRange) return []\n\n const merged: { start: number; end: number }[] = [firstRange]\n\n for (let i = 1; i < sorted.length; i++) {\n const current = sorted[i]\n const last = merged[merged.length - 1]\n\n // Both current and last should exist, but TypeScript needs explicit checks\n if (!current || !last) continue\n\n // If current range overlaps or is adjacent to the last merged range\n if (current.start <= last.end + 1) {\n // Merge ranges by extending the end\n last.end = Math.max(last.end, current.end)\n } else {\n // No overlap, add as new range\n merged.push(current)\n }\n }\n\n return merged\n }\n\n}\n","import { logger } from '../utils/logger.js'\nimport { ShellCompletion } from '../lib/ShellCompletion.js'\nimport chalk from 'chalk'\nimport { mkdir, writeFile, readFile } from 'fs/promises'\nimport { existsSync } from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport { detectClaudeCli, launchClaude } from '../utils/claude.js'\nimport { PromptTemplateManager } from '../lib/PromptTemplateManager.js'\nimport { fileURLToPath } from 'url'\nimport { GitRemote, parseGitRemotes } from '../utils/remote.js'\nimport { SettingsMigrationManager } from '../lib/SettingsMigrationManager.js'\nimport { isFileGitignored } from '../utils/git.js'\n\n/**\n * Initialize iloom configuration\n * Implements the `il init` command requested in issue #94\n */\nexport class InitCommand {\n private readonly shellCompletion: ShellCompletion\n private readonly templateManager: PromptTemplateManager\n\n constructor(shellCompletion?: ShellCompletion, templateManager?: PromptTemplateManager) {\n this.shellCompletion = shellCompletion ?? new ShellCompletion()\n this.templateManager = templateManager ?? new PromptTemplateManager()\n }\n\n /**\n * Main entry point for the init command\n * @param customInitialMessage Optional custom initial message to send to Claude (defaults to \"Help me configure iloom settings.\")\n */\n public async execute(customInitialMessage?: string): Promise<void> {\n try {\n logger.debug('InitCommand.execute() starting', {\n cwd: process.cwd(),\n nodeVersion: process.version,\n hasCustomInitialMessage: !!customInitialMessage\n })\n\n logger.info(chalk.bold('Welcome to iloom setup'))\n\n // Setup project configuration\n logger.info(chalk.bold('Verifying current setup...'))\n\n await this.setupProjectConfiguration()\n\n // Launch guided Claude configuration if available\n await this.launchGuidedInit(customInitialMessage)\n\n logger.info(chalk.green('Setup complete! Enjoy using iloom CLI.'))\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error'\n logger.error(`Initialization failed: ${message}`)\n throw error\n }\n }\n\n /**\n * Setup project configuration files\n * Creates settings.local.json and updates .gitignore\n */\n private async setupProjectConfiguration(): Promise<void> {\n logger.debug('setupProjectConfiguration() starting')\n\n // Migrate legacy .hatchbox settings to .iloom (BEFORE creating new files)\n try {\n logger.debug('Loading SettingsMigrationManager for legacy migration')\n const migrationManager = new SettingsMigrationManager()\n logger.debug('Running settings migration check')\n await migrationManager.migrateSettingsIfNeeded()\n logger.debug('Settings migration check completed')\n } catch (error) {\n // Log warning but don't fail\n logger.warn(`Settings migration failed: ${error instanceof Error ? error.message : 'Unknown'}`)\n logger.debug('Settings migration error details', { error })\n }\n\n // Update .gitignore\n logger.debug('Starting .gitignore update')\n await this.updateGitignore()\n logger.debug('setupProjectConfiguration() completed')\n\n // Ensure .iloom directory exists\n const iloomDir = path.join(process.cwd(), '.iloom')\n logger.debug('Creating .iloom directory', { iloomDir })\n await mkdir(iloomDir, { recursive: true })\n logger.debug('.iloom directory created/verified')\n\n // // Create settings.local.json if it doesn't exist\n // const settingsLocalPath = path.join(iloomDir, 'settings.local.json')\n // logger.debug('Checking for existing settings.local.json', { settingsLocalPath })\n\n // if (!existsSync(settingsLocalPath)) {\n // logger.debug('Creating settings.local.json file')\n // await writeFile(settingsLocalPath, '{}\\n', 'utf-8')\n // logger.info('Created .iloom/settings.local.json')\n // logger.debug('settings.local.json file created successfully')\n // } else {\n // logger.debug('settings.local.json file already exists, skipping')\n // }\n }\n\n /**\n * Add settings.local.json to .gitignore if not already present\n */\n private async updateGitignore(): Promise<void> {\n const gitignorePath = path.join(process.cwd(), '.gitignore')\n const entryToAdd = '.iloom/settings.local.json'\n\n logger.debug('updateGitignore() starting', {\n gitignorePath,\n entryToAdd\n })\n\n // Read existing .gitignore or create empty\n let content = ''\n if (existsSync(gitignorePath)) {\n logger.debug('.gitignore file exists, reading content')\n content = await readFile(gitignorePath, 'utf-8')\n logger.debug('Read .gitignore content', {\n contentLength: content.length,\n lineCount: content.split('\\n').length\n })\n } else {\n logger.debug('.gitignore file does not exist, will create new one')\n }\n\n // Check if entry already exists\n const lines = content.split('\\n')\n const entryExists = lines.some(line => line.trim() === entryToAdd)\n logger.debug('Checking if entry already exists', {\n entryExists,\n totalLines: lines.length\n })\n\n if (entryExists) {\n logger.debug('Entry already exists, skipping .gitignore update')\n return\n }\n\n // Add entry with comment\n const commentLine = '\\n# Added by iloom CLI'\n const separator = content.endsWith('\\n') || content === '' ? '' : '\\n'\n const newContent = content + separator + commentLine + '\\n' + entryToAdd + '\\n'\n\n logger.debug('Writing updated .gitignore', {\n originalLength: content.length,\n newLength: newContent.length,\n addedLines: 3 // comment + entry + newline\n })\n\n await writeFile(gitignorePath, newContent, 'utf-8')\n logger.info('Added .iloom/settings.local.json to .gitignore')\n logger.debug('.gitignore update completed successfully')\n }\n\n /**\n * Launch interactive Claude-guided configuration\n * @param customInitialMessage Optional custom initial message to send to Claude\n */\n private async launchGuidedInit(customInitialMessage?: string): Promise<void> {\n logger.debug('launchGuidedInit() starting', { hasCustomInitialMessage: !!customInitialMessage })\n logger.info(chalk.bold('Starting interactive Claude-guided configuration...'))\n\n // Check if Claude CLI is available\n logger.debug('Checking Claude CLI availability')\n const claudeAvailable = await detectClaudeCli()\n logger.debug('Claude CLI availability check result', { claudeAvailable })\n\n if (!claudeAvailable) {\n logger.warn('Claude Code not detected. Skipping guided configuration.')\n logger.info('iloom won\\'t be able to help you much without Claude Code, so please install it: npm install -g @anthropic-ai/claude-code')\n logger.debug('Exiting launchGuidedInit() due to missing Claude CLI')\n return\n }\n\n try {\n // Load schema from dist/schema/settings.schema.json\n // Use similar approach to PromptTemplateManager for path resolution\n const __filename = fileURLToPath(import.meta.url)\n const __dirname = path.dirname(__filename)\n\n // Walk up to find the schema directory (in case of chunked files)\n let schemaPath = path.join(__dirname, 'schema', 'settings.schema.json')\n\n logger.debug('Loading settings schema', {\n __filename,\n __dirname,\n schemaPath,\n schemaExists: existsSync(schemaPath)\n })\n\n let schemaContent = ''\n if (existsSync(schemaPath)) {\n logger.debug('Reading schema file')\n schemaContent = await readFile(schemaPath, 'utf-8')\n logger.debug('Schema file loaded', {\n contentLength: schemaContent.length,\n isValidJson: ((): boolean => {\n try {\n JSON.parse(schemaContent)\n return true\n } catch {\n return false\n }\n })()\n })\n } else {\n logger.warn('Schema file not found - Claude will work without schema validation')\n logger.debug('Schema file not found at expected path', { schemaPath })\n }\n\n // Check for existing settings - read ALL three files if they exist (global, project, local)\n const settingsGlobalPath = path.join(os.homedir(), '.config', 'iloom-ai', 'settings.json')\n const settingsLocalPath = path.join(process.cwd(), '.iloom', 'settings.local.json')\n const settingsCommittedPath = path.join(process.cwd(), '.iloom', 'settings.json')\n\n let settingsGlobalJson = ''\n let settingsJson = ''\n let settingsLocalJson = ''\n\n logger.debug('Checking for settings files', {\n settingsGlobalPath,\n settingsLocalPath,\n settingsCommittedPath,\n globalExists: existsSync(settingsGlobalPath),\n localExists: existsSync(settingsLocalPath),\n committedExists: existsSync(settingsCommittedPath)\n })\n\n // Read global settings.json if it exists\n if (existsSync(settingsGlobalPath)) {\n logger.debug('Reading global settings.json')\n const content = await readFile(settingsGlobalPath, 'utf-8')\n const trimmed = content.trim()\n if (trimmed !== '{}' && trimmed !== '') {\n settingsGlobalJson = content\n logger.debug('global settings.json loaded', {\n contentLength: content.length,\n isValidJson: ((): boolean => {\n try {\n JSON.parse(content)\n return true\n } catch {\n return false\n }\n })()\n })\n } else {\n logger.debug('global settings.json is empty, skipping')\n }\n } else {\n logger.debug('global settings.json does not exist')\n }\n\n // Read settings.json if it exists\n if (existsSync(settingsCommittedPath)) {\n logger.debug('Reading settings.json')\n const content = await readFile(settingsCommittedPath, 'utf-8')\n const trimmed = content.trim()\n if (trimmed !== '{}' && trimmed !== '') {\n settingsJson = content\n logger.debug('settings.json loaded', {\n contentLength: content.length,\n isValidJson: ((): boolean => {\n try {\n JSON.parse(content)\n return true\n } catch {\n return false\n }\n })()\n })\n } else {\n logger.debug('settings.json is empty, skipping')\n }\n } else {\n logger.debug('settings.json does not exist')\n }\n\n // Read settings.local.json if it exists\n if (existsSync(settingsLocalPath)) {\n logger.debug('Reading settings.local.json')\n const content = await readFile(settingsLocalPath, 'utf-8')\n const trimmed = content.trim()\n if (trimmed !== '{}' && trimmed !== '') {\n settingsLocalJson = content\n logger.debug('settings.local.json loaded', {\n contentLength: content.length,\n isValidJson: ((): boolean => {\n try {\n JSON.parse(content)\n return true\n } catch {\n return false\n }\n })()\n })\n } else {\n logger.debug('settings.local.json is empty, skipping')\n }\n } else {\n logger.debug('settings.local.json does not exist')\n }\n\n // Log summary\n logger.debug('Settings files summary', {\n hasSettingsGlobalJson: !!settingsGlobalJson,\n hasSettingsJson: !!settingsJson,\n hasSettingsLocalJson: !!settingsLocalJson,\n settingsGlobalJsonLength: settingsGlobalJson.length,\n settingsJsonLength: settingsJson.length,\n settingsLocalJsonLength: settingsLocalJson.length\n })\n\n // Detect shell and read config\n logger.debug('Detecting user shell')\n const shell = this.shellCompletion.detectShell()\n logger.debug('Shell detection result', { shell })\n\n let shellConfigPath = ''\n let shellConfigContent = ''\n\n if (shell !== 'unknown') {\n logger.debug('Grepping shell config for completion setup')\n const shellConfig = await this.shellCompletion.grepCompletionConfig(shell)\n if (shellConfig) {\n shellConfigPath = shellConfig.path\n shellConfigContent = shellConfig.content\n logger.debug('Shell config completion grep completed', {\n path: shellConfigPath,\n contentLength: shellConfigContent.length,\n configExists: existsSync(shellConfigPath),\n hasMatches: shellConfigContent.trim().length > 0\n })\n } else {\n logger.debug('Could not read shell config')\n }\n } else {\n logger.debug('Unknown shell detected, skipping config read')\n }\n\n let remotes: GitRemote[] = []\n try {\n // Detect git remotes for GitHub configuration\n logger.debug('Detecting git remotes for GitHub configuration')\n remotes = await parseGitRemotes()\n logger.debug('Git remotes detected', { count: remotes.length, remotes })\n } catch (error) {\n const message = error instanceof Error ? error.stack : 'Unknown error'\n logger.debug(\"Error occured while getting remote info: \", message)\n }\n\n // Detect if .vscode/settings.json is gitignored\n let vscodeSettingsGitignored = false\n try {\n vscodeSettingsGitignored = await isFileGitignored('.vscode/settings.json')\n logger.debug('VSCode settings gitignore status', { vscodeSettingsGitignored })\n } catch (error) {\n logger.debug('Could not detect gitignore status for .vscode/settings.json', { error })\n }\n\n let remotesInfo = ''\n let multipleRemotes = false\n let singleRemote = false\n let singleRemoteName = ''\n let singleRemoteUrl = ''\n let noRemotes = false\n\n if (remotes.length === 0) {\n noRemotes = true\n remotesInfo = 'No git remotes detected in this repository.'\n } else if (remotes.length === 1 && remotes[0]) {\n singleRemote = true\n singleRemoteName = remotes[0].name\n singleRemoteUrl = remotes[0].url\n remotesInfo = `Detected Remote:\\n- **${remotes[0].name}**: ${remotes[0].url} (${remotes[0].owner}/${remotes[0].repo})`\n } else {\n multipleRemotes = true\n remotesInfo = `Detected Remotes (${remotes.length}):\\n` +\n remotes.map(r => `- **${r.name}**: ${r.url} (${r.owner}/${r.repo})`).join('\\n')\n }\n\n // Load README content for comprehensive documentation\n logger.debug('README content loading...')\n const readmeContent = await this.loadReadmeContent()\n logger.debug('README content loaded', {\n readmeContentLength: readmeContent.length,\n })\n\n // Build template variables\n const variables = {\n SETTINGS_SCHEMA: schemaContent,\n SETTINGS_GLOBAL_JSON: settingsGlobalJson,\n SETTINGS_JSON: settingsJson,\n SETTINGS_LOCAL_JSON: settingsLocalJson,\n SHELL_TYPE: shell,\n SHELL_CONFIG_PATH: shellConfigPath,\n SHELL_CONFIG_CONTENT: shellConfigContent,\n REMOTES_INFO: remotesInfo,\n MULTIPLE_REMOTES: multipleRemotes.toString(),\n SINGLE_REMOTE: singleRemote.toString(),\n SINGLE_REMOTE_NAME: singleRemoteName,\n SINGLE_REMOTE_URL: singleRemoteUrl,\n NO_REMOTES: noRemotes.toString(),\n README_CONTENT: readmeContent,\n VSCODE_SETTINGS_GITIGNORED: vscodeSettingsGitignored.toString(),\n }\n\n logger.debug('Building template variables', {\n variableKeys: Object.keys(variables),\n schemaContentLength: schemaContent.length,\n settingsGlobalJsonLength: settingsGlobalJson.length,\n settingsJsonLength: settingsJson.length,\n settingsLocalJsonLength: settingsLocalJson.length\n })\n\n // Get init prompt\n logger.debug('Loading init prompt template')\n const prompt = await this.templateManager.getPrompt('init', variables)\n\n logger.debug('Init prompt loaded', {\n promptLength: prompt.length,\n containsSchema: prompt.includes('SETTINGS_SCHEMA'),\n containsExistingSettings: prompt.includes('EXISTING_SETTINGS')\n })\n\n const claudeOptions = {\n headless: false,\n appendSystemPrompt: prompt,\n addDir: process.cwd(),\n }\n\n logger.debug('Launching Claude with options', {\n optionKeys: Object.keys(claudeOptions),\n headless: claudeOptions.headless,\n hasSystemPrompt: !!claudeOptions.appendSystemPrompt,\n addDir: claudeOptions.addDir,\n promptLength: prompt.length,\n hasCustomInitialMessage: !!customInitialMessage\n })\n\n // Launch Claude in interactive mode with custom initial message if provided\n const initialMessage = customInitialMessage ?? 'Help me configure iloom settings.'\n await launchClaude(initialMessage, claudeOptions)\n logger.debug('Claude session completed')\n\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error'\n logger.warn(`Guided configuration failed: ${message}`)\n logger.debug('launchGuidedInit() error details', error instanceof Error ? error.stack : {error})\n logger.info('You can manually edit .iloom/settings.json to configure iloom.')\n }\n\n logger.debug('launchGuidedInit() completed')\n }\n\n /**\n * Load README.md content for init prompt\n * Walks up from dist directory to find README.md in project root\n */\n private async loadReadmeContent(): Promise<string> {\n try {\n // Walk up from current file location to find README.md\n // Use same pattern as PromptTemplateManager for finding files\n let currentDir = path.dirname(fileURLToPath(import.meta.url))\n\n // Walk up to find README.md\n while (currentDir !== path.dirname(currentDir)) {\n const readmePath = path.join(currentDir, 'README.md')\n try {\n const content = await readFile(readmePath, 'utf-8')\n logger.debug('Loaded README.md for init prompt', { readmePath })\n return content\n } catch {\n currentDir = path.dirname(currentDir)\n }\n }\n\n logger.debug('README.md not found, returning empty string')\n return ''\n } catch (error) {\n // Graceful degradation - return empty string on error\n logger.debug(`Failed to load README.md: ${error}`)\n return ''\n }\n }\n\n}\n"],"mappings":"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","names":["readFile","existsSync","path","os","path","existsSync","readFile","os"]}
|