@sixsevenai/ai-dlc-installer 1.4.0 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/dist/cli.js +19 -3
  2. package/dist/cli.js.map +1 -1
  3. package/library/commands/ai-dlc/add-unit.md +1 -0
  4. package/library/commands/ai-dlc/analyze-refinement-scope.md +1 -0
  5. package/library/commands/ai-dlc/apply-refinements.md +1 -0
  6. package/library/commands/ai-dlc/archive-session.md +1 -0
  7. package/library/commands/ai-dlc/assess-risks.md +1 -0
  8. package/library/commands/ai-dlc/build-tests.md +1 -0
  9. package/library/commands/ai-dlc/claude-execute.md +1 -0
  10. package/library/commands/ai-dlc/claude-parallel.md +1 -0
  11. package/library/commands/ai-dlc/claude-review.md +1 -0
  12. package/library/commands/ai-dlc/code-skeptic.md +1 -0
  13. package/library/commands/ai-dlc/codex-execute.md +1 -0
  14. package/library/commands/ai-dlc/collect-refinement-feedback.md +1 -0
  15. package/library/commands/ai-dlc/complete-bolt.md +1 -0
  16. package/library/commands/ai-dlc/construct-unit.md +234 -233
  17. package/library/commands/ai-dlc/create-diagram.md +1 -0
  18. package/library/commands/ai-dlc/create-excalidraw-diagram.md +1 -0
  19. package/library/commands/ai-dlc/create-pipeline.md +1 -0
  20. package/library/commands/ai-dlc/create-runbook.md +1 -0
  21. package/library/commands/ai-dlc/create-units.md +1 -0
  22. package/library/commands/ai-dlc/deploy.md +1 -0
  23. package/library/commands/ai-dlc/design-api.md +1 -0
  24. package/library/commands/ai-dlc/design-database.md +1 -0
  25. package/library/commands/ai-dlc/design-domain-models.md +1 -0
  26. package/library/commands/ai-dlc/design-ui-tests.md +1 -0
  27. package/library/commands/ai-dlc/design-ui.md +1 -0
  28. package/library/commands/ai-dlc/domain-model.md +1 -0
  29. package/library/commands/ai-dlc/elicit-nfrs.md +1 -0
  30. package/library/commands/ai-dlc/engage-stakeholders.md +1 -0
  31. package/library/commands/ai-dlc/generate-code.md +1 -0
  32. package/library/commands/ai-dlc/generate-docs.md +1 -0
  33. package/library/commands/ai-dlc/generate-stories.md +1 -0
  34. package/library/commands/ai-dlc/handle-cross-phase-refinement.md +1 -0
  35. package/library/commands/ai-dlc/implement-ui-tests.md +1 -0
  36. package/library/commands/ai-dlc/incident-respond.md +1 -0
  37. package/library/commands/ai-dlc/logical-design.md +1 -0
  38. package/library/commands/ai-dlc/maker-execute.md +1 -0
  39. package/library/commands/ai-dlc/maker-status.md +1 -0
  40. package/library/commands/ai-dlc/mob-elaborate.md +172 -171
  41. package/library/commands/ai-dlc/multi-ai-compare.md +1 -0
  42. package/library/commands/ai-dlc/next-bolt.md +1 -0
  43. package/library/commands/ai-dlc/next-phase.md +1 -0
  44. package/library/commands/ai-dlc/package-unit.md +1 -0
  45. package/library/commands/ai-dlc/plan-bolt.md +1 -0
  46. package/library/commands/ai-dlc/plan-workflow.md +1 -0
  47. package/library/commands/ai-dlc/prepare-release.md +1 -0
  48. package/library/commands/ai-dlc/review-artifacts.md +725 -724
  49. package/library/commands/ai-dlc/review-code.md +1 -0
  50. package/library/commands/ai-dlc/run-workflow.md +215 -214
  51. package/library/commands/ai-dlc/security-audit.md +1 -0
  52. package/library/commands/ai-dlc/setup-monitoring.md +1 -0
  53. package/library/commands/ai-dlc/setup.md +1 -0
  54. package/library/commands/ai-dlc/start-intent.md +1 -0
  55. package/library/commands/ai-dlc/status.md +1 -0
  56. package/library/commands/ai-dlc/talk.md +1 -0
  57. package/library/commands/ai-dlc/trace.md +1 -0
  58. package/library/commands/ai-dlc/upgrade.md +1 -0
  59. package/library/commands/ai-dlc/validate-framework.md +1 -0
  60. package/library/commands/ai-dlc/validate-phase.md +1 -0
  61. package/library/commands/ai-dlc/validate-unit.md +1 -0
  62. package/library/commands/ai-dlc/validate-workflow.md +1 -0
  63. package/library/commands/ai-dlc/visualize.md +1 -0
  64. package/library/commands/ai-dlc/workflow-cancel.md +1 -0
  65. package/library/commands/ai-dlc/workflow-pause.md +1 -0
  66. package/library/commands/ai-dlc/workflow-resume.md +1 -0
  67. package/library/commands/ai-dlc/workflow-status.md +1 -0
  68. package/library/commands/brn/assess.md +1 -0
  69. package/library/commands/brn/audit.md +1 -0
  70. package/library/commands/brn/document.md +1 -0
  71. package/library/commands/brn/modernize.md +1 -0
  72. package/library/commands/brn/optimize.md +1 -0
  73. package/library/commands/brn/plan.md +1 -0
  74. package/library/commands/brn/refactor.md +1 -0
  75. package/library/commands/brn/roi.md +1 -0
  76. package/library/commands/brn/secure.md +1 -0
  77. package/library/commands/brn/test.md +1 -0
  78. package/library/commands/commit.md +124 -124
  79. package/library/commands/dba/azure-advisor.md +163 -162
  80. package/library/commands/dba/azure-health.md +235 -234
  81. package/library/commands/dba/azure-scale.md +238 -237
  82. package/library/commands/dba/backup-status.md +194 -193
  83. package/library/commands/dba/bacpac-export.md +192 -191
  84. package/library/commands/dba/bacpac-import.md +206 -205
  85. package/library/commands/dba/blocking.md +263 -262
  86. package/library/commands/dba/dacpac-extract.md +176 -175
  87. package/library/commands/dba/dacpac-publish.md +248 -247
  88. package/library/commands/dba/explain-plan.md +189 -188
  89. package/library/commands/dba/format-sql.md +223 -222
  90. package/library/commands/dba/health-check.md +216 -215
  91. package/library/commands/dba/index-analysis.md +293 -292
  92. package/library/commands/dba/index-rebuild.md +257 -256
  93. package/library/commands/dba/index-stats.md +274 -273
  94. package/library/commands/dba/migrate-assess.md +190 -189
  95. package/library/commands/dba/monitor.md +206 -205
  96. package/library/commands/dba/parquet-export.md +168 -167
  97. package/library/commands/dba/parquet-import.md +181 -180
  98. package/library/commands/dba/query.md +194 -193
  99. package/library/commands/dba/schema-compare.md +190 -189
  100. package/library/commands/dba/top-queries.md +242 -241
  101. package/library/commands/dba/wait-stats.md +222 -221
  102. package/library/commands/docs/ask-codebase.md +1 -0
  103. package/library/commands/docs/document-solution.md +1 -0
  104. package/library/commands/docs/shard.md +188 -187
  105. package/library/commands/elicit/brainstorm.md +1 -0
  106. package/library/commands/elicit/challenge.md +1 -0
  107. package/library/commands/elicit/design.md +1 -0
  108. package/library/commands/elicit/edges.md +1 -0
  109. package/library/commands/elicit/empathy.md +1 -0
  110. package/library/commands/elicit/five-whys.md +1 -0
  111. package/library/commands/elicit/jobs.md +1 -0
  112. package/library/commands/elicit/prioritize.md +1 -0
  113. package/library/commands/elicit/requirements.md +1 -0
  114. package/library/commands/elicit/scamper.md +1 -0
  115. package/library/commands/elicit/stories.md +1 -0
  116. package/library/commands/elicit/technique.md +1 -0
  117. package/library/commands/elicit/validate.md +1 -0
  118. package/library/commands/elicit/value.md +1 -0
  119. package/library/commands/elicit/vision.md +1 -0
  120. package/library/commands/git/check-duplicates.md +1 -0
  121. package/library/commands/instruct-me.md +1 -0
  122. package/library/commands/issue-to-done.md +143 -0
  123. package/library/commands/it-ops/azure-costs.md +76 -75
  124. package/library/commands/it-ops/azure-health.md +63 -62
  125. package/library/commands/it-ops/entra-audit.md +72 -71
  126. package/library/commands/it-ops/entra-users.md +66 -65
  127. package/library/commands/it-ops/helpdesk-new.md +95 -94
  128. package/library/commands/it-ops/helpdesk-summary.md +86 -85
  129. package/library/commands/it-ops/intune-compliance.md +65 -64
  130. package/library/commands/it-ops/intune-devices.md +63 -62
  131. package/library/commands/it-ops/o365-health.md +65 -64
  132. package/library/commands/it-ops/o365-licenses.md +64 -63
  133. package/library/commands/it-ops/soc-incidents.md +80 -79
  134. package/library/commands/it-ops/soc-score.md +69 -68
  135. package/library/commands/spec/analyze.md +245 -244
  136. package/library/commands/spec/checklist.md +1 -0
  137. package/library/commands/spec/clarify.md +310 -309
  138. package/library/commands/spec/complete.md +1 -0
  139. package/library/commands/spec/constitution.md +1 -0
  140. package/library/commands/spec/implement.md +218 -217
  141. package/library/commands/spec/plan.md +1 -0
  142. package/library/commands/spec/specify.md +425 -424
  143. package/library/commands/spec/task-to-issue.md +1 -0
  144. package/library/commands/spec/tasks.md +191 -190
  145. package/library/commands/spec/to-intent.md +1 -0
  146. package/library/commands/task/clarify.md +1 -0
  147. package/library/commands/task/complete.md +1 -0
  148. package/library/commands/task/execute.md +1 -0
  149. package/library/commands/task/plan.md +1 -0
  150. package/library/commands/worktree/create.md +1 -0
  151. package/library/commands/worktree/list.md +1 -0
  152. package/library/commands/worktree/remove.md +1 -0
  153. package/library/commands/worktree/status.md +1 -0
  154. package/library/skills/azure-infra-monitor/SKILL.md +147 -147
  155. package/library/skills/azure-infra-monitor/scripts/Get-AzureCostSummary.ps1 +234 -234
  156. package/library/skills/azure-infra-monitor/scripts/Get-AzureResourceHealth.ps1 +138 -138
  157. package/library/skills/azure-infra-monitor/templates/azure-monitor-alert-template.json +188 -188
  158. package/library/skills/dba-azure-sql/SKILL.md +421 -421
  159. package/library/skills/dba-migration/SKILL.md +462 -462
  160. package/library/skills/dba-tsql-reference/SKILL.md +690 -690
  161. package/library/skills/entra-id-admin/SKILL.md +139 -139
  162. package/library/skills/entra-id-admin/scripts/Get-EntraSignInAudit.ps1 +189 -189
  163. package/library/skills/entra-id-admin/scripts/Get-EntraUserReport.ps1 +163 -163
  164. package/library/skills/intune-inventory/SKILL.md +132 -132
  165. package/library/skills/intune-inventory/scripts/Get-IntuneComplianceReport.ps1 +175 -175
  166. package/library/skills/intune-inventory/scripts/Get-IntuneDeviceInventory.ps1 +190 -190
  167. package/library/skills/itsm-helpdesk/SKILL.md +182 -182
  168. package/library/skills/itsm-helpdesk/scripts/Connect-Itsm.ps1 +78 -78
  169. package/library/skills/itsm-helpdesk/scripts/Get-HelpdeskTicketSummary.ps1 +355 -355
  170. package/library/skills/itsm-helpdesk/scripts/New-HelpdeskTicket.ps1 +225 -225
  171. package/library/skills/ms-graph-auth/SKILL.md +188 -188
  172. package/library/skills/ms-graph-auth/scripts/Connect-AzureRM.ps1 +190 -190
  173. package/library/skills/ms-graph-auth/scripts/Connect-MsGraph.ps1 +168 -168
  174. package/library/skills/ms-graph-auth/scripts/Invoke-ArmApi.ps1 +13 -13
  175. package/library/skills/ms-graph-auth/scripts/Invoke-GraphApi.ps1 +13 -13
  176. package/library/skills/ms-graph-auth/scripts/Invoke-PaginatedApi.ps1 +109 -109
  177. package/library/skills/o365-admin/SKILL.md +149 -149
  178. package/library/skills/o365-admin/scripts/Get-O365LicenseReport.ps1 +214 -214
  179. package/library/skills/o365-admin/scripts/Get-O365ServiceHealth.ps1 +263 -263
  180. package/library/skills/soc-adherence/SKILL.md +160 -160
  181. package/library/skills/soc-adherence/scripts/Get-SecureScoreReport.ps1 +216 -216
  182. package/library/skills/soc-adherence/scripts/Get-SentinelIncidents.ps1 +245 -245
  183. package/package.json +1 -1
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/orchestrator/workflow.ts","../src/orchestrator/types.ts","../src/orchestrator/config.ts","../src/ui/theme.ts","../src/ui/banner.ts","../src/ui/progress.ts","../src/ui/types.ts","../src/ui/prompts.ts","../src/ui/error-display.ts","../src/engine/category-filter.ts","../src/ui/summary.ts","../src/ui/sixseven-animation.ts","../src/orchestrator/error-handler.ts","../src/platform/types.ts","../src/platform/detector.ts","../src/platform/paths.ts","../src/platform/permissions.ts","../src/platform/terminal.ts","../src/platform/shell.ts","../src/platform/runtime.ts","../src/platform/facade.ts","../src/engine/manifest.ts","../src/engine/conflict-detector.ts","../src/engine/file-copier.ts","../src/engine/rollback.ts","../src/engine/validator.ts","../src/index.ts","../src/cli.ts"],"sourcesContent":["/**\r\n * CLI Orchestrator - Installation Workflow\r\n *\r\n * The core orchestration logic that drives the 12-step installation\r\n * workflow. Delegates to platform, UI, and engine subsystems through\r\n * their public APIs. Manages workflow state, error recovery, and\r\n * cancellation handling.\r\n *\r\n * @module orchestrator/workflow\r\n */\r\n\r\nimport * as path from 'node:path';\r\nimport { mkdir, writeFile, readFile, stat } from 'node:fs/promises';\r\n\r\nimport type {\r\n CLIOptions,\r\n ExitCode,\r\n InstallationContext,\r\n InstallationConfig,\r\n OverwriteMode,\r\n WorkflowState,\r\n WorkflowStepId,\r\n WorkflowStepState,\r\n StepOutput,\r\n DryRunReport,\r\n DryRunStepDetail,\r\n} from './types.js';\r\nimport { EXIT_SUCCESS, EXIT_CANCELLED } from './types.js';\r\n\r\nimport {\r\n WORKFLOW_STEPS,\r\n INSTALLER_VERSION,\r\n CLAUDE_DIRECTORY_NAME,\r\n shouldSkipStep,\r\n resolveConfig,\r\n resolveSourceDirectory,\r\n resolveAiDlcSourceDirectory,\r\n} from './config.js';\r\n\r\nimport { ErrorHandler } from './error-handler.js';\r\n\r\n// -- Platform imports\r\nimport {\r\n PlatformFacade,\r\n type PlatformEnvironment,\r\n} from '../platform/index.js';\r\n\r\n// -- UI imports\r\nimport {\r\n ThemeEngine,\r\n renderBanner,\r\n ProgressTracker,\r\n renderError,\r\n renderSummary,\r\n getDefaultNextSteps,\r\n promptDirectorySelection,\r\n promptConfirmation,\r\n promptOverwriteMode,\r\n promptCategorySelection,\r\n promptRetry,\r\n promptIntro,\r\n promptOutro,\r\n UserCancellationError,\r\n SixSevenSpinner,\r\n formatDuration,\r\n mapColorSupport,\r\n type TerminalCapabilities,\r\n type DirectoryOption,\r\n type ErrorPanelContent,\r\n type InstallationSummary,\r\n} from '../ui/index.js';\r\n\r\n// -- Engine imports\r\nimport {\r\n scanSourceDirectory,\r\n detectConflicts,\r\n copyFiles,\r\n createBackup,\r\n restoreFromBackup,\r\n validateInstallation,\r\n resolveCategories,\r\n filterMappingsByCategories,\r\n INSTALL_CATEGORIES,\r\n type ComponentManifest,\r\n type ConflictReport,\r\n type FileMapping,\r\n type BackupManifest,\r\n} from '../engine/index.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Workflow State Factory\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction createInitialState(): WorkflowState {\r\n return {\r\n status: 'pending',\r\n steps: WORKFLOW_STEPS.map(def => ({\r\n def,\r\n status: 'pending',\r\n output: null,\r\n error: null,\r\n startedAt: null,\r\n completedAt: null,\r\n })),\r\n currentStepId: null,\r\n startedAt: null,\r\n completedAt: null,\r\n cancellationReason: null,\r\n };\r\n}\r\n\r\nfunction createInitialContext(sourceDirectory: string): InstallationContext {\r\n return {\r\n platformEnv: null,\r\n terminalCapabilities: null,\r\n runtimeReport: null,\r\n targetDirectory: null,\r\n claudeDirectory: null,\r\n sourceDirectory,\r\n manifest: null,\r\n conflictReport: null,\r\n backupManifest: null,\r\n installationResult: null,\r\n validationReport: null,\r\n fileMappings: [],\r\n overwriteMode: null,\r\n selectedCategories: [],\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helper: Terminal Capabilities from Platform\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction buildTerminalCapabilities(env: PlatformEnvironment): TerminalCapabilities {\r\n return {\r\n colorSupport: mapColorSupport(env.terminal.colorSupport),\r\n unicodeSupport: env.terminal.unicodeSupport.supported,\r\n width: env.terminal.dimensions.columns,\r\n height: env.terminal.dimensions.rows,\r\n isInteractive: env.terminal.interactivity.isInteractive,\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helper: Build File Mappings\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction buildFileMappings(\r\n manifest: ComponentManifest,\r\n sourceDirectory: string,\r\n claudeDirectory: string,\r\n): FileMapping[] {\r\n return manifest.entries.map(entry => ({\r\n relativePath: entry.relativePath,\r\n sourcePath: path.join(sourceDirectory, entry.relativePath),\r\n destinationPath: path.join(claudeDirectory, entry.relativePath),\r\n componentType: entry.componentType,\r\n fileName: entry.fileName,\r\n sizeBytes: entry.sizeBytes,\r\n }));\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helper: Build Installation Summary\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction buildInstallationSummary(\r\n ctx: InstallationContext,\r\n workflow: WorkflowState,\r\n): InstallationSummary {\r\n const elapsed = workflow.completedAt && workflow.startedAt\r\n ? workflow.completedAt - workflow.startedAt\r\n : 0;\r\n\r\n const result = ctx.installationResult;\r\n const manifest = ctx.manifest;\r\n\r\n return {\r\n success: result?.success ?? false,\r\n targetDirectory: ctx.targetDirectory ?? 'unknown',\r\n componentCounts: {\r\n agents: manifest?.countsByType.agents ?? 0,\r\n skills: manifest?.countsByType.skills ?? 0,\r\n commands: manifest?.countsByType.commands ?? 0,\r\n cliFiles: manifest?.countsByType.cli ?? 0,\r\n other: (manifest?.countsByType.workflows ?? 0) + (manifest?.countsByType.metadata ?? 0),\r\n },\r\n totalDuration: formatDuration(elapsed),\r\n totalFilesCopied: result?.copiedCount ?? 0,\r\n totalFilesSkipped: result?.skippedCount ?? 0,\r\n totalFilesFailed: result?.errors.length ?? 0,\r\n installerVersion: INSTALLER_VERSION,\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helper: Build Directory Options\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction buildDirectoryOptions(env: PlatformEnvironment): DirectoryOption[] {\r\n const cwd = process.cwd();\r\n const home = env.platform.homeDirectory.path;\r\n\r\n const options: DirectoryOption[] = [\r\n {\r\n path: cwd,\r\n label: cwd,\r\n isDefault: true,\r\n exists: true,\r\n },\r\n ];\r\n\r\n if (home !== cwd) {\r\n options.push({\r\n path: home,\r\n label: home,\r\n isDefault: false,\r\n exists: true,\r\n });\r\n }\r\n\r\n return options;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Verbose Logger\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction verboseLog(verbose: boolean, ...args: unknown[]): void {\r\n if (verbose) {\r\n console.error('[verbose]', ...args);\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Main Workflow Execution\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Execute the full installation workflow.\r\n *\r\n * This is the core orchestration function that drives the 10-step\r\n * installation pipeline. It delegates to platform, UI, and engine\r\n * subsystems, manages state transitions, and handles errors with\r\n * recovery/rollback.\r\n *\r\n * @param options - Parsed CLI options\r\n * @returns Process exit code (0 = success, 1 = error, 2 = cancelled)\r\n */\r\nexport async function executeInstallation(options: CLIOptions): Promise<ExitCode> {\r\n const errorHandler = new ErrorHandler();\r\n const workflow = createInitialState();\r\n let sourceDirectory: string;\r\n\r\n // Resolve source directory before starting workflow\r\n try {\r\n sourceDirectory = await resolveSourceDirectory();\r\n } catch (error) {\r\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\r\n return EXIT_CANCELLED;\r\n }\r\n\r\n const ctx = createInitialContext(sourceDirectory);\r\n\r\n // Register SIGINT handler for graceful cancellation\r\n let cancelled = false;\r\n const sigintHandler = () => {\r\n cancelled = true;\r\n workflow.status = 'cancelled';\r\n workflow.cancellationReason = 'User pressed Ctrl+C';\r\n };\r\n process.on('SIGINT', sigintHandler);\r\n\r\n // Start workflow\r\n workflow.status = 'running';\r\n workflow.startedAt = Date.now();\r\n\r\n let theme: ThemeEngine | null = null;\r\n\r\n try {\r\n for (const stepState of workflow.steps) {\r\n // Check for cancellation between steps\r\n if (cancelled) {\r\n break;\r\n }\r\n\r\n const stepId = stepState.def.id;\r\n const isInteractive = ctx.terminalCapabilities?.isInteractive ?? true;\r\n\r\n // Check if step should be skipped\r\n if (stepState.def.isSkippable && shouldSkipStep(stepId, options, isInteractive)) {\r\n stepState.status = 'skipped';\r\n verboseLog(options.verbose, `Skipping step: ${stepState.def.name}`);\r\n continue;\r\n }\r\n\r\n // Mark step as running\r\n stepState.status = 'running';\r\n stepState.startedAt = Date.now();\r\n workflow.currentStepId = stepId;\r\n verboseLog(options.verbose, `Starting step: ${stepState.def.name}`);\r\n\r\n try {\r\n const output = await executeStep(stepId, options, ctx, theme, errorHandler);\r\n stepState.status = 'completed';\r\n stepState.output = output;\r\n stepState.completedAt = Date.now();\r\n\r\n // Update theme after platform detection\r\n if (stepId === 'detect-platform' && ctx.terminalCapabilities) {\r\n theme = ThemeEngine.initialize(ctx.terminalCapabilities, {\r\n forceNoColor: options.noColor,\r\n forceColor: false,\r\n });\r\n }\r\n\r\n verboseLog(\r\n options.verbose,\r\n `Completed step: ${stepState.def.name} (${stepState.completedAt - (stepState.startedAt ?? 0)}ms)`,\r\n );\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n\r\n // Handle user cancellation\r\n if (err instanceof UserCancellationError) {\r\n workflow.status = 'cancelled';\r\n workflow.cancellationReason = err.message;\r\n break;\r\n }\r\n\r\n // Classify error and determine recovery\r\n const recovery = errorHandler.handleError(err, stepId);\r\n stepState.status = 'failed';\r\n stepState.error = err;\r\n stepState.completedAt = Date.now();\r\n\r\n verboseLog(options.verbose, `Step failed: ${stepState.def.name} - ${err.message}`);\r\n verboseLog(options.verbose, `Recovery strategy: ${recovery.strategy}`);\r\n\r\n // Execute recovery strategy\r\n if (recovery.strategy === 'PromptUser' && isInteractive && theme) {\r\n // Show error and ask to retry\r\n const errorContent: ErrorPanelContent = {\r\n title: 'Installation Error',\r\n message: recovery.userGuidance,\r\n cause: err.message,\r\n suggestedActions: recovery.platformGuidance\r\n ? [{ step: 1, instruction: recovery.platformGuidance, command: null }]\r\n : [],\r\n retryAvailable: true,\r\n errorCode: null,\r\n };\r\n const lines = renderError(errorContent, theme);\r\n for (const line of lines) {\r\n console.log(line);\r\n }\r\n\r\n const shouldRetry = await promptRetry();\r\n if (shouldRetry && errorHandler.canRetry(stepId)) {\r\n errorHandler.recordRetry(stepId);\r\n // Reset step state for retry\r\n stepState.status = 'running';\r\n stepState.error = null;\r\n stepState.startedAt = Date.now();\r\n stepState.completedAt = null;\r\n\r\n try {\r\n const output = await executeStep(stepId, options, ctx, theme, errorHandler);\r\n stepState.status = 'completed';\r\n stepState.output = output;\r\n stepState.completedAt = Date.now();\r\n continue;\r\n } catch (retryError) {\r\n const retryErr = retryError instanceof Error ? retryError : new Error(String(retryError));\r\n stepState.status = 'failed';\r\n stepState.error = retryErr;\r\n stepState.completedAt = Date.now();\r\n errorHandler.handleError(retryErr, stepId);\r\n }\r\n }\r\n // Fall through to abort\r\n workflow.status = 'failed';\r\n break;\r\n }\r\n\r\n if (recovery.strategy === 'RollbackAndAbort' || recovery.strategy === 'AbortImmediately') {\r\n // Attempt rollback if we have a backup\r\n await attemptRollback(ctx, options);\r\n\r\n // Show error if we have a theme\r\n if (theme) {\r\n const errorContent: ErrorPanelContent = {\r\n title: 'Installation Failed',\r\n message: recovery.userGuidance,\r\n cause: err.message,\r\n suggestedActions: recovery.platformGuidance\r\n ? [{ step: 1, instruction: recovery.platformGuidance, command: null }]\r\n : [],\r\n retryAvailable: false,\r\n errorCode: null,\r\n };\r\n const lines = renderError(errorContent, theme);\r\n for (const line of lines) {\r\n console.log(line);\r\n }\r\n } else {\r\n console.error(`\\nError: ${err.message}`);\r\n console.error(recovery.userGuidance);\r\n }\r\n\r\n workflow.status = 'failed';\r\n break;\r\n }\r\n\r\n // SkipAndContinue\r\n if (recovery.strategy === 'SkipAndContinue' && stepState.def.isSkippable) {\r\n stepState.status = 'skipped';\r\n continue;\r\n }\r\n\r\n // Default: fail workflow\r\n workflow.status = 'failed';\r\n break;\r\n }\r\n }\r\n\r\n // Finalize workflow\r\n if (workflow.status === 'running') {\r\n workflow.status = 'completed';\r\n }\r\n workflow.completedAt = Date.now();\r\n\r\n // Handle cancellation cleanup\r\n if (workflow.status === 'cancelled') {\r\n await attemptRollback(ctx, options);\r\n if (theme) {\r\n promptOutro('Installation cancelled. All changes have been rolled back.');\r\n } else {\r\n console.log('\\nInstallation cancelled. All changes have been rolled back.');\r\n }\r\n }\r\n } finally {\r\n // Remove SIGINT handler\r\n process.removeListener('SIGINT', sigintHandler);\r\n }\r\n\r\n return errorHandler.getExitCode(workflow);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Dry Run Execution\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Execute a dry run of the installation workflow.\r\n *\r\n * Runs the full pipeline without writing any files. Reports what\r\n * would happen if the installation were executed for real.\r\n *\r\n * @param options - Parsed CLI options\r\n * @returns Process exit code\r\n */\r\nexport async function executeDryRun(options: CLIOptions): Promise<ExitCode> {\r\n let sourceDirectory: string;\r\n\r\n try {\r\n sourceDirectory = await resolveSourceDirectory();\r\n } catch (error) {\r\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\r\n return EXIT_CANCELLED;\r\n }\r\n\r\n const ctx = createInitialContext(sourceDirectory);\r\n const details: DryRunStepDetail[] = [];\r\n\r\n console.log('\\n[dry-run] Simulating installation workflow...\\n');\r\n\r\n // Step 1: Detect platform\r\n try {\r\n const facade = new PlatformFacade();\r\n ctx.platformEnv = await facade.detectAll();\r\n ctx.terminalCapabilities = buildTerminalCapabilities(ctx.platformEnv);\r\n details.push({\r\n stepId: 'detect-platform',\r\n stepName: 'Detect Platform',\r\n result: `${ctx.platformEnv.platform.os.family} ${ctx.platformEnv.platform.os.architecture.name}`,\r\n warnings: [],\r\n });\r\n } catch (error) {\r\n console.error(`Platform detection failed: ${error instanceof Error ? error.message : String(error)}`);\r\n return EXIT_CANCELLED;\r\n }\r\n\r\n // Step 2: Check prerequisites\r\n const prereqWarnings: string[] = [];\r\n if (!ctx.platformEnv!.runtime.allRequirementsMet) {\r\n for (const err of ctx.platformEnv!.runtime.errors) {\r\n prereqWarnings.push(err.message);\r\n }\r\n }\r\n details.push({\r\n stepId: 'check-prerequisites',\r\n stepName: 'Check Prerequisites',\r\n result: prereqWarnings.length === 0 ? 'All prerequisites met' : `${prereqWarnings.length} issue(s)`,\r\n warnings: prereqWarnings,\r\n });\r\n\r\n // Resolve target directory\r\n const targetDir = options.target ?? process.cwd();\r\n ctx.targetDirectory = targetDir;\r\n ctx.claudeDirectory = path.join(targetDir, CLAUDE_DIRECTORY_NAME);\r\n\r\n details.push({\r\n stepId: 'select-directory',\r\n stepName: 'Select Target Directory',\r\n result: `Target: ${targetDir}`,\r\n warnings: [],\r\n });\r\n\r\n // Step 5: Scan source\r\n try {\r\n ctx.manifest = await scanSourceDirectory(sourceDirectory);\r\n details.push({\r\n stepId: 'scan-source',\r\n stepName: 'Scan Source Components',\r\n result: `${ctx.manifest.totalCount} components found`,\r\n warnings: [],\r\n });\r\n } catch (error) {\r\n console.error(`Source scan failed: ${error instanceof Error ? error.message : String(error)}`);\r\n return EXIT_CANCELLED;\r\n }\r\n\r\n // Step 6: Detect conflicts\r\n try {\r\n ctx.conflictReport = await detectConflicts(ctx.manifest, sourceDirectory, ctx.claudeDirectory!);\r\n const conflictWarnings: string[] = [];\r\n if (ctx.conflictReport.hasConflicts) {\r\n conflictWarnings.push(`${ctx.conflictReport.modifiedCount} file(s) differ from source`);\r\n }\r\n details.push({\r\n stepId: 'detect-conflicts',\r\n stepName: 'Detect Conflicts',\r\n result: ctx.conflictReport.hasConflicts\r\n ? `${ctx.conflictReport.modifiedCount} conflict(s) detected`\r\n : 'No conflicts',\r\n warnings: conflictWarnings,\r\n });\r\n } catch (error) {\r\n details.push({\r\n stepId: 'detect-conflicts',\r\n stepName: 'Detect Conflicts',\r\n result: `Could not check: ${error instanceof Error ? error.message : 'unknown'}`,\r\n warnings: [],\r\n });\r\n }\r\n\r\n // Build dry-run report\r\n const report: DryRunReport = {\r\n filesToInstall: ctx.manifest.totalCount,\r\n filesToOverwrite: ctx.conflictReport?.modifiedCount ?? 0,\r\n conflictsDetected: ctx.conflictReport?.modifiedCount ?? 0,\r\n wouldSucceed: prereqWarnings.length === 0,\r\n details,\r\n };\r\n\r\n // Print dry-run report\r\n console.log('[dry-run] Installation Preview');\r\n console.log('─'.repeat(50));\r\n console.log(` Files to install: ${report.filesToInstall}`);\r\n console.log(` Files to overwrite: ${report.filesToOverwrite}`);\r\n console.log(` Conflicts detected: ${report.conflictsDetected}`);\r\n console.log(` Would succeed: ${report.wouldSucceed ? 'yes' : 'no'}`);\r\n console.log('');\r\n\r\n for (const detail of report.details) {\r\n console.log(` ${detail.stepName}: ${detail.result}`);\r\n for (const warning of detail.warnings) {\r\n console.log(` ! ${warning}`);\r\n }\r\n }\r\n\r\n console.log('');\r\n console.log('[dry-run] No files were modified.');\r\n\r\n return EXIT_SUCCESS;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Step Executor\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Execute a single workflow step by delegating to the appropriate subsystem.\r\n */\r\nasync function executeStep(\r\n stepId: WorkflowStepId,\r\n options: CLIOptions,\r\n ctx: InstallationContext,\r\n theme: ThemeEngine | null,\r\n errorHandler: ErrorHandler,\r\n): Promise<StepOutput> {\r\n switch (stepId) {\r\n case 'detect-platform':\r\n return executeDetectPlatform(ctx, options);\r\n\r\n case 'check-prerequisites':\r\n return executeCheckPrerequisites(ctx, options);\r\n\r\n case 'show-banner':\r\n return executeShowBanner(ctx, options, theme);\r\n\r\n case 'select-directory':\r\n return executeSelectDirectory(ctx, options, theme);\r\n\r\n case 'scan-source':\r\n return executeScanSource(ctx, options);\r\n\r\n case 'detect-conflicts':\r\n return executeDetectConflicts(ctx, options, theme);\r\n\r\n case 'select-overwrite-mode':\r\n return executeSelectOverwriteMode(ctx, options, theme);\r\n\r\n case 'select-categories':\r\n return executeSelectCategories(ctx, options, theme);\r\n\r\n case 'confirm-installation':\r\n return executeConfirmInstallation(ctx, options, theme);\r\n\r\n case 'execute-installation':\r\n return executeInstallFiles(ctx, options, theme);\r\n\r\n case 'validate-installation':\r\n return executeValidateInstallation(ctx, options);\r\n\r\n case 'show-summary':\r\n return executeShowSummary(ctx, options, theme);\r\n\r\n default: {\r\n const _exhaustive: never = stepId;\r\n throw new Error(`Unknown step: ${_exhaustive}`);\r\n }\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Step Implementations\r\n// ---------------------------------------------------------------------------\r\n\r\nasync function executeDetectPlatform(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n): Promise<StepOutput> {\r\n const facade = new PlatformFacade();\r\n ctx.platformEnv = await facade.detectAll();\r\n ctx.terminalCapabilities = buildTerminalCapabilities(ctx.platformEnv);\r\n ctx.runtimeReport = ctx.platformEnv.runtime;\r\n\r\n const os = ctx.platformEnv.platform.os;\r\n\r\n return {\r\n data: { os: os.family, arch: os.architecture.name, version: os.version },\r\n summary: `Platform: ${os.family} ${os.architecture.name} (${os.version})`,\r\n };\r\n}\r\n\r\nasync function executeCheckPrerequisites(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n): Promise<StepOutput> {\r\n const runtime = ctx.runtimeReport ?? ctx.platformEnv?.runtime;\r\n\r\n if (!runtime) {\r\n throw new Error('Platform detection must complete before prerequisite check.');\r\n }\r\n\r\n if (!runtime.allRequirementsMet) {\r\n const errorMessages = runtime.errors.map(e => e.message);\r\n const fixMessages = runtime.errors.map(e => e.fix);\r\n\r\n throw new Error(\r\n 'Runtime requirements not met:\\n' +\r\n errorMessages.map((msg, i) => ` - ${msg}\\n Fix: ${fixMessages[i]}`).join('\\n'),\r\n );\r\n }\r\n\r\n const nodeVersion = runtime.node.version.raw;\r\n const npmVersion = runtime.npm?.version.raw ?? 'not detected';\r\n\r\n return {\r\n data: { nodeVersion, npmVersion },\r\n summary: `Node.js ${nodeVersion}, npm ${npmVersion}`,\r\n };\r\n}\r\n\r\nasync function executeShowBanner(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n if (!theme) {\r\n // No theme means we're in plain mode\r\n console.log('\\n SixSevenAI - AI-DLC Framework Installer\\n');\r\n return { data: {}, summary: 'Banner displayed (plain)' };\r\n }\r\n\r\n const lines = renderBanner(INSTALLER_VERSION, theme);\r\n for (const line of lines) {\r\n console.log(line);\r\n }\r\n\r\n promptIntro(`SixSevenAI Installer v${INSTALLER_VERSION}`);\r\n\r\n return { data: {}, summary: 'Banner displayed' };\r\n}\r\n\r\nasync function executeSelectDirectory(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n // If --target was provided, use it\r\n if (options.target) {\r\n ctx.targetDirectory = path.resolve(options.target);\r\n ctx.claudeDirectory = path.join(ctx.targetDirectory, CLAUDE_DIRECTORY_NAME);\r\n return {\r\n data: { targetDirectory: ctx.targetDirectory },\r\n summary: `Target: ${ctx.targetDirectory} (from --target)`,\r\n };\r\n }\r\n\r\n // Interactive directory selection\r\n if (!ctx.platformEnv) {\r\n throw new Error('Platform detection must complete before directory selection.');\r\n }\r\n\r\n if (!theme) {\r\n // Non-interactive fallback: use current directory\r\n ctx.targetDirectory = process.cwd();\r\n ctx.claudeDirectory = path.join(ctx.targetDirectory, CLAUDE_DIRECTORY_NAME);\r\n return {\r\n data: { targetDirectory: ctx.targetDirectory },\r\n summary: `Target: ${ctx.targetDirectory} (default)`,\r\n };\r\n }\r\n\r\n const dirOptions = buildDirectoryOptions(ctx.platformEnv);\r\n const selection = await promptDirectorySelection(dirOptions, theme);\r\n\r\n ctx.targetDirectory = path.resolve(selection.path);\r\n ctx.claudeDirectory = path.join(ctx.targetDirectory, CLAUDE_DIRECTORY_NAME);\r\n\r\n return {\r\n data: { targetDirectory: ctx.targetDirectory, isCustom: selection.isCustom },\r\n summary: `Target: ${ctx.targetDirectory}`,\r\n };\r\n}\r\n\r\nasync function executeScanSource(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n): Promise<StepOutput> {\r\n const spinner = new SixSevenSpinner({ quiet: options.quiet });\r\n spinner.start('Scanning source components...');\r\n\r\n ctx.manifest = await scanSourceDirectory(ctx.sourceDirectory);\r\n\r\n spinner.stop(`${ctx.manifest.totalCount} components found`);\r\n\r\n verboseLog(options.verbose, `Scanned ${ctx.manifest.totalCount} components from ${ctx.sourceDirectory}`);\r\n verboseLog(options.verbose, ` Agents: ${ctx.manifest.countsByType.agents}`);\r\n verboseLog(options.verbose, ` Skills: ${ctx.manifest.countsByType.skills}`);\r\n verboseLog(options.verbose, ` Commands: ${ctx.manifest.countsByType.commands}`);\r\n\r\n return {\r\n data: {\r\n totalCount: ctx.manifest.totalCount,\r\n countsByType: ctx.manifest.countsByType,\r\n },\r\n summary: `${ctx.manifest.totalCount} components scanned`,\r\n };\r\n}\r\n\r\nasync function executeDetectConflicts(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n if (!ctx.manifest || !ctx.claudeDirectory) {\r\n throw new Error('Source scan and directory selection must complete before conflict detection.');\r\n }\r\n\r\n // T2.3.1: Fresh install with --custom — skip conflict detection entirely\r\n if (options.custom) {\r\n let claudeDirExists = false;\r\n try {\r\n await stat(ctx.claudeDirectory);\r\n claudeDirExists = true;\r\n } catch {\r\n claudeDirExists = false;\r\n }\r\n if (!claudeDirExists) {\r\n verboseLog(options.verbose, 'Fresh install with --custom, skipping conflict detection');\r\n return {\r\n data: { skipped: true, reason: 'fresh-install-custom' },\r\n summary: 'Conflict detection skipped (fresh install with --custom)',\r\n };\r\n }\r\n }\r\n\r\n const spinner = new SixSevenSpinner({ quiet: options.quiet });\r\n spinner.start('Checking for existing files...');\r\n\r\n ctx.conflictReport = await detectConflicts(\r\n ctx.manifest,\r\n ctx.sourceDirectory,\r\n ctx.claudeDirectory,\r\n );\r\n\r\n spinner.stop(\r\n ctx.conflictReport.hasConflicts\r\n ? `${ctx.conflictReport.modifiedCount} modified, ${ctx.conflictReport.identicalCount} unchanged, ${ctx.conflictReport.newCount} new`\r\n : ctx.conflictReport.identicalCount > 0\r\n ? `${ctx.conflictReport.identicalCount} files up to date, ${ctx.conflictReport.newCount} new`\r\n : `${ctx.conflictReport.newCount} new files to install`,\r\n );\r\n\r\n return {\r\n data: {\r\n hasConflicts: ctx.conflictReport.hasConflicts,\r\n newCount: ctx.conflictReport.newCount,\r\n identicalCount: ctx.conflictReport.identicalCount,\r\n modifiedCount: ctx.conflictReport.modifiedCount,\r\n },\r\n summary: ctx.conflictReport.hasConflicts\r\n ? `${ctx.conflictReport.modifiedCount} conflict(s) found`\r\n : 'No conflicts',\r\n };\r\n}\r\n\r\nasync function executeSelectOverwriteMode(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n if (!ctx.claudeDirectory) {\r\n throw new Error('Directory selection must complete before overwrite mode selection.');\r\n }\r\n\r\n // T2.3.1: Fresh install with --custom — no existing .claude/, skip overwrite mode\r\n let claudeDirExists = false;\r\n try {\r\n await stat(ctx.claudeDirectory);\r\n claudeDirExists = true;\r\n } catch {\r\n claudeDirExists = false;\r\n }\r\n\r\n if (!claudeDirExists && options.custom) {\r\n ctx.overwriteMode = 'all';\r\n return {\r\n data: { mode: 'all', reason: 'fresh-install-custom' },\r\n summary: 'Fresh install with --custom, no overwrite needed',\r\n };\r\n }\r\n\r\n // T2.3.2: Non-interactive --overwrite array provided via CLI\r\n if (options.overwrite.length > 0) {\r\n ctx.selectedCategories = resolveCategories(options.overwrite as string[]);\r\n ctx.overwriteMode = 'choose';\r\n return {\r\n data: { mode: 'choose', categories: ctx.selectedCategories },\r\n summary: `Overwrite mode: choose (${ctx.selectedCategories.length} categories from CLI)`,\r\n };\r\n }\r\n\r\n // T2.3.3: --profile provided — load profile and map to category IDs\r\n if (options.profile) {\r\n const profileCategories = await loadProfileCategories(options.profile);\r\n ctx.selectedCategories = profileCategories;\r\n ctx.overwriteMode = 'choose';\r\n return {\r\n data: { mode: 'choose', profile: options.profile, categories: profileCategories },\r\n summary: `Overwrite mode: choose (profile \"${options.profile}\", ${profileCategories.length} categories)`,\r\n };\r\n }\r\n\r\n // No conflict report yet means detect-conflicts was skipped (e.g. fresh install)\r\n if (!ctx.conflictReport) {\r\n ctx.overwriteMode = 'all';\r\n return {\r\n data: { mode: 'all', reason: 'no-conflicts-detected' },\r\n summary: 'No conflicts detected, installing all',\r\n };\r\n }\r\n\r\n // All existing files identical — prompt to continue\r\n if (ctx.conflictReport.identicalCount > 0 && !ctx.conflictReport.hasConflicts) {\r\n if (theme) {\r\n const totalExisting = ctx.conflictReport.identicalCount;\r\n const newCount = ctx.conflictReport.newCount;\r\n const continueInstall = await promptConfirmation(\r\n `All ${totalExisting} existing files are up to date. No changes detected.${newCount > 0 ? ` ${newCount} new file(s) to install.` : ''} Continue?`,\r\n newCount > 0,\r\n );\r\n if (!continueInstall) {\r\n throw new UserCancellationError('User declined to continue — no changes needed.');\r\n }\r\n }\r\n ctx.overwriteMode = 'all';\r\n return {\r\n data: { mode: 'all', reason: 'all-identical' },\r\n summary: 'All existing files up to date',\r\n };\r\n }\r\n\r\n // Modified files detected — prompt for overwrite strategy\r\n if (ctx.conflictReport.hasConflicts && theme) {\r\n const mode: OverwriteMode = await promptOverwriteMode(ctx.claudeDirectory);\r\n ctx.overwriteMode = mode;\r\n\r\n // Create backup when mode is 'all' or 'choose'\r\n if (mode === 'all' || mode === 'choose') {\r\n try {\r\n ctx.backupManifest = await createBackup(\r\n ctx.claudeDirectory,\r\n ctx.conflictReport.modifiedFiles,\r\n );\r\n if (ctx.backupManifest) {\r\n verboseLog(\r\n options.verbose,\r\n `Backed up ${ctx.backupManifest.files.length} files to ${ctx.backupManifest.backupDirectory}`,\r\n );\r\n }\r\n } catch (backupError) {\r\n verboseLog(options.verbose, `Backup warning: ${backupError instanceof Error ? backupError.message : String(backupError)}`);\r\n }\r\n }\r\n\r\n return {\r\n data: { mode },\r\n summary: `Overwrite mode: ${mode}`,\r\n };\r\n }\r\n\r\n // Default: overwrite all (non-interactive or no conflicts)\r\n ctx.overwriteMode = 'all';\r\n return {\r\n data: { mode: 'all', reason: 'default' },\r\n summary: 'Overwrite mode: all (default)',\r\n };\r\n}\r\n\r\nasync function executeSelectCategories(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n // T2.3.2: Non-interactive --overwrite already resolved categories in select-overwrite-mode\r\n if (options.overwrite.length > 0 && ctx.selectedCategories.length > 0) {\r\n // Categories already set, apply filtering\r\n ctx.fileMappings = applySelectedCategoryFilter(ctx);\r\n return {\r\n data: { categories: ctx.selectedCategories, source: 'cli-overwrite' },\r\n summary: `${ctx.selectedCategories.length} categories selected via --overwrite`,\r\n };\r\n }\r\n\r\n // T2.3.3: --profile already resolved categories in select-overwrite-mode\r\n if (options.profile && ctx.selectedCategories.length > 0) {\r\n ctx.fileMappings = applySelectedCategoryFilter(ctx);\r\n return {\r\n data: { categories: ctx.selectedCategories, source: 'profile' },\r\n summary: `${ctx.selectedCategories.length} categories selected via --profile \"${options.profile}\"`,\r\n };\r\n }\r\n\r\n // If overwrite mode is not 'choose', no category selection needed\r\n if (ctx.overwriteMode !== 'choose') {\r\n return {\r\n data: { skipped: true, reason: `overwrite-mode-${ctx.overwriteMode ?? 'null'}` },\r\n summary: `Category selection skipped (mode: ${ctx.overwriteMode ?? 'all'})`,\r\n };\r\n }\r\n\r\n // Interactive category selection\r\n if (!theme) {\r\n return {\r\n data: { skipped: true, reason: 'non-interactive' },\r\n summary: 'Category selection skipped (non-interactive)',\r\n };\r\n }\r\n\r\n // Determine which categories have modified files\r\n const modifiedSet = new Set(\r\n (ctx.conflictReport?.modifiedFiles ?? []).map((p) => p.replace(/\\\\/g, '/')),\r\n );\r\n\r\n const modifiedCategoryIds: string[] = INSTALL_CATEGORIES\r\n .filter((cat) =>\r\n [...modifiedSet].some((fp) => fp.startsWith(cat.pathPrefix)),\r\n )\r\n .map((cat) => cat.id);\r\n\r\n const categoryOptions = INSTALL_CATEGORIES.map((cat) => ({\r\n value: cat.id,\r\n label: cat.label,\r\n hint: cat.hint,\r\n }));\r\n\r\n ctx.selectedCategories = await promptCategorySelection(\r\n categoryOptions,\r\n modifiedCategoryIds,\r\n );\r\n\r\n // T2.2.3 / T2.4.1: Apply category filter to build filtered mappings\r\n ctx.fileMappings = applySelectedCategoryFilter(ctx);\r\n\r\n return {\r\n data: { categories: ctx.selectedCategories, count: ctx.fileMappings.length },\r\n summary: `${ctx.selectedCategories.length} categories selected, ${ctx.fileMappings.length} files to install`,\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helper: Apply Category Filter to File Mappings\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Build and filter file mappings based on selected categories.\r\n * Stores the filtered result in ctx.fileMappings.\r\n */\r\nfunction applySelectedCategoryFilter(ctx: InstallationContext): FileMapping[] {\r\n if (!ctx.manifest || !ctx.claudeDirectory) {\r\n return [];\r\n }\r\n\r\n const allMappings = buildFileMappings(ctx.manifest, ctx.sourceDirectory, ctx.claudeDirectory);\r\n return filterMappingsByCategories(allMappings, ctx.selectedCategories);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helper: Load Profile Categories\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Load a profile from tools/installer/profiles.json and map its component\r\n * lists to install category IDs.\r\n */\r\nasync function loadProfileCategories(profileName: string): Promise<string[]> {\r\n // Try multiple locations for profiles.json\r\n const candidatePaths = [\r\n path.resolve(process.cwd(), 'tools', 'installer', 'profiles.json'),\r\n path.resolve(process.cwd(), 'profiles.json'),\r\n ];\r\n\r\n let profileData: Record<string, unknown> | null = null;\r\n for (const candidate of candidatePaths) {\r\n try {\r\n const raw = await readFile(candidate, 'utf-8');\r\n profileData = JSON.parse(raw) as Record<string, unknown>;\r\n break;\r\n } catch {\r\n continue;\r\n }\r\n }\r\n\r\n if (!profileData) {\r\n throw new Error(\r\n `Could not locate profiles.json. Searched: ${candidatePaths.join(', ')}`,\r\n );\r\n }\r\n\r\n const profiles = profileData['profiles'] as Record<string, Record<string, unknown>> | undefined;\r\n if (!profiles || !profiles[profileName]) {\r\n const available = profiles ? Object.keys(profiles).join(', ') : 'none';\r\n throw new Error(\r\n `Unknown profile \"${profileName}\". Available profiles: ${available}`,\r\n );\r\n }\r\n\r\n const profile = profiles[profileName];\r\n const categoryIds: string[] = [];\r\n\r\n // Map profile component keys to install category IDs\r\n // A wildcard \"*\" means include the category\r\n // An array means the category has specific items (still include it)\r\n const keyToCategoryMap: Record<string, string> = {\r\n agents: 'agents',\r\n skills: 'skills',\r\n templates: 'templates',\r\n docs: 'docs',\r\n };\r\n\r\n for (const [key, catId] of Object.entries(keyToCategoryMap)) {\r\n const value = profile[key];\r\n if (value === '*' || (Array.isArray(value) && value.length > 0)) {\r\n categoryIds.push(catId);\r\n }\r\n }\r\n\r\n // Commands are split into sub-categories in INSTALL_CATEGORIES\r\n const commands = profile['commands'];\r\n if (commands === '*') {\r\n // Include all command categories\r\n for (const cat of INSTALL_CATEGORIES) {\r\n if (cat.id.startsWith('commands/') && !categoryIds.includes(cat.id)) {\r\n categoryIds.push(cat.id);\r\n }\r\n }\r\n } else if (Array.isArray(commands) && commands.length > 0) {\r\n // Include all command categories (profile lists command names, not sub-paths)\r\n for (const cat of INSTALL_CATEGORIES) {\r\n if (cat.id.startsWith('commands/') && !categoryIds.includes(cat.id)) {\r\n categoryIds.push(cat.id);\r\n }\r\n }\r\n }\r\n\r\n // Include ai-dlc core and memory if referenced\r\n if (profile['metadata'] === '*' || profile['workflows'] === '*') {\r\n if (!categoryIds.includes('ai-dlc')) {\r\n categoryIds.push('ai-dlc');\r\n }\r\n }\r\n\r\n if (profile['rules'] === '*') {\r\n // Rules don't have a separate category in INSTALL_CATEGORIES but\r\n // we include scripts as a proxy for rule-related files\r\n if (!categoryIds.includes('scripts')) {\r\n categoryIds.push('scripts');\r\n }\r\n }\r\n\r\n return categoryIds;\r\n}\r\n\r\nasync function executeConfirmInstallation(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n if (!ctx.manifest) {\r\n throw new Error('Source scan must complete before confirmation.');\r\n }\r\n\r\n const target = ctx.claudeDirectory ?? ctx.targetDirectory ?? 'unknown';\r\n\r\n // Show accurate count: use pre-filtered mappings when available\r\n let fileCount: number;\r\n if (ctx.fileMappings.length > 0 && (ctx.overwriteMode === 'choose' || ctx.selectedCategories.length > 0)) {\r\n // Mappings were already filtered in select-categories step\r\n fileCount = ctx.fileMappings.length;\r\n } else if (ctx.overwriteMode === 'choose' && ctx.selectedCategories.length > 0) {\r\n const previewMappings = buildFileMappings(ctx.manifest, ctx.sourceDirectory, ctx.claudeDirectory ?? target);\r\n fileCount = filterMappingsByCategories(previewMappings, ctx.selectedCategories).length;\r\n } else if (ctx.overwriteMode === 'none' && ctx.conflictReport) {\r\n fileCount = ctx.manifest.totalCount - ctx.conflictReport.existingFiles.length;\r\n } else {\r\n fileCount = ctx.manifest.totalCount;\r\n }\r\n\r\n const confirmed = await promptConfirmation(\r\n `Install ${fileCount} files to ${target}?`,\r\n true,\r\n );\r\n\r\n if (!confirmed) {\r\n throw new UserCancellationError('User declined installation.');\r\n }\r\n\r\n return {\r\n data: { confirmed: true },\r\n summary: 'Installation confirmed',\r\n };\r\n}\r\n\r\nasync function executeInstallFiles(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n if (!ctx.manifest || !ctx.claudeDirectory) {\r\n throw new Error('Source scan and directory selection must complete before installation.');\r\n }\r\n\r\n // T2.4.2: Use pre-filtered mappings from select-categories when available\r\n if (ctx.fileMappings.length > 0 && (ctx.overwriteMode === 'choose' || (options.custom && ctx.selectedCategories.length > 0))) {\r\n // Mappings were already filtered in executeSelectCategories — use as-is\r\n verboseLog(options.verbose, `Using ${ctx.fileMappings.length} pre-filtered file mappings`);\r\n } else {\r\n // Build file mappings from full manifest\r\n ctx.fileMappings = buildFileMappings(ctx.manifest, ctx.sourceDirectory, ctx.claudeDirectory);\r\n\r\n // Apply overwrite-mode filtering before copying\r\n if (ctx.overwriteMode === 'none' && ctx.conflictReport) {\r\n // Keep only new files — filter out everything that already exists at target\r\n const existingSet = new Set(\r\n ctx.conflictReport.existingFiles.map((p) => p.replace(/\\\\/g, '/')),\r\n );\r\n ctx.fileMappings = ctx.fileMappings.filter(\r\n (m) => !existingSet.has(m.relativePath.replace(/\\\\/g, '/')),\r\n );\r\n } else if (ctx.overwriteMode === 'choose' && ctx.selectedCategories.length > 0) {\r\n // Only install files matching the selected categories\r\n ctx.fileMappings = filterMappingsByCategories(\r\n ctx.fileMappings,\r\n ctx.selectedCategories,\r\n );\r\n }\r\n // 'all' or null: no filtering needed — keep all mappings\r\n }\r\n\r\n if (options.dryRun) {\r\n return {\r\n data: { dryRun: true, fileCount: ctx.fileMappings.length },\r\n summary: `[dry-run] Would install ${ctx.fileMappings.length} files`,\r\n };\r\n }\r\n\r\n // Create spinner for animated progress feedback\r\n const spinner = new SixSevenSpinner({ quiet: options.quiet });\r\n\r\n // Create progress tracker if theme available\r\n let progressTracker: ProgressTracker | null = null;\r\n if (theme && !options.quiet) {\r\n progressTracker = new ProgressTracker();\r\n progressTracker.addStep({ id: 'copy-files', label: `Installing ${ctx.fileMappings.length} files` });\r\n progressTracker.start();\r\n progressTracker.startStep('copy-files');\r\n }\r\n\r\n // Execute file copy\r\n spinner.start('Installing AI-DLC framework...');\r\n\r\n const result = await copyFiles(ctx.fileMappings, {\r\n concurrency: 16,\r\n onProgress: (event) => {\r\n spinner.updateProgress(event.current, event.total, event.fileName);\r\n verboseLog(\r\n options.verbose,\r\n ` [${event.current}/${event.total}] ${event.fileName}`,\r\n );\r\n },\r\n });\r\n\r\n spinner.stop('Framework files installed');\r\n\r\n // Track merged totals (since InstallationResult is readonly)\r\n let totalCopied = result.copiedCount;\r\n let totalSkipped = result.skippedCount;\r\n const allErrors = [...result.errors];\r\n let overallSuccess = result.success;\r\n\r\n // Also install .ai-dlc framework files\r\n // Skip ai-dlc config files when overwrite mode is 'none' or 'choose' —\r\n // these are infrastructure config files that don't belong to any user-selectable category.\r\n // Only copy them on fresh install (null) or when overwriting everything ('all').\r\n const shouldCopyAiDlcFiles = ctx.overwriteMode === null || ctx.overwriteMode === 'all';\r\n const aiDlcSourceDir = shouldCopyAiDlcFiles ? await resolveAiDlcSourceDirectory() : null;\r\n if (aiDlcSourceDir) {\r\n const targetRoot = path.dirname(ctx.claudeDirectory!);\r\n const aiDlcTargetDir = path.join(targetRoot, '.ai-dlc');\r\n\r\n const aiDlcManifest = await scanSourceDirectory(aiDlcSourceDir);\r\n const aiDlcMappings: FileMapping[] = aiDlcManifest.entries.map(entry => ({\r\n relativePath: entry.relativePath,\r\n sourcePath: path.join(aiDlcSourceDir, entry.relativePath),\r\n destinationPath: path.join(aiDlcTargetDir, entry.relativePath),\r\n componentType: entry.componentType,\r\n fileName: entry.fileName,\r\n sizeBytes: entry.sizeBytes,\r\n }));\r\n\r\n spinner.start('Installing .ai-dlc configuration...');\r\n\r\n const aiDlcResult = await copyFiles(aiDlcMappings, {\r\n concurrency: 16,\r\n onProgress: (event) => {\r\n spinner.updateProgress(event.current, event.total, event.fileName);\r\n verboseLog(options.verbose, ` [ai-dlc ${event.current}/${event.total}] ${event.fileName}`);\r\n },\r\n });\r\n\r\n spinner.stop('Configuration files installed');\r\n\r\n // Merge results\r\n totalCopied += aiDlcResult.copiedCount;\r\n totalSkipped += aiDlcResult.skippedCount;\r\n allErrors.push(...aiDlcResult.errors);\r\n if (!aiDlcResult.success) {\r\n overallSuccess = false;\r\n }\r\n\r\n // Add to file mappings for validation\r\n ctx.fileMappings.push(...aiDlcMappings);\r\n }\r\n\r\n // Build merged result for context\r\n ctx.installationResult = {\r\n success: overallSuccess,\r\n copiedCount: totalCopied,\r\n skippedCount: totalSkipped,\r\n warnings: result.warnings,\r\n errors: allErrors,\r\n durationMs: result.durationMs,\r\n componentCounts: result.componentCounts,\r\n };\r\n\r\n // Generate ai-dlc-installation.json metadata\r\n if (overallSuccess) {\r\n try {\r\n const targetRoot = path.dirname(ctx.claudeDirectory!);\r\n const aiDlcDir = path.join(targetRoot, '.ai-dlc');\r\n await mkdir(aiDlcDir, { recursive: true });\r\n\r\n // Extract component lists from file mappings\r\n const agentNames = ctx.fileMappings\r\n .filter(m => m.relativePath.match(/^agents[/\\\\][^/\\\\]+\\.md$/))\r\n .map(m => path.basename(m.fileName, '.md'))\r\n .sort();\r\n\r\n const skillNames = [...new Set(\r\n ctx.fileMappings\r\n .filter(m => m.relativePath.match(/^skills[/\\\\]/))\r\n .map(m => m.relativePath.replace(/\\\\/g, '/').split('/')[1])\r\n )].sort();\r\n\r\n const commandNames = ctx.fileMappings\r\n .filter(m => m.relativePath.match(/^commands[/\\\\].*\\.md$/))\r\n .map(m => {\r\n const parts = m.relativePath.replace(/\\\\/g, '/').split('/');\r\n if (parts.length === 3) {\r\n return `${parts[1]}:${path.basename(parts[2], '.md')}`;\r\n }\r\n return path.basename(m.fileName, '.md');\r\n })\r\n .sort();\r\n\r\n const totalSizeBytes = ctx.fileMappings.reduce((sum, m) => sum + m.sizeBytes, 0);\r\n\r\n const installationMetadata = {\r\n installation: {\r\n version: INSTALLER_VERSION,\r\n installedBy: 'sixsevenai-installer',\r\n sourceRoot: 'npm:@sixsevenai/ai-dlc-installer',\r\n profile: 'npm-global',\r\n backupLocation: '',\r\n projectRoot: ctx.targetDirectory ?? targetRoot,\r\n installedDate: new Date().toISOString(),\r\n },\r\n components: {\r\n commands: { count: commandNames.length, installed: commandNames },\r\n agents: { count: agentNames.length, installed: agentNames },\r\n skills: { count: skillNames.length, installed: skillNames },\r\n },\r\n statistics: {\r\n filesSkipped: totalSkipped,\r\n totalSizeBytes,\r\n totalSizeMB: Math.round(totalSizeBytes / (1024 * 1024) * 100) / 100,\r\n filesProcessed: totalCopied,\r\n },\r\n };\r\n\r\n const metadataPath = path.join(aiDlcDir, 'ai-dlc-installation.json');\r\n await writeFile(metadataPath, JSON.stringify(installationMetadata, null, 2), 'utf-8');\r\n verboseLog(options.verbose, `Installation metadata written to ${metadataPath}`);\r\n } catch (metadataError) {\r\n // Non-fatal: log warning but don't fail the installation\r\n verboseLog(\r\n options.verbose,\r\n `Warning: Could not write installation metadata: ${metadataError instanceof Error ? metadataError.message : String(metadataError)}`,\r\n );\r\n }\r\n }\r\n\r\n // Complete progress\r\n if (progressTracker) {\r\n if (overallSuccess) {\r\n progressTracker.completeStep('copy-files');\r\n } else {\r\n progressTracker.failStep('copy-files', { message: 'File copy failed', cause: null });\r\n }\r\n progressTracker.finish();\r\n }\r\n\r\n if (!overallSuccess) {\r\n const errorMessages = allErrors.map(e => e.message).join('; ');\r\n throw new Error(`File installation failed: ${errorMessages}`);\r\n }\r\n\r\n return {\r\n data: {\r\n copiedCount: totalCopied,\r\n skippedCount: totalSkipped,\r\n errorCount: allErrors.length,\r\n },\r\n summary: `${totalCopied} files installed, ${totalSkipped} skipped`,\r\n };\r\n}\r\n\r\nasync function executeValidateInstallation(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n): Promise<StepOutput> {\r\n if (!ctx.fileMappings || ctx.fileMappings.length === 0) {\r\n // Skip validation if dry-run or no files were copied\r\n return {\r\n data: { valid: true, skipped: true },\r\n summary: 'Validation skipped (no files to validate)',\r\n };\r\n }\r\n\r\n ctx.validationReport = await validateInstallation(ctx.fileMappings);\r\n\r\n if (!ctx.validationReport.valid) {\r\n const missing = ctx.validationReport.missingFiles;\r\n const invalid = ctx.validationReport.invalidFiles;\r\n throw new Error(\r\n `Installation validation failed: ` +\r\n `${missing.length} missing file(s), ` +\r\n `${invalid.length} invalid file(s)`,\r\n );\r\n }\r\n\r\n return {\r\n data: {\r\n valid: true,\r\n totalChecked: ctx.validationReport.totalChecked,\r\n validCount: ctx.validationReport.validCount,\r\n },\r\n summary: `${ctx.validationReport.validCount} files validated`,\r\n };\r\n}\r\n\r\nasync function executeShowSummary(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n // Build summary using actual workflow results\r\n // We use a simplified state here since we don't track full WorkflowState in scope\r\n const elapsed = Date.now() - (ctx.installationResult ? Date.now() : Date.now());\r\n\r\n const summary: InstallationSummary = {\r\n success: ctx.installationResult?.success ?? true,\r\n targetDirectory: ctx.targetDirectory ?? 'unknown',\r\n componentCounts: {\r\n agents: ctx.manifest?.countsByType.agents ?? 0,\r\n skills: ctx.manifest?.countsByType.skills ?? 0,\r\n commands: ctx.manifest?.countsByType.commands ?? 0,\r\n cliFiles: ctx.manifest?.countsByType.cli ?? 0,\r\n other: (ctx.manifest?.countsByType.workflows ?? 0) + (ctx.manifest?.countsByType.metadata ?? 0),\r\n },\r\n totalDuration: formatDuration(0), // Will be updated by caller\r\n totalFilesCopied: ctx.installationResult?.copiedCount ?? 0,\r\n totalFilesSkipped: ctx.installationResult?.skippedCount ?? 0,\r\n totalFilesFailed: ctx.installationResult?.errors.length ?? 0,\r\n installerVersion: INSTALLER_VERSION,\r\n };\r\n\r\n const nextSteps = getDefaultNextSteps(summary.success);\r\n\r\n if (theme && !options.quiet) {\r\n const lines = renderSummary(summary, nextSteps, theme);\r\n for (const line of lines) {\r\n console.log(line);\r\n }\r\n\r\n if (summary.success) {\r\n promptOutro('Installation complete!');\r\n }\r\n } else if (!options.quiet) {\r\n // Plain text summary\r\n console.log('\\n--- Installation Summary ---');\r\n console.log(` Status: ${summary.success ? 'Success' : 'Failed'}`);\r\n console.log(` Files installed: ${summary.totalFilesCopied}`);\r\n console.log(` Files skipped: ${summary.totalFilesSkipped}`);\r\n console.log(` Target: ${summary.targetDirectory}`);\r\n if (summary.success) {\r\n console.log('\\n Next steps:');\r\n for (const step of nextSteps) {\r\n console.log(` ${step.order}. ${step.title}`);\r\n if (step.command) {\r\n console.log(` $ ${step.command}`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return {\r\n data: { success: summary.success },\r\n summary: summary.success ? 'Installation successful' : 'Installation completed with errors',\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Rollback Helper\r\n// ---------------------------------------------------------------------------\r\n\r\nasync function attemptRollback(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n): Promise<void> {\r\n if (!ctx.backupManifest || !ctx.claudeDirectory) {\r\n verboseLog(options.verbose, 'No backup available for rollback.');\r\n return;\r\n }\r\n\r\n try {\r\n verboseLog(options.verbose, 'Rolling back installation...');\r\n const rollbackResult = await restoreFromBackup(ctx.backupManifest, ctx.claudeDirectory);\r\n if (rollbackResult.success) {\r\n verboseLog(options.verbose, `Rollback complete: ${rollbackResult.restoredCount} files restored.`);\r\n } else {\r\n const errorMessages = rollbackResult.errors.map(e => e.message).join('; ');\r\n console.error(`Rollback encountered errors: ${errorMessages}`);\r\n }\r\n } catch (error) {\r\n console.error(\r\n `Rollback failed: ${error instanceof Error ? error.message : String(error)}`,\r\n );\r\n }\r\n}\r\n","/**\r\n * CLI Orchestrator - Shared Types\r\n *\r\n * Workflow state, installation context, error classification, and\r\n * configuration types used by the orchestration layer.\r\n *\r\n * @module orchestrator/types\r\n */\r\n\r\nimport type {\r\n ComponentManifest,\r\n ConflictReport,\r\n BackupManifest,\r\n InstallationResult,\r\n ValidationReport,\r\n FileMapping,\r\n} from '../engine/index.js';\r\n\r\nimport type {\r\n PlatformEnvironment,\r\n RuntimeReport,\r\n} from '../platform/index.js';\r\n\r\nimport type {\r\n TerminalCapabilities,\r\n InstallationSummary,\r\n Duration,\r\n} from '../ui/index.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Overwrite Mode\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Controls how existing files are handled during installation. */\r\nexport type OverwriteMode = 'all' | 'none' | 'choose';\r\n\r\n// ---------------------------------------------------------------------------\r\n// CLI Options\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Parsed and validated CLI options. */\r\nexport interface CLIOptions {\r\n readonly command: CLICommand;\r\n readonly target: string | null;\r\n readonly force: boolean;\r\n readonly dryRun: boolean;\r\n readonly verbose: boolean;\r\n readonly noColor: boolean;\r\n readonly quiet: boolean;\r\n readonly overwrite: readonly string[];\r\n readonly custom: boolean;\r\n readonly profile: string | null;\r\n readonly rawArgs: readonly string[];\r\n}\r\n\r\n/** Top-level CLI command type. */\r\nexport type CLICommand = 'install' | 'help' | 'version';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Exit Codes\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Process exit codes with defined semantics. */\r\nexport type ExitCode = 0 | 1 | 2;\r\n\r\nexport const EXIT_SUCCESS: ExitCode = 0;\r\nexport const EXIT_ERROR: ExitCode = 1;\r\nexport const EXIT_CANCELLED: ExitCode = 2;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Workflow Status\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Lifecycle status of the installation workflow. */\r\nexport type WorkflowStatus =\r\n | 'pending'\r\n | 'running'\r\n | 'completed'\r\n | 'failed'\r\n | 'cancelled';\r\n\r\n/** Lifecycle status of a single workflow step. */\r\nexport type StepStatus =\r\n | 'pending'\r\n | 'running'\r\n | 'completed'\r\n | 'failed'\r\n | 'skipped';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Workflow Step Definitions\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Identifier for a workflow step. */\r\nexport type WorkflowStepId =\r\n | 'detect-platform'\r\n | 'check-prerequisites'\r\n | 'show-banner'\r\n | 'select-directory'\r\n | 'scan-source'\r\n | 'detect-conflicts'\r\n | 'select-overwrite-mode'\r\n | 'select-categories'\r\n | 'confirm-installation'\r\n | 'execute-installation'\r\n | 'validate-installation'\r\n | 'show-summary';\r\n\r\n/** Definition of a single workflow step. */\r\nexport interface WorkflowStepDef {\r\n readonly id: WorkflowStepId;\r\n readonly name: string;\r\n readonly order: number;\r\n readonly isSkippable: boolean;\r\n}\r\n\r\n/** Runtime state of a single workflow step. */\r\nexport interface WorkflowStepState {\r\n readonly def: WorkflowStepDef;\r\n status: StepStatus;\r\n output: StepOutput | null;\r\n error: Error | null;\r\n startedAt: number | null;\r\n completedAt: number | null;\r\n}\r\n\r\n/** Output produced by a completed step. */\r\nexport interface StepOutput {\r\n readonly data: Record<string, unknown>;\r\n readonly summary: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Workflow State\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Complete state of the installation workflow. */\r\nexport interface WorkflowState {\r\n status: WorkflowStatus;\r\n readonly steps: WorkflowStepState[];\r\n currentStepId: WorkflowStepId | null;\r\n startedAt: number | null;\r\n completedAt: number | null;\r\n cancellationReason: string | null;\r\n}\r\n\r\n/** Progress metrics for the workflow. */\r\nexport interface WorkflowProgress {\r\n readonly completedSteps: number;\r\n readonly totalSteps: number;\r\n readonly percentage: number;\r\n readonly currentStepName: string;\r\n readonly elapsedTime: Duration;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Installation Context (accumulated during workflow)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Runtime context assembled during workflow execution. */\r\nexport interface InstallationContext {\r\n platformEnv: PlatformEnvironment | null;\r\n terminalCapabilities: TerminalCapabilities | null;\r\n runtimeReport: RuntimeReport | null;\r\n targetDirectory: string | null;\r\n claudeDirectory: string | null;\r\n sourceDirectory: string;\r\n manifest: ComponentManifest | null;\r\n conflictReport: ConflictReport | null;\r\n backupManifest: BackupManifest | null;\r\n installationResult: InstallationResult | null;\r\n validationReport: ValidationReport | null;\r\n fileMappings: FileMapping[];\r\n overwriteMode: OverwriteMode | null;\r\n selectedCategories: string[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Installation Config\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Resolved configuration for the installation. */\r\nexport interface InstallationConfig {\r\n readonly targetDirectory: string;\r\n readonly claudeDirectory: string;\r\n readonly sourceDirectory: string;\r\n readonly forceOverwrite: boolean;\r\n readonly dryRunMode: boolean;\r\n readonly verboseLogging: boolean;\r\n readonly colorEnabled: boolean;\r\n readonly interactiveMode: boolean;\r\n readonly maxConcurrency: number;\r\n readonly backupEnabled: boolean;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Error Classification\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Categories of errors that can occur during installation. */\r\nexport type ErrorCategory =\r\n | 'Permission'\r\n | 'DiskSpace'\r\n | 'InvalidPath'\r\n | 'RuntimeVersion'\r\n | 'ConflictResolution'\r\n | 'ValidationFailure'\r\n | 'IntegrityError'\r\n | 'InternalError'\r\n | 'Cancellation';\r\n\r\n/** Severity levels for classified errors. */\r\nexport type ErrorSeverity = 'Warning' | 'Recoverable' | 'Fatal';\r\n\r\n/** Recovery strategy for handling errors. */\r\nexport type RecoveryStrategy =\r\n | 'Retry'\r\n | 'RollbackAndAbort'\r\n | 'SkipAndContinue'\r\n | 'PromptUser'\r\n | 'AbortImmediately';\r\n\r\n/** An error classified with category, severity, and recovery strategy. */\r\nexport interface ClassifiedError {\r\n readonly errorId: string;\r\n readonly originalError: Error;\r\n readonly category: ErrorCategory;\r\n readonly severity: ErrorSeverity;\r\n readonly sourceStep: WorkflowStepId;\r\n readonly recoveryStrategy: RecoveryStrategy;\r\n readonly retryCount: number;\r\n readonly timestamp: Date;\r\n readonly userMessage: string;\r\n readonly technicalDetail: string;\r\n}\r\n\r\n/** Action to take when recovering from an error. */\r\nexport interface RecoveryAction {\r\n readonly strategy: RecoveryStrategy;\r\n readonly stepId: WorkflowStepId;\r\n readonly userGuidance: string;\r\n readonly platformGuidance: string | null;\r\n}\r\n\r\n/** Summary of all errors accumulated during the workflow. */\r\nexport interface ErrorSummaryInfo {\r\n readonly totalErrors: number;\r\n readonly fatalCount: number;\r\n readonly recoverableCount: number;\r\n readonly warningCount: number;\r\n readonly messages: readonly string[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Dry Run\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Report produced by dry-run mode. */\r\nexport interface DryRunReport {\r\n readonly filesToInstall: number;\r\n readonly filesToOverwrite: number;\r\n readonly conflictsDetected: number;\r\n readonly wouldSucceed: boolean;\r\n readonly details: readonly DryRunStepDetail[];\r\n}\r\n\r\n/** Detail for a single step in dry-run mode. */\r\nexport interface DryRunStepDetail {\r\n readonly stepId: string;\r\n readonly stepName: string;\r\n readonly result: string;\r\n readonly warnings: readonly string[];\r\n}\r\n","/**\r\n * CLI Orchestrator - Configuration\r\n *\r\n * Default configuration values, source directory resolution, and\r\n * the standard workflow step definitions.\r\n *\r\n * @module orchestrator/config\r\n */\r\n\r\nimport * as path from 'node:path';\r\nimport * as fs from 'node:fs/promises';\r\nimport { readFileSync } from 'node:fs';\r\nimport { fileURLToPath } from 'node:url';\r\n\r\nimport type {\r\n InstallationConfig,\r\n WorkflowStepDef,\r\n WorkflowStepId,\r\n CLIOptions,\r\n} from './types.js';\r\n\r\nimport type { PlatformEnvironment } from '../platform/index.js';\r\nimport type { TerminalCapabilities } from '../ui/index.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Package Version\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Installer version, dynamically read from package.json to stay in sync automatically. */\r\nexport const INSTALLER_VERSION: string = (() => {\r\n try {\r\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\r\n const pkgPath = path.resolve(__dirname, '../package.json');\r\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as { version: string };\r\n return pkg.version;\r\n } catch {\r\n return '0.0.0-unknown';\r\n }\r\n})();\r\n\r\n// ---------------------------------------------------------------------------\r\n// Default Configuration Values\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Default max parallel file copy operations. */\r\nexport const DEFAULT_MAX_CONCURRENCY = 16;\r\n\r\n/** Default target subdirectory name within the project. */\r\nexport const CLAUDE_DIRECTORY_NAME = '.claude';\r\n\r\n/**\r\n * Source library relative path from the compiled CLI entry point.\r\n * The bundled library is at `library/` in the package root.\r\n * Since the built CLI is at `dist/cli.js`, the relative path is `../library`.\r\n */\r\nconst SOURCE_LIBRARY_RELATIVE = '../library';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Source Directory Resolution\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Resolve the absolute path to the AI-DLC library source directory.\r\n *\r\n * Resolution order:\r\n * 1. AIDLC_SOURCE_DIR environment variable\r\n * 2. Relative path from this package root\r\n *\r\n * @returns Absolute path to the source library directory\r\n */\r\nexport async function resolveSourceDirectory(): Promise<string> {\r\n // Check environment variable first\r\n const envSource = process.env['AIDLC_SOURCE_DIR'];\r\n if (envSource) {\r\n try {\r\n const stat = await fs.stat(envSource);\r\n if (stat.isDirectory()) {\r\n return path.resolve(envSource);\r\n }\r\n } catch {\r\n // Fall through to default resolution\r\n }\r\n }\r\n\r\n // Resolve relative to this file's location\r\n const thisFile = fileURLToPath(import.meta.url);\r\n const thisDir = path.dirname(thisFile);\r\n const resolved = path.resolve(thisDir, SOURCE_LIBRARY_RELATIVE);\r\n\r\n try {\r\n const stat = await fs.stat(resolved);\r\n if (stat.isDirectory()) {\r\n return resolved;\r\n }\r\n } catch {\r\n // Fall through\r\n }\r\n\r\n // Fallback: try from current working directory (for development)\r\n const cwdSource = path.resolve(process.cwd(), 'src', 'installer', 'library');\r\n try {\r\n const stat = await fs.stat(cwdSource);\r\n if (stat.isDirectory()) {\r\n return cwdSource;\r\n }\r\n } catch {\r\n // Fall through\r\n }\r\n\r\n throw new Error(\r\n 'Cannot locate AI-DLC library source directory. ' +\r\n 'Set the AIDLC_SOURCE_DIR environment variable to the library path, ' +\r\n 'or ensure the library/ directory exists in the package root.',\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// AI-DLC Source Directory Resolution\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Resolve the absolute path to the AI-DLC framework source directory\r\n * (the .ai-dlc bundle shipped alongside the library).\r\n *\r\n * Resolution order:\r\n * 1. AIDLC_FRAMEWORK_DIR environment variable\r\n * 2. Relative path from this package root (../library-aidlc)\r\n * 3. CWD fallback for development\r\n *\r\n * @returns Absolute path to the ai-dlc framework directory, or null if not found\r\n */\r\nexport async function resolveAiDlcSourceDirectory(): Promise<string | null> {\r\n const envSource = process.env['AIDLC_FRAMEWORK_DIR'];\r\n if (envSource) {\r\n try {\r\n const stat = await fs.stat(envSource);\r\n if (stat.isDirectory()) return path.resolve(envSource);\r\n } catch { /* fall through */ }\r\n }\r\n\r\n const thisFile = fileURLToPath(import.meta.url);\r\n const thisDir = path.dirname(thisFile);\r\n const resolved = path.resolve(thisDir, '../library-aidlc');\r\n\r\n try {\r\n const stat = await fs.stat(resolved);\r\n if (stat.isDirectory()) return resolved;\r\n } catch { /* fall through */ }\r\n\r\n // CWD fallback\r\n const cwdFallback = path.resolve(process.cwd(), 'src', 'installer', 'library-aidlc');\r\n try {\r\n const stat = await fs.stat(cwdFallback);\r\n if (stat.isDirectory()) return cwdFallback;\r\n } catch { /* fall through */ }\r\n\r\n return null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Workflow Step Definitions\r\n// ---------------------------------------------------------------------------\r\n\r\n/** The ordered sequence of installation workflow steps. */\r\nexport const WORKFLOW_STEPS: readonly WorkflowStepDef[] = [\r\n { id: 'detect-platform', name: 'Detect Platform', order: 1, isSkippable: false },\r\n { id: 'check-prerequisites', name: 'Check Prerequisites', order: 2, isSkippable: false },\r\n { id: 'show-banner', name: 'Show Banner', order: 3, isSkippable: true },\r\n { id: 'select-directory', name: 'Select Target Directory', order: 4, isSkippable: true },\r\n { id: 'scan-source', name: 'Scan Source Components', order: 5, isSkippable: false },\r\n { id: 'detect-conflicts', name: 'Detect Conflicts', order: 6, isSkippable: true },\r\n { id: 'select-overwrite-mode', name: 'Select Overwrite Mode', order: 7, isSkippable: true },\r\n { id: 'select-categories', name: 'Select Categories', order: 8, isSkippable: true },\r\n { id: 'confirm-installation', name: 'Confirm Installation', order: 9, isSkippable: true },\r\n { id: 'execute-installation', name: 'Install Files', order: 10, isSkippable: false },\r\n { id: 'validate-installation', name: 'Validate Installation', order: 11, isSkippable: false },\r\n { id: 'show-summary', name: 'Show Summary', order: 12, isSkippable: false },\r\n];\r\n\r\n// ---------------------------------------------------------------------------\r\n// Step Skip Conditions\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Determine whether a step should be skipped given the current options\r\n * and capabilities.\r\n */\r\nexport function shouldSkipStep(\r\n stepId: WorkflowStepId,\r\n options: CLIOptions,\r\n isInteractive: boolean,\r\n): boolean {\r\n switch (stepId) {\r\n case 'show-banner':\r\n return !isInteractive || options.quiet;\r\n\r\n case 'select-directory':\r\n // Never skip — the step itself handles --target with a fast path\r\n // that sets ctx.targetDirectory and ctx.claudeDirectory without prompting.\r\n return false;\r\n\r\n case 'detect-conflicts':\r\n return options.force;\r\n\r\n case 'select-overwrite-mode':\r\n return options.force;\r\n\r\n case 'select-categories':\r\n return !options.custom && options.overwrite.length === 0;\r\n\r\n case 'confirm-installation':\r\n return options.force || !isInteractive;\r\n\r\n default:\r\n return false;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Configuration Resolution\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Resolve the complete installation configuration from CLI options,\r\n * platform environment, and terminal capabilities.\r\n *\r\n * Priority: CLI flags > environment variables > platform-detected > defaults\r\n */\r\nexport function resolveConfig(\r\n options: CLIOptions,\r\n platformEnv: PlatformEnvironment,\r\n capabilities: TerminalCapabilities,\r\n sourceDirectory: string,\r\n targetDirectory: string,\r\n): InstallationConfig {\r\n const claudeDirectory = path.join(targetDirectory, CLAUDE_DIRECTORY_NAME);\r\n\r\n const noColorEnv = process.env['NO_COLOR'] !== undefined;\r\n const colorEnabled = !options.noColor && !noColorEnv && capabilities.colorSupport !== 'none';\r\n\r\n const interactiveMode = capabilities.isInteractive && !options.force && !options.quiet;\r\n\r\n return {\r\n targetDirectory,\r\n claudeDirectory,\r\n sourceDirectory,\r\n forceOverwrite: options.force,\r\n dryRunMode: options.dryRun,\r\n verboseLogging: options.verbose,\r\n colorEnabled,\r\n interactiveMode,\r\n maxConcurrency: DEFAULT_MAX_CONCURRENCY,\r\n backupEnabled: !options.force,\r\n };\r\n}\r\n","/**\r\n * Theme Engine - Color palette, symbol sets, and rendering tier management.\r\n *\r\n * Centralizes all visual styling decisions. Selects the appropriate\r\n * rendering tier based on terminal capabilities and provides color/symbol\r\n * helpers to all other UI components.\r\n *\r\n * @module ui/theme\r\n */\r\n\r\nimport chalk from 'chalk';\r\nimport gradientString from 'gradient-string';\r\n\r\nimport type {\r\n ColorScheme,\r\n GradientSpec,\r\n RenderingTier,\r\n SymbolSet,\r\n TerminalCapabilities,\r\n ThemeColor,\r\n ThemeInitParams,\r\n CLIColorOverrides,\r\n} from './types.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Predefined Color Schemes\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Truecolor (24-bit) color scheme using hex values via chalk. */\r\nconst TRUECOLOR_SCHEME: ColorScheme = {\r\n header: '#3B82F6',\r\n accent: '#06B6D4',\r\n success: '#10B981',\r\n error: '#EF4444',\r\n warning: '#F59E0B',\r\n muted: '#6B7280',\r\n};\r\n\r\n/** Basic (16-color ANSI) color scheme. */\r\nconst BASIC_SCHEME: ColorScheme = {\r\n header: 'blue',\r\n accent: 'cyan',\r\n success: 'green',\r\n error: 'red',\r\n warning: 'yellow',\r\n muted: 'gray',\r\n};\r\n\r\n/** Plain (no color) scheme -- all empty strings. */\r\nconst PLAIN_SCHEME: ColorScheme = {\r\n header: '',\r\n accent: '',\r\n success: '',\r\n error: '',\r\n warning: '',\r\n muted: '',\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Predefined Symbol Sets\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Unicode symbol set for Full and Basic tiers. */\r\nconst UNICODE_SYMBOLS: SymbolSet = {\r\n pending: '\\u25CB', // White circle\r\n running: '\\u25CF', // Filled circle\r\n completed: '\\u2713', // Checkmark\r\n failed: '\\u2717', // Cross\r\n skipped: '\\u2500', // Horizontal line\r\n bullet: '\\u2022', // Bullet\r\n arrow: '\\u25B8', // Right-pointing triangle\r\n boxTopLeft: '\\u250C',\r\n boxTopRight: '\\u2510',\r\n boxBottomLeft: '\\u2514',\r\n boxBottomRight: '\\u2518',\r\n boxHorizontal: '\\u2500',\r\n boxVertical: '\\u2502',\r\n boxDividerLeft: '\\u251C',\r\n boxDividerRight: '\\u2524',\r\n doubleTopLeft: '\\u2554',\r\n doubleTopRight: '\\u2557',\r\n doubleBottomLeft: '\\u255A',\r\n doubleBottomRight: '\\u255D',\r\n doubleHorizontal: '\\u2550',\r\n doubleVertical: '\\u2551',\r\n};\r\n\r\n/** ASCII symbol set for Plain tier. */\r\nconst ASCII_SYMBOLS: SymbolSet = {\r\n pending: 'o',\r\n running: '*',\r\n completed: '+',\r\n failed: 'x',\r\n skipped: '-',\r\n bullet: '*',\r\n arrow: '>',\r\n boxTopLeft: '+',\r\n boxTopRight: '+',\r\n boxBottomLeft: '+',\r\n boxBottomRight: '+',\r\n boxHorizontal: '-',\r\n boxVertical: '|',\r\n boxDividerLeft: '+',\r\n boxDividerRight: '+',\r\n doubleTopLeft: '+',\r\n doubleTopRight: '+',\r\n doubleBottomLeft: '+',\r\n doubleBottomRight: '+',\r\n doubleHorizontal: '=',\r\n doubleVertical: '|',\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Tier Selection\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Determine the rendering tier from terminal capabilities and overrides.\r\n *\r\n * Selection rules:\r\n * - forceNoColor -> Plain\r\n * - truecolor + Unicode -> Full\r\n * - (basic | 256) + Unicode -> Basic\r\n * - all other -> Plain\r\n */\r\nfunction selectTier(\r\n capabilities: TerminalCapabilities,\r\n overrides: CLIColorOverrides,\r\n): RenderingTier {\r\n if (overrides.forceNoColor) {\r\n return 'plain';\r\n }\r\n\r\n if (!capabilities.unicodeSupport) {\r\n return 'plain';\r\n }\r\n\r\n if (capabilities.colorSupport === 'none') {\r\n return 'plain';\r\n }\r\n\r\n if (capabilities.colorSupport === 'truecolor') {\r\n return 'full';\r\n }\r\n\r\n // basic or 256 with Unicode\r\n return 'basic';\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// ThemeEngine\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * ThemeEngine manages rendering tier, color scheme, symbol set, and\r\n * terminal width for the entire UI layer. Must be initialized before\r\n * any component calls render().\r\n */\r\nexport class ThemeEngine {\r\n private _tier: RenderingTier;\r\n private _colorScheme: ColorScheme;\r\n private _symbolSet: SymbolSet;\r\n private _terminalWidth: number;\r\n private _forceNoColor: boolean;\r\n\r\n private constructor(params: ThemeInitParams) {\r\n this._tier = params.tier;\r\n this._colorScheme = params.colorScheme;\r\n this._symbolSet = params.symbolSet;\r\n this._terminalWidth = params.terminalWidth;\r\n this._forceNoColor = params.forceNoColor;\r\n }\r\n\r\n /** Current rendering tier. */\r\n get tier(): RenderingTier {\r\n return this._tier;\r\n }\r\n\r\n /** Active color scheme. */\r\n get colorScheme(): ColorScheme {\r\n return this._colorScheme;\r\n }\r\n\r\n /** Active symbol set. */\r\n get symbolSet(): SymbolSet {\r\n return this._symbolSet;\r\n }\r\n\r\n /** Detected or default terminal width. */\r\n get terminalWidth(): number {\r\n return this._terminalWidth;\r\n }\r\n\r\n /** Whether color output is forcibly disabled. */\r\n get forceNoColor(): boolean {\r\n return this._forceNoColor;\r\n }\r\n\r\n /**\r\n * Apply a semantic color to text. Returns unmodified text for Plain tier.\r\n */\r\n colorize(text: string, color: ThemeColor): string {\r\n if (this._tier === 'plain') {\r\n return text;\r\n }\r\n\r\n const colorValue = this._colorScheme[color];\r\n if (!colorValue) {\r\n return text;\r\n }\r\n\r\n if (this._tier === 'full') {\r\n return chalk.hex(colorValue)(text);\r\n }\r\n\r\n // Basic tier: use named colors\r\n const chalkFn = this.getBasicChalkFn(color);\r\n return chalkFn(text);\r\n }\r\n\r\n /**\r\n * Apply bold styling to text. Returns unmodified text for Plain tier.\r\n */\r\n bold(text: string): string {\r\n if (this._tier === 'plain') {\r\n return text;\r\n }\r\n return chalk.bold(text);\r\n }\r\n\r\n /**\r\n * Apply dim styling to text. Returns unmodified text for Plain tier.\r\n */\r\n dim(text: string): string {\r\n if (this._tier === 'plain') {\r\n return text;\r\n }\r\n return chalk.dim(text);\r\n }\r\n\r\n /**\r\n * Apply underline styling to text. Returns unmodified text for Plain tier.\r\n */\r\n underline(text: string): string {\r\n if (this._tier === 'plain') {\r\n return text;\r\n }\r\n return chalk.underline(text);\r\n }\r\n\r\n /**\r\n * Apply gradient coloring to text. Full tier uses gradient-string.\r\n * Basic tier applies a single accent color. Plain tier returns unmodified text.\r\n */\r\n applyGradient(text: string, gradient?: GradientSpec): string {\r\n if (this._tier === 'plain') {\r\n return text;\r\n }\r\n\r\n if (this._tier === 'full') {\r\n const colors = gradient?.colors ?? ['#4F46E5', '#06B6D4'];\r\n const grad = gradientString(...(colors as [string, string, ...string[]]));\r\n return grad(text);\r\n }\r\n\r\n // Basic tier: single accent color\r\n return chalk.blue(text);\r\n }\r\n\r\n /**\r\n * Get the status symbol for a step status, colorized for the active tier.\r\n */\r\n statusSymbol(status: 'pending' | 'running' | 'completed' | 'failed' | 'skipped'): string {\r\n const symbol = this._symbolSet[status];\r\n\r\n if (this._tier === 'plain') {\r\n return `[${symbol}]`;\r\n }\r\n\r\n switch (status) {\r\n case 'completed':\r\n return this.colorize(symbol, 'success');\r\n case 'failed':\r\n return this.colorize(symbol, 'error');\r\n case 'running':\r\n return this.colorize(symbol, 'accent');\r\n case 'skipped':\r\n return this.colorize(symbol, 'muted');\r\n case 'pending':\r\n return this.colorize(symbol, 'muted');\r\n default:\r\n return symbol;\r\n }\r\n }\r\n\r\n /**\r\n * Get a chalk function for basic (16-color) mode.\r\n */\r\n private getBasicChalkFn(color: ThemeColor): (text: string) => string {\r\n switch (color) {\r\n case 'header': return chalk.blue;\r\n case 'accent': return chalk.cyan;\r\n case 'success': return chalk.green;\r\n case 'error': return chalk.red;\r\n case 'warning': return chalk.yellow;\r\n case 'muted': return chalk.gray;\r\n default: return (t: string) => t;\r\n }\r\n }\r\n\r\n /**\r\n * Create and initialize a ThemeEngine from terminal capabilities and overrides.\r\n */\r\n static initialize(\r\n capabilities: TerminalCapabilities,\r\n overrides: CLIColorOverrides = { forceNoColor: false, forceColor: false },\r\n ): ThemeEngine {\r\n const tier = selectTier(capabilities, overrides);\r\n\r\n let colorScheme: ColorScheme;\r\n let symbolSet: SymbolSet;\r\n\r\n switch (tier) {\r\n case 'full':\r\n colorScheme = TRUECOLOR_SCHEME;\r\n symbolSet = UNICODE_SYMBOLS;\r\n break;\r\n case 'basic':\r\n colorScheme = BASIC_SCHEME;\r\n symbolSet = UNICODE_SYMBOLS;\r\n break;\r\n case 'plain':\r\n default:\r\n colorScheme = PLAIN_SCHEME;\r\n symbolSet = ASCII_SYMBOLS;\r\n break;\r\n }\r\n\r\n const terminalWidth = capabilities.width > 0 ? capabilities.width : 80;\r\n\r\n return new ThemeEngine({\r\n tier,\r\n colorScheme,\r\n symbolSet,\r\n terminalWidth,\r\n forceNoColor: overrides.forceNoColor,\r\n });\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Convenience Exports\r\n// ---------------------------------------------------------------------------\r\n\r\nexport { TRUECOLOR_SCHEME, BASIC_SCHEME, PLAIN_SCHEME };\r\nexport { UNICODE_SYMBOLS, ASCII_SYMBOLS };\r\n","/**\r\n * Banner Component - ASCII art banner with gradient coloring.\r\n *\r\n * Renders the \"SixSevenAI\" product name as ASCII art using figlet,\r\n * applies gradient coloring for Full tier, single color for Basic tier,\r\n * and plain text for Plain tier. Includes subtitle and version.\r\n *\r\n * @module ui/banner\r\n */\r\n\r\nimport figlet from 'figlet';\r\n\r\nimport type { BannerConfig, FigletFont, GradientSpec, RenderOptions } from './types.js';\r\nimport { ThemeEngine } from './theme.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Default Configuration\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Default gradient for the Full tier banner. */\r\nconst DEFAULT_GRADIENT: GradientSpec = {\r\n colors: ['#4F46E5', '#06B6D4'],\r\n direction: 'horizontal',\r\n};\r\n\r\n/** Default figlet font for wide terminals. */\r\nconst DEFAULT_FONT: FigletFont = 'ANSI Shadow';\r\n\r\n/** Narrow figlet font for terminals < 80 columns. */\r\nconst NARROW_FONT: FigletFont = 'Small';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Banner Rendering\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Generate ASCII art text using figlet.\r\n *\r\n * Returns null if figlet rendering fails, allowing the caller\r\n * to fall back to plain text.\r\n */\r\nfunction generateFigletText(text: string, font: FigletFont): string | null {\r\n try {\r\n const result = figlet.textSync(text, {\r\n font: font as never,\r\n horizontalLayout: 'default',\r\n verticalLayout: 'default',\r\n });\r\n return result;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Render the plain text fallback banner when figlet is unavailable\r\n * or the terminal is too narrow.\r\n */\r\nfunction renderFallbackBanner(version: string, theme: ThemeEngine): string[] {\r\n const separator = '='.repeat(Math.min(43, theme.terminalWidth - 4));\r\n const lines: string[] = [];\r\n\r\n lines.push(` ${separator}`);\r\n lines.push(' SixSevenAI - AI-DLC Framework');\r\n lines.push(` Installer ${version}`);\r\n lines.push(` ${separator}`);\r\n lines.push('');\r\n\r\n return lines;\r\n}\r\n\r\n/**\r\n * Render the ASCII art banner with tier-appropriate styling.\r\n *\r\n * Full tier: figlet + gradient coloring + styled subtitle\r\n * Basic tier: figlet + single blue color + styled subtitle\r\n * Plain tier: figlet (simple font) or fallback + plain subtitle\r\n *\r\n * @param version - Semantic version string (e.g., \"v1.0.0\")\r\n * @param theme - Initialized ThemeEngine for color/symbol decisions\r\n * @param config - Optional banner configuration override\r\n * @returns Array of output lines ready for terminal writing\r\n */\r\nexport function renderBanner(\r\n version: string,\r\n theme: ThemeEngine,\r\n config?: Partial<BannerConfig>,\r\n): string[] {\r\n const title = config?.title ?? 'SixSevenAI';\r\n const subtitle = config?.subtitle ?? 'AI-DLC Framework Installer';\r\n const tier = theme.tier;\r\n const width = theme.terminalWidth;\r\n\r\n // Select font based on terminal width\r\n let font: FigletFont;\r\n if (tier === 'plain') {\r\n font = config?.font ?? 'Standard';\r\n } else {\r\n font = config?.font ?? (width >= 80 ? DEFAULT_FONT : NARROW_FONT);\r\n }\r\n\r\n // Generate ASCII art\r\n const figletText = generateFigletText(title, font);\r\n\r\n // If figlet fails, use fallback\r\n if (!figletText) {\r\n return renderFallbackBanner(version, theme);\r\n }\r\n\r\n // Check if the figlet output fits the terminal width\r\n const figletLines = figletText.split('\\n').filter((line) => line.trim().length > 0);\r\n const maxLineWidth = Math.max(...figletLines.map((line) => line.length));\r\n\r\n // If too wide, try narrow font or fall back\r\n if (maxLineWidth > width - 4) {\r\n if (font !== NARROW_FONT) {\r\n const narrowText = generateFigletText(title, NARROW_FONT);\r\n if (narrowText) {\r\n const narrowLines = narrowText.split('\\n').filter((line) => line.trim().length > 0);\r\n const narrowMax = Math.max(...narrowLines.map((line) => line.length));\r\n if (narrowMax <= width - 4) {\r\n return buildBannerOutput(narrowLines, subtitle, version, theme);\r\n }\r\n }\r\n }\r\n return renderFallbackBanner(version, theme);\r\n }\r\n\r\n return buildBannerOutput(figletLines, subtitle, version, theme);\r\n}\r\n\r\n/**\r\n * Assemble the final banner output with ASCII art, subtitle, and version.\r\n */\r\nfunction buildBannerOutput(\r\n artLines: string[],\r\n subtitle: string,\r\n version: string,\r\n theme: ThemeEngine,\r\n): string[] {\r\n const lines: string[] = [];\r\n\r\n // Apply tier-appropriate coloring to the ASCII art\r\n for (const artLine of artLines) {\r\n const indented = ` ${artLine}`;\r\n switch (theme.tier) {\r\n case 'full':\r\n lines.push(theme.applyGradient(indented, DEFAULT_GRADIENT));\r\n break;\r\n case 'basic':\r\n lines.push(theme.colorize(indented, 'header'));\r\n break;\r\n case 'plain':\r\n default:\r\n lines.push(indented);\r\n break;\r\n }\r\n }\r\n\r\n // Blank line after art\r\n lines.push('');\r\n\r\n // Subtitle with version\r\n const versionStr = version.startsWith('v') ? version : `v${version}`;\r\n const subtitleLine = ` ${subtitle} ${versionStr}`;\r\n\r\n switch (theme.tier) {\r\n case 'full': {\r\n const styledSubtitle = theme.dim(subtitle);\r\n const styledVersion = theme.bold(theme.colorize(versionStr, 'accent'));\r\n lines.push(` ${styledSubtitle} ${styledVersion}`);\r\n break;\r\n }\r\n case 'basic': {\r\n const styledSubtitle = theme.dim(subtitle);\r\n const styledVersion = theme.colorize(versionStr, 'accent');\r\n lines.push(` ${styledSubtitle} ${styledVersion}`);\r\n break;\r\n }\r\n case 'plain':\r\n default:\r\n lines.push(subtitleLine);\r\n break;\r\n }\r\n\r\n // Trailing blank line\r\n lines.push('');\r\n\r\n return lines;\r\n}\r\n","/**\r\n * Progress Tracker Component - Hierarchical step tracking with live updates.\r\n *\r\n * Tracks multiple installation steps with status lifecycle management,\r\n * elapsed time display, and tier-appropriate symbol/color rendering.\r\n * The ProgressTracker produces string[] output; actual terminal I/O\r\n * is handled by the render service.\r\n *\r\n * @module ui/progress\r\n */\r\n\r\nimport ora, { type Ora } from 'ora';\r\n\r\nimport type {\r\n CompletionRatio,\r\n Duration,\r\n ErrorDetail,\r\n ProgressStep,\r\n StepStatus,\r\n} from './types.js';\r\nimport { formatDuration } from './types.js';\r\nimport { ThemeEngine } from './theme.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Valid State Transitions\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Map of valid transitions from each status to allowed target statuses. */\r\nconst VALID_TRANSITIONS: Record<StepStatus, readonly StepStatus[]> = {\r\n pending: ['running', 'skipped'],\r\n running: ['completed', 'failed'],\r\n completed: [],\r\n failed: [],\r\n skipped: [],\r\n};\r\n\r\n/**\r\n * Check whether a status transition is valid.\r\n */\r\nfunction isValidTransition(from: StepStatus, to: StepStatus): boolean {\r\n return VALID_TRANSITIONS[from].includes(to);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// ProgressTracker\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Manages a hierarchical tree of installation steps with status lifecycle\r\n * tracking, elapsed time computation, and rendering.\r\n *\r\n * Usage:\r\n * ```typescript\r\n * const tracker = new ProgressTracker();\r\n * tracker.addStep({ id: 'detect', label: 'Detect platform' });\r\n * tracker.addStep({ id: 'install', label: 'Install components', children: [\r\n * { id: 'agents', label: 'Copy agents' },\r\n * { id: 'skills', label: 'Copy skills' },\r\n * ]});\r\n * tracker.start();\r\n * tracker.startStep('detect');\r\n * tracker.completeStep('detect');\r\n * ```\r\n */\r\nexport class ProgressTracker {\r\n private readonly _steps: ProgressStep[] = [];\r\n private _startTime: number | null = null;\r\n private _endTime: number | null = null;\r\n private _isActive: boolean = false;\r\n private _spinner: Ora | null = null;\r\n\r\n /** Ordered list of top-level steps. */\r\n get steps(): readonly ProgressStep[] {\r\n return this._steps;\r\n }\r\n\r\n /** Whether tracking is in progress. */\r\n get isActive(): boolean {\r\n return this._isActive;\r\n }\r\n\r\n /**\r\n * Append a top-level step. Throws if tracker is already finished.\r\n */\r\n addStep(config: {\r\n id: string;\r\n label: string;\r\n children?: Array<{ id: string; label: string }>;\r\n }): void {\r\n if (this._endTime !== null) {\r\n throw new Error('Cannot add steps to a finished tracker.');\r\n }\r\n\r\n // Check for duplicate IDs\r\n if (this.findStep(config.id)) {\r\n throw new Error(`Duplicate step ID: \"${config.id}\".`);\r\n }\r\n\r\n const children: ProgressStep[] = (config.children ?? []).map((child) => {\r\n if (this.findStep(child.id)) {\r\n throw new Error(`Duplicate step ID: \"${child.id}\".`);\r\n }\r\n return {\r\n id: child.id,\r\n label: child.label,\r\n status: 'pending' as StepStatus,\r\n children: [],\r\n startTime: null,\r\n endTime: null,\r\n error: null,\r\n };\r\n });\r\n\r\n this._steps.push({\r\n id: config.id,\r\n label: config.label,\r\n status: 'pending',\r\n children,\r\n startTime: null,\r\n endTime: null,\r\n error: null,\r\n });\r\n }\r\n\r\n /**\r\n * Mark the tracker as active and record the start time.\r\n */\r\n start(): void {\r\n this._startTime = Date.now();\r\n this._isActive = true;\r\n }\r\n\r\n /**\r\n * Transition a step from Pending to Running.\r\n */\r\n startStep(stepId: string): void {\r\n const step = this.requireStep(stepId);\r\n this.transitionStep(step, 'running');\r\n step.startTime = Date.now();\r\n }\r\n\r\n /**\r\n * Transition a step from Running to Completed.\r\n */\r\n completeStep(stepId: string): void {\r\n const step = this.requireStep(stepId);\r\n this.transitionStep(step, 'completed');\r\n step.endTime = Date.now();\r\n }\r\n\r\n /**\r\n * Transition a step from Running to Failed with error details.\r\n */\r\n failStep(stepId: string, error: ErrorDetail): void {\r\n const step = this.requireStep(stepId);\r\n this.transitionStep(step, 'failed');\r\n step.endTime = Date.now();\r\n step.error = error;\r\n }\r\n\r\n /**\r\n * Transition a step from Pending to Skipped.\r\n */\r\n skipStep(stepId: string, _reason: string): void {\r\n const step = this.requireStep(stepId);\r\n this.transitionStep(step, 'skipped');\r\n }\r\n\r\n /**\r\n * Mark the tracker as finished. Throws if any steps are still Running.\r\n */\r\n finish(): void {\r\n const runningSteps = this.flattenSteps().filter((s) => s.status === 'running');\r\n if (runningSteps.length > 0) {\r\n const ids = runningSteps.map((s) => s.id).join(', ');\r\n throw new Error(`Cannot finish tracker while steps are running: ${ids}`);\r\n }\r\n\r\n this._endTime = Date.now();\r\n this._isActive = false;\r\n this.stopSpinner();\r\n }\r\n\r\n /**\r\n * Get the elapsed time since tracking started.\r\n */\r\n getElapsedTime(): Duration {\r\n if (this._startTime === null) {\r\n return { milliseconds: 0, formatted: '0ms' };\r\n }\r\n const end = this._endTime ?? Date.now();\r\n return formatDuration(end - this._startTime);\r\n }\r\n\r\n /**\r\n * Get the completion ratio across all steps (including children).\r\n */\r\n getCompletionRatio(): CompletionRatio {\r\n const allSteps = this.flattenSteps();\r\n const completed = allSteps.filter(\r\n (s) => s.status === 'completed' || s.status === 'skipped',\r\n ).length;\r\n const total = allSteps.length;\r\n const percentage = total > 0 ? Math.round((completed / total) * 100) : 0;\r\n\r\n return { completed, total, percentage };\r\n }\r\n\r\n /**\r\n * Render the current progress state as terminal output lines.\r\n *\r\n * @param theme - ThemeEngine for colors and symbols\r\n * @returns Array of output lines\r\n */\r\n render(theme: ThemeEngine): string[] {\r\n const lines: string[] = [];\r\n const width = theme.terminalWidth;\r\n\r\n for (const step of this._steps) {\r\n lines.push(this.renderStep(step, 0, theme, width));\r\n\r\n for (const child of step.children) {\r\n lines.push(this.renderStep(child, 1, theme, width));\r\n }\r\n }\r\n\r\n return lines;\r\n }\r\n\r\n /**\r\n * Start the ora spinner for the currently running step.\r\n * Used by the render service for animated Running indicators.\r\n */\r\n startSpinner(text?: string): Ora | null {\r\n if (this._spinner) {\r\n this._spinner.stop();\r\n }\r\n\r\n const runningStep = this.flattenSteps().find((s) => s.status === 'running');\r\n if (!runningStep) {\r\n return null;\r\n }\r\n\r\n this._spinner = ora({\r\n text: text ?? runningStep.label,\r\n spinner: 'dots',\r\n });\r\n this._spinner.start();\r\n return this._spinner;\r\n }\r\n\r\n /**\r\n * Stop the ora spinner if one is running.\r\n */\r\n stopSpinner(): void {\r\n if (this._spinner) {\r\n this._spinner.stop();\r\n this._spinner = null;\r\n }\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Private Helpers\r\n // -------------------------------------------------------------------------\r\n\r\n /**\r\n * Find a step by ID across all levels of the hierarchy.\r\n */\r\n private findStep(stepId: string): ProgressStep | null {\r\n for (const step of this._steps) {\r\n if (step.id === stepId) return step;\r\n for (const child of step.children) {\r\n if (child.id === stepId) return child;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * Find a step by ID, throwing if not found.\r\n */\r\n private requireStep(stepId: string): ProgressStep {\r\n const step = this.findStep(stepId);\r\n if (!step) {\r\n throw new Error(`Step not found: \"${stepId}\".`);\r\n }\r\n return step;\r\n }\r\n\r\n /**\r\n * Enforce valid status transitions.\r\n */\r\n private transitionStep(step: ProgressStep, to: StepStatus): void {\r\n if (!isValidTransition(step.status, to)) {\r\n throw new Error(\r\n `Invalid transition for step \"${step.id}\": ${step.status} -> ${to}. ` +\r\n `Allowed: [${VALID_TRANSITIONS[step.status].join(', ')}].`,\r\n );\r\n }\r\n step.status = to;\r\n }\r\n\r\n /**\r\n * Flatten all steps (parents + children) into a single array.\r\n */\r\n private flattenSteps(): ProgressStep[] {\r\n const result: ProgressStep[] = [];\r\n for (const step of this._steps) {\r\n result.push(step);\r\n result.push(...step.children);\r\n }\r\n return result;\r\n }\r\n\r\n /**\r\n * Render a single step line with indentation, symbol, label, and elapsed time.\r\n */\r\n private renderStep(\r\n step: ProgressStep,\r\n depth: number,\r\n theme: ThemeEngine,\r\n terminalWidth: number,\r\n ): string {\r\n const tier = theme.tier;\r\n\r\n // Indentation: 2 spaces per depth level for Unicode, 4 for Plain\r\n const indentSize = tier === 'plain' ? 4 : 2;\r\n const indent = ' '.repeat(2 + depth * indentSize);\r\n\r\n // Status symbol\r\n const symbol = theme.statusSymbol(step.status);\r\n\r\n // Elapsed time (only if started)\r\n let elapsed = '';\r\n if (step.startTime !== null) {\r\n const end = step.endTime ?? Date.now();\r\n const duration = formatDuration(end - step.startTime);\r\n elapsed = duration.formatted;\r\n }\r\n\r\n // Compose the line\r\n const labelPart = `${indent}${symbol} ${step.label}`;\r\n\r\n if (!elapsed) {\r\n return labelPart;\r\n }\r\n\r\n // Right-align the elapsed time\r\n const elapsedDisplay = theme.dim(elapsed);\r\n const rawLabelLength = stripAnsi(labelPart).length;\r\n const rawElapsedLength = elapsed.length;\r\n const padding = Math.max(4, terminalWidth - rawLabelLength - rawElapsedLength - 2);\r\n\r\n return `${labelPart}${' '.repeat(padding)}${elapsedDisplay}`;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Utility\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Strip ANSI escape codes from a string for accurate length calculation.\r\n */\r\nfunction stripAnsi(text: string): string {\r\n // eslint-disable-next-line no-control-regex\r\n return text.replace(/\\x1b\\[[0-9;]*m/g, '');\r\n}\r\n","/**\r\n * Terminal UI Components - Shared Types\r\n *\r\n * All value objects, enumerations, and interfaces used throughout\r\n * the terminal UI subsystem. Mirrors the domain model from\r\n * domain-model-unit-terminal-ui-20260213-001.md.\r\n *\r\n * @module ui/types\r\n */\r\n\r\nimport type { ColorSupportLevel, TerminalProfile } from '../platform/types.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Rendering Tier\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Discrete rendering fidelity level, selected based on terminal capabilities.\r\n *\r\n * - Full: truecolor + Unicode -- gradient colors, box-drawing, rich symbols\r\n * - Basic: 16/256-color + Unicode -- single ANSI colors, box-drawing, rich symbols\r\n * - Plain: no color or no Unicode -- uncolored text, ASCII-only symbols\r\n */\r\nexport type RenderingTier = 'full' | 'basic' | 'plain';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Step Status\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Lifecycle state of a progress step.\r\n *\r\n * Valid transitions:\r\n * Pending -> Running\r\n * Pending -> Skipped\r\n * Running -> Completed\r\n * Running -> Failed\r\n *\r\n * Completed, Failed, and Skipped are terminal states.\r\n */\r\nexport type StepStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Progress Step\r\n// ---------------------------------------------------------------------------\r\n\r\n/** A single trackable item in the progress hierarchy. */\r\nexport interface ProgressStep {\r\n readonly id: string;\r\n readonly label: string;\r\n status: StepStatus;\r\n readonly children: ProgressStep[];\r\n startTime: number | null;\r\n endTime: number | null;\r\n error: ErrorDetail | null;\r\n}\r\n\r\n/** Error information associated with a failed step. */\r\nexport interface ErrorDetail {\r\n readonly message: string;\r\n readonly cause: string | null;\r\n}\r\n\r\n/** Ratio of completed steps to total steps. */\r\nexport interface CompletionRatio {\r\n readonly completed: number;\r\n readonly total: number;\r\n readonly percentage: number;\r\n}\r\n\r\n/** Human-readable duration value object. */\r\nexport interface Duration {\r\n readonly milliseconds: number;\r\n readonly formatted: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Color Scheme\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Color palette used across all components. */\r\nexport interface ColorScheme {\r\n readonly header: string;\r\n readonly accent: string;\r\n readonly success: string;\r\n readonly error: string;\r\n readonly warning: string;\r\n readonly muted: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Symbol Set\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Set of status indicator glyphs for rendering. */\r\nexport interface SymbolSet {\r\n readonly pending: string;\r\n readonly running: string;\r\n readonly completed: string;\r\n readonly failed: string;\r\n readonly skipped: string;\r\n readonly bullet: string;\r\n readonly arrow: string;\r\n readonly boxTopLeft: string;\r\n readonly boxTopRight: string;\r\n readonly boxBottomLeft: string;\r\n readonly boxBottomRight: string;\r\n readonly boxHorizontal: string;\r\n readonly boxVertical: string;\r\n readonly boxDividerLeft: string;\r\n readonly boxDividerRight: string;\r\n readonly doubleTopLeft: string;\r\n readonly doubleTopRight: string;\r\n readonly doubleBottomLeft: string;\r\n readonly doubleBottomRight: string;\r\n readonly doubleHorizontal: string;\r\n readonly doubleVertical: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Render Options\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Options that control rendering behavior, derived from terminal capabilities. */\r\nexport interface RenderOptions {\r\n readonly tier: RenderingTier;\r\n readonly unicodeSupport: boolean;\r\n readonly width: number;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Theme Color (semantic color names)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Semantic color names that map to the active ColorScheme fields. */\r\nexport type ThemeColor = 'header' | 'accent' | 'success' | 'error' | 'warning' | 'muted';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Banner Config\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Configuration for the ASCII art banner component. */\r\nexport interface BannerConfig {\r\n readonly title: string;\r\n readonly subtitle: string;\r\n readonly version: string;\r\n readonly font: FigletFont;\r\n}\r\n\r\n/** Recognized figlet font names. */\r\nexport type FigletFont = 'ANSI Shadow' | 'Standard' | 'Slant' | 'Small' | 'Banner3';\r\n\r\n/** Gradient color specification for banner rendering. */\r\nexport interface GradientSpec {\r\n readonly colors: readonly string[];\r\n readonly direction: 'horizontal' | 'vertical';\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Error Display\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Content for an error panel. */\r\nexport interface ErrorPanelContent {\r\n readonly title: string;\r\n readonly message: string;\r\n readonly cause: string | null;\r\n readonly suggestedActions: readonly SuggestedAction[];\r\n readonly retryAvailable: boolean;\r\n readonly errorCode: string | null;\r\n}\r\n\r\n/** Content for a warning panel. */\r\nexport interface WarningPanelContent {\r\n readonly title: string;\r\n readonly message: string;\r\n readonly suggestedActions: readonly SuggestedAction[];\r\n readonly continueAvailable: boolean;\r\n}\r\n\r\n/** A numbered remediation step shown in error/warning panels. */\r\nexport interface SuggestedAction {\r\n readonly step: number;\r\n readonly instruction: string;\r\n readonly command: string | null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Summary Screen\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Post-installation summary data. */\r\nexport interface InstallationSummary {\r\n readonly success: boolean;\r\n readonly targetDirectory: string;\r\n readonly componentCounts: ComponentCounts;\r\n readonly totalDuration: Duration;\r\n readonly totalFilesCopied: number;\r\n readonly totalFilesSkipped: number;\r\n readonly totalFilesFailed: number;\r\n readonly installerVersion: string;\r\n}\r\n\r\n/** Breakdown of installed component counts. */\r\nexport interface ComponentCounts {\r\n readonly agents: number;\r\n readonly skills: number;\r\n readonly commands: number;\r\n readonly cliFiles: number;\r\n readonly other: number;\r\n}\r\n\r\n/** Post-installation guidance step. */\r\nexport interface NextStep {\r\n readonly order: number;\r\n readonly title: string;\r\n readonly instruction: string;\r\n readonly command: string | null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Directory Selector\r\n// ---------------------------------------------------------------------------\r\n\r\n/** A selectable directory option in the directory selector. */\r\nexport interface DirectoryOption {\r\n readonly path: string;\r\n readonly label: string;\r\n readonly isDefault: boolean;\r\n readonly exists: boolean;\r\n}\r\n\r\n/** Confirmed directory selection result. */\r\nexport interface DirectorySelection {\r\n readonly path: string;\r\n readonly isCustom: boolean;\r\n}\r\n\r\n/** Path validation result. */\r\nexport interface PathValidation {\r\n readonly isValid: boolean;\r\n readonly path: string;\r\n readonly errors: readonly ValidationError[];\r\n readonly warnings: readonly ValidationWarning[];\r\n}\r\n\r\n/** A specific validation error for a path. */\r\nexport interface ValidationError {\r\n readonly code: string;\r\n readonly message: string;\r\n}\r\n\r\n/** A non-blocking validation warning for a path. */\r\nexport interface ValidationWarning {\r\n readonly code: string;\r\n readonly message: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Terminal Capabilities (consumed from platform context)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Terminal capabilities consumed from the cross-platform context.\r\n * Maps to the platform module's TerminalProfile type.\r\n */\r\nexport interface TerminalCapabilities {\r\n readonly colorSupport: 'none' | 'basic' | '256' | 'truecolor';\r\n readonly unicodeSupport: boolean;\r\n readonly width: number;\r\n readonly height: number;\r\n readonly isInteractive: boolean;\r\n}\r\n\r\n/** CLI-level color overrides (e.g., --no-color flag). */\r\nexport interface CLIColorOverrides {\r\n readonly forceNoColor: boolean;\r\n readonly forceColor: boolean;\r\n}\r\n\r\n/** Parameters for initializing the ThemeEngine. */\r\nexport interface ThemeInitParams {\r\n readonly tier: RenderingTier;\r\n readonly colorScheme: ColorScheme;\r\n readonly symbolSet: SymbolSet;\r\n readonly terminalWidth: number;\r\n readonly forceNoColor: boolean;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Component Counts Utility\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Calculate the total from a ComponentCounts value. */\r\nexport function totalComponentCount(counts: ComponentCounts): number {\r\n return counts.agents + counts.skills + counts.commands + counts.cliFiles + counts.other;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Duration Utility\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Format a duration in milliseconds to a human-readable string. */\r\nexport function formatDuration(ms: number): Duration {\r\n if (ms < 1000) {\r\n return { milliseconds: ms, formatted: `${ms}ms` };\r\n }\r\n if (ms < 60_000) {\r\n const seconds = (ms / 1000).toFixed(1);\r\n return { milliseconds: ms, formatted: `${seconds}s` };\r\n }\r\n const minutes = Math.floor(ms / 60_000);\r\n const seconds = Math.round((ms % 60_000) / 1000);\r\n return { milliseconds: ms, formatted: `${minutes}m ${seconds}s` };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Color Support Mapping\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Map the platform module's ColorSupportLevel enum to the UI-local\r\n * TerminalCapabilities color support string.\r\n */\r\nexport function mapColorSupport(level: ColorSupportLevel): TerminalCapabilities['colorSupport'] {\r\n switch (level) {\r\n case 0: return 'none';\r\n case 1: return 'basic';\r\n case 2: return '256';\r\n case 3: return 'truecolor';\r\n default: return 'none';\r\n }\r\n}\r\n","/**\r\n * Prompts Component - Interactive terminal prompts using @clack/prompts.\r\n *\r\n * Provides directory selection, confirmation, component selection, and\r\n * text input prompts. Falls back to non-interactive defaults when the\r\n * terminal does not support interactive input.\r\n *\r\n * @module ui/prompts\r\n */\r\n\r\nimport * as clack from '@clack/prompts';\r\n\r\nimport type { DirectoryOption, DirectorySelection } from './types.js';\r\nimport type { OverwriteMode } from '../orchestrator/types.js';\r\nimport type { CategoryConflictSummary } from '../engine/conflict-detector.js';\r\nimport { ThemeEngine } from './theme.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Directory Selection\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Prompt the user to select an installation directory from a list of options.\r\n *\r\n * Uses @clack/prompts.select() with domain-specific options and a \"Custom path\"\r\n * entry. If the user selects \"Custom path\", a text prompt collects the path.\r\n *\r\n * @param options - Suggested directory options\r\n * @param theme - ThemeEngine for styling (used in message formatting)\r\n * @returns The selected directory or throws on cancellation\r\n */\r\nexport async function promptDirectorySelection(\r\n options: readonly DirectoryOption[],\r\n theme: ThemeEngine,\r\n): Promise<DirectorySelection> {\r\n const selectOptions = options.map((opt) => ({\r\n value: opt.path,\r\n label: opt.path,\r\n hint: opt.isDefault ? '(default)' : opt.exists ? '(exists)' : '(will be created)',\r\n }));\r\n\r\n // Add custom path option\r\n selectOptions.push({\r\n value: '__custom__',\r\n label: 'Custom path...',\r\n hint: 'Enter a custom directory path',\r\n });\r\n\r\n const selected = await clack.select({\r\n message: 'Select installation directory:',\r\n options: selectOptions,\r\n initialValue: options.find((o) => o.isDefault)?.path ?? options[0]?.path,\r\n });\r\n\r\n if (clack.isCancel(selected)) {\r\n throw new UserCancellationError('Directory selection cancelled.');\r\n }\r\n\r\n // Custom path entry\r\n if (selected === '__custom__') {\r\n const customPath = await clack.text({\r\n message: 'Enter installation directory path:',\r\n placeholder: process.cwd(),\r\n validate: (value) => {\r\n if (!value || value.trim().length === 0) {\r\n return 'Path cannot be empty.';\r\n }\r\n // Basic absolute path check\r\n const isAbsolute = /^[A-Za-z]:[\\\\/]/.test(value) || value.startsWith('/');\r\n if (!isAbsolute) {\r\n return 'Path must be absolute (e.g., C:\\\\dev\\\\project or /home/user/project).';\r\n }\r\n return undefined;\r\n },\r\n });\r\n\r\n if (clack.isCancel(customPath)) {\r\n throw new UserCancellationError('Custom path entry cancelled.');\r\n }\r\n\r\n return {\r\n path: customPath as string,\r\n isCustom: true,\r\n };\r\n }\r\n\r\n return {\r\n path: selected as string,\r\n isCustom: false,\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Confirmation Prompt\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Display a yes/no confirmation prompt.\r\n *\r\n * @param message - The question to display\r\n * @param defaultValue - Default answer if the user presses Enter\r\n * @returns true for yes, false for no\r\n */\r\nexport async function promptConfirmation(\r\n message: string,\r\n defaultValue: boolean = true,\r\n): Promise<boolean> {\r\n const result = await clack.confirm({\r\n message,\r\n initialValue: defaultValue,\r\n });\r\n\r\n if (clack.isCancel(result)) {\r\n throw new UserCancellationError('Confirmation cancelled.');\r\n }\r\n\r\n return result as boolean;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Overwrite Existing Prompt\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Prompt whether to overwrite an existing installation.\r\n *\r\n * @param targetPath - The directory that already contains files\r\n * @returns true to overwrite, false to cancel\r\n */\r\nexport async function promptOverwriteExisting(\r\n targetPath: string,\r\n): Promise<boolean> {\r\n const result = await clack.confirm({\r\n message: `Directory \"${targetPath}\" already contains AI-DLC files. Overwrite?`,\r\n initialValue: false,\r\n });\r\n\r\n if (clack.isCancel(result)) {\r\n throw new UserCancellationError('Overwrite confirmation cancelled.');\r\n }\r\n\r\n return result as boolean;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Component Selection Prompt\r\n// ---------------------------------------------------------------------------\r\n\r\n/** A selectable component category for installation. */\r\nexport interface ComponentOption {\r\n readonly value: string;\r\n readonly label: string;\r\n readonly hint?: string;\r\n}\r\n\r\n/**\r\n * Prompt the user to select which components to install.\r\n *\r\n * @param components - Available component categories\r\n * @returns Array of selected component values\r\n */\r\nexport async function promptComponentSelection(\r\n components: readonly ComponentOption[],\r\n): Promise<string[]> {\r\n const result = await clack.multiselect({\r\n message: 'Select components to install:',\r\n options: components.map((c) => ({\r\n value: c.value,\r\n label: c.label,\r\n hint: c.hint,\r\n })),\r\n required: true,\r\n });\r\n\r\n if (clack.isCancel(result)) {\r\n throw new UserCancellationError('Component selection cancelled.');\r\n }\r\n\r\n return result as string[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Retry Prompt\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Prompt the user whether to retry a failed operation.\r\n *\r\n * @returns true to retry, false to abort\r\n */\r\nexport async function promptRetry(): Promise<boolean> {\r\n const result = await clack.confirm({\r\n message: 'Would you like to retry?',\r\n initialValue: true,\r\n });\r\n\r\n if (clack.isCancel(result)) {\r\n return false;\r\n }\r\n\r\n return result as boolean;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Overwrite Mode Prompt\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Prompt the user to select how existing files should be handled.\r\n *\r\n * Offers three strategies: overwrite all, skip existing, or choose by category.\r\n *\r\n * @param targetPath - The directory that already contains files\r\n * @returns The selected overwrite mode\r\n */\r\nexport async function promptOverwriteMode(\r\n targetPath: string,\r\n): Promise<OverwriteMode> {\r\n const result = await clack.select({\r\n message: `Directory \"${targetPath}\" already contains AI-DLC files. How should existing files be handled?`,\r\n options: [\r\n { value: 'all' as const, label: 'Overwrite all', hint: 'Replace all existing files with latest versions' },\r\n { value: 'none' as const, label: 'Skip existing', hint: 'Only install new files, keep all existing' },\r\n { value: 'choose' as const, label: 'Choose categories', hint: 'Select which component categories to overwrite' },\r\n ],\r\n });\r\n\r\n if (clack.isCancel(result)) {\r\n throw new UserCancellationError('Overwrite mode selection cancelled.');\r\n }\r\n\r\n return result as OverwriteMode;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Category Selection Prompt\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Prompt the user to select which component categories to overwrite.\r\n *\r\n * Categories that have been modified since the last installation are annotated\r\n * with \"(modified)\" in their hint text. When conflict stats are provided,\r\n * file counts and modification counts are shown in the hint.\r\n *\r\n * @param categories - Available categories with value, label, and hint\r\n * @param modifiedCategories - Category values that have local modifications\r\n * @param conflictStats - Optional per-category conflict summaries for file count display\r\n * @returns Array of selected category values (may be empty)\r\n */\r\nexport async function promptCategorySelection(\r\n categories: Array<{ value: string; label: string; hint: string }>,\r\n modifiedCategories: string[],\r\n conflictStats?: CategoryConflictSummary[],\r\n): Promise<string[]> {\r\n const statsMap = new Map<string, CategoryConflictSummary>();\r\n if (conflictStats) {\r\n for (const stat of conflictStats) {\r\n statsMap.set(stat.categoryId, stat);\r\n }\r\n }\r\n\r\n const options = categories.map((cat) => {\r\n let hint = cat.hint;\r\n const stat = statsMap.get(cat.value);\r\n\r\n // Append file count and modification info when stats are available\r\n if (stat) {\r\n const parts: string[] = [`${stat.totalFiles} files`];\r\n if (stat.modifiedFiles > 0) {\r\n parts.push(`${stat.modifiedFiles} modified`);\r\n }\r\n if (stat.newFiles > 0) {\r\n parts.push(`${stat.newFiles} new`);\r\n }\r\n hint = `${hint} (${parts.join(', ')})`;\r\n } else if (modifiedCategories.includes(cat.value)) {\r\n hint = `${hint} (modified)`;\r\n }\r\n\r\n return {\r\n value: cat.value,\r\n label: cat.label,\r\n hint,\r\n };\r\n });\r\n\r\n const result = await clack.multiselect({\r\n message: 'Select categories to overwrite:',\r\n options,\r\n required: false,\r\n });\r\n\r\n if (clack.isCancel(result)) {\r\n throw new UserCancellationError('Category selection cancelled.');\r\n }\r\n\r\n return result as string[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Clack Lifecycle Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Display the @clack/prompts intro banner.\r\n * Should be called once at the start of the interactive session.\r\n */\r\nexport function promptIntro(title: string): void {\r\n clack.intro(title);\r\n}\r\n\r\n/**\r\n * Display the @clack/prompts outro banner.\r\n * Should be called once at the end of the interactive session.\r\n */\r\nexport function promptOutro(message: string): void {\r\n clack.outro(message);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// User Cancellation Error\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Error thrown when the user cancels an interactive prompt (Ctrl+C or Escape).\r\n * The CLI orchestrator should catch this and exit with code 2.\r\n */\r\nexport class UserCancellationError extends Error {\r\n readonly code = 'USER_CANCELLED';\r\n\r\n constructor(message: string = 'Operation cancelled by user.') {\r\n super(message);\r\n this.name = 'UserCancellationError';\r\n }\r\n}\r\n","/**\r\n * Error Display Component - Styled error and warning panels.\r\n *\r\n * Renders error and warning information in bordered terminal panels\r\n * with colored borders, structured details, and actionable remediation\r\n * suggestions. Adapts panel style to the active rendering tier.\r\n *\r\n * @module ui/error-display\r\n */\r\n\r\nimport type { ErrorPanelContent, SuggestedAction, WarningPanelContent } from './types.js';\r\nimport { ThemeEngine } from './theme.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Error Panel Rendering\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render an error panel with red border, title, message, cause, and\r\n * suggested remediation actions.\r\n *\r\n * @param content - Error panel content\r\n * @param theme - ThemeEngine for colors, symbols, and terminal width\r\n * @returns Array of output lines\r\n */\r\nexport function renderError(\r\n content: ErrorPanelContent,\r\n theme: ThemeEngine,\r\n): string[] {\r\n return renderPanel(content, 'error', theme);\r\n}\r\n\r\n/**\r\n * Render a warning panel with yellow border, title, message, and\r\n * suggested actions.\r\n *\r\n * @param content - Warning panel content\r\n * @param theme - ThemeEngine for colors, symbols, and terminal width\r\n * @returns Array of output lines\r\n */\r\nexport function renderWarning(\r\n content: WarningPanelContent,\r\n theme: ThemeEngine,\r\n): string[] {\r\n return renderPanel(content, 'warning', theme);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Panel Rendering Core\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render a styled panel (error or warning) with the appropriate border\r\n * color and structure.\r\n */\r\nfunction renderPanel(\r\n content: ErrorPanelContent | WarningPanelContent,\r\n panelType: 'error' | 'warning',\r\n theme: ThemeEngine,\r\n): string[] {\r\n const symbols = theme.symbolSet;\r\n const width = Math.min(theme.terminalWidth - 4, 75);\r\n const innerWidth = width - 4; // 2 for border + 1 space padding each side\r\n const tier = theme.tier;\r\n\r\n // Select colorize function based on panel type\r\n const colorFn = (text: string): string => {\r\n return theme.colorize(text, panelType === 'error' ? 'error' : 'warning');\r\n };\r\n\r\n const lines: string[] = [];\r\n\r\n // Top border\r\n const topBorder = buildHorizontalBorder(\r\n symbols.boxTopLeft,\r\n symbols.boxHorizontal,\r\n symbols.boxTopRight,\r\n width,\r\n );\r\n lines.push(` ${colorFn(topBorder)}`);\r\n\r\n // Title line\r\n const statusSymbol = panelType === 'error'\r\n ? theme.statusSymbol('failed')\r\n : (tier === 'plain' ? '[!]' : '\\u26A0');\r\n const titleText = `${statusSymbol} ${content.title}`;\r\n lines.push(buildContentLine(titleText, symbols.boxVertical, innerWidth, colorFn, theme));\r\n\r\n // Divider\r\n const divider = buildHorizontalBorder(\r\n symbols.boxDividerLeft,\r\n symbols.boxHorizontal,\r\n symbols.boxDividerRight,\r\n width,\r\n );\r\n lines.push(` ${colorFn(divider)}`);\r\n\r\n // Blank line\r\n lines.push(buildEmptyLine(symbols.boxVertical, innerWidth, colorFn));\r\n\r\n // Message\r\n const messageLines = wordWrap(content.message, innerWidth - 2);\r\n for (const msgLine of messageLines) {\r\n lines.push(buildContentLine(` ${msgLine}`, symbols.boxVertical, innerWidth, colorFn, theme));\r\n }\r\n\r\n // Cause (error panels only)\r\n if ('cause' in content && content.cause) {\r\n lines.push(buildEmptyLine(symbols.boxVertical, innerWidth, colorFn));\r\n const causePrefix = theme.bold('Cause:');\r\n const causeLines = wordWrap(`${content.cause}`, innerWidth - 9);\r\n lines.push(\r\n buildContentLine(` ${causePrefix} ${causeLines[0] ?? ''}`, symbols.boxVertical, innerWidth, colorFn, theme),\r\n );\r\n for (let i = 1; i < causeLines.length; i++) {\r\n lines.push(\r\n buildContentLine(` ${causeLines[i]}`, symbols.boxVertical, innerWidth, colorFn, theme),\r\n );\r\n }\r\n }\r\n\r\n // Suggested actions\r\n if (content.suggestedActions.length > 0) {\r\n lines.push(buildEmptyLine(symbols.boxVertical, innerWidth, colorFn));\r\n lines.push(\r\n buildContentLine(' Suggested actions:', symbols.boxVertical, innerWidth, colorFn, theme),\r\n );\r\n lines.push(buildEmptyLine(symbols.boxVertical, innerWidth, colorFn));\r\n\r\n for (const action of content.suggestedActions) {\r\n lines.push(...renderSuggestedAction(action, symbols.boxVertical, innerWidth, colorFn, theme));\r\n }\r\n }\r\n\r\n // Blank line before close\r\n lines.push(buildEmptyLine(symbols.boxVertical, innerWidth, colorFn));\r\n\r\n // Bottom border\r\n const bottomBorder = buildHorizontalBorder(\r\n symbols.boxBottomLeft,\r\n symbols.boxHorizontal,\r\n symbols.boxBottomRight,\r\n width,\r\n );\r\n lines.push(` ${colorFn(bottomBorder)}`);\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Line Builders\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Build a horizontal border line (top, bottom, or divider).\r\n */\r\nfunction buildHorizontalBorder(\r\n left: string,\r\n horizontal: string,\r\n right: string,\r\n totalWidth: number,\r\n): string {\r\n const fill = horizontal.repeat(totalWidth - 2);\r\n return `${left}${fill}${right}`;\r\n}\r\n\r\n/**\r\n * Build a content line with vertical borders and inner padding.\r\n */\r\nfunction buildContentLine(\r\n content: string,\r\n vertical: string,\r\n innerWidth: number,\r\n colorFn: (text: string) => string,\r\n theme: ThemeEngine,\r\n): string {\r\n const strippedLength = stripAnsi(content).length;\r\n const padding = Math.max(0, innerWidth - strippedLength);\r\n return ` ${colorFn(vertical)} ${content}${' '.repeat(padding)}${colorFn(vertical)}`;\r\n}\r\n\r\n/**\r\n * Build an empty line with vertical borders.\r\n */\r\nfunction buildEmptyLine(\r\n vertical: string,\r\n innerWidth: number,\r\n colorFn: (text: string) => string,\r\n): string {\r\n return ` ${colorFn(vertical)}${' '.repeat(innerWidth + 2)}${colorFn(vertical)}`;\r\n}\r\n\r\n/**\r\n * Render a suggested action as one or more lines.\r\n */\r\nfunction renderSuggestedAction(\r\n action: SuggestedAction,\r\n vertical: string,\r\n innerWidth: number,\r\n colorFn: (text: string) => string,\r\n theme: ThemeEngine,\r\n): string[] {\r\n const lines: string[] = [];\r\n\r\n // Numbered instruction\r\n const numberPrefix = ` ${action.step}. `;\r\n const instructionLines = wordWrap(action.instruction, innerWidth - numberPrefix.length - 2);\r\n\r\n lines.push(\r\n buildContentLine(\r\n `${numberPrefix}${instructionLines[0] ?? ''}`,\r\n vertical,\r\n innerWidth,\r\n colorFn,\r\n theme,\r\n ),\r\n );\r\n\r\n // Continuation lines\r\n const continuationIndent = ' '.repeat(numberPrefix.length);\r\n for (let i = 1; i < instructionLines.length; i++) {\r\n lines.push(\r\n buildContentLine(\r\n `${continuationIndent}${instructionLines[i]}`,\r\n vertical,\r\n innerWidth,\r\n colorFn,\r\n theme,\r\n ),\r\n );\r\n }\r\n\r\n // Command (if present)\r\n if (action.command) {\r\n const commandText = theme.colorize(action.command, 'accent');\r\n lines.push(\r\n buildContentLine(\r\n `${continuationIndent}${commandText}`,\r\n vertical,\r\n innerWidth,\r\n colorFn,\r\n theme,\r\n ),\r\n );\r\n }\r\n\r\n // Blank line between actions\r\n lines.push(buildEmptyLine(vertical, innerWidth, colorFn));\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Utility\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Word wrap text to fit within a maximum width.\r\n */\r\nfunction wordWrap(text: string, maxWidth: number): string[] {\r\n if (maxWidth <= 0) return [text];\r\n\r\n const words = text.split(' ');\r\n const lines: string[] = [];\r\n let currentLine = '';\r\n\r\n for (const word of words) {\r\n if (currentLine.length === 0) {\r\n currentLine = word;\r\n } else if (currentLine.length + 1 + word.length <= maxWidth) {\r\n currentLine += ` ${word}`;\r\n } else {\r\n lines.push(currentLine);\r\n currentLine = word;\r\n }\r\n }\r\n\r\n if (currentLine.length > 0) {\r\n lines.push(currentLine);\r\n }\r\n\r\n return lines.length > 0 ? lines : [''];\r\n}\r\n\r\n/**\r\n * Strip ANSI escape codes from a string for accurate length calculation.\r\n */\r\nfunction stripAnsi(text: string): string {\r\n // eslint-disable-next-line no-control-regex\r\n return text.replace(/\\x1b\\[[0-9;]*m/g, '');\r\n}\r\n","/**\r\n * Installation Engine - Category Filter\r\n *\r\n * Defines install categories and provides functions to filter file mappings\r\n * by category selection, supporting the granular `--overwrite` workflow.\r\n *\r\n * @module engine/category-filter\r\n */\r\n\r\nimport type { FileMapping } from './types.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Install Category Type\r\n// ---------------------------------------------------------------------------\r\n\r\n/** A category of installable files. */\r\nexport interface InstallCategory {\r\n /** Unique identifier used in `--overwrite` flags. */\r\n readonly id: string;\r\n /** Human-readable label for UI display. */\r\n readonly label: string;\r\n /** Short description shown alongside the label. */\r\n readonly hint: string;\r\n /** Path prefix used to match file mappings to this category. */\r\n readonly pathPrefix: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Install Categories\r\n// ---------------------------------------------------------------------------\r\n\r\n/** All recognised install categories with their path prefixes. */\r\nexport const INSTALL_CATEGORIES: readonly InstallCategory[] = [\r\n { id: 'agents', pathPrefix: 'agents/', label: 'Agents', hint: 'AI agent definitions' },\r\n { id: 'commands/ai-dlc', pathPrefix: 'commands/ai-dlc/', label: 'Commands: AI-DLC', hint: 'AI-DLC lifecycle commands' },\r\n { id: 'commands/brn', pathPrefix: 'commands/brn/', label: 'Commands: Brownfield', hint: 'Brownfield refactoring commands' },\r\n { id: 'commands/docs', pathPrefix: 'commands/docs/', label: 'Commands: Docs', hint: 'Documentation commands' },\r\n { id: 'commands/elicit', pathPrefix: 'commands/elicit/', label: 'Commands: Elicit', hint: 'Elicitation commands' },\r\n { id: 'commands/git', pathPrefix: 'commands/git/', label: 'Commands: Git', hint: 'Git workflow commands' },\r\n { id: 'commands/spec', pathPrefix: 'commands/spec/', label: 'Commands: Spec', hint: 'Specification commands' },\r\n { id: 'commands/task', pathPrefix: 'commands/task/', label: 'Commands: Task', hint: 'Task management commands' },\r\n { id: 'commands/worktree', pathPrefix: 'commands/worktree/', label: 'Commands: Worktree', hint: 'Worktree management commands' },\r\n { id: 'skills', pathPrefix: 'skills/', label: 'Skills', hint: 'Reusable skill definitions' },\r\n { id: 'templates', pathPrefix: 'templates/', label: 'Templates', hint: 'Project templates' },\r\n { id: 'scripts', pathPrefix: 'scripts/', label: 'Scripts', hint: 'Utility scripts' },\r\n { id: 'docs', pathPrefix: 'docs/', label: 'Documentation', hint: 'Framework documentation' },\r\n { id: 'ai-dlc', pathPrefix: 'ai-dlc/', label: 'AI-DLC Core', hint: 'Core AI-DLC framework files' },\r\n { id: 'memory', pathPrefix: 'memory/', label: 'Memory', hint: 'Memory templates' },\r\n] as const;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Filter Functions\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Filters file mappings to only include files belonging to the specified\r\n * categories. A file matches a category when its `relativePath` (normalised\r\n * to forward slashes) starts with the category's `pathPrefix`.\r\n *\r\n * @param mappings - The full set of file mappings from the source scan.\r\n * @param categories - Category IDs to include (must match `InstallCategory.id`).\r\n * @returns A subset of `mappings` whose relative paths match a selected category.\r\n */\r\nexport function filterMappingsByCategories(\r\n mappings: FileMapping[],\r\n categories: string[],\r\n): FileMapping[] {\r\n const prefixes = INSTALL_CATEGORIES\r\n .filter((cat) => categories.includes(cat.id))\r\n .map((cat) => cat.pathPrefix);\r\n\r\n if (prefixes.length === 0) {\r\n return [];\r\n }\r\n\r\n return mappings.filter((mapping) => {\r\n const normalised = mapping.relativePath.replace(/\\\\/g, '/');\r\n return prefixes.some((prefix) => normalised.startsWith(prefix));\r\n });\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Resolution / Validation\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Validates `--overwrite` flag values against known categories and returns\r\n * the resolved list of category IDs.\r\n *\r\n * @param overwriteFlags - Raw values passed via `--overwrite` CLI flags.\r\n * @returns An array of validated category IDs.\r\n * @throws {Error} If any flag value does not match a known category ID.\r\n */\r\nexport function resolveCategories(overwriteFlags: string[]): string[] {\r\n const validIds = INSTALL_CATEGORIES.map((cat) => cat.id);\r\n const unknown = overwriteFlags.filter((flag) => !validIds.includes(flag));\r\n\r\n if (unknown.length > 0) {\r\n throw new Error(\r\n `Unknown overwrite categories: ${unknown.join(', ')}. ` +\r\n `Valid categories are: ${validIds.join(', ')}`,\r\n );\r\n }\r\n\r\n return [...overwriteFlags];\r\n}\r\n","/**\r\n * Summary Screen Component - Post-installation summary display.\r\n *\r\n * Renders installation results with a success/failure header, component\r\n * counts, file statistics, elapsed time, and numbered next-step guidance.\r\n * Adapts layout and styling to the active rendering tier.\r\n *\r\n * @module ui/summary\r\n */\r\n\r\nimport type {\r\n ComponentCounts,\r\n Duration,\r\n InstallationSummary,\r\n NextStep,\r\n} from './types.js';\r\nimport { totalComponentCount } from './types.js';\r\nimport { ThemeEngine } from './theme.js';\r\nimport type { CategoryConflictSummary } from '../engine/conflict-detector.js';\r\nimport { INSTALL_CATEGORIES } from '../engine/category-filter.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Summary Rendering\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Optional category installation details for the summary screen. */\r\nexport interface CategoryInstallInfo {\r\n /** IDs of categories that were selected for installation. */\r\n readonly installedCategories: string[];\r\n /** Per-category file statistics (from conflict detection). */\r\n readonly categoryStats?: CategoryConflictSummary[];\r\n}\r\n\r\n/**\r\n * Render the post-installation summary screen.\r\n *\r\n * @param summary - Installation result data\r\n * @param nextSteps - Ordered list of next-step guidance\r\n * @param theme - ThemeEngine for colors, symbols, and terminal width\r\n * @param categoryInfo - Optional category installation details\r\n * @returns Array of output lines\r\n */\r\nexport function renderSummary(\r\n summary: InstallationSummary,\r\n nextSteps: readonly NextStep[],\r\n theme: ThemeEngine,\r\n categoryInfo?: CategoryInstallInfo,\r\n): string[] {\r\n const width = theme.terminalWidth;\r\n const lines: string[] = [];\r\n\r\n // Header box\r\n lines.push(...renderHeaderBox(summary, theme, width));\r\n lines.push('');\r\n\r\n // Target directory\r\n const dirLabel = summary.success ? 'Installed to:' : 'Target directory:';\r\n lines.push(` ${dirLabel} ${theme.colorize(summary.targetDirectory, 'accent')}`);\r\n lines.push('');\r\n\r\n // Installed categories (when selective installation was used)\r\n if (categoryInfo && categoryInfo.installedCategories.length > 0) {\r\n lines.push(...renderInstalledCategories(categoryInfo, theme));\r\n lines.push('');\r\n }\r\n\r\n // Component counts (only on success or partial success)\r\n if (summary.success || summary.totalFilesCopied > 0) {\r\n lines.push(...renderComponentCounts(summary.componentCounts, theme));\r\n lines.push('');\r\n }\r\n\r\n // File statistics\r\n lines.push(...renderFileStatistics(summary, theme));\r\n lines.push('');\r\n\r\n // Total time\r\n lines.push(` Total time: ${theme.bold(summary.totalDuration.formatted)}`);\r\n lines.push('');\r\n\r\n // Divider\r\n lines.push(renderDivider(theme, width));\r\n lines.push('');\r\n\r\n // Next steps\r\n if (nextSteps.length > 0) {\r\n lines.push(...renderNextSteps(nextSteps, theme));\r\n lines.push('');\r\n lines.push(renderDivider(theme, width));\r\n }\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Header Box\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render the success/failure header box with double-line borders.\r\n */\r\nfunction renderHeaderBox(\r\n summary: InstallationSummary,\r\n theme: ThemeEngine,\r\n width: number,\r\n): string[] {\r\n const symbols = theme.symbolSet;\r\n const boxWidth = Math.min(width - 4, 72);\r\n const innerWidth = boxWidth - 4;\r\n\r\n // Determine header content and color\r\n let statusSymbol: string;\r\n let title: string;\r\n let colorName: 'success' | 'error' | 'warning';\r\n\r\n if (summary.success && summary.totalFilesFailed === 0) {\r\n statusSymbol = theme.statusSymbol('completed');\r\n title = 'Installation Complete!';\r\n colorName = 'success';\r\n } else if (summary.success && summary.totalFilesFailed > 0) {\r\n statusSymbol = theme.tier === 'plain' ? '[!]' : '\\u26A0';\r\n title = 'Installation Completed with Warnings';\r\n colorName = 'warning';\r\n } else {\r\n statusSymbol = theme.statusSymbol('failed');\r\n title = 'Installation Failed';\r\n colorName = 'error';\r\n }\r\n\r\n const colorFn = (text: string): string => theme.colorize(text, colorName);\r\n\r\n const lines: string[] = [];\r\n\r\n // Top border\r\n const topBorder = `${symbols.doubleTopLeft}${symbols.doubleHorizontal.repeat(boxWidth - 2)}${symbols.doubleTopRight}`;\r\n lines.push(` ${colorFn(topBorder)}`);\r\n\r\n // Empty line\r\n const emptyLine = `${symbols.doubleVertical}${' '.repeat(boxWidth - 2)}${symbols.doubleVertical}`;\r\n lines.push(` ${colorFn(emptyLine)}`);\r\n\r\n // Title line (centered)\r\n const titleContent = `${statusSymbol} ${theme.bold(colorFn(title))}`;\r\n const strippedTitleLength = stripAnsi(titleContent).length;\r\n const leftPad = Math.max(0, Math.floor((innerWidth - strippedTitleLength) / 2));\r\n const rightPad = Math.max(0, innerWidth - strippedTitleLength - leftPad);\r\n const titleLine = `${symbols.doubleVertical} ${' '.repeat(leftPad)}${titleContent}${' '.repeat(rightPad)} ${symbols.doubleVertical}`;\r\n lines.push(` ${colorFn(symbols.doubleVertical)} ${' '.repeat(leftPad)}${titleContent}${' '.repeat(rightPad)} ${colorFn(symbols.doubleVertical)}`);\r\n\r\n // Empty line\r\n lines.push(` ${colorFn(emptyLine)}`);\r\n\r\n // Bottom border\r\n const bottomBorder = `${symbols.doubleBottomLeft}${symbols.doubleHorizontal.repeat(boxWidth - 2)}${symbols.doubleBottomRight}`;\r\n lines.push(` ${colorFn(bottomBorder)}`);\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Component Counts\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render component counts as a bulleted list.\r\n */\r\nfunction renderComponentCounts(\r\n counts: ComponentCounts,\r\n theme: ThemeEngine,\r\n): string[] {\r\n const bullet = theme.symbolSet.bullet;\r\n const lines: string[] = [];\r\n\r\n lines.push(` ${theme.bold(theme.colorize('Components installed:', 'header'))}`);\r\n\r\n const items: Array<{ label: string; count: number }> = [\r\n { label: 'agents', count: counts.agents },\r\n { label: 'skills', count: counts.skills },\r\n { label: 'commands', count: counts.commands },\r\n { label: 'TypeScript CLI files', count: counts.cliFiles },\r\n { label: 'configuration files', count: counts.other },\r\n ];\r\n\r\n for (const item of items) {\r\n if (item.count > 0) {\r\n const countStr = theme.colorize(String(item.count), 'accent');\r\n lines.push(` ${bullet} ${countStr} ${item.label}`);\r\n }\r\n }\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Installed Categories\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render installed categories as a bulleted list with file counts.\r\n */\r\nfunction renderInstalledCategories(\r\n categoryInfo: CategoryInstallInfo,\r\n theme: ThemeEngine,\r\n): string[] {\r\n const bullet = theme.symbolSet.bullet;\r\n const lines: string[] = [];\r\n\r\n lines.push(` ${theme.bold(theme.colorize('Categories installed:', 'header'))}`);\r\n\r\n // Build a stats lookup from the optional conflict summaries\r\n const statsMap = new Map<string, CategoryConflictSummary>();\r\n if (categoryInfo.categoryStats) {\r\n for (const stat of categoryInfo.categoryStats) {\r\n statsMap.set(stat.categoryId, stat);\r\n }\r\n }\r\n\r\n for (const catId of categoryInfo.installedCategories) {\r\n // Find the category definition for its label\r\n const catDef = INSTALL_CATEGORIES.find((c) => c.id === catId);\r\n const label = catDef?.label ?? catId;\r\n\r\n const stat = statsMap.get(catId);\r\n if (stat) {\r\n const countStr = theme.colorize(String(stat.totalFiles), 'accent');\r\n lines.push(` ${bullet} ${label}: ${countStr} files`);\r\n } else {\r\n lines.push(` ${bullet} ${label}`);\r\n }\r\n }\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// File Statistics\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render file copy statistics with status symbols.\r\n */\r\nfunction renderFileStatistics(\r\n summary: InstallationSummary,\r\n theme: ThemeEngine,\r\n): string[] {\r\n const lines: string[] = [];\r\n\r\n lines.push(` ${theme.bold(theme.colorize('File statistics:', 'header'))}`);\r\n\r\n // Copied\r\n const copiedSymbol = theme.statusSymbol('completed');\r\n lines.push(` ${copiedSymbol} ${summary.totalFilesCopied} files copied successfully`);\r\n\r\n // Skipped\r\n const skippedSymbol = theme.statusSymbol('skipped');\r\n if (summary.totalFilesSkipped > 0) {\r\n lines.push(\r\n ` ${skippedSymbol} ${summary.totalFilesSkipped} files skipped (already up-to-date)`,\r\n );\r\n }\r\n\r\n // Failed\r\n const failedSymbol = theme.statusSymbol('failed');\r\n const failedText = summary.totalFilesFailed > 0\r\n ? `${summary.totalFilesFailed} files failed`\r\n : '0 files failed';\r\n lines.push(` ${failedSymbol} ${failedText}`);\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Next Steps\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render numbered next-step guidance with optional copyable commands.\r\n */\r\nfunction renderNextSteps(\r\n steps: readonly NextStep[],\r\n theme: ThemeEngine,\r\n): string[] {\r\n const lines: string[] = [];\r\n\r\n lines.push(` ${theme.bold(theme.colorize('Next steps:', 'header'))}`);\r\n lines.push('');\r\n\r\n for (const step of steps) {\r\n // Numbered title\r\n lines.push(` ${step.order}. ${step.title}:`);\r\n\r\n // Instruction or command\r\n if (step.command) {\r\n lines.push(` ${theme.colorize(step.command, 'accent')}`);\r\n } else {\r\n lines.push(` ${step.instruction}`);\r\n }\r\n\r\n lines.push('');\r\n }\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Divider\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render a horizontal divider line.\r\n */\r\nfunction renderDivider(theme: ThemeEngine, width: number): string {\r\n const dividerWidth = Math.min(width - 4, 72);\r\n const char = theme.symbolSet.boxHorizontal;\r\n return ` ${theme.dim(char.repeat(dividerWidth))}`;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Utility\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Strip ANSI escape codes from a string for accurate length calculation.\r\n */\r\nfunction stripAnsi(text: string): string {\r\n // eslint-disable-next-line no-control-regex\r\n return text.replace(/\\x1b\\[[0-9;]*m/g, '');\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Default Next Steps\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Generate default next-step guidance based on installation result.\r\n */\r\nexport function getDefaultNextSteps(success: boolean): NextStep[] {\r\n if (success) {\r\n return [\r\n {\r\n order: 1,\r\n title: 'Verify the installation',\r\n instruction: 'Run the status command to verify',\r\n command: 'ai-dlc status',\r\n },\r\n {\r\n order: 2,\r\n title: 'Start your first AI-DLC project',\r\n instruction: 'Create an intent to begin',\r\n command: 'ai-dlc start-intent \"Your project idea\"',\r\n },\r\n {\r\n order: 3,\r\n title: 'View available commands',\r\n instruction: 'See all available commands',\r\n command: 'ai-dlc help',\r\n },\r\n {\r\n order: 4,\r\n title: 'Read the documentation',\r\n instruction: 'Visit the documentation site',\r\n command: 'https://github.com/SixSevenAI/ai-dlc/docs',\r\n },\r\n ];\r\n }\r\n\r\n return [\r\n {\r\n order: 1,\r\n title: 'Review the error messages above',\r\n instruction: 'Identify the root cause of the failure',\r\n command: null,\r\n },\r\n {\r\n order: 2,\r\n title: 'Fix the underlying issue',\r\n instruction: 'Address permissions, disk space, or network issues',\r\n command: null,\r\n },\r\n {\r\n order: 3,\r\n title: 'Run the installer again',\r\n instruction: 'Retry the installation',\r\n command: 'npx @sixsevenai/ai-dlc install',\r\n },\r\n {\r\n order: 4,\r\n title: 'Get help',\r\n instruction: 'Report an issue on GitHub',\r\n command: 'https://github.com/SixSevenAI/ai-dlc/issues',\r\n },\r\n ];\r\n}\r\n","/**\r\n * SixSeven Animation Module\r\n *\r\n * Provides a terminal spinner with a bouncing/wave animation between\r\n * the digits 6 and 7 — the SixSevenAI brand motif. Supports plain\r\n * text mode (hidden cursor, frame cycling) and a progress-bar variant\r\n * for long-running file-copy operations.\r\n *\r\n * All output goes to `process.stderr` so it never contaminates stdout\r\n * piping. In non-TTY / quiet mode every method is a silent no-op.\r\n *\r\n * @module ui/sixseven-animation\r\n */\r\n\r\n// ---------------------------------------------------------------------------\r\n// Animation Frames\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Six frames depicting two dots bouncing between the digits 6 and 7.\r\n * Every frame is exactly 15 characters wide so the line stays stable.\r\n */\r\nconst FRAMES = [\r\n ' 6 * 7 ',\r\n ' 6 * 7 ',\r\n ' 6 * 7 ',\r\n ' 6 * 7 ',\r\n ' 6 * 7 ',\r\n ' 6 * 7 ',\r\n];\r\n\r\n// ---------------------------------------------------------------------------\r\n// Progress Bar Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\nconst BAR_WIDTH = 20;\r\n\r\nfunction renderBar(current: number, total: number): string {\r\n const ratio = total > 0 ? Math.min(current / total, 1) : 0;\r\n const filled = Math.round(ratio * BAR_WIDTH);\r\n const empty = BAR_WIDTH - filled;\r\n return '\\u2588'.repeat(filled) + '\\u2591'.repeat(empty);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// SixSevenSpinner\r\n// ---------------------------------------------------------------------------\r\n\r\nexport class SixSevenSpinner {\r\n private intervalId: ReturnType<typeof setInterval> | null = null;\r\n private frameIndex = 0;\r\n private message = '';\r\n private isActive = false;\r\n private readonly isSilent: boolean;\r\n\r\n constructor(options?: { quiet?: boolean }) {\r\n this.isSilent = options?.quiet ?? !process.stderr.isTTY;\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Public API\r\n // -------------------------------------------------------------------------\r\n\r\n /**\r\n * Start the spinner animation with an initial message.\r\n */\r\n start(message: string): void {\r\n if (this.isSilent) return;\r\n if (this.isActive) return;\r\n\r\n this.message = message;\r\n this.frameIndex = 0;\r\n this.isActive = true;\r\n\r\n // Hide cursor\r\n process.stderr.write('\\x1b[?25l');\r\n\r\n this.render();\r\n this.intervalId = setInterval(() => {\r\n this.frameIndex = (this.frameIndex + 1) % FRAMES.length;\r\n this.render();\r\n }, 150);\r\n }\r\n\r\n /**\r\n * Update the message text displayed alongside the animation.\r\n */\r\n update(message: string): void {\r\n if (this.isSilent) return;\r\n this.message = message;\r\n }\r\n\r\n /**\r\n * Update with a progress bar showing current/total and a category label.\r\n *\r\n * Renders: ` 6 * 7 [████░░░░] 12/48 Installing agents...`\r\n */\r\n updateProgress(current: number, total: number, category: string): void {\r\n if (this.isSilent) return;\r\n const bar = renderBar(current, total);\r\n const counter = `${current}/${total}`.padStart(String(total).length * 2 + 1);\r\n this.message = `[${bar}] ${counter} ${category}`;\r\n }\r\n\r\n /**\r\n * Stop the spinner, display a final message with a checkmark, and\r\n * restore the cursor.\r\n */\r\n stop(finalMessage: string): void {\r\n if (this.isSilent) return;\r\n\r\n if (this.intervalId !== null) {\r\n clearInterval(this.intervalId);\r\n this.intervalId = null;\r\n }\r\n\r\n this.isActive = false;\r\n\r\n // Clear line, write final message, restore cursor\r\n process.stderr.write(`\\r\\x1b[K \\x1b[32m\\u2714\\x1b[0m ${finalMessage}\\n`);\r\n process.stderr.write('\\x1b[?25h');\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Internal\r\n // -------------------------------------------------------------------------\r\n\r\n private render(): void {\r\n const frame = FRAMES[this.frameIndex];\r\n process.stderr.write(`\\r\\x1b[K${frame} ${this.message}`);\r\n }\r\n}\r\n","/**\r\n * CLI Orchestrator - Error Handler\r\n *\r\n * Centralized error classification, recovery strategy selection, and\r\n * actionable message generation. Provides rollback coordination when\r\n * fatal errors occur during installation.\r\n *\r\n * @module orchestrator/error-handler\r\n */\r\n\r\nimport type {\r\n ClassifiedError,\r\n ErrorCategory,\r\n ErrorSeverity,\r\n ErrorSummaryInfo,\r\n ExitCode,\r\n RecoveryAction,\r\n RecoveryStrategy,\r\n WorkflowState,\r\n WorkflowStepId,\r\n} from './types.js';\r\nimport {\r\n EXIT_SUCCESS,\r\n EXIT_ERROR,\r\n EXIT_CANCELLED,\r\n} from './types.js';\r\n\r\nimport { UserCancellationError } from '../ui/index.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Constants\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Maximum number of retries per step. */\r\nconst MAX_RETRIES = 2;\r\n\r\n/** Counter for generating unique error IDs. */\r\nlet errorCounter = 0;\r\n\r\n// ---------------------------------------------------------------------------\r\n// ErrorHandler\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Centralized error classification and recovery coordinator.\r\n *\r\n * Catches errors from any subsystem, classifies them by category and\r\n * severity, determines the appropriate recovery strategy, and produces\r\n * actionable user-facing messages.\r\n */\r\nexport class ErrorHandler {\r\n private readonly errors: ClassifiedError[] = [];\r\n private readonly retryCounts: Map<WorkflowStepId, number> = new Map();\r\n\r\n /**\r\n * Classify an error and determine the recovery action.\r\n *\r\n * @param error - Raw error from any subsystem\r\n * @param stepId - The workflow step where the error occurred\r\n * @returns Recovery action to take\r\n */\r\n handleError(error: Error, stepId: WorkflowStepId): RecoveryAction {\r\n const category = classifyCategory(error);\r\n const severity = classifySeverity(category);\r\n const recoveryStrategy = selectRecoveryStrategy(category, severity, this.canRetry(stepId));\r\n\r\n const classified: ClassifiedError = {\r\n errorId: `err-${++errorCounter}`,\r\n originalError: error,\r\n category,\r\n severity,\r\n sourceStep: stepId,\r\n recoveryStrategy,\r\n retryCount: this.getRetryCount(stepId),\r\n timestamp: new Date(),\r\n userMessage: buildUserMessage(category, error),\r\n technicalDetail: error.stack ?? error.message,\r\n };\r\n\r\n this.errors.push(classified);\r\n\r\n return {\r\n strategy: recoveryStrategy,\r\n stepId,\r\n userGuidance: buildUserGuidance(category, error),\r\n platformGuidance: buildPlatformGuidance(category),\r\n };\r\n }\r\n\r\n /**\r\n * Check whether the specified step can be retried.\r\n */\r\n canRetry(stepId: WorkflowStepId): boolean {\r\n return this.getRetryCount(stepId) < MAX_RETRIES;\r\n }\r\n\r\n /**\r\n * Record a retry attempt for a step.\r\n */\r\n recordRetry(stepId: WorkflowStepId): void {\r\n const current = this.retryCounts.get(stepId) ?? 0;\r\n this.retryCounts.set(stepId, current + 1);\r\n }\r\n\r\n /**\r\n * Get the current retry count for a step.\r\n */\r\n getRetryCount(stepId: WorkflowStepId): number {\r\n return this.retryCounts.get(stepId) ?? 0;\r\n }\r\n\r\n /**\r\n * Check if the workflow should abort due to accumulated errors.\r\n */\r\n shouldAbort(): boolean {\r\n return this.errors.some(e => e.severity === 'Fatal');\r\n }\r\n\r\n /**\r\n * Get a summary of all accumulated errors.\r\n */\r\n getErrorSummary(): ErrorSummaryInfo {\r\n const fatalCount = this.errors.filter(e => e.severity === 'Fatal').length;\r\n const recoverableCount = this.errors.filter(e => e.severity === 'Recoverable').length;\r\n const warningCount = this.errors.filter(e => e.severity === 'Warning').length;\r\n\r\n return {\r\n totalErrors: this.errors.length,\r\n fatalCount,\r\n recoverableCount,\r\n warningCount,\r\n messages: this.errors.map(e => e.userMessage),\r\n };\r\n }\r\n\r\n /**\r\n * Determine the appropriate exit code based on workflow state and errors.\r\n */\r\n getExitCode(workflow: WorkflowState): ExitCode {\r\n if (workflow.status === 'cancelled') {\r\n return EXIT_CANCELLED;\r\n }\r\n\r\n if (workflow.status === 'failed') {\r\n return EXIT_ERROR;\r\n }\r\n\r\n if (this.errors.some(e => e.severity === 'Fatal')) {\r\n return EXIT_ERROR;\r\n }\r\n\r\n return EXIT_SUCCESS;\r\n }\r\n\r\n /**\r\n * Get all classified errors for inspection.\r\n */\r\n getErrors(): readonly ClassifiedError[] {\r\n return this.errors;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Classification Functions\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Classify the error category based on error type and message patterns.\r\n */\r\nfunction classifyCategory(error: Error): ErrorCategory {\r\n if (error instanceof UserCancellationError || error.name === 'UserCancellationError') {\r\n return 'Cancellation';\r\n }\r\n\r\n const message = error.message.toLowerCase();\r\n const code = (error as NodeJS.ErrnoException).code;\r\n\r\n // Permission errors\r\n if (code === 'EACCES' || code === 'EPERM' || message.includes('permission denied')) {\r\n return 'Permission';\r\n }\r\n\r\n // Disk space errors\r\n if (code === 'ENOSPC' || message.includes('disk full') || message.includes('no space')) {\r\n return 'DiskSpace';\r\n }\r\n\r\n // Path errors\r\n if (\r\n code === 'ENOENT' ||\r\n code === 'ENOTDIR' ||\r\n message.includes('invalid path') ||\r\n message.includes('not a directory') ||\r\n message.includes('does not exist')\r\n ) {\r\n return 'InvalidPath';\r\n }\r\n\r\n // Runtime version\r\n if (\r\n message.includes('node.js') ||\r\n message.includes('node version') ||\r\n message.includes('npm') ||\r\n message.includes('minimum required')\r\n ) {\r\n return 'RuntimeVersion';\r\n }\r\n\r\n // Validation failures\r\n if (\r\n message.includes('validation') ||\r\n message.includes('missing files') ||\r\n message.includes('corrupt')\r\n ) {\r\n return 'ValidationFailure';\r\n }\r\n\r\n // Integrity errors\r\n if (\r\n message.includes('integrity') ||\r\n message.includes('hash') ||\r\n message.includes('source directory')\r\n ) {\r\n return 'IntegrityError';\r\n }\r\n\r\n // Conflict resolution\r\n if (message.includes('conflict') || message.includes('overwrite')) {\r\n return 'ConflictResolution';\r\n }\r\n\r\n return 'InternalError';\r\n}\r\n\r\n/**\r\n * Map error category to severity level.\r\n */\r\nfunction classifySeverity(category: ErrorCategory): ErrorSeverity {\r\n switch (category) {\r\n case 'Cancellation':\r\n return 'Fatal';\r\n case 'DiskSpace':\r\n return 'Fatal';\r\n case 'IntegrityError':\r\n return 'Fatal';\r\n case 'RuntimeVersion':\r\n return 'Fatal';\r\n case 'Permission':\r\n return 'Recoverable';\r\n case 'InvalidPath':\r\n return 'Recoverable';\r\n case 'ConflictResolution':\r\n return 'Recoverable';\r\n case 'ValidationFailure':\r\n return 'Fatal';\r\n case 'InternalError':\r\n return 'Fatal';\r\n }\r\n}\r\n\r\n/**\r\n * Select the appropriate recovery strategy.\r\n */\r\nfunction selectRecoveryStrategy(\r\n category: ErrorCategory,\r\n severity: ErrorSeverity,\r\n canRetry: boolean,\r\n): RecoveryStrategy {\r\n if (category === 'Cancellation') {\r\n return 'AbortImmediately';\r\n }\r\n\r\n if (severity === 'Fatal') {\r\n return 'RollbackAndAbort';\r\n }\r\n\r\n if (severity === 'Recoverable' && canRetry) {\r\n return 'PromptUser';\r\n }\r\n\r\n if (severity === 'Recoverable') {\r\n return 'RollbackAndAbort';\r\n }\r\n\r\n return 'SkipAndContinue';\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Message Builders\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction buildUserMessage(category: ErrorCategory, error: Error): string {\r\n switch (category) {\r\n case 'Permission':\r\n return `Permission denied: ${error.message}`;\r\n case 'DiskSpace':\r\n return `Insufficient disk space: ${error.message}`;\r\n case 'InvalidPath':\r\n return `Invalid path: ${error.message}`;\r\n case 'RuntimeVersion':\r\n return `Runtime requirement not met: ${error.message}`;\r\n case 'ValidationFailure':\r\n return `Installation validation failed: ${error.message}`;\r\n case 'IntegrityError':\r\n return `Source integrity error: ${error.message}`;\r\n case 'ConflictResolution':\r\n return `Conflict resolution failed: ${error.message}`;\r\n case 'Cancellation':\r\n return 'Installation cancelled by user.';\r\n case 'InternalError':\r\n return `Unexpected error: ${error.message}`;\r\n }\r\n}\r\n\r\nfunction buildUserGuidance(category: ErrorCategory, error: Error): string {\r\n switch (category) {\r\n case 'Permission':\r\n return 'Run the installer with elevated permissions or choose a different target directory.';\r\n case 'DiskSpace':\r\n return 'Free up disk space and try again.';\r\n case 'InvalidPath':\r\n return 'Check that the target directory path is valid and the parent directory exists.';\r\n case 'RuntimeVersion':\r\n return 'Upgrade Node.js to version 18 or later. Visit https://nodejs.org/';\r\n case 'ValidationFailure':\r\n return 'Try running the installer again. If the problem persists, check file permissions.';\r\n case 'IntegrityError':\r\n return 'The AI-DLC library source may be corrupted. Re-clone the repository or re-install the package.';\r\n case 'ConflictResolution':\r\n return 'Use --force to overwrite existing files, or manually resolve conflicts.';\r\n case 'Cancellation':\r\n return 'Installation was cancelled. No changes were made.';\r\n case 'InternalError':\r\n return 'This is an unexpected error. Please report it with the --verbose output.';\r\n }\r\n}\r\n\r\nfunction buildPlatformGuidance(category: ErrorCategory): string | null {\r\n switch (category) {\r\n case 'Permission':\r\n return process.platform === 'win32'\r\n ? 'Right-click your terminal and select \"Run as Administrator\".'\r\n : 'Prefix the command with sudo: sudo sixsevenai install';\r\n default:\r\n return null;\r\n }\r\n}\r\n","/**\r\n * Platform Abstraction Layer - Shared Types\r\n *\r\n * All immutable value objects, enumerations, branded types, and interfaces\r\n * used throughout the platform detection subsystem.\r\n *\r\n * @module platform/types\r\n */\r\n\r\n// ---------------------------------------------------------------------------\r\n// Branded Type: NormalizedPath\r\n// ---------------------------------------------------------------------------\r\n\r\ndeclare const NormalizedPathBrand: unique symbol;\r\n\r\n/**\r\n * A branded string type representing a normalized file system path.\r\n * Internally always uses forward slashes. Created only through\r\n * PathNormalizer methods to enforce normalization invariants.\r\n */\r\nexport type NormalizedPath = string & {\r\n readonly [NormalizedPathBrand]: typeof NormalizedPathBrand;\r\n};\r\n\r\n/**\r\n * Cast a raw string to NormalizedPath. Use only in factory methods\r\n * or tests where you know the string is already normalized.\r\n */\r\nexport function createNormalizedPath(value: string): NormalizedPath {\r\n return value as NormalizedPath;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Operating System\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Supported OS family identifiers. */\r\nexport type OsFamily = 'windows' | 'macos' | 'linux';\r\n\r\n/** Supported CPU architectures. */\r\nexport type ArchitectureName = 'x64' | 'arm64' | 'x86';\r\n\r\n/** CPU architecture value object. */\r\nexport interface Architecture {\r\n readonly name: ArchitectureName;\r\n}\r\n\r\n/** Operating system value object. */\r\nexport interface OperatingSystem {\r\n readonly family: OsFamily;\r\n readonly version: string;\r\n readonly release: string;\r\n readonly architecture: Architecture;\r\n}\r\n\r\n/** Resolved user home directory. */\r\nexport interface HomeDirectory {\r\n readonly path: string;\r\n readonly source: 'USERPROFILE' | 'HOME' | 'os.homedir';\r\n}\r\n\r\n/** System temp directory. */\r\nexport interface TempDirectory {\r\n readonly path: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Platform Snapshot\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Complete, immutable snapshot of the host platform. */\r\nexport interface PlatformSnapshot {\r\n readonly os: OperatingSystem;\r\n readonly homeDirectory: HomeDirectory;\r\n readonly tempDirectory: TempDirectory;\r\n readonly detectedAt: Date;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Shell\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Recognized shell types. */\r\nexport type ShellType =\r\n | 'powershell'\r\n | 'cmd'\r\n | 'bash'\r\n | 'zsh'\r\n | 'fish'\r\n | 'unknown';\r\n\r\n/** Basic shell information included in PlatformSnapshot. */\r\nexport interface ShellInfo {\r\n readonly type: ShellType;\r\n readonly version: string | null;\r\n readonly profilePath: string | null;\r\n readonly executablePath: string;\r\n}\r\n\r\n/** Complete shell detection result. */\r\nexport interface ShellEnvironment {\r\n readonly type: ShellType;\r\n readonly version: string | null;\r\n readonly executablePath: string;\r\n readonly profilePath: NormalizedPath | null;\r\n readonly profileExists: boolean;\r\n readonly pathSeparator: ';' | ':';\r\n readonly pathModificationCommand: string | null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Terminal\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Color support tiers, ordered by capability. */\r\nexport enum ColorSupportLevel {\r\n /** No color support (piped output, NO_COLOR set, non-TTY). */\r\n None = 0,\r\n /** 16 colors (basic ANSI). */\r\n Basic = 1,\r\n /** 256 colors (xterm-256color). */\r\n Extended = 2,\r\n /** 16 million colors (24-bit true color). */\r\n TrueColor = 3,\r\n}\r\n\r\n/** Terminal viewport dimensions. */\r\nexport interface TerminalDimensions {\r\n readonly columns: number;\r\n readonly rows: number;\r\n}\r\n\r\n/** Unicode rendering capability. */\r\nexport interface UnicodeSupport {\r\n readonly supported: boolean;\r\n readonly detectionMethod: 'locale' | 'env' | 'terminal' | 'default';\r\n}\r\n\r\n/** Terminal interactivity mode. */\r\nexport interface InteractivityMode {\r\n readonly isInteractive: boolean;\r\n readonly isTTY: boolean;\r\n readonly supportsRawMode: boolean;\r\n}\r\n\r\n/** Identified terminal emulator. */\r\nexport interface TerminalEmulator {\r\n readonly name: string | null;\r\n readonly version: string | null;\r\n readonly isKnown: boolean;\r\n}\r\n\r\n/** Complete terminal capability profile. */\r\nexport interface TerminalProfile {\r\n readonly colorSupport: ColorSupportLevel;\r\n readonly dimensions: TerminalDimensions;\r\n readonly unicodeSupport: UnicodeSupport;\r\n readonly interactivity: InteractivityMode;\r\n readonly emulator: TerminalEmulator;\r\n readonly detectedAt: Date;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Permissions\r\n// ---------------------------------------------------------------------------\r\n\r\n/** File access modes for permission checking. */\r\nexport enum AccessMode {\r\n Read = 'read',\r\n Write = 'write',\r\n Execute = 'execute',\r\n ReadWrite = 'readwrite',\r\n}\r\n\r\n/** Platform-specific guidance for obtaining elevated privileges. */\r\nexport interface ElevationInstructions {\r\n readonly platform: OsFamily;\r\n readonly command: string;\r\n readonly description: string;\r\n readonly shellSpecificHint: string | null;\r\n}\r\n\r\n/** Result of a permission check on a specific path. */\r\nexport interface PermissionResult {\r\n readonly targetPath: NormalizedPath;\r\n readonly canRead: boolean;\r\n readonly canWrite: boolean;\r\n readonly canExecute: boolean;\r\n readonly exists: boolean;\r\n readonly isDirectory: boolean;\r\n readonly requiresElevation: boolean;\r\n readonly elevationInstructions: ElevationInstructions | null;\r\n readonly checkedAt: Date;\r\n}\r\n\r\n/** Symlink creation capability. */\r\nexport interface SymlinkCapability {\r\n readonly supported: boolean;\r\n readonly requiresDeveloperMode: boolean;\r\n readonly requiresElevation: boolean;\r\n readonly instructions: string | null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Runtime Validation\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Parsed semantic version for comparison. */\r\nexport interface SemVer {\r\n readonly major: number;\r\n readonly minor: number;\r\n readonly patch: number;\r\n readonly raw: string;\r\n}\r\n\r\n/** A detected runtime tool with its version. */\r\nexport interface RuntimeVersion {\r\n readonly tool: 'node' | 'npm' | 'npx' | 'git';\r\n readonly version: SemVer;\r\n readonly executablePath: string;\r\n readonly meetsMinimum: boolean;\r\n readonly minimumRequired: SemVer;\r\n}\r\n\r\n/** The directory where npm installs global package executables. */\r\nexport interface GlobalBinDirectory {\r\n readonly path: NormalizedPath;\r\n readonly isOnPath: boolean;\r\n readonly pathFixCommand: string | null;\r\n}\r\n\r\n/** Runtime validation error types. */\r\nexport type RuntimeErrorType = 'not_found' | 'version_too_low' | 'not_on_path';\r\n\r\n/** A specific runtime validation failure. */\r\nexport interface RuntimeError {\r\n readonly tool: string;\r\n readonly errorType: RuntimeErrorType;\r\n readonly message: string;\r\n readonly fix: string;\r\n}\r\n\r\n/** Complete runtime validation result. */\r\nexport interface RuntimeReport {\r\n readonly node: RuntimeVersion;\r\n readonly npm: RuntimeVersion | null;\r\n readonly git: RuntimeVersion | null;\r\n readonly globalBinDir: GlobalBinDirectory | null;\r\n readonly allRequirementsMet: boolean;\r\n readonly errors: readonly RuntimeError[];\r\n readonly validatedAt: Date;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Composite: PlatformEnvironment\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Complete platform environment returned by IPlatformFacade.detectAll(). */\r\nexport interface PlatformEnvironment {\r\n readonly platform: PlatformSnapshot;\r\n readonly terminal: TerminalProfile;\r\n readonly shell: ShellEnvironment;\r\n readonly runtime: RuntimeReport;\r\n readonly permissions: {\r\n checkWriteAccess(path: NormalizedPath): Promise<PermissionResult>;\r\n checkDirectoryCreatable(path: NormalizedPath): Promise<PermissionResult>;\r\n };\r\n readonly paths: IPathNormalizer;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Disposable\r\n// ---------------------------------------------------------------------------\r\n\r\n/** A resource that can be disposed to release subscriptions. */\r\nexport interface Disposable {\r\n dispose(): void;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Interfaces (Ports)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Detects the host operating system, architecture, and directories. */\r\nexport interface IPlatformDetector {\r\n detect(): PlatformSnapshot;\r\n}\r\n\r\n/** Stateless path manipulation utility. */\r\nexport interface IPathNormalizer {\r\n normalize(rawPath: string, os: OperatingSystem): NormalizedPath;\r\n toNative(path: NormalizedPath, os: OperatingSystem): string;\r\n resolveHome(path: string, homeDir: HomeDirectory): NormalizedPath;\r\n toAbsolute(path: NormalizedPath, basePath: NormalizedPath): NormalizedPath;\r\n toRelative(path: NormalizedPath, basePath: NormalizedPath): NormalizedPath;\r\n join(base: NormalizedPath, ...segments: string[]): NormalizedPath;\r\n parent(path: NormalizedPath): NormalizedPath | null;\r\n extension(path: NormalizedPath): string | null;\r\n getDefaultClaudeDir(homeDir: HomeDirectory, os: OperatingSystem): NormalizedPath;\r\n}\r\n\r\n/** Checks file system permissions and elevation status. */\r\nexport interface IPermissionChecker {\r\n checkAccess(\r\n path: NormalizedPath,\r\n desiredAccess: AccessMode,\r\n platform: PlatformSnapshot,\r\n ): Promise<PermissionResult>;\r\n checkWriteAccess(\r\n path: NormalizedPath,\r\n platform: PlatformSnapshot,\r\n ): Promise<PermissionResult>;\r\n checkDirectoryCreatable(\r\n path: NormalizedPath,\r\n platform: PlatformSnapshot,\r\n ): Promise<PermissionResult>;\r\n detectElevation(platform: PlatformSnapshot): Promise<boolean>;\r\n checkSymlinkCapability(\r\n platform: PlatformSnapshot,\r\n ): Promise<SymlinkCapability>;\r\n}\r\n\r\n/** Detects terminal rendering and interaction capabilities. */\r\nexport interface ITerminalDetector {\r\n detectProfile(): TerminalProfile;\r\n detectColorSupport(): ColorSupportLevel;\r\n detectDimensions(): TerminalDimensions;\r\n onResize(callback: (dimensions: TerminalDimensions) => void): Disposable;\r\n}\r\n\r\n/** Identifies the active shell and its configuration. */\r\nexport interface IShellDetector {\r\n detectShell(platform: PlatformSnapshot): Promise<ShellEnvironment>;\r\n getPathModificationCommand(\r\n shell: ShellEnvironment,\r\n directory: NormalizedPath,\r\n ): string;\r\n getProfileEditCommand(shell: ShellEnvironment): string | null;\r\n}\r\n\r\n/** Validates Node.js and npm runtime versions and paths. */\r\nexport interface IRuntimeValidator {\r\n validate(minimumNode: SemVer, minimumNpm: SemVer): Promise<RuntimeReport>;\r\n checkNodeVersion(minimum: SemVer): RuntimeVersion;\r\n checkNpmVersion(minimum: SemVer): Promise<RuntimeVersion>;\r\n resolveGlobalBinDir(\r\n shell: ShellEnvironment,\r\n ): Promise<GlobalBinDirectory>;\r\n checkToolAvailable(\r\n toolName: string,\r\n ): Promise<{ available: boolean; path: string | null }>;\r\n}\r\n\r\n/** High-level entry point for all platform detection. */\r\nexport interface IPlatformFacade {\r\n detectAll(): Promise<PlatformEnvironment>;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Error Types\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Error codes for platform detection failures. */\r\nexport type PlatformErrorCode =\r\n | 'UNSUPPORTED_PLATFORM'\r\n | 'DETECTION_FAILED'\r\n | 'INVALID_PATH'\r\n | 'PERMISSION_ERROR'\r\n | 'RUNTIME_NOT_FOUND'\r\n | 'RUNTIME_VERSION_LOW'\r\n | 'CHILD_PROCESS_TIMEOUT'\r\n | 'CHILD_PROCESS_ERROR';\r\n\r\n/** Base error for all platform detection failures. */\r\nexport class PlatformError extends Error {\r\n readonly code: PlatformErrorCode;\r\n readonly component: string;\r\n readonly context?: Record<string, unknown>;\r\n\r\n constructor(\r\n code: PlatformErrorCode,\r\n component: string,\r\n message: string,\r\n context?: Record<string, unknown>,\r\n ) {\r\n super(message);\r\n this.name = 'PlatformError';\r\n this.code = code;\r\n this.component = component;\r\n this.context = context;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// SemVer Utilities\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Parse a version string like \"20.11.0\" or \"v20.11.0\" into a SemVer object.\r\n * Returns null if parsing fails.\r\n */\r\nexport function parseSemVer(versionString: string): SemVer | null {\r\n const cleaned = versionString.trim().replace(/^v/i, '');\r\n const match = /^(\\d+)\\.(\\d+)\\.(\\d+)/.exec(cleaned);\r\n if (!match) {\r\n return null;\r\n }\r\n return {\r\n major: parseInt(match[1], 10),\r\n minor: parseInt(match[2], 10),\r\n patch: parseInt(match[3], 10),\r\n raw: versionString.trim(),\r\n };\r\n}\r\n\r\n/**\r\n * Check if `version` satisfies the minimum requirement (>=).\r\n */\r\nexport function semVerSatisfiesMinimum(\r\n version: SemVer,\r\n minimum: SemVer,\r\n): boolean {\r\n if (version.major !== minimum.major) {\r\n return version.major > minimum.major;\r\n }\r\n if (version.minor !== minimum.minor) {\r\n return version.minor > minimum.minor;\r\n }\r\n return version.patch >= minimum.patch;\r\n}\r\n\r\n/**\r\n * Compare two SemVer values. Returns -1, 0, or 1.\r\n */\r\nexport function semVerCompare(a: SemVer, b: SemVer): -1 | 0 | 1 {\r\n if (a.major !== b.major) return a.major < b.major ? -1 : 1;\r\n if (a.minor !== b.minor) return a.minor < b.minor ? -1 : 1;\r\n if (a.patch !== b.patch) return a.patch < b.patch ? -1 : 1;\r\n return 0;\r\n}\r\n\r\n/**\r\n * Create a SemVer from explicit version numbers. Useful for defining constants.\r\n */\r\nexport function semVer(\r\n major: number,\r\n minor: number,\r\n patch: number,\r\n): SemVer {\r\n return {\r\n major,\r\n minor,\r\n patch,\r\n raw: `${major}.${minor}.${patch}`,\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// CI Environment Detection\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Known CI environment variables. */\r\nexport interface CIEnvironment {\r\n readonly isCI: boolean;\r\n readonly name: string | null;\r\n}\r\n","/**\r\n * Platform Detection - Detects OS, architecture, home directory, and temp directory.\r\n *\r\n * This is the primary entry point for platform identification. It produces\r\n * a PlatformSnapshot value object consumed by all other platform subsystems.\r\n *\r\n * @module platform/detector\r\n */\r\n\r\nimport * as os from 'node:os';\r\n\r\nimport {\r\n type Architecture,\r\n type ArchitectureName,\r\n type HomeDirectory,\r\n type IPlatformDetector,\r\n type OperatingSystem,\r\n type OsFamily,\r\n type PlatformSnapshot,\r\n PlatformError,\r\n type TempDirectory,\r\n} from './types.js';\r\n\r\n/**\r\n * Map process.platform values to OsFamily. Only win32, darwin, and linux\r\n * are supported. All other values produce an UNSUPPORTED_PLATFORM error.\r\n */\r\nfunction resolveOsFamily(platform: string): OsFamily {\r\n switch (platform) {\r\n case 'win32':\r\n return 'windows';\r\n case 'darwin':\r\n return 'macos';\r\n case 'linux':\r\n return 'linux';\r\n default:\r\n throw new PlatformError(\r\n 'UNSUPPORTED_PLATFORM',\r\n 'PlatformDetector',\r\n `Unsupported platform: \"${platform}\". Only Windows, macOS, and Linux are supported.`,\r\n { platform },\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Map process.arch values to ArchitectureName.\r\n * Supported: x64, arm64, ia32 (mapped to x86).\r\n * All other values default to x64 with a warning logged to stderr.\r\n */\r\nfunction resolveArchitecture(arch: string): Architecture {\r\n const archMap: Record<string, ArchitectureName> = {\r\n x64: 'x64',\r\n arm64: 'arm64',\r\n ia32: 'x86',\r\n x86: 'x86',\r\n };\r\n\r\n const name = archMap[arch];\r\n if (name) {\r\n return { name };\r\n }\r\n\r\n // Fallback for unknown architectures -- default to x64\r\n return { name: 'x64' };\r\n}\r\n\r\n/**\r\n * Build a human-readable OS release name from os.type(), os.release(),\r\n * and os.version() where available.\r\n */\r\nfunction resolveReleaseName(family: OsFamily, version: string): string {\r\n switch (family) {\r\n case 'windows': {\r\n // os.version() returns something like \"Windows 10 Pro\" or \"Windows 11 Home\"\r\n // os.release() returns the NT version like \"10.0.22621\"\r\n try {\r\n const osVersion = os.version();\r\n if (osVersion) {\r\n return osVersion;\r\n }\r\n } catch {\r\n // os.version() not available on older Node versions\r\n }\r\n return `Windows NT ${version}`;\r\n }\r\n case 'macos': {\r\n // Map major version to macOS marketing name\r\n const majorMinor = version.split('.').slice(0, 2).join('.');\r\n const macVersionNames: Record<string, string> = {\r\n '24': 'Sequoia',\r\n '23': 'Sonoma',\r\n '22': 'Ventura',\r\n '21': 'Monterey',\r\n '20': 'Big Sur',\r\n '19': 'Catalina',\r\n };\r\n const major = version.split('.')[0];\r\n const name = macVersionNames[major];\r\n return name ? `macOS ${name} ${majorMinor}` : `macOS ${majorMinor}`;\r\n }\r\n case 'linux': {\r\n try {\r\n const osVersion = os.version();\r\n if (osVersion) {\r\n return osVersion;\r\n }\r\n } catch {\r\n // os.version() not available on older Node versions\r\n }\r\n return `Linux ${version}`;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Resolve the user home directory with platform-specific fallbacks.\r\n *\r\n * Priority:\r\n * 1. Windows: USERPROFILE env var\r\n * 2. Unix: HOME env var\r\n * 3. Fallback: os.homedir()\r\n */\r\nfunction resolveHomeDirectory(family: OsFamily): HomeDirectory {\r\n if (family === 'windows') {\r\n const userProfile = process.env['USERPROFILE'];\r\n if (userProfile) {\r\n return { path: userProfile, source: 'USERPROFILE' };\r\n }\r\n }\r\n\r\n const home = process.env['HOME'];\r\n if (home) {\r\n return { path: home, source: 'HOME' };\r\n }\r\n\r\n return { path: os.homedir(), source: 'os.homedir' };\r\n}\r\n\r\n/**\r\n * Resolve the system temp directory.\r\n */\r\nfunction resolveTempDirectory(): TempDirectory {\r\n return { path: os.tmpdir() };\r\n}\r\n\r\n/**\r\n * PlatformDetector implementation.\r\n *\r\n * Detects the host operating system, CPU architecture, home directory,\r\n * and temp directory. All operations are synchronous since they read\r\n * from process globals and the os module.\r\n */\r\nexport class PlatformDetector implements IPlatformDetector {\r\n /**\r\n * Detect platform information and return an immutable PlatformSnapshot.\r\n *\r\n * @throws PlatformError with code UNSUPPORTED_PLATFORM if the OS is not\r\n * win32, darwin, or linux.\r\n */\r\n detect(): PlatformSnapshot {\r\n const family = resolveOsFamily(process.platform);\r\n const version = os.release();\r\n const release = resolveReleaseName(family, version);\r\n const architecture = resolveArchitecture(process.arch);\r\n\r\n const operatingSystem: OperatingSystem = {\r\n family,\r\n version,\r\n release,\r\n architecture,\r\n };\r\n\r\n const homeDirectory = resolveHomeDirectory(family);\r\n const tempDirectory = resolveTempDirectory();\r\n\r\n return {\r\n os: operatingSystem,\r\n homeDirectory,\r\n tempDirectory,\r\n detectedAt: new Date(),\r\n };\r\n }\r\n}\r\n","/**\r\n * Path Normalization - Cross-platform path manipulation utility.\r\n *\r\n * All internal paths use forward slashes. This module provides conversion\r\n * between platform-native and normalized representations, home directory\r\n * expansion, and path manipulation operations.\r\n *\r\n * @module platform/paths\r\n */\r\n\r\nimport {\r\n type HomeDirectory,\r\n type IPathNormalizer,\r\n type NormalizedPath,\r\n type OperatingSystem,\r\n PlatformError,\r\n createNormalizedPath,\r\n} from './types.js';\r\n\r\n/**\r\n * Check if a path starts with a Windows drive letter pattern (e.g., C:/ or C:\\).\r\n */\r\nfunction hasDriveLetter(path: string): boolean {\r\n return /^[a-zA-Z]:[/\\\\]/.test(path);\r\n}\r\n\r\n/**\r\n * Check if a path is a UNC path (\\\\server\\share or //server/share).\r\n */\r\nfunction isUncPath(path: string): boolean {\r\n return /^[/\\\\]{2}[^/\\\\]/.test(path);\r\n}\r\n\r\n/**\r\n * Resolve `.` and `..` segments in a path.\r\n * Does not access the filesystem -- purely string-based resolution.\r\n */\r\nfunction resolveSegments(segments: string[]): string[] {\r\n const resolved: string[] = [];\r\n\r\n for (const segment of segments) {\r\n if (segment === '.' || segment === '') {\r\n continue;\r\n }\r\n if (segment === '..') {\r\n if (resolved.length > 0) {\r\n resolved.pop();\r\n }\r\n continue;\r\n }\r\n resolved.push(segment);\r\n }\r\n\r\n return resolved;\r\n}\r\n\r\n/**\r\n * PathNormalizer implementation.\r\n *\r\n * Stateless utility for cross-platform path handling. All methods are\r\n * pure functions -- they take an OperatingSystem or HomeDirectory value\r\n * object as context rather than reading from process or os modules.\r\n */\r\nexport class PathNormalizer implements IPathNormalizer {\r\n /**\r\n * Convert a platform-native path to normalized internal form (forward slashes).\r\n *\r\n * Rules:\r\n * 1. Replace all backslashes with forward slashes\r\n * 2. Uppercase Windows drive letters (c:/ -> C:/)\r\n * 3. Preserve UNC path prefix (\\\\server\\share -> //server/share)\r\n * 4. Resolve . and .. segments\r\n * 5. Strip trailing separator (except root paths like / or C:/)\r\n * 6. Collapse double separators (except UNC prefix)\r\n *\r\n * @throws PlatformError with code INVALID_PATH for empty input\r\n */\r\n normalize(rawPath: string, os: OperatingSystem): NormalizedPath {\r\n if (!rawPath || rawPath.trim().length === 0) {\r\n throw new PlatformError(\r\n 'INVALID_PATH',\r\n 'PathNormalizer',\r\n 'Path cannot be empty',\r\n { rawPath },\r\n );\r\n }\r\n\r\n let path = rawPath;\r\n\r\n // Replace all backslashes with forward slashes\r\n path = path.replace(/\\\\/g, '/');\r\n\r\n // Handle UNC paths: preserve the // prefix\r\n let uncPrefix = '';\r\n if (isUncPath(rawPath)) {\r\n uncPrefix = '//';\r\n path = path.slice(2);\r\n }\r\n\r\n // Uppercase Windows drive letter\r\n if (os.family === 'windows' && hasDriveLetter(path)) {\r\n path = path[0].toUpperCase() + path.slice(1);\r\n }\r\n\r\n // Split into segments\r\n const segments = path.split('/');\r\n\r\n // Extract root prefix (drive letter or leading /)\r\n let root = '';\r\n if (uncPrefix) {\r\n // UNC path: first two segments are server and share\r\n const server = segments[0];\r\n const share = segments[1];\r\n root = `${uncPrefix}${server}/${share}`;\r\n segments.splice(0, 2);\r\n } else if (hasDriveLetter(path)) {\r\n root = segments[0] + '/';\r\n segments.splice(0, 1);\r\n } else if (path.startsWith('/')) {\r\n root = '/';\r\n segments.splice(0, 1);\r\n }\r\n\r\n // Resolve . and .. segments\r\n const resolved = resolveSegments(segments);\r\n\r\n // Reassemble the path\r\n let normalized = root + resolved.join('/');\r\n\r\n // Collapse double slashes (but not in UNC prefix or after drive letter)\r\n if (!uncPrefix) {\r\n normalized = normalized.replace(/\\/{2,}/g, '/');\r\n }\r\n\r\n // Strip trailing separator unless it is a root path\r\n if (normalized.length > 1 && normalized.endsWith('/')) {\r\n const isRootPath =\r\n normalized === '/' ||\r\n /^[A-Z]:\\/$/.test(normalized) ||\r\n /^\\/\\/[^/]+\\/[^/]+\\/?$/.test(normalized);\r\n if (!isRootPath) {\r\n normalized = normalized.replace(/\\/+$/, '');\r\n }\r\n }\r\n\r\n return createNormalizedPath(normalized);\r\n }\r\n\r\n /**\r\n * Convert a normalized path back to platform-native form for OS API calls.\r\n * On Windows, replaces forward slashes with backslashes.\r\n * On Unix, returns as-is.\r\n */\r\n toNative(path: NormalizedPath, os: OperatingSystem): string {\r\n if (os.family === 'windows') {\r\n return path.replace(/\\//g, '\\\\');\r\n }\r\n return path;\r\n }\r\n\r\n /**\r\n * Replace home directory tokens (~, $HOME, %USERPROFILE%) with the\r\n * actual home directory path.\r\n *\r\n * Token expansion happens before normalization:\r\n * - ~ or ~/ at the start of the path\r\n * - $HOME at the start of the path\r\n * - %USERPROFILE% at the start of the path\r\n *\r\n * @throws PlatformError with code INVALID_PATH for empty input\r\n */\r\n resolveHome(path: string, homeDir: HomeDirectory): NormalizedPath {\r\n if (!path || path.trim().length === 0) {\r\n throw new PlatformError(\r\n 'INVALID_PATH',\r\n 'PathNormalizer',\r\n 'Path cannot be empty',\r\n { path },\r\n );\r\n }\r\n\r\n let resolved = path;\r\n\r\n // Normalize the home directory path (forward slashes)\r\n const normalizedHome = homeDir.path.replace(/\\\\/g, '/');\r\n\r\n // Expand ~ or ~/ at the start\r\n if (resolved === '~') {\r\n resolved = normalizedHome;\r\n } else if (resolved.startsWith('~/') || resolved.startsWith('~\\\\')) {\r\n resolved = normalizedHome + '/' + resolved.slice(2);\r\n }\r\n\r\n // Expand $HOME at the start\r\n if (resolved === '$HOME') {\r\n resolved = normalizedHome;\r\n } else if (\r\n resolved.startsWith('$HOME/') ||\r\n resolved.startsWith('$HOME\\\\')\r\n ) {\r\n resolved = normalizedHome + '/' + resolved.slice(6);\r\n }\r\n\r\n // Expand %USERPROFILE% at the start\r\n if (resolved === '%USERPROFILE%') {\r\n resolved = normalizedHome;\r\n } else if (\r\n resolved.startsWith('%USERPROFILE%/') ||\r\n resolved.startsWith('%USERPROFILE%\\\\')\r\n ) {\r\n resolved = normalizedHome + '/' + resolved.slice(14);\r\n }\r\n\r\n // Normalize the result\r\n const family = normalizedHome.match(/^[A-Z]:/i) ? 'windows' : 'linux';\r\n const os: OperatingSystem = {\r\n family: family as 'windows' | 'linux',\r\n version: '',\r\n release: '',\r\n architecture: { name: 'x64' },\r\n };\r\n\r\n return this.normalize(resolved, os);\r\n }\r\n\r\n /**\r\n * Convert a relative path to absolute using the given base path.\r\n * If the path is already absolute, returns it unchanged.\r\n */\r\n toAbsolute(\r\n path: NormalizedPath,\r\n basePath: NormalizedPath,\r\n ): NormalizedPath {\r\n if (this.isAbsolute(path)) {\r\n return path;\r\n }\r\n return createNormalizedPath(\r\n this.stripTrailing(basePath) + '/' + path,\r\n );\r\n }\r\n\r\n /**\r\n * Convert an absolute path to relative from the given base path.\r\n * If the path is not under the base, returns the original absolute path.\r\n */\r\n toRelative(\r\n path: NormalizedPath,\r\n basePath: NormalizedPath,\r\n ): NormalizedPath {\r\n const normalBase = this.stripTrailing(basePath);\r\n const normalPath = this.stripTrailing(path);\r\n\r\n if (!normalPath.startsWith(normalBase + '/') && normalPath !== normalBase) {\r\n // Path is not under base, split both and compute relative\r\n const pathParts = normalPath.split('/');\r\n const baseParts = normalBase.split('/');\r\n\r\n // Find common prefix length\r\n let commonLength = 0;\r\n while (\r\n commonLength < pathParts.length &&\r\n commonLength < baseParts.length &&\r\n pathParts[commonLength] === baseParts[commonLength]\r\n ) {\r\n commonLength++;\r\n }\r\n\r\n // Build relative path\r\n const upCount = baseParts.length - commonLength;\r\n const upSegments = Array(upCount).fill('..');\r\n const downSegments = pathParts.slice(commonLength);\r\n const relativeParts = [...upSegments, ...downSegments];\r\n\r\n return createNormalizedPath(\r\n relativeParts.length > 0 ? relativeParts.join('/') : '.',\r\n );\r\n }\r\n\r\n if (normalPath === normalBase) {\r\n return createNormalizedPath('.');\r\n }\r\n\r\n return createNormalizedPath(normalPath.slice(normalBase.length + 1));\r\n }\r\n\r\n /**\r\n * Join path segments, normalizing the result.\r\n * The base path is used as the starting point.\r\n */\r\n join(base: NormalizedPath, ...segments: string[]): NormalizedPath {\r\n const allSegments = [base, ...segments].filter(Boolean);\r\n const joined = allSegments.join('/');\r\n\r\n // Determine OS context from the base path\r\n const isWindows = /^[A-Z]:/i.test(base);\r\n const os: OperatingSystem = {\r\n family: isWindows ? 'windows' : 'linux',\r\n version: '',\r\n release: '',\r\n architecture: { name: 'x64' },\r\n };\r\n\r\n return this.normalize(joined, os);\r\n }\r\n\r\n /**\r\n * Return the parent directory path, or null for root paths.\r\n */\r\n parent(path: NormalizedPath): NormalizedPath | null {\r\n const stripped = this.stripTrailing(path);\r\n\r\n // Check if this is a root path\r\n if (stripped === '/' || /^[A-Z]:\\/?$/i.test(stripped)) {\r\n return null;\r\n }\r\n\r\n // UNC root (//server/share)\r\n if (/^\\/\\/[^/]+\\/[^/]+\\/?$/.test(stripped)) {\r\n return null;\r\n }\r\n\r\n const lastSlash = stripped.lastIndexOf('/');\r\n if (lastSlash === -1) {\r\n return null;\r\n }\r\n\r\n // If the parent is the root\r\n if (lastSlash === 0) {\r\n return createNormalizedPath('/');\r\n }\r\n\r\n // If the parent ends with a drive letter colon\r\n const parentStr = stripped.slice(0, lastSlash);\r\n if (/^[A-Z]:$/i.test(parentStr)) {\r\n return createNormalizedPath(parentStr + '/');\r\n }\r\n\r\n return createNormalizedPath(parentStr);\r\n }\r\n\r\n /**\r\n * Extract file extension (without leading dot), or null if none.\r\n */\r\n extension(path: NormalizedPath): string | null {\r\n const stripped = this.stripTrailing(path);\r\n const lastSlash = stripped.lastIndexOf('/');\r\n const filename = lastSlash >= 0 ? stripped.slice(lastSlash + 1) : stripped;\r\n\r\n // No extension for dotfiles like .gitignore (unless they have a second dot)\r\n if (filename.startsWith('.') && filename.indexOf('.', 1) === -1) {\r\n return null;\r\n }\r\n\r\n const lastDot = filename.lastIndexOf('.');\r\n if (lastDot <= 0) {\r\n return null;\r\n }\r\n\r\n return filename.slice(lastDot + 1);\r\n }\r\n\r\n /**\r\n * Get the default .claude directory path for the given home directory.\r\n */\r\n getDefaultClaudeDir(\r\n homeDir: HomeDirectory,\r\n os: OperatingSystem,\r\n ): NormalizedPath {\r\n const homePath = this.normalize(homeDir.path, os);\r\n return this.join(homePath, '.claude');\r\n }\r\n\r\n /**\r\n * Check if a normalized path is absolute.\r\n */\r\n private isAbsolute(path: string): boolean {\r\n return (\r\n path.startsWith('/') ||\r\n /^[A-Z]:\\//i.test(path) ||\r\n path.startsWith('//')\r\n );\r\n }\r\n\r\n /**\r\n * Strip trailing slash from a path (preserving root paths).\r\n */\r\n private stripTrailing(path: string): string {\r\n if (\r\n path === '/' ||\r\n /^[A-Z]:\\/$/.test(path) ||\r\n /^\\/\\/[^/]+\\/[^/]+\\/$/.test(path)\r\n ) {\r\n return path;\r\n }\r\n return path.replace(/\\/+$/, '');\r\n }\r\n}\r\n","/**\r\n * Permission Checking - File system permission queries and elevation detection.\r\n *\r\n * Checks read/write/execute access to paths, detects elevated privilege status,\r\n * and provides platform-specific elevation guidance. Never modifies permissions\r\n * or attempts to elevate -- only detects and advises.\r\n *\r\n * @module platform/permissions\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport { execSync } from 'node:child_process';\r\n\r\nimport {\r\n AccessMode,\r\n type ElevationInstructions,\r\n type IPermissionChecker,\r\n type NormalizedPath,\r\n type PermissionResult,\r\n type PlatformSnapshot,\r\n type SymlinkCapability,\r\n} from './types.js';\r\nimport { PathNormalizer } from './paths.js';\r\n\r\n/**\r\n * Map AccessMode to fs.constants flags.\r\n */\r\nfunction accessModeToFlags(mode: AccessMode): number {\r\n const mapping: Record<AccessMode, number> = {\r\n [AccessMode.Read]: fs.constants.R_OK,\r\n [AccessMode.Write]: fs.constants.W_OK,\r\n [AccessMode.Execute]: fs.constants.X_OK,\r\n [AccessMode.ReadWrite]: fs.constants.R_OK | fs.constants.W_OK,\r\n };\r\n return mapping[mode];\r\n}\r\n\r\n// Ensure accessModeToFlags is referenced (prevents dead-code lint warnings)\r\nvoid accessModeToFlags;\r\n\r\n/**\r\n * Check if a path exists and whether it is a directory.\r\n */\r\nasync function statPath(\r\n nativePath: string,\r\n): Promise<{ exists: boolean; isDirectory: boolean }> {\r\n try {\r\n const stat = await fs.promises.stat(nativePath);\r\n return { exists: true, isDirectory: stat.isDirectory() };\r\n } catch {\r\n return { exists: false, isDirectory: false };\r\n }\r\n}\r\n\r\n/**\r\n * Check specific access permission on a path using fs.access.\r\n */\r\nasync function checkPermission(\r\n nativePath: string,\r\n flag: number,\r\n): Promise<boolean> {\r\n try {\r\n await fs.promises.access(nativePath, flag);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Build platform-specific elevation instructions.\r\n */\r\nfunction buildElevationInstructions(\r\n platform: PlatformSnapshot,\r\n targetPath: string,\r\n): ElevationInstructions {\r\n const family = platform.os.family;\r\n\r\n switch (family) {\r\n case 'windows':\r\n return {\r\n platform: 'windows',\r\n command: 'Run terminal as Administrator',\r\n description:\r\n \"Right-click your terminal and select 'Run as Administrator', then re-run the command.\",\r\n shellSpecificHint:\r\n 'In PowerShell: Start-Process pwsh -Verb RunAs',\r\n };\r\n case 'macos':\r\n return {\r\n platform: 'macos',\r\n command: `sudo sixsevenai install --target \"${targetPath}\"`,\r\n description:\r\n 'Prefix the command with sudo to run with root privileges.',\r\n shellSpecificHint: null,\r\n };\r\n case 'linux':\r\n return {\r\n platform: 'linux',\r\n command: `sudo sixsevenai install --target \"${targetPath}\"`,\r\n description:\r\n 'Prefix the command with sudo to run with root privileges.',\r\n shellSpecificHint: null,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Find the nearest existing parent directory for a path.\r\n * Used for checking directory creatability when the target does not exist.\r\n */\r\nfunction findNearestExistingParent(nativePath: string): string {\r\n let current = nativePath;\r\n\r\n // Walk up the directory tree until we find one that exists\r\n // eslint-disable-next-line no-constant-condition\r\n while (true) {\r\n try {\r\n const stat = fs.statSync(current);\r\n if (stat.isDirectory()) {\r\n return current;\r\n }\r\n } catch {\r\n // Directory does not exist, try parent\r\n }\r\n\r\n const parent = getParentNative(current);\r\n if (!parent || parent === current) {\r\n return current;\r\n }\r\n current = parent;\r\n }\r\n}\r\n\r\n/**\r\n * Get the native parent path. Handles both forward and backslash separators.\r\n */\r\nfunction getParentNative(nativePath: string): string | null {\r\n // Normalize separators for comparison\r\n const normalized = nativePath.replace(/\\\\/g, '/');\r\n const lastSlash = normalized.lastIndexOf('/');\r\n\r\n if (lastSlash <= 0) {\r\n return null;\r\n }\r\n\r\n // Check if this is already a root\r\n if (/^[A-Z]:\\/?$/i.test(normalized)) {\r\n return null;\r\n }\r\n\r\n const parent = normalized.slice(0, lastSlash);\r\n if (/^[A-Z]:$/i.test(parent)) {\r\n return parent + '/';\r\n }\r\n\r\n return parent || '/';\r\n}\r\n\r\n/**\r\n * PermissionChecker implementation.\r\n *\r\n * All methods return PermissionResult value objects and never throw.\r\n * Elevation detection reads OS state but never attempts to elevate.\r\n */\r\nexport class PermissionChecker implements IPermissionChecker {\r\n private readonly pathNormalizer = new PathNormalizer();\r\n\r\n /**\r\n * Check access to a path with the specified access mode.\r\n * Never throws -- returns a PermissionResult with appropriate flags.\r\n */\r\n async checkAccess(\r\n path: NormalizedPath,\r\n desiredAccess: AccessMode,\r\n platform: PlatformSnapshot,\r\n ): Promise<PermissionResult> {\r\n const nativePath = this.pathNormalizer.toNative(path, platform.os);\r\n const now = new Date();\r\n\r\n try {\r\n const { exists, isDirectory } = await statPath(nativePath);\r\n\r\n if (!exists) {\r\n return {\r\n targetPath: path,\r\n canRead: false,\r\n canWrite: false,\r\n canExecute: false,\r\n exists: false,\r\n isDirectory: false,\r\n requiresElevation: false,\r\n elevationInstructions: null,\r\n checkedAt: now,\r\n };\r\n }\r\n\r\n const canRead = await checkPermission(nativePath, fs.constants.R_OK);\r\n const canWrite = await checkPermission(nativePath, fs.constants.W_OK);\r\n const canExecute = await checkPermission(nativePath, fs.constants.X_OK);\r\n\r\n // Determine if elevation is needed based on desired access\r\n let needsElevation = false;\r\n switch (desiredAccess) {\r\n case 'read':\r\n needsElevation = !canRead;\r\n break;\r\n case 'write':\r\n needsElevation = !canWrite;\r\n break;\r\n case 'execute':\r\n needsElevation = !canExecute;\r\n break;\r\n case 'readwrite':\r\n needsElevation = !canRead || !canWrite;\r\n break;\r\n }\r\n\r\n const elevationInstructions = needsElevation\r\n ? buildElevationInstructions(platform, nativePath)\r\n : null;\r\n\r\n return {\r\n targetPath: path,\r\n canRead,\r\n canWrite,\r\n canExecute,\r\n exists,\r\n isDirectory,\r\n requiresElevation: needsElevation,\r\n elevationInstructions,\r\n checkedAt: now,\r\n };\r\n } catch {\r\n // Unexpected error -- return safe defaults\r\n return {\r\n targetPath: path,\r\n canRead: false,\r\n canWrite: false,\r\n canExecute: false,\r\n exists: false,\r\n isDirectory: false,\r\n requiresElevation: false,\r\n elevationInstructions: null,\r\n checkedAt: now,\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Convenience method: check write access to a path.\r\n */\r\n async checkWriteAccess(\r\n path: NormalizedPath,\r\n platform: PlatformSnapshot,\r\n ): Promise<PermissionResult> {\r\n return this.checkAccess(path, 'write' as AccessMode, platform);\r\n }\r\n\r\n /**\r\n * Check whether a directory can be created at the given path.\r\n * If the path does not exist, checks permissions on the nearest\r\n * existing parent directory.\r\n */\r\n async checkDirectoryCreatable(\r\n path: NormalizedPath,\r\n platform: PlatformSnapshot,\r\n ): Promise<PermissionResult> {\r\n const nativePath = this.pathNormalizer.toNative(path, platform.os);\r\n const now = new Date();\r\n\r\n try {\r\n // Check if the path already exists\r\n const { exists, isDirectory } = await statPath(nativePath);\r\n\r\n if (exists) {\r\n if (isDirectory) {\r\n // Directory already exists, check write access on it\r\n return this.checkAccess(path, 'write' as AccessMode, platform);\r\n }\r\n // A file exists at this path, cannot create directory\r\n return {\r\n targetPath: path,\r\n canRead: false,\r\n canWrite: false,\r\n canExecute: false,\r\n exists: true,\r\n isDirectory: false,\r\n requiresElevation: false,\r\n elevationInstructions: null,\r\n checkedAt: now,\r\n };\r\n }\r\n\r\n // Path does not exist, check nearest existing parent\r\n const nearestParent = findNearestExistingParent(nativePath);\r\n const canWriteParent = await checkPermission(\r\n nearestParent,\r\n fs.constants.W_OK,\r\n );\r\n\r\n const needsElevation = !canWriteParent;\r\n const elevationInstructions = needsElevation\r\n ? buildElevationInstructions(platform, nativePath)\r\n : null;\r\n\r\n return {\r\n targetPath: path,\r\n canRead: false,\r\n canWrite: canWriteParent,\r\n canExecute: false,\r\n exists: false,\r\n isDirectory: false,\r\n requiresElevation: needsElevation,\r\n elevationInstructions,\r\n checkedAt: now,\r\n };\r\n } catch {\r\n return {\r\n targetPath: path,\r\n canRead: false,\r\n canWrite: false,\r\n canExecute: false,\r\n exists: false,\r\n isDirectory: false,\r\n requiresElevation: false,\r\n elevationInstructions: null,\r\n checkedAt: now,\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Detect whether the current process is running with elevated privileges.\r\n *\r\n * - Unix: checks process.getuid() === 0\r\n * - Windows: executes `net session` via child_process.execSync\r\n *\r\n * Never throws. Returns false on detection failure.\r\n */\r\n async detectElevation(platform: PlatformSnapshot): Promise<boolean> {\r\n try {\r\n if (platform.os.family === 'windows') {\r\n return this.detectWindowsElevation();\r\n }\r\n return this.detectUnixElevation();\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Detect whether symbolic links can be created on the current platform.\r\n *\r\n * - Unix: always supported (no restrictions)\r\n * - Windows: depends on Developer Mode and/or elevation status\r\n */\r\n async checkSymlinkCapability(\r\n platform: PlatformSnapshot,\r\n ): Promise<SymlinkCapability> {\r\n if (platform.os.family !== 'windows') {\r\n return {\r\n supported: true,\r\n requiresDeveloperMode: false,\r\n requiresElevation: false,\r\n instructions: null,\r\n };\r\n }\r\n\r\n // Windows symlink capability\r\n const isElevated = await this.detectElevation(platform);\r\n\r\n if (isElevated) {\r\n return {\r\n supported: true,\r\n requiresDeveloperMode: false,\r\n requiresElevation: false,\r\n instructions: null,\r\n };\r\n }\r\n\r\n // Check if Developer Mode is enabled via registry\r\n const hasDeveloperMode = this.checkWindowsDeveloperMode();\r\n\r\n if (hasDeveloperMode) {\r\n return {\r\n supported: true,\r\n requiresDeveloperMode: false,\r\n requiresElevation: false,\r\n instructions: null,\r\n };\r\n }\r\n\r\n return {\r\n supported: false,\r\n requiresDeveloperMode: true,\r\n requiresElevation: true,\r\n instructions:\r\n 'Enable Developer Mode in Windows Settings > For developers, or run the installer as Administrator.',\r\n };\r\n }\r\n\r\n /**\r\n * Detect Windows elevation by running `net session`.\r\n * If it succeeds, the process is elevated. If it fails with exit code 5\r\n * (Access denied), the process is not elevated.\r\n */\r\n private detectWindowsElevation(): boolean {\r\n try {\r\n execSync('net session', {\r\n stdio: 'pipe',\r\n timeout: 5000,\r\n });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Detect Unix elevation by checking the effective user ID.\r\n */\r\n private detectUnixElevation(): boolean {\r\n if (typeof process.getuid === 'function') {\r\n return process.getuid() === 0;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Check if Windows Developer Mode is enabled by reading the registry.\r\n */\r\n private checkWindowsDeveloperMode(): boolean {\r\n try {\r\n const result = execSync(\r\n 'reg query \"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\AppModelUnlock\" /v AllowDevelopmentWithoutDevLicense',\r\n { stdio: 'pipe', timeout: 5000 },\r\n ).toString();\r\n return result.includes('0x1');\r\n } catch {\r\n return false;\r\n }\r\n }\r\n}\r\n","/**\r\n * Terminal Capability Detection - Color support, Unicode, dimensions, interactivity.\r\n *\r\n * Detects the rendering and interaction capabilities of the current terminal\r\n * environment. Follows the NO_COLOR standard (https://no-color.org/) and\r\n * uses well-known environment variable conventions for detection.\r\n *\r\n * @module platform/terminal\r\n */\r\n\r\nimport * as os from 'node:os';\r\n\r\nimport {\r\n type CIEnvironment,\r\n ColorSupportLevel,\r\n type Disposable,\r\n type ITerminalDetector,\r\n type InteractivityMode,\r\n type TerminalDimensions,\r\n type TerminalEmulator,\r\n type TerminalProfile,\r\n type UnicodeSupport,\r\n} from './types.js';\r\n\r\n/**\r\n * Detect the CI environment, if any.\r\n */\r\nfunction detectCIEnvironment(): CIEnvironment {\r\n const env = process.env;\r\n\r\n // Check common CI environment variables\r\n if (env['CI'] || env['CONTINUOUS_INTEGRATION'] || env['BUILD_NUMBER']) {\r\n // Try to identify the specific CI service\r\n if (env['GITHUB_ACTIONS']) return { isCI: true, name: 'GitHub Actions' };\r\n if (env['AZURE_PIPELINES'] || env['TF_BUILD']) return { isCI: true, name: 'Azure Pipelines' };\r\n if (env['GITLAB_CI']) return { isCI: true, name: 'GitLab CI' };\r\n if (env['CIRCLECI']) return { isCI: true, name: 'CircleCI' };\r\n if (env['TRAVIS']) return { isCI: true, name: 'Travis CI' };\r\n if (env['JENKINS_URL']) return { isCI: true, name: 'Jenkins' };\r\n if (env['CODEBUILD_BUILD_ID']) return { isCI: true, name: 'AWS CodeBuild' };\r\n if (env['TEAMCITY_VERSION']) return { isCI: true, name: 'TeamCity' };\r\n if (env['BITBUCKET_BUILD_NUMBER']) return { isCI: true, name: 'Bitbucket Pipelines' };\r\n\r\n return { isCI: true, name: 'Unknown CI' };\r\n }\r\n\r\n return { isCI: false, name: null };\r\n}\r\n\r\n/**\r\n * Detect the terminal emulator from environment variables.\r\n */\r\nfunction detectEmulator(): TerminalEmulator {\r\n const env = process.env;\r\n\r\n // Windows Terminal\r\n if (env['WT_SESSION']) {\r\n return {\r\n name: 'Windows Terminal',\r\n version: env['WT_SESSION'] ?? null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // VS Code integrated terminal\r\n if (env['TERM_PROGRAM'] === 'vscode') {\r\n return {\r\n name: 'VS Code Terminal',\r\n version: env['TERM_PROGRAM_VERSION'] ?? null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // iTerm2\r\n if (env['TERM_PROGRAM'] === 'iTerm.app') {\r\n return {\r\n name: 'iTerm2',\r\n version: env['TERM_PROGRAM_VERSION'] ?? null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // Apple Terminal\r\n if (env['TERM_PROGRAM'] === 'Apple_Terminal') {\r\n return {\r\n name: 'Apple Terminal',\r\n version: env['TERM_PROGRAM_VERSION'] ?? null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // ConEmu / Cmder\r\n if (env['ConEmuPID'] || env['ConEmuANSI']) {\r\n return {\r\n name: 'ConEmu',\r\n version: null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // GNOME Terminal\r\n if (env['GNOME_TERMINAL_SERVICE'] || env['GNOME_TERMINAL_SCREEN']) {\r\n return {\r\n name: 'GNOME Terminal',\r\n version: null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // Hyper\r\n if (env['TERM_PROGRAM'] === 'Hyper') {\r\n return {\r\n name: 'Hyper',\r\n version: env['TERM_PROGRAM_VERSION'] ?? null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // Alacritty\r\n if (env['TERM_PROGRAM'] === 'Alacritty' || env['ALACRITTY_LOG']) {\r\n return {\r\n name: 'Alacritty',\r\n version: null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // Kitty\r\n if (env['TERM'] === 'xterm-kitty' || env['KITTY_WINDOW_ID']) {\r\n return {\r\n name: 'Kitty',\r\n version: null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // WezTerm\r\n if (env['TERM_PROGRAM'] === 'WezTerm') {\r\n return {\r\n name: 'WezTerm',\r\n version: env['TERM_PROGRAM_VERSION'] ?? null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // Generic TERM_PROGRAM\r\n if (env['TERM_PROGRAM']) {\r\n return {\r\n name: env['TERM_PROGRAM'],\r\n version: env['TERM_PROGRAM_VERSION'] ?? null,\r\n isKnown: false,\r\n };\r\n }\r\n\r\n // Fallback to TERM\r\n if (env['TERM'] && env['TERM'] !== 'dumb') {\r\n return {\r\n name: env['TERM'],\r\n version: null,\r\n isKnown: false,\r\n };\r\n }\r\n\r\n return {\r\n name: null,\r\n version: null,\r\n isKnown: false,\r\n };\r\n}\r\n\r\n/**\r\n * Parse the FORCE_COLOR environment variable into a ColorSupportLevel.\r\n * Follows the convention: 0=None, 1=Basic, 2=Extended, 3=TrueColor.\r\n */\r\nfunction parseForcedColor(value: string): ColorSupportLevel | null {\r\n switch (value) {\r\n case '0':\r\n return ColorSupportLevel.None;\r\n case '1':\r\n case 'true':\r\n case '':\r\n return ColorSupportLevel.Basic;\r\n case '2':\r\n return ColorSupportLevel.Extended;\r\n case '3':\r\n return ColorSupportLevel.TrueColor;\r\n default:\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * TerminalDetector implementation.\r\n *\r\n * Detects terminal capabilities using environment variables, process\r\n * stream properties, and well-known terminal emulator conventions.\r\n * All detection methods are synchronous (no child process calls).\r\n */\r\nexport class TerminalDetector implements ITerminalDetector {\r\n /**\r\n * Detect all terminal capabilities and return a complete profile.\r\n */\r\n detectProfile(): TerminalProfile {\r\n return {\r\n colorSupport: this.detectColorSupport(),\r\n dimensions: this.detectDimensions(),\r\n unicodeSupport: this.detectUnicodeSupport(),\r\n interactivity: this.detectInteractivity(),\r\n emulator: detectEmulator(),\r\n detectedAt: new Date(),\r\n };\r\n }\r\n\r\n /**\r\n * Detect the color support level of the current terminal.\r\n *\r\n * Priority chain:\r\n * 1. NO_COLOR env var set -> None\r\n * 2. FORCE_COLOR env var set -> forced level\r\n * 3. stdout is not a TTY -> None\r\n * 4. COLORTERM = \"truecolor\" or \"24bit\" -> TrueColor\r\n * 5. Known terminal emulator -> emulator-specific level\r\n * 6. TERM = \"xterm-256color\" -> Extended\r\n * 7. TERM contains \"color\" -> Basic\r\n * 8. Windows version >= 10.0.14393 -> Extended minimum\r\n * 9. Default -> Basic\r\n */\r\n detectColorSupport(): ColorSupportLevel {\r\n const env = process.env;\r\n\r\n // 1. NO_COLOR standard (https://no-color.org/)\r\n if ('NO_COLOR' in env) {\r\n return ColorSupportLevel.None;\r\n }\r\n\r\n // 2. FORCE_COLOR override\r\n if ('FORCE_COLOR' in env) {\r\n const forced = parseForcedColor(env['FORCE_COLOR'] ?? '');\r\n if (forced !== null) {\r\n return forced;\r\n }\r\n }\r\n\r\n // 3. Non-TTY check\r\n if (!process.stdout.isTTY) {\r\n return ColorSupportLevel.None;\r\n }\r\n\r\n // 4. COLORTERM environment variable\r\n const colorTerm = env['COLORTERM'];\r\n if (colorTerm === 'truecolor' || colorTerm === '24bit') {\r\n return ColorSupportLevel.TrueColor;\r\n }\r\n\r\n // 5. Known terminal emulators\r\n const termProgram = env['TERM_PROGRAM'];\r\n\r\n // Windows Terminal -> TrueColor\r\n if (env['WT_SESSION']) {\r\n return ColorSupportLevel.TrueColor;\r\n }\r\n\r\n // VS Code -> TrueColor\r\n if (termProgram === 'vscode') {\r\n return ColorSupportLevel.TrueColor;\r\n }\r\n\r\n // iTerm2 -> TrueColor\r\n if (termProgram === 'iTerm.app') {\r\n return ColorSupportLevel.TrueColor;\r\n }\r\n\r\n // Apple Terminal -> Extended\r\n if (termProgram === 'Apple_Terminal') {\r\n return ColorSupportLevel.Extended;\r\n }\r\n\r\n // ConEmu -> Extended\r\n if (env['ConEmuANSI'] === 'ON') {\r\n return ColorSupportLevel.Extended;\r\n }\r\n\r\n // GNOME Terminal -> Extended\r\n if (env['GNOME_TERMINAL_SERVICE']) {\r\n return ColorSupportLevel.Extended;\r\n }\r\n\r\n // Kitty, Alacritty, WezTerm, Hyper -> TrueColor\r\n if (\r\n env['TERM'] === 'xterm-kitty' ||\r\n env['KITTY_WINDOW_ID'] ||\r\n termProgram === 'Alacritty' ||\r\n termProgram === 'WezTerm' ||\r\n termProgram === 'Hyper'\r\n ) {\r\n return ColorSupportLevel.TrueColor;\r\n }\r\n\r\n // 6. TERM = xterm-256color\r\n const term = env['TERM'];\r\n if (term === 'xterm-256color' || term === 'screen-256color') {\r\n return ColorSupportLevel.Extended;\r\n }\r\n\r\n // 7. TERM contains \"color\"\r\n if (term && /color/i.test(term)) {\r\n return ColorSupportLevel.Basic;\r\n }\r\n\r\n // 8. Windows version check (>= 10.0.14393 supports ANSI escape codes)\r\n if (process.platform === 'win32') {\r\n const osRelease = os.release();\r\n const versionParts = osRelease.split('.');\r\n const major = parseInt(versionParts[0], 10);\r\n const build = parseInt(versionParts[2], 10);\r\n\r\n if (major >= 10 && build >= 14393) {\r\n return ColorSupportLevel.Extended;\r\n }\r\n }\r\n\r\n // 9. Default\r\n return ColorSupportLevel.Basic;\r\n }\r\n\r\n /**\r\n * Detect terminal dimensions (columns x rows).\r\n * Falls back to 80x24 if detection fails.\r\n */\r\n detectDimensions(): TerminalDimensions {\r\n const columns = process.stdout.columns;\r\n const rows = process.stdout.rows;\r\n\r\n return {\r\n columns: columns && columns > 0 ? columns : 80,\r\n rows: rows && rows > 0 ? rows : 24,\r\n };\r\n }\r\n\r\n /**\r\n * Subscribe to terminal resize events.\r\n * Returns a Disposable to unsubscribe.\r\n */\r\n onResize(\r\n callback: (dimensions: TerminalDimensions) => void,\r\n ): Disposable {\r\n const handler = (): void => {\r\n callback(this.detectDimensions());\r\n };\r\n\r\n process.stdout.on('resize', handler);\r\n\r\n return {\r\n dispose: (): void => {\r\n process.stdout.removeListener('resize', handler);\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Detect Unicode support in the terminal.\r\n *\r\n * Detection methods:\r\n * 1. Check LANG, LC_ALL, LC_CTYPE for UTF-8 reference\r\n * 2. Check for modern terminal emulators (WT_SESSION, TERM_PROGRAM)\r\n * 3. On Windows, check if running in a modern terminal\r\n * 4. Default to true on macOS/Linux, false on Windows CMD\r\n */\r\n private detectUnicodeSupport(): UnicodeSupport {\r\n const env = process.env;\r\n\r\n // Check locale environment variables for UTF-8\r\n const localeVars = [env['LC_ALL'], env['LC_CTYPE'], env['LANG']];\r\n for (const localeVar of localeVars) {\r\n if (localeVar && /utf-?8/i.test(localeVar)) {\r\n return { supported: true, detectionMethod: 'locale' };\r\n }\r\n }\r\n\r\n // Check for known modern terminal emulators\r\n if (\r\n env['WT_SESSION'] ||\r\n env['TERM_PROGRAM'] === 'vscode' ||\r\n env['TERM_PROGRAM'] === 'iTerm.app' ||\r\n env['TERM_PROGRAM'] === 'Hyper' ||\r\n env['TERM_PROGRAM'] === 'Alacritty' ||\r\n env['TERM_PROGRAM'] === 'WezTerm' ||\r\n env['KITTY_WINDOW_ID'] ||\r\n env['TERM'] === 'xterm-kitty'\r\n ) {\r\n return { supported: true, detectionMethod: 'terminal' };\r\n }\r\n\r\n // ConEmu/Cmder supports Unicode\r\n if (env['ConEmuANSI'] === 'ON') {\r\n return { supported: true, detectionMethod: 'env' };\r\n }\r\n\r\n // Platform defaults\r\n if (process.platform === 'darwin') {\r\n // macOS defaults to UTF-8\r\n return { supported: true, detectionMethod: 'default' };\r\n }\r\n\r\n if (process.platform === 'linux') {\r\n // Most modern Linux distros default to UTF-8\r\n return { supported: true, detectionMethod: 'default' };\r\n }\r\n\r\n if (process.platform === 'win32') {\r\n // Windows: only modern terminals support Unicode well\r\n // If we reach here, the user is in a legacy terminal (CMD without WT)\r\n return { supported: false, detectionMethod: 'default' };\r\n }\r\n\r\n return { supported: true, detectionMethod: 'default' };\r\n }\r\n\r\n /**\r\n * Detect terminal interactivity mode.\r\n */\r\n private detectInteractivity(): InteractivityMode {\r\n const isTTY = !!process.stdout.isTTY;\r\n const isInteractive = !!process.stdin.isTTY;\r\n\r\n // Raw mode is available when stdin is a TTY and setRawMode exists\r\n const supportsRawMode =\r\n isInteractive &&\r\n typeof (process.stdin as NodeJS.ReadStream).setRawMode === 'function';\r\n\r\n return {\r\n isInteractive,\r\n isTTY,\r\n supportsRawMode,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Detect CI environment. Exported for use by other modules.\r\n */\r\nexport { detectCIEnvironment };\r\n","/**\r\n * Shell Detection - Identifies the active shell and its configuration.\r\n *\r\n * Detects the current shell (PowerShell, CMD, bash, zsh, fish) from\r\n * environment variables, locates profile files, and generates shell-specific\r\n * PATH modification commands.\r\n *\r\n * @module platform/shell\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\n\r\nimport {\r\n type IShellDetector,\r\n type NormalizedPath,\r\n type PlatformSnapshot,\r\n type ShellEnvironment,\r\n type ShellType,\r\n createNormalizedPath,\r\n} from './types.js';\r\nimport { PathNormalizer } from './paths.js';\r\n\r\n/**\r\n * Resolve the shell type from environment variables.\r\n *\r\n * Detection order:\r\n * 1. PSModulePath (PowerShell -- works across platforms)\r\n * 2. SHELL (Unix -- bash, zsh, fish)\r\n * 3. MSYSTEM (Git Bash on Windows)\r\n * 4. ComSpec (Windows CMD fallback)\r\n * 5. Default based on platform\r\n */\r\nfunction resolveShellType(env: NodeJS.ProcessEnv, platform: 'windows' | 'macos' | 'linux'): {\r\n type: ShellType;\r\n executablePath: string;\r\n} {\r\n // Check for PowerShell (cross-platform)\r\n if (env['PSModulePath']) {\r\n // Determine executable name: pwsh (PowerShell Core) or powershell (Windows PowerShell)\r\n const psPath = env['PSModulePath'] ?? '';\r\n const isPwshCore = psPath.includes('PowerShell') && !psPath.includes('WindowsPowerShell');\r\n\r\n if (platform === 'windows') {\r\n return {\r\n type: 'powershell',\r\n executablePath: isPwshCore ? 'pwsh.exe' : 'powershell.exe',\r\n };\r\n }\r\n return {\r\n type: 'powershell',\r\n executablePath: 'pwsh',\r\n };\r\n }\r\n\r\n // Check SHELL environment variable (Unix systems)\r\n const shell = env['SHELL'];\r\n if (shell) {\r\n const shellName = shell.split('/').pop()?.toLowerCase() ?? '';\r\n\r\n if (shellName.includes('zsh')) {\r\n return { type: 'zsh', executablePath: shell };\r\n }\r\n if (shellName.includes('bash')) {\r\n return { type: 'bash', executablePath: shell };\r\n }\r\n if (shellName.includes('fish')) {\r\n return { type: 'fish', executablePath: shell };\r\n }\r\n }\r\n\r\n // Check for Git Bash on Windows (MSYSTEM indicates MSYS2/Git Bash)\r\n if (env['MSYSTEM']) {\r\n const bashPath = env['SHELL'] ?? 'bash';\r\n return { type: 'bash', executablePath: bashPath };\r\n }\r\n\r\n // Check ComSpec for Windows CMD\r\n if (platform === 'windows') {\r\n const comspec = env['ComSpec'];\r\n if (comspec && comspec.toLowerCase().endsWith('cmd.exe')) {\r\n return { type: 'cmd', executablePath: comspec };\r\n }\r\n // Default to PowerShell on modern Windows\r\n return { type: 'powershell', executablePath: 'pwsh.exe' };\r\n }\r\n\r\n // Default based on platform\r\n if (platform === 'macos') {\r\n // zsh is the default since macOS Catalina\r\n return { type: 'zsh', executablePath: '/bin/zsh' };\r\n }\r\n\r\n // Linux default\r\n return { type: 'bash', executablePath: '/bin/bash' };\r\n}\r\n\r\n/**\r\n * Resolve the profile file path for a given shell type.\r\n * Returns null for shells without profile files (CMD, unknown).\r\n */\r\nfunction resolveProfilePath(\r\n shellType: ShellType,\r\n platform: 'windows' | 'macos' | 'linux',\r\n homePath: string,\r\n): string | null {\r\n const home = homePath.replace(/\\\\/g, '/');\r\n\r\n switch (shellType) {\r\n case 'powershell': {\r\n if (platform === 'windows') {\r\n // PowerShell Core: Documents/PowerShell/Microsoft.PowerShell_profile.ps1\r\n // Windows PowerShell: Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1\r\n // Default to PowerShell Core path\r\n return `${home}/Documents/PowerShell/Microsoft.PowerShell_profile.ps1`;\r\n }\r\n // Cross-platform PowerShell on Unix\r\n return `${home}/.config/powershell/Microsoft.PowerShell_profile.ps1`;\r\n }\r\n case 'bash': {\r\n if (platform === 'macos') {\r\n // macOS uses .bash_profile for login shells\r\n return `${home}/.bash_profile`;\r\n }\r\n // Linux uses .bashrc\r\n return `${home}/.bashrc`;\r\n }\r\n case 'zsh':\r\n return `${home}/.zshrc`;\r\n case 'fish':\r\n return `${home}/.config/fish/config.fish`;\r\n case 'cmd':\r\n // CMD uses registry, not profile files\r\n return null;\r\n case 'unknown':\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Generate a shell-specific command to add a directory to PATH.\r\n */\r\nfunction buildPathModificationCommand(\r\n shellType: ShellType,\r\n directory: string,\r\n profilePath: string | null,\r\n): string | null {\r\n switch (shellType) {\r\n case 'powershell':\r\n return `$env:PATH = \"${directory}\" + [System.IO.Path]::PathSeparator + $env:PATH`;\r\n case 'bash':\r\n case 'zsh':\r\n return `export PATH=\"${directory}:$PATH\"`;\r\n case 'fish':\r\n return `set -gx PATH \"${directory}\" $PATH`;\r\n case 'cmd':\r\n return `set PATH=${directory};%PATH%`;\r\n case 'unknown':\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Generate a persistent PATH modification command (for writing to profile).\r\n */\r\nfunction buildPersistentPathCommand(\r\n shellType: ShellType,\r\n directory: string,\r\n profilePath: string | null,\r\n): string | null {\r\n if (!profilePath) return null;\r\n\r\n switch (shellType) {\r\n case 'powershell':\r\n return `Add-Content -Path \"${profilePath}\" -Value '$env:PATH = \"${directory}\" + [System.IO.Path]::PathSeparator + $env:PATH'`;\r\n case 'bash':\r\n case 'zsh':\r\n return `echo 'export PATH=\"${directory}:$PATH\"' >> \"${profilePath}\"`;\r\n case 'fish':\r\n return `echo 'set -gx PATH \"${directory}\" $PATH' >> \"${profilePath}\"`;\r\n case 'cmd':\r\n return `setx PATH \"${directory};%PATH%\"`;\r\n case 'unknown':\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Detect the shell version by checking for version-related environment variables.\r\n * Does not execute child processes -- uses only environment variables.\r\n */\r\nfunction detectShellVersion(\r\n shellType: ShellType,\r\n env: NodeJS.ProcessEnv,\r\n): string | null {\r\n switch (shellType) {\r\n case 'bash': {\r\n // BASH_VERSION is set by bash\r\n return env['BASH_VERSION'] ?? null;\r\n }\r\n case 'zsh': {\r\n // ZSH_VERSION is set by zsh\r\n return env['ZSH_VERSION'] ?? null;\r\n }\r\n case 'fish': {\r\n // FISH_VERSION is set by fish\r\n return env['FISH_VERSION'] ?? null;\r\n }\r\n case 'powershell': {\r\n // No standard env var for PowerShell version detection\r\n // PSVersionTable is available inside PowerShell but not as an env var\r\n return null;\r\n }\r\n default:\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * ShellDetector implementation.\r\n *\r\n * Identifies the active shell from environment variables, locates\r\n * profile files, and generates shell-specific commands. Uses environment\r\n * variable detection as the primary mechanism per ADR-003.\r\n */\r\nexport class ShellDetector implements IShellDetector {\r\n private readonly pathNormalizer = new PathNormalizer();\r\n\r\n /**\r\n * Detect the active shell and its profile configuration.\r\n */\r\n async detectShell(platform: PlatformSnapshot): Promise<ShellEnvironment> {\r\n const osFamily = platform.os.family;\r\n const env = process.env;\r\n\r\n // Resolve shell type\r\n const { type, executablePath } = resolveShellType(env, osFamily);\r\n\r\n // Resolve profile path\r\n const rawProfilePath = resolveProfilePath(\r\n type,\r\n osFamily,\r\n platform.homeDirectory.path,\r\n );\r\n\r\n // Normalize profile path\r\n let profilePath: NormalizedPath | null = null;\r\n let profileExists = false;\r\n\r\n if (rawProfilePath) {\r\n profilePath = this.pathNormalizer.normalize(rawProfilePath, platform.os);\r\n const nativePath = this.pathNormalizer.toNative(profilePath, platform.os);\r\n try {\r\n profileExists = fs.existsSync(nativePath);\r\n } catch {\r\n profileExists = false;\r\n }\r\n }\r\n\r\n // Detect shell version\r\n const version = detectShellVersion(type, env);\r\n\r\n // Build PATH modification command for the default global npm bin dir\r\n const pathModCommand = buildPathModificationCommand(\r\n type,\r\n '{directory}',\r\n rawProfilePath,\r\n );\r\n\r\n // Determine PATH separator\r\n const pathSeparator: ';' | ':' = osFamily === 'windows' ? ';' : ':';\r\n\r\n return {\r\n type,\r\n version,\r\n executablePath,\r\n profilePath,\r\n profileExists,\r\n pathSeparator,\r\n pathModificationCommand: pathModCommand,\r\n };\r\n }\r\n\r\n /**\r\n * Generate a shell-specific command to add a directory to PATH.\r\n * The returned command can be run immediately in the current session.\r\n */\r\n getPathModificationCommand(\r\n shell: ShellEnvironment,\r\n directory: NormalizedPath,\r\n ): string {\r\n const nativeDir =\r\n shell.pathSeparator === ';'\r\n ? directory.replace(/\\//g, '\\\\')\r\n : (directory as string);\r\n\r\n const command = buildPathModificationCommand(\r\n shell.type,\r\n nativeDir,\r\n shell.profilePath,\r\n );\r\n\r\n return command ?? `# Unable to generate PATH command for ${shell.type} shell`;\r\n }\r\n\r\n /**\r\n * Generate a command to open the shell's profile file for editing.\r\n * Returns null if the shell has no profile file.\r\n */\r\n getProfileEditCommand(shell: ShellEnvironment): string | null {\r\n if (!shell.profilePath) {\r\n return null;\r\n }\r\n\r\n const profileStr = shell.profilePath as string;\r\n\r\n switch (shell.type) {\r\n case 'powershell':\r\n return `code \"${profileStr}\" # or notepad \"${profileStr}\"`;\r\n case 'bash':\r\n case 'zsh':\r\n case 'fish':\r\n return `${process.env['EDITOR'] ?? 'nano'} \"${profileStr}\"`;\r\n case 'cmd':\r\n return null;\r\n case 'unknown':\r\n return null;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Exported for testing and reuse by other modules.\r\n */\r\nexport { buildPersistentPathCommand, resolveShellType, resolveProfilePath };\r\n","/**\r\n * Runtime Validation - Node.js, npm, and git version checking.\r\n *\r\n * Validates that required runtime tools meet minimum version requirements\r\n * and resolves the global npm binary directory. Provides actionable\r\n * error messages for all validation failures.\r\n *\r\n * @module platform/runtime\r\n */\r\n\r\nimport { execSync } from 'node:child_process';\r\n\r\nimport {\r\n type GlobalBinDirectory,\r\n type IRuntimeValidator,\r\n type NormalizedPath,\r\n type RuntimeError,\r\n type RuntimeReport,\r\n type RuntimeVersion,\r\n type SemVer,\r\n type ShellEnvironment,\r\n createNormalizedPath,\r\n parseSemVer,\r\n semVer,\r\n semVerSatisfiesMinimum,\r\n} from './types.js';\r\n\r\n/** Default minimum Node.js version requirement. */\r\nexport const MINIMUM_NODE_VERSION: SemVer = semVer(18, 0, 0);\r\n\r\n/** Default minimum npm version requirement. */\r\nexport const MINIMUM_NPM_VERSION: SemVer = semVer(9, 0, 0);\r\n\r\n/** Timeout for child process commands (10 seconds). */\r\nconst COMMAND_TIMEOUT_MS = 10_000;\r\n\r\n/**\r\n * Execute a command and return its trimmed stdout, or null on failure.\r\n */\r\nfunction execCommand(command: string): string | null {\r\n try {\r\n const result = execSync(command, {\r\n encoding: 'utf-8',\r\n stdio: ['pipe', 'pipe', 'pipe'],\r\n timeout: COMMAND_TIMEOUT_MS,\r\n });\r\n return result.trim();\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Resolve the executable path for a tool using `which` (Unix) or `where` (Windows).\r\n */\r\nfunction resolveExecutablePath(toolName: string): string | null {\r\n const isWindows = process.platform === 'win32';\r\n const command = isWindows ? `where ${toolName}` : `which ${toolName}`;\r\n\r\n const result = execCommand(command);\r\n if (!result) return null;\r\n\r\n // `where` on Windows may return multiple lines; take the first\r\n return result.split(/\\r?\\n/)[0].trim();\r\n}\r\n\r\n/**\r\n * RuntimeValidator implementation.\r\n *\r\n * Validates Node.js and npm versions, resolves the global npm binary\r\n * directory, and checks for arbitrary tool availability. Uses child_process\r\n * for npm and git commands with a 10-second timeout.\r\n */\r\nexport class RuntimeValidator implements IRuntimeValidator {\r\n /**\r\n * Run all runtime validation checks and return a complete RuntimeReport.\r\n */\r\n async validate(\r\n minimumNode: SemVer,\r\n minimumNpm: SemVer,\r\n ): Promise<RuntimeReport> {\r\n const errors: RuntimeError[] = [];\r\n\r\n // Check Node.js version (synchronous -- already running in Node)\r\n const node = this.checkNodeVersion(minimumNode);\r\n if (!node.meetsMinimum) {\r\n errors.push({\r\n tool: 'node',\r\n errorType: 'version_too_low',\r\n message: `Node.js ${node.version.raw} is below the minimum required ${minimumNode.raw}.`,\r\n fix: `Upgrade Node.js to ${minimumNode.raw} or later. Visit https://nodejs.org/ or use nvm: nvm install ${minimumNode.major}`,\r\n });\r\n }\r\n\r\n // Check npm version (async -- child process)\r\n let npm: RuntimeVersion | null = null;\r\n try {\r\n npm = await this.checkNpmVersion(minimumNpm);\r\n if (!npm.meetsMinimum) {\r\n errors.push({\r\n tool: 'npm',\r\n errorType: 'version_too_low',\r\n message: `npm ${npm.version.raw} is below the minimum required ${minimumNpm.raw}.`,\r\n fix: `Upgrade npm: npm install -g npm@latest`,\r\n });\r\n }\r\n } catch {\r\n errors.push({\r\n tool: 'npm',\r\n errorType: 'not_found',\r\n message: 'npm is not installed or not available on PATH.',\r\n fix: 'Install Node.js (which includes npm) from https://nodejs.org/ or install npm separately.',\r\n });\r\n }\r\n\r\n // Check git availability (optional but reported)\r\n let git: RuntimeVersion | null = null;\r\n try {\r\n const gitResult = await this.checkGitVersion();\r\n git = gitResult;\r\n } catch {\r\n // git is optional, do not add to errors\r\n }\r\n\r\n // Resolve global bin directory\r\n let globalBinDir: GlobalBinDirectory | null = null;\r\n if (npm) {\r\n try {\r\n globalBinDir = await this.resolveGlobalBinDir({\r\n type: 'unknown',\r\n version: null,\r\n executablePath: '',\r\n profilePath: null,\r\n profileExists: false,\r\n pathSeparator: process.platform === 'win32' ? ';' : ':',\r\n pathModificationCommand: null,\r\n });\r\n\r\n if (!globalBinDir.isOnPath) {\r\n errors.push({\r\n tool: 'npm',\r\n errorType: 'not_on_path',\r\n message: `npm global bin directory (${globalBinDir.path}) is not on PATH.`,\r\n fix: globalBinDir.pathFixCommand ??\r\n `Add ${globalBinDir.path} to your PATH environment variable.`,\r\n });\r\n }\r\n } catch {\r\n // Non-fatal: global bin dir resolution failed\r\n }\r\n }\r\n\r\n const allRequirementsMet =\r\n node.meetsMinimum &&\r\n (npm?.meetsMinimum ?? false) &&\r\n (globalBinDir?.isOnPath ?? false);\r\n\r\n return {\r\n node,\r\n npm,\r\n git,\r\n globalBinDir,\r\n allRequirementsMet,\r\n errors,\r\n validatedAt: new Date(),\r\n };\r\n }\r\n\r\n /**\r\n * Check Node.js version against the minimum requirement.\r\n * This is synchronous since we read from process.version.\r\n */\r\n checkNodeVersion(minimum: SemVer): RuntimeVersion {\r\n const rawVersion = process.version; // e.g., \"v20.11.0\"\r\n const version = parseSemVer(rawVersion);\r\n\r\n if (!version) {\r\n return {\r\n tool: 'node',\r\n version: semVer(0, 0, 0),\r\n executablePath: process.execPath,\r\n meetsMinimum: false,\r\n minimumRequired: minimum,\r\n };\r\n }\r\n\r\n return {\r\n tool: 'node',\r\n version,\r\n executablePath: process.execPath,\r\n meetsMinimum: semVerSatisfiesMinimum(version, minimum),\r\n minimumRequired: minimum,\r\n };\r\n }\r\n\r\n /**\r\n * Check npm version against the minimum requirement.\r\n * Executes `npm --version` via child_process.\r\n */\r\n async checkNpmVersion(minimum: SemVer): Promise<RuntimeVersion> {\r\n const rawVersion = execCommand('npm --version');\r\n\r\n if (!rawVersion) {\r\n throw new Error('npm is not available');\r\n }\r\n\r\n const version = parseSemVer(rawVersion);\r\n if (!version) {\r\n throw new Error(`Unable to parse npm version: ${rawVersion}`);\r\n }\r\n\r\n const executablePath = resolveExecutablePath('npm') ?? 'npm';\r\n\r\n return {\r\n tool: 'npm',\r\n version,\r\n executablePath,\r\n meetsMinimum: semVerSatisfiesMinimum(version, minimum),\r\n minimumRequired: minimum,\r\n };\r\n }\r\n\r\n /**\r\n * Check git version. Git is not strictly required but is reported.\r\n */\r\n private async checkGitVersion(): Promise<RuntimeVersion> {\r\n const rawVersion = execCommand('git --version');\r\n\r\n if (!rawVersion) {\r\n throw new Error('git is not available');\r\n }\r\n\r\n // git --version returns \"git version 2.43.0\" or similar\r\n const versionMatch = /(\\d+\\.\\d+\\.\\d+)/.exec(rawVersion);\r\n if (!versionMatch) {\r\n throw new Error(`Unable to parse git version: ${rawVersion}`);\r\n }\r\n\r\n const version = parseSemVer(versionMatch[1]);\r\n if (!version) {\r\n throw new Error(`Unable to parse git version: ${versionMatch[1]}`);\r\n }\r\n\r\n const executablePath = resolveExecutablePath('git') ?? 'git';\r\n\r\n // git minimum is not enforced, so meetsMinimum is always true\r\n return {\r\n tool: 'git',\r\n version,\r\n executablePath,\r\n meetsMinimum: true,\r\n minimumRequired: semVer(0, 0, 0),\r\n };\r\n }\r\n\r\n /**\r\n * Resolve the npm global bin directory and check if it is on PATH.\r\n *\r\n * On Unix: `npm config get prefix` returns the prefix, bin dir is `{prefix}/bin`\r\n * On Windows: `npm config get prefix` returns the prefix, which IS the bin dir\r\n */\r\n async resolveGlobalBinDir(\r\n shell: ShellEnvironment,\r\n ): Promise<GlobalBinDirectory> {\r\n const prefix = execCommand('npm config get prefix');\r\n\r\n if (!prefix) {\r\n throw new Error('Unable to resolve npm global bin directory');\r\n }\r\n\r\n const isWindows = process.platform === 'win32';\r\n const binDir = isWindows\r\n ? prefix.replace(/\\\\/g, '/')\r\n : prefix.replace(/\\\\/g, '/') + '/bin';\r\n\r\n const normalizedBinDir = createNormalizedPath(binDir);\r\n\r\n // Check if the bin directory is on PATH\r\n const pathEnv = process.env['PATH'] ?? process.env['Path'] ?? '';\r\n const pathDirs = pathEnv.split(shell.pathSeparator);\r\n\r\n const isOnPath = pathDirs.some((dir) => {\r\n const normalizedDir = dir.replace(/\\\\/g, '/').replace(/\\/+$/, '');\r\n return (\r\n normalizedDir.toLowerCase() === binDir.toLowerCase() ||\r\n normalizedDir.toLowerCase() === binDir.replace(/\\/bin$/, '').toLowerCase()\r\n );\r\n });\r\n\r\n let pathFixCommand: string | null = null;\r\n if (!isOnPath) {\r\n if (isWindows) {\r\n pathFixCommand = `$env:PATH = \"${binDir.replace(/\\//g, '\\\\')}\" + \";\" + $env:PATH`;\r\n } else {\r\n pathFixCommand = `export PATH=\"${binDir}:$PATH\"`;\r\n }\r\n }\r\n\r\n return {\r\n path: normalizedBinDir,\r\n isOnPath,\r\n pathFixCommand,\r\n };\r\n }\r\n\r\n /**\r\n * Check if an arbitrary tool is available on PATH.\r\n */\r\n async checkToolAvailable(\r\n toolName: string,\r\n ): Promise<{ available: boolean; path: string | null }> {\r\n const executablePath = resolveExecutablePath(toolName);\r\n return {\r\n available: executablePath !== null,\r\n path: executablePath,\r\n };\r\n }\r\n}\r\n","/**\r\n * Platform Facade - High-level entry point for all platform detection.\r\n *\r\n * Orchestrates all detection subsystems into a single detectAll() call.\r\n * Returns a complete PlatformEnvironment value object. Handles partial\r\n * failures gracefully -- only PlatformDetector failure is fatal.\r\n *\r\n * @module platform/facade\r\n */\r\n\r\nimport {\r\n ColorSupportLevel,\r\n type IPlatformFacade,\r\n type NormalizedPath,\r\n type PlatformEnvironment,\r\n PlatformError,\r\n type RuntimeReport,\r\n type ShellEnvironment,\r\n type TerminalProfile,\r\n semVer,\r\n} from './types.js';\r\nimport { PlatformDetector } from './detector.js';\r\nimport { PathNormalizer } from './paths.js';\r\nimport { PermissionChecker } from './permissions.js';\r\nimport { TerminalDetector } from './terminal.js';\r\nimport { ShellDetector } from './shell.js';\r\nimport { RuntimeValidator, MINIMUM_NODE_VERSION, MINIMUM_NPM_VERSION } from './runtime.js';\r\n\r\n/**\r\n * Safe defaults for terminal profile when detection fails.\r\n */\r\nfunction safeTerminalProfile(): TerminalProfile {\r\n return {\r\n colorSupport: ColorSupportLevel.None,\r\n dimensions: { columns: 80, rows: 24 },\r\n unicodeSupport: { supported: false, detectionMethod: 'default' },\r\n interactivity: { isInteractive: false, isTTY: false, supportsRawMode: false },\r\n emulator: { name: null, version: null, isKnown: false },\r\n detectedAt: new Date(),\r\n };\r\n}\r\n\r\n/**\r\n * Safe defaults for shell environment when detection fails.\r\n */\r\nfunction safeShellEnvironment(): ShellEnvironment {\r\n return {\r\n type: 'unknown',\r\n version: null,\r\n executablePath: '',\r\n profilePath: null,\r\n profileExists: false,\r\n pathSeparator: process.platform === 'win32' ? ';' : ':',\r\n pathModificationCommand: null,\r\n };\r\n}\r\n\r\n/**\r\n * Safe defaults for runtime report when validation fails.\r\n */\r\nfunction safeRuntimeReport(): RuntimeReport {\r\n return {\r\n node: {\r\n tool: 'node',\r\n version: semVer(0, 0, 0),\r\n executablePath: process.execPath,\r\n meetsMinimum: false,\r\n minimumRequired: MINIMUM_NODE_VERSION,\r\n },\r\n npm: null,\r\n git: null,\r\n globalBinDir: null,\r\n allRequirementsMet: false,\r\n errors: [\r\n {\r\n tool: 'runtime',\r\n errorType: 'not_found',\r\n message: 'Runtime validation failed unexpectedly.',\r\n fix: 'Ensure Node.js >= 18.0.0 and npm >= 9.0.0 are installed.',\r\n },\r\n ],\r\n validatedAt: new Date(),\r\n };\r\n}\r\n\r\n/**\r\n * PlatformFacade implementation.\r\n *\r\n * Orchestrates all platform detection subsystems. Called once at installer\r\n * startup by unit-cli-orchestrator. Follows graceful degradation per ADR-007:\r\n * only PlatformDetector failure is fatal.\r\n */\r\nexport class PlatformFacade implements IPlatformFacade {\r\n private readonly platformDetector: PlatformDetector;\r\n private readonly pathNormalizer: PathNormalizer;\r\n private readonly permissionChecker: PermissionChecker;\r\n private readonly terminalDetector: TerminalDetector;\r\n private readonly shellDetector: ShellDetector;\r\n private readonly runtimeValidator: RuntimeValidator;\r\n\r\n constructor() {\r\n this.platformDetector = new PlatformDetector();\r\n this.pathNormalizer = new PathNormalizer();\r\n this.permissionChecker = new PermissionChecker();\r\n this.terminalDetector = new TerminalDetector();\r\n this.shellDetector = new ShellDetector();\r\n this.runtimeValidator = new RuntimeValidator();\r\n }\r\n\r\n /**\r\n * Detect all platform capabilities in a single coordinated call.\r\n *\r\n * Detection flow:\r\n * 1. PlatformDetector.detect() -- FATAL on failure\r\n * 2. TerminalDetector.detectProfile() -- parallel with step 3\r\n * 3. ShellDetector.detectShell(snapshot) -- parallel with step 2\r\n * 4. RuntimeValidator.validate() -- depends on step 3\r\n * 5. Assemble PlatformEnvironment\r\n *\r\n * @throws PlatformError with code UNSUPPORTED_PLATFORM if OS detection fails\r\n */\r\n async detectAll(): Promise<PlatformEnvironment> {\r\n // Step 1: Platform detection (synchronous, FATAL on failure)\r\n const platform = this.platformDetector.detect();\r\n\r\n // Steps 2 & 3: Terminal and Shell detection (parallel)\r\n const [terminal, shell] = await Promise.all([\r\n this.safeDetectTerminal(),\r\n this.safeDetectShell(platform),\r\n ]);\r\n\r\n // Step 4: Runtime validation (depends on shell)\r\n const runtime = await this.safeValidateRuntime();\r\n\r\n // Step 5: Assemble PlatformEnvironment\r\n const permissionChecker = this.permissionChecker;\r\n const pathNormalizer = this.pathNormalizer;\r\n\r\n return {\r\n platform,\r\n terminal,\r\n shell,\r\n runtime,\r\n permissions: {\r\n checkWriteAccess: (path: NormalizedPath) =>\r\n permissionChecker.checkWriteAccess(path, platform),\r\n checkDirectoryCreatable: (path: NormalizedPath) =>\r\n permissionChecker.checkDirectoryCreatable(path, platform),\r\n },\r\n paths: pathNormalizer,\r\n };\r\n }\r\n\r\n /**\r\n * Safely detect terminal profile. Returns safe defaults on failure.\r\n */\r\n private async safeDetectTerminal(): Promise<TerminalProfile> {\r\n try {\r\n return this.terminalDetector.detectProfile();\r\n } catch {\r\n return safeTerminalProfile();\r\n }\r\n }\r\n\r\n /**\r\n * Safely detect shell environment. Returns safe defaults on failure.\r\n */\r\n private async safeDetectShell(\r\n platform: ReturnType<PlatformDetector['detect']>,\r\n ): Promise<ShellEnvironment> {\r\n try {\r\n return await this.shellDetector.detectShell(platform);\r\n } catch {\r\n return safeShellEnvironment();\r\n }\r\n }\r\n\r\n /**\r\n * Safely validate runtime. Returns safe defaults on failure.\r\n */\r\n private async safeValidateRuntime(): Promise<RuntimeReport> {\r\n try {\r\n return await this.runtimeValidator.validate(\r\n MINIMUM_NODE_VERSION,\r\n MINIMUM_NPM_VERSION,\r\n );\r\n } catch {\r\n return safeRuntimeReport();\r\n }\r\n }\r\n}\r\n","/**\r\n * Component Manifest - Source directory scanning and component classification.\r\n *\r\n * Walks the source directory tree, classifies files into categories based on\r\n * directory structure conventions, and produces an immutable ComponentManifest.\r\n * Uses fs/promises exclusively for all I/O operations.\r\n *\r\n * @module engine/manifest\r\n */\r\n\r\nimport * as fs from 'node:fs/promises';\r\nimport * as path from 'node:path';\r\n\r\nimport type {\r\n ComponentEntry,\r\n ComponentManifest,\r\n ComponentType,\r\n} from './types.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Classification Rules\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Directory patterns mapped to component types.\r\n * Order matters: first match wins for classification.\r\n */\r\nconst CATEGORY_RULES: ReadonlyArray<{\r\n readonly pattern: RegExp;\r\n readonly type: ComponentType;\r\n}> = [\r\n { pattern: /^agents[/\\\\]/, type: 'agents' },\r\n { pattern: /^skills[/\\\\]/, type: 'skills' },\r\n { pattern: /^commands[/\\\\]/, type: 'commands' },\r\n { pattern: /^cli[/\\\\]/, type: 'cli' },\r\n { pattern: /^typescript[/\\\\]/, type: 'cli' },\r\n { pattern: /^workflows[/\\\\]/, type: 'workflows' },\r\n { pattern: /^metadata[/\\\\]/, type: 'metadata' },\r\n];\r\n\r\n/**\r\n * Directories to ignore during scanning.\r\n * These are never recursed into.\r\n */\r\nconst IGNORED_DIRECTORIES: ReadonlySet<string> = new Set([\r\n 'node_modules',\r\n '.git',\r\n 'dist',\r\n 'build',\r\n 'out',\r\n '.next',\r\n '__pycache__',\r\n 'coverage',\r\n]);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Classification Logic\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Classify a file's relative path into a ComponentType.\r\n * Falls back to 'metadata' for files that do not match any rule.\r\n */\r\nfunction classifyComponent(relativePath: string): ComponentType {\r\n // Normalize to forward slashes for pattern matching\r\n const normalized = relativePath.replace(/\\\\/g, '/');\r\n\r\n for (const rule of CATEGORY_RULES) {\r\n if (rule.pattern.test(normalized)) {\r\n return rule.type;\r\n }\r\n }\r\n\r\n return 'metadata';\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Directory Walking\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Recursively walk a directory and collect all file entries.\r\n * Skips ignored directories and hidden directories (except conventions\r\n * like .claude/ that may appear within the source).\r\n *\r\n * @param rootDir - Absolute path to the root directory being scanned.\r\n * @param currentDir - Absolute path to the current directory being processed.\r\n * @returns Array of ComponentEntry objects for all discovered files.\r\n */\r\nasync function walkDirectory(\r\n rootDir: string,\r\n currentDir: string,\r\n): Promise<ComponentEntry[]> {\r\n const entries: ComponentEntry[] = [];\r\n let dirEntries: import('fs').Dirent[];\r\n\r\n try {\r\n dirEntries = await fs.readdir(currentDir, { withFileTypes: true });\r\n } catch {\r\n // If we cannot read the directory, skip it silently\r\n return entries;\r\n }\r\n\r\n for (const dirEntry of dirEntries) {\r\n const fullPath = path.join(currentDir, dirEntry.name);\r\n\r\n if (dirEntry.isDirectory()) {\r\n // Skip ignored directories\r\n if (IGNORED_DIRECTORIES.has(dirEntry.name)) {\r\n continue;\r\n }\r\n\r\n // Recurse into subdirectories\r\n const subEntries = await walkDirectory(rootDir, fullPath);\r\n entries.push(...subEntries);\r\n } else if (dirEntry.isFile()) {\r\n const relativePath = path.relative(rootDir, fullPath);\r\n const componentType = classifyComponent(relativePath);\r\n\r\n try {\r\n const stat = await fs.stat(fullPath);\r\n entries.push({\r\n relativePath,\r\n fileName: dirEntry.name,\r\n componentType,\r\n sizeBytes: stat.size,\r\n });\r\n } catch {\r\n // If we cannot stat the file, skip it\r\n continue;\r\n }\r\n }\r\n }\r\n\r\n return entries;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Scan a source directory and build a ComponentManifest.\r\n *\r\n * Walks the entire directory tree, classifies each file into a category\r\n * based on its directory path, and returns an immutable manifest with\r\n * component counts.\r\n *\r\n * @param sourceDirectory - Absolute path to the source AI-DLC library directory.\r\n * @returns A fully populated ComponentManifest.\r\n * @throws Error if the source directory does not exist or is not readable.\r\n */\r\nexport async function scanSourceDirectory(\r\n sourceDirectory: string,\r\n): Promise<ComponentManifest> {\r\n // Validate source directory exists\r\n try {\r\n const stat = await fs.stat(sourceDirectory);\r\n if (!stat.isDirectory()) {\r\n throw new Error(\r\n `Source path is not a directory: ${sourceDirectory}`,\r\n );\r\n }\r\n } catch (error) {\r\n if (error instanceof Error && error.message.startsWith('Source path')) {\r\n throw error;\r\n }\r\n throw new Error(\r\n `Source directory does not exist or is not accessible: ${sourceDirectory}`,\r\n );\r\n }\r\n\r\n const entries = await walkDirectory(sourceDirectory, sourceDirectory);\r\n\r\n const countsByType = countComponentsByType(entries);\r\n\r\n return {\r\n entries,\r\n totalCount: entries.length,\r\n countsByType,\r\n };\r\n}\r\n\r\n/**\r\n * Filter manifest entries by one or more component types.\r\n *\r\n * @param manifest - The manifest to filter.\r\n * @param types - One or more ComponentType values to include.\r\n * @returns A new array containing only entries matching the specified types.\r\n */\r\nexport function filterByComponentType(\r\n manifest: ComponentManifest,\r\n ...types: ComponentType[]\r\n): readonly ComponentEntry[] {\r\n const typeSet = new Set(types);\r\n return manifest.entries.filter((entry) => typeSet.has(entry.componentType));\r\n}\r\n\r\n/**\r\n * Count components grouped by type.\r\n *\r\n * @param entries - Array of ComponentEntry objects.\r\n * @returns A record mapping each ComponentType to its count.\r\n */\r\nexport function countComponentsByType(\r\n entries: readonly ComponentEntry[],\r\n): Record<ComponentType, number> {\r\n const counts: Record<ComponentType, number> = {\r\n agents: 0,\r\n skills: 0,\r\n commands: 0,\r\n cli: 0,\r\n workflows: 0,\r\n metadata: 0,\r\n };\r\n\r\n for (const entry of entries) {\r\n counts[entry.componentType]++;\r\n }\r\n\r\n return counts;\r\n}\r\n","/**\r\n * Conflict Detector - Detect conflicts between source and target directories.\r\n *\r\n * Compares a ComponentManifest against the existing contents of a target\r\n * directory. Classifies every file as new, identical, or modified using\r\n * SHA-256 content hashes. Detects partial installations and existing\r\n * .claude/ directories.\r\n *\r\n * Uses fs/promises and node:crypto exclusively. No external dependencies.\r\n *\r\n * @module engine/conflict-detector\r\n */\r\n\r\nimport * as fs from 'node:fs/promises';\r\nimport * as crypto from 'node:crypto';\r\nimport * as nodePath from 'node:path';\r\n\r\nimport type {\r\n ComponentManifest,\r\n ConflictFileEntry,\r\n ConflictReport,\r\n FileConflictStatus,\r\n} from './types.js';\r\n\r\nimport { INSTALL_CATEGORIES } from './category-filter.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Hashing\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Compute the SHA-256 hash of a file using streaming reads.\r\n * Reads the file in chunks to avoid loading entire contents into memory.\r\n *\r\n * @param filePath - Absolute path to the file.\r\n * @returns Hex-encoded SHA-256 hash string.\r\n */\r\nasync function computeFileHash(filePath: string): Promise<string> {\r\n const content = await fs.readFile(filePath);\r\n return crypto.createHash('sha256').update(content).digest('hex');\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Target Directory Detection\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Check if a directory exists at the given path.\r\n *\r\n * @param dirPath - Absolute path to check.\r\n * @returns True if the path exists and is a directory.\r\n */\r\nasync function directoryExists(dirPath: string): Promise<boolean> {\r\n try {\r\n const stat = await fs.stat(dirPath);\r\n return stat.isDirectory();\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Check if a file exists at the given path.\r\n *\r\n * @param filePath - Absolute path to check.\r\n * @returns True if the path exists and is a file.\r\n */\r\nasync function fileExists(filePath: string): Promise<boolean> {\r\n try {\r\n const stat = await fs.stat(filePath);\r\n return stat.isFile();\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Detect conflicts between a source component manifest and a target directory.\r\n *\r\n * For each component entry in the manifest:\r\n * 1. If the target file does not exist: status = 'new'\r\n * 2. If the target file exists: compute SHA-256 hashes of both source and target\r\n * - If hashes match: status = 'identical'\r\n * - If hashes differ: status = 'modified'\r\n *\r\n * Also detects whether the target .claude/ directory exists (indicating a\r\n * brownfield / existing installation).\r\n *\r\n * @param manifest - The ComponentManifest describing all source files.\r\n * @param sourceDirectory - Absolute path to the source library directory.\r\n * @param targetDirectory - Absolute path to the target .claude/ directory.\r\n * @returns A ConflictReport with all file statuses and conflict summary.\r\n */\r\nexport async function detectConflicts(\r\n manifest: ComponentManifest,\r\n sourceDirectory: string,\r\n targetDirectory: string,\r\n): Promise<ConflictReport> {\r\n const isExistingInstallation = await directoryExists(targetDirectory);\r\n\r\n const files: ConflictFileEntry[] = [];\r\n const existingFiles: string[] = [];\r\n const modifiedFiles: string[] = [];\r\n let newCount = 0;\r\n let identicalCount = 0;\r\n let modifiedCount = 0;\r\n\r\n for (const entry of manifest.entries) {\r\n const sourcePath = nodePath.join(sourceDirectory, entry.relativePath);\r\n const targetPath = nodePath.join(targetDirectory, entry.relativePath);\r\n\r\n const targetFileExists = await fileExists(targetPath);\r\n\r\n if (!targetFileExists) {\r\n // File does not exist at target -- always a new file\r\n const sourceHash = await computeFileHash(sourcePath);\r\n files.push({\r\n relativePath: entry.relativePath,\r\n status: 'new' as FileConflictStatus,\r\n sourceHash,\r\n targetHash: null,\r\n });\r\n newCount++;\r\n continue;\r\n }\r\n\r\n // File exists at target -- compute hashes and compare\r\n existingFiles.push(entry.relativePath);\r\n\r\n const [sourceHash, targetHash] = await Promise.all([\r\n computeFileHash(sourcePath),\r\n computeFileHash(targetPath),\r\n ]);\r\n\r\n if (sourceHash === targetHash) {\r\n files.push({\r\n relativePath: entry.relativePath,\r\n status: 'identical' as FileConflictStatus,\r\n sourceHash,\r\n targetHash,\r\n });\r\n identicalCount++;\r\n } else {\r\n files.push({\r\n relativePath: entry.relativePath,\r\n status: 'modified' as FileConflictStatus,\r\n sourceHash,\r\n targetHash,\r\n });\r\n modifiedFiles.push(entry.relativePath);\r\n modifiedCount++;\r\n }\r\n }\r\n\r\n return {\r\n files,\r\n existingFiles,\r\n modifiedFiles,\r\n newCount,\r\n identicalCount,\r\n modifiedCount,\r\n hasConflicts: modifiedCount > 0,\r\n isExistingInstallation,\r\n };\r\n}\r\n\r\n/**\r\n * List existing files in a target directory that would be affected\r\n * by installation. Returns relative paths of all files found.\r\n *\r\n * @param targetDirectory - Absolute path to the target .claude/ directory.\r\n * @returns Array of relative file paths, or empty array if directory does not exist.\r\n */\r\nexport async function listExistingFiles(\r\n targetDirectory: string,\r\n): Promise<readonly string[]> {\r\n const exists = await directoryExists(targetDirectory);\r\n if (!exists) {\r\n return [];\r\n }\r\n\r\n const results: string[] = [];\r\n\r\n async function walk(dir: string): Promise<void> {\r\n let entries: import('fs').Dirent[];\r\n try {\r\n entries = await fs.readdir(dir, { withFileTypes: true });\r\n } catch {\r\n return;\r\n }\r\n\r\n for (const entry of entries) {\r\n const fullPath = nodePath.join(dir, entry.name);\r\n if (entry.isDirectory()) {\r\n await walk(fullPath);\r\n } else if (entry.isFile()) {\r\n results.push(nodePath.relative(targetDirectory, fullPath));\r\n }\r\n }\r\n }\r\n\r\n await walk(targetDirectory);\r\n return results;\r\n}\r\n\r\n/**\r\n * Detect whether an installation is partial by checking if the target\r\n * directory exists but contains fewer files than the source manifest.\r\n *\r\n * @param manifest - The ComponentManifest describing all source files.\r\n * @param targetDirectory - Absolute path to the target .claude/ directory.\r\n * @returns True if the target exists but has fewer files than the source.\r\n */\r\nexport async function isPartialInstallation(\r\n manifest: ComponentManifest,\r\n targetDirectory: string,\r\n): Promise<boolean> {\r\n const exists = await directoryExists(targetDirectory);\r\n if (!exists) {\r\n return false;\r\n }\r\n\r\n const existing = await listExistingFiles(targetDirectory);\r\n\r\n // Partial: target exists with some files but fewer than expected\r\n return existing.length > 0 && existing.length < manifest.totalCount;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Category Conflict Analysis\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Per-category conflict statistics. */\r\nexport interface CategoryConflictSummary {\r\n /** Category identifier matching InstallCategory.id. */\r\n readonly categoryId: string;\r\n /** Total number of files in this category. */\r\n readonly totalFiles: number;\r\n /** Number of files that have been modified since the last install. */\r\n readonly modifiedFiles: number;\r\n /** Number of files that are new (do not exist at target). */\r\n readonly newFiles: number;\r\n}\r\n\r\n/**\r\n * Map conflicting (modified) files back to their category IDs.\r\n *\r\n * For each modified file in the conflict report, determines which\r\n * install category it belongs to based on path prefix matching.\r\n *\r\n * @param conflicts - The conflict report from `detectConflicts`.\r\n * @returns Array of unique category IDs that contain modified files.\r\n */\r\nexport function getModifiedCategories(conflicts: ConflictReport): string[] {\r\n const categoryIds = new Set<string>();\r\n\r\n for (const filePath of conflicts.modifiedFiles) {\r\n const normalised = filePath.replace(/\\\\/g, '/');\r\n for (const cat of INSTALL_CATEGORIES) {\r\n if (normalised.startsWith(cat.pathPrefix)) {\r\n categoryIds.add(cat.id);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n return [...categoryIds];\r\n}\r\n\r\n/**\r\n * Build per-category conflict statistics from a conflict report.\r\n *\r\n * Each category in `INSTALL_CATEGORIES` is checked against the conflict\r\n * report's file entries. Only categories with at least one file are included.\r\n *\r\n * @param conflicts - The conflict report from `detectConflicts`.\r\n * @returns Array of per-category summaries, ordered by INSTALL_CATEGORIES order.\r\n */\r\nexport function getCategorySummary(conflicts: ConflictReport): CategoryConflictSummary[] {\r\n const summaries: CategoryConflictSummary[] = [];\r\n\r\n for (const cat of INSTALL_CATEGORIES) {\r\n let totalFiles = 0;\r\n let modifiedFiles = 0;\r\n let newFiles = 0;\r\n\r\n for (const file of conflicts.files) {\r\n const normalised = file.relativePath.replace(/\\\\/g, '/');\r\n if (normalised.startsWith(cat.pathPrefix)) {\r\n totalFiles++;\r\n if (file.status === 'modified') {\r\n modifiedFiles++;\r\n } else if (file.status === 'new') {\r\n newFiles++;\r\n }\r\n }\r\n }\r\n\r\n if (totalFiles > 0) {\r\n summaries.push({ categoryId: cat.id, totalFiles, modifiedFiles, newFiles });\r\n }\r\n }\r\n\r\n return summaries;\r\n}\r\n","/**\r\n * File Copier - Parallel file copy with bounded concurrency.\r\n *\r\n * Copies files from source to destination according to an InstallationPlan.\r\n * Uses a semaphore-based work queue to limit concurrent I/O operations,\r\n * preventing file descriptor exhaustion. Reports progress via callback\r\n * after each completed operation.\r\n *\r\n * Uses fs/promises exclusively. No external dependencies.\r\n *\r\n * @module engine/file-copier\r\n */\r\n\r\nimport * as fs from 'node:fs/promises';\r\nimport * as path from 'node:path';\r\n\r\nimport type {\r\n ComponentType,\r\n FileMapping,\r\n InstallationError,\r\n InstallationResult,\r\n InstallationWarning,\r\n ProgressCallback,\r\n} from './types.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Semaphore - Bounded Concurrency Control\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * A counting semaphore for limiting concurrent async operations.\r\n * Uses a FIFO queue: when all permits are taken, new acquirers wait\r\n * in order. When a permit is released, the next waiter is woken.\r\n */\r\nclass Semaphore {\r\n private permits: number;\r\n private readonly queue: Array<() => void> = [];\r\n\r\n constructor(maxConcurrent: number) {\r\n this.permits = maxConcurrent;\r\n }\r\n\r\n /** Acquire a permit. Resolves immediately if available, else waits. */\r\n async acquire(): Promise<void> {\r\n if (this.permits > 0) {\r\n this.permits--;\r\n return;\r\n }\r\n return new Promise<void>((resolve) => this.queue.push(resolve));\r\n }\r\n\r\n /** Release a permit. Wakes the next waiter if any. */\r\n release(): void {\r\n const next = this.queue.shift();\r\n if (next) {\r\n next();\r\n } else {\r\n this.permits++;\r\n }\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Directory Creation\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Collect all unique parent directories from file mappings\r\n * and create them. Deduplicates and sorts to ensure parents\r\n * are created before children.\r\n */\r\nasync function ensureDirectories(files: readonly FileMapping[]): Promise<void> {\r\n const dirs = new Set<string>();\r\n\r\n for (const file of files) {\r\n const dir = path.dirname(file.destinationPath);\r\n dirs.add(dir);\r\n }\r\n\r\n // Sort so that shorter (parent) paths are created first\r\n const sorted = Array.from(dirs).sort((a, b) => a.length - b.length);\r\n\r\n for (const dir of sorted) {\r\n await fs.mkdir(dir, { recursive: true });\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Single File Copy\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Copy a single file from source to destination.\r\n * Uses fs.copyFile which leverages the most efficient platform mechanism\r\n * (sendfile on Linux, COPYFILE_FICLONE on macOS).\r\n */\r\nasync function copySingleFile(\r\n sourcePath: string,\r\n destinationPath: string,\r\n): Promise<void> {\r\n await fs.copyFile(sourcePath, destinationPath);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Default concurrency limit for parallel file copy. */\r\nexport const DEFAULT_CONCURRENCY = 10;\r\n\r\n/** Minimum allowed concurrency limit. */\r\nexport const MIN_CONCURRENCY = 1;\r\n\r\n/** Maximum allowed concurrency limit. */\r\nexport const MAX_CONCURRENCY = 64;\r\n\r\n/**\r\n * Copy files from source to destination according to file mappings.\r\n *\r\n * Creates all necessary directories, then copies files in parallel\r\n * up to the configured concurrency limit. Reports progress via\r\n * callback after each file completes. Implements fail-fast: on\r\n * any copy failure, stops dispatching new work (in-flight copies\r\n * are allowed to complete).\r\n *\r\n * @param files - Array of FileMapping objects describing source/destination pairs.\r\n * @param options - Configuration options.\r\n * @param options.concurrency - Maximum parallel copy operations (default: 10, range: 1-64).\r\n * @param options.onProgress - Callback invoked after each file completes.\r\n * @returns InstallationResult with success status, counts, and any errors.\r\n */\r\nexport async function copyFiles(\r\n files: readonly FileMapping[],\r\n options: {\r\n concurrency?: number;\r\n onProgress?: ProgressCallback;\r\n } = {},\r\n): Promise<InstallationResult> {\r\n const startTime = Date.now();\r\n\r\n // Clamp concurrency to valid range\r\n const concurrency = Math.max(\r\n MIN_CONCURRENCY,\r\n Math.min(MAX_CONCURRENCY, options.concurrency ?? DEFAULT_CONCURRENCY),\r\n );\r\n\r\n const onProgress = options.onProgress ?? (() => {});\r\n const total = files.length;\r\n\r\n if (total === 0) {\r\n return buildResult(true, 0, 0, [], [], startTime, {});\r\n }\r\n\r\n // Create all target directories up front\r\n await ensureDirectories(files);\r\n\r\n // Track results\r\n const errors: InstallationError[] = [];\r\n const warnings: InstallationWarning[] = [];\r\n const componentCounts: Record<ComponentType, number> = {\r\n agents: 0,\r\n skills: 0,\r\n commands: 0,\r\n cli: 0,\r\n workflows: 0,\r\n metadata: 0,\r\n };\r\n\r\n let copiedCount = 0;\r\n let skippedCount = 0;\r\n let completedCount = 0;\r\n let hasFailed = false;\r\n\r\n const semaphore = new Semaphore(concurrency);\r\n\r\n // Launch all copy tasks. The semaphore limits actual parallelism.\r\n const tasks = files.map(async (file) => {\r\n await semaphore.acquire();\r\n\r\n try {\r\n // If a previous file failed, skip remaining work\r\n if (hasFailed) {\r\n skippedCount++;\r\n return;\r\n }\r\n\r\n await copySingleFile(file.sourcePath, file.destinationPath);\r\n copiedCount++;\r\n componentCounts[file.componentType]++;\r\n } catch (error) {\r\n hasFailed = true;\r\n const message =\r\n error instanceof Error ? error.message : String(error);\r\n errors.push({\r\n code: 'COPY_FAILED',\r\n message: `Failed to copy ${file.relativePath}: ${message}`,\r\n filePath: file.relativePath,\r\n originalError: message,\r\n });\r\n } finally {\r\n completedCount++;\r\n try {\r\n onProgress({\r\n fileName: file.fileName,\r\n current: completedCount,\r\n total,\r\n });\r\n } catch {\r\n // Progress callback errors must not halt installation\r\n }\r\n semaphore.release();\r\n }\r\n });\r\n\r\n await Promise.all(tasks);\r\n\r\n const success = errors.length === 0;\r\n\r\n return buildResult(\r\n success,\r\n copiedCount,\r\n skippedCount,\r\n warnings,\r\n errors,\r\n startTime,\r\n componentCounts,\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Result Builder\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Build an InstallationResult from the provided metrics.\r\n */\r\nfunction buildResult(\r\n success: boolean,\r\n copiedCount: number,\r\n skippedCount: number,\r\n warnings: readonly InstallationWarning[],\r\n errors: readonly InstallationError[],\r\n startTime: number,\r\n componentCounts: Record<string, number>,\r\n): InstallationResult {\r\n return {\r\n success,\r\n copiedCount,\r\n skippedCount,\r\n warnings,\r\n errors,\r\n durationMs: Date.now() - startTime,\r\n componentCounts: {\r\n agents: componentCounts['agents'] ?? 0,\r\n skills: componentCounts['skills'] ?? 0,\r\n commands: componentCounts['commands'] ?? 0,\r\n cli: componentCounts['cli'] ?? 0,\r\n workflows: componentCounts['workflows'] ?? 0,\r\n metadata: componentCounts['metadata'] ?? 0,\r\n },\r\n };\r\n}\r\n","/**\r\n * Rollback - Backup creation, restoration, and cleanup.\r\n *\r\n * Creates timestamped backup directories before overwriting existing files.\r\n * Provides rollback restoration on installation failure and cleanup on\r\n * success. Backup directory naming follows the convention:\r\n * .ai-dlc-backup/{ISO-timestamp}/\r\n *\r\n * Uses fs/promises exclusively. No external dependencies.\r\n *\r\n * @module engine/rollback\r\n */\r\n\r\nimport * as fs from 'node:fs/promises';\r\nimport * as path from 'node:path';\r\n\r\nimport type {\r\n BackedUpFile,\r\n BackupManifest,\r\n InstallationError,\r\n RollbackResult,\r\n} from './types.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Constants\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Directory name prefix for backup directories within the target.\r\n * Full path: {targetDirectory}/.ai-dlc-backup/{timestamp}/\r\n */\r\nconst BACKUP_ROOT_DIR = '.ai-dlc-backup';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Timestamp\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Generate a filesystem-safe ISO 8601 timestamp.\r\n * Replaces colons with hyphens for Windows compatibility.\r\n *\r\n * @returns A string like \"2026-02-13T163000Z\"\r\n */\r\nfunction generateTimestamp(): string {\r\n return new Date()\r\n .toISOString()\r\n .replace(/:/g, '')\r\n .replace(/\\.\\d+Z$/, 'Z');\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Create a timestamped backup directory and copy files that will be\r\n * overwritten during installation.\r\n *\r\n * @param targetDirectory - Absolute path to the target .claude/ directory.\r\n * @param filesToBackup - Relative paths (from targetDirectory) of files to back up.\r\n * @returns A BackupManifest describing the backup, or null if no files needed backup.\r\n */\r\nexport async function createBackup(\r\n targetDirectory: string,\r\n filesToBackup: readonly string[],\r\n): Promise<BackupManifest | null> {\r\n if (filesToBackup.length === 0) {\r\n return null;\r\n }\r\n\r\n const timestamp = generateTimestamp();\r\n const backupDirectory = path.join(\r\n targetDirectory,\r\n BACKUP_ROOT_DIR,\r\n timestamp,\r\n );\r\n\r\n // Create the backup directory\r\n await fs.mkdir(backupDirectory, { recursive: true });\r\n\r\n const backedUpFiles: BackedUpFile[] = [];\r\n\r\n for (const relativePath of filesToBackup) {\r\n const sourcePath = path.join(targetDirectory, relativePath);\r\n const backupPath = path.join(backupDirectory, relativePath);\r\n\r\n try {\r\n // Check the source file exists before attempting backup\r\n await fs.access(sourcePath);\r\n\r\n // Create parent directory in backup location\r\n await fs.mkdir(path.dirname(backupPath), { recursive: true });\r\n\r\n // Copy the file to backup\r\n await fs.copyFile(sourcePath, backupPath);\r\n\r\n backedUpFiles.push({\r\n originalRelativePath: relativePath,\r\n backupPath,\r\n });\r\n } catch {\r\n // If we cannot back up a file (e.g., it was deleted between\r\n // conflict detection and backup), skip it. This is not fatal.\r\n continue;\r\n }\r\n }\r\n\r\n return {\r\n backupDirectory,\r\n files: backedUpFiles,\r\n createdAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\n/**\r\n * Restore all backed-up files to their original locations in the\r\n * target directory. This is the rollback operation invoked on\r\n * installation failure.\r\n *\r\n * Rollback is designed to be idempotent: calling it multiple times\r\n * produces the same result.\r\n *\r\n * @param backup - The BackupManifest from a prior createBackup call.\r\n * @param targetDirectory - Absolute path to the target .claude/ directory.\r\n * @returns A RollbackResult with success status and restore counts.\r\n */\r\nexport async function restoreFromBackup(\r\n backup: BackupManifest,\r\n targetDirectory: string,\r\n): Promise<RollbackResult> {\r\n const errors: InstallationError[] = [];\r\n let restoredCount = 0;\r\n\r\n for (const file of backup.files) {\r\n const restorePath = path.join(targetDirectory, file.originalRelativePath);\r\n\r\n try {\r\n // Ensure the parent directory exists (it may have been modified)\r\n await fs.mkdir(path.dirname(restorePath), { recursive: true });\r\n\r\n // Copy the backed-up file back to its original location\r\n await fs.copyFile(file.backupPath, restorePath);\r\n restoredCount++;\r\n } catch (error) {\r\n const message =\r\n error instanceof Error ? error.message : String(error);\r\n errors.push({\r\n code: 'ROLLBACK_RESTORE_FAILED',\r\n message: `Failed to restore ${file.originalRelativePath}: ${message}`,\r\n filePath: file.originalRelativePath,\r\n originalError: message,\r\n });\r\n }\r\n }\r\n\r\n return {\r\n success: errors.length === 0,\r\n restoredCount,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Delete the backup directory after a successful installation.\r\n * Removes the entire backup directory tree.\r\n *\r\n * Cleanup failure is non-fatal: the backup directory simply remains\r\n * on disk and can be manually deleted.\r\n *\r\n * @param backup - The BackupManifest to clean up.\r\n */\r\nexport async function cleanupBackup(backup: BackupManifest): Promise<void> {\r\n try {\r\n await fs.rm(backup.backupDirectory, { recursive: true, force: true });\r\n } catch {\r\n // Cleanup failure is non-fatal. The backup directory remains\r\n // on disk but does not affect the installation.\r\n }\r\n}\r\n\r\n/**\r\n * List all existing backup directories under the target directory.\r\n * Returns absolute paths sorted by name (which are timestamps,\r\n * so sorting is chronological).\r\n *\r\n * @param targetDirectory - Absolute path to the target .claude/ directory.\r\n * @returns Array of absolute paths to backup directories.\r\n */\r\nexport async function listBackups(\r\n targetDirectory: string,\r\n): Promise<readonly string[]> {\r\n const backupRoot = path.join(targetDirectory, BACKUP_ROOT_DIR);\r\n\r\n try {\r\n const entries = await fs.readdir(backupRoot, { withFileTypes: true });\r\n return entries\r\n .filter((entry) => entry.isDirectory())\r\n .map((entry) => path.join(backupRoot, entry.name))\r\n .sort();\r\n } catch {\r\n // If the backup root does not exist, there are no backups\r\n return [];\r\n }\r\n}\r\n","/**\r\n * Validator - Post-installation integrity verification.\r\n *\r\n * Verifies that all expected files exist at their destination paths\r\n * and have non-zero file sizes. Produces a ValidationReport that\r\n * the orchestrator uses to determine installation success.\r\n *\r\n * Uses fs/promises exclusively. No external dependencies.\r\n *\r\n * @module engine/validator\r\n */\r\n\r\nimport * as fs from 'node:fs/promises';\r\nimport * as path from 'node:path';\r\n\r\nimport type {\r\n FileMapping,\r\n InvalidFile,\r\n ValidationReport,\r\n} from './types.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Single File Validation\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Validate that a single file exists at its expected destination\r\n * and has a non-zero file size.\r\n *\r\n * @param destinationPath - Absolute path where the file should exist.\r\n * @param relativePath - Relative path for reporting purposes.\r\n * @returns null if valid, or an InvalidFile describing the issue.\r\n */\r\nasync function validateSingleFile(\r\n destinationPath: string,\r\n relativePath: string,\r\n): Promise<InvalidFile | null> {\r\n try {\r\n const stat = await fs.stat(destinationPath);\r\n\r\n if (!stat.isFile()) {\r\n return {\r\n relativePath,\r\n reason: 'Path exists but is not a regular file',\r\n };\r\n }\r\n\r\n if (stat.size === 0) {\r\n return {\r\n relativePath,\r\n reason: 'File exists but has zero size',\r\n };\r\n }\r\n\r\n return null;\r\n } catch (error) {\r\n // File does not exist or is not accessible\r\n const code =\r\n error instanceof Error && 'code' in error\r\n ? (error as NodeJS.ErrnoException).code\r\n : undefined;\r\n\r\n if (code === 'ENOENT') {\r\n return {\r\n relativePath,\r\n reason: 'File does not exist at destination',\r\n };\r\n }\r\n\r\n const message =\r\n error instanceof Error ? error.message : String(error);\r\n return {\r\n relativePath,\r\n reason: `Cannot access file: ${message}`,\r\n };\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Validate that all files in the installation plan exist at their\r\n * destination and have non-zero file sizes.\r\n *\r\n * @param files - Array of FileMapping objects that were copied.\r\n * @returns A ValidationReport with pass/fail status and details.\r\n */\r\nexport async function validateInstallation(\r\n files: readonly FileMapping[],\r\n): Promise<ValidationReport> {\r\n if (files.length === 0) {\r\n return {\r\n valid: true,\r\n totalChecked: 0,\r\n validCount: 0,\r\n missingFiles: [],\r\n invalidFiles: [],\r\n };\r\n }\r\n\r\n const missingFiles: string[] = [];\r\n const invalidFiles: InvalidFile[] = [];\r\n let validCount = 0;\r\n\r\n // Validate each file\r\n for (const file of files) {\r\n const issue = await validateSingleFile(\r\n file.destinationPath,\r\n file.relativePath,\r\n );\r\n\r\n if (issue === null) {\r\n validCount++;\r\n } else if (issue.reason.includes('does not exist')) {\r\n missingFiles.push(file.relativePath);\r\n invalidFiles.push(issue);\r\n } else {\r\n invalidFiles.push(issue);\r\n }\r\n }\r\n\r\n return {\r\n valid: missingFiles.length === 0 && invalidFiles.length === 0,\r\n totalChecked: files.length,\r\n validCount,\r\n missingFiles,\r\n invalidFiles,\r\n };\r\n}\r\n\r\n/**\r\n * Validate that a target directory exists and contains the expected\r\n * number of files. A lightweight check that does not inspect individual\r\n * file contents.\r\n *\r\n * @param targetDirectory - Absolute path to the target .claude/ directory.\r\n * @param expectedFileCount - Number of files expected in the directory tree.\r\n * @returns A ValidationReport with pass/fail status.\r\n */\r\nexport async function validateTargetDirectory(\r\n targetDirectory: string,\r\n expectedFileCount: number,\r\n): Promise<ValidationReport> {\r\n try {\r\n const stat = await fs.stat(targetDirectory);\r\n if (!stat.isDirectory()) {\r\n return {\r\n valid: false,\r\n totalChecked: 0,\r\n validCount: 0,\r\n missingFiles: [],\r\n invalidFiles: [\r\n {\r\n relativePath: targetDirectory,\r\n reason: 'Target path exists but is not a directory',\r\n },\r\n ],\r\n };\r\n }\r\n } catch {\r\n return {\r\n valid: false,\r\n totalChecked: 0,\r\n validCount: 0,\r\n missingFiles: [targetDirectory],\r\n invalidFiles: [\r\n {\r\n relativePath: targetDirectory,\r\n reason: 'Target directory does not exist',\r\n },\r\n ],\r\n };\r\n }\r\n\r\n // Count all files recursively\r\n const actualCount = await countFilesRecursive(targetDirectory);\r\n\r\n if (actualCount < expectedFileCount) {\r\n return {\r\n valid: false,\r\n totalChecked: actualCount,\r\n validCount: actualCount,\r\n missingFiles: [],\r\n invalidFiles: [\r\n {\r\n relativePath: targetDirectory,\r\n reason: `Expected ${expectedFileCount} files but found ${actualCount}`,\r\n },\r\n ],\r\n };\r\n }\r\n\r\n return {\r\n valid: true,\r\n totalChecked: actualCount,\r\n validCount: actualCount,\r\n missingFiles: [],\r\n invalidFiles: [],\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Recursively count all files in a directory tree.\r\n *\r\n * @param directory - Absolute path to the directory.\r\n * @returns Total number of regular files found.\r\n */\r\nasync function countFilesRecursive(directory: string): Promise<number> {\r\n let count = 0;\r\n\r\n let entries: import('fs').Dirent[];\r\n try {\r\n entries = await fs.readdir(directory, { withFileTypes: true });\r\n } catch {\r\n return 0;\r\n }\r\n\r\n for (const entry of entries) {\r\n const fullPath = path.join(directory, entry.name);\r\n if (entry.isDirectory()) {\r\n count += await countFilesRecursive(fullPath);\r\n } else if (entry.isFile()) {\r\n count++;\r\n }\r\n }\r\n\r\n return count;\r\n}\r\n","/**\r\n * @sixsevenai/ai-dlc-installer - Public API\r\n *\r\n * Re-exports the core installer entry point and shared types\r\n * for programmatic use and CLI bootstrapping.\r\n *\r\n * @module index\r\n */\r\n\r\nimport {\r\n executeInstallation,\r\n executeDryRun,\r\n type CLIOptions,\r\n type ExitCode,\r\n EXIT_SUCCESS,\r\n} from './orchestrator/index.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type { CliFlags } from './cli.js';\r\n\r\n/**\r\n * Options accepted by the installer's programmatic entry point.\r\n */\r\nexport interface InstallerOptions {\r\n /** Enable verbose logging during installation. */\r\n readonly verbose?: boolean;\r\n /** Preview changes without modifying the file system. */\r\n readonly dryRun?: boolean;\r\n /** Overwrite existing files without confirmation prompts. */\r\n readonly force?: boolean;\r\n /** Suppress non-error output. */\r\n readonly quiet?: boolean;\r\n /** Disable colored output. */\r\n readonly noColor?: boolean;\r\n /** Target directory for installation. */\r\n readonly target?: string;\r\n /** Category names to selectively overwrite (from `--overwrite` flags). */\r\n readonly overwrite?: readonly string[];\r\n /** Enable selective installation mode. */\r\n readonly custom?: boolean;\r\n /** Comma-separated category IDs to install. */\r\n readonly categories?: readonly string[];\r\n /** Auto-select categories from a named profile. */\r\n readonly profile?: string;\r\n}\r\n\r\n/**\r\n * Result returned after an installation run completes.\r\n */\r\nexport interface InstallerResult {\r\n /** Whether the installation completed successfully. */\r\n readonly success: boolean;\r\n /** Number of files written to disk. */\r\n readonly filesWritten: number;\r\n /** Human-readable summary of what was done. */\r\n readonly summary: string;\r\n /** Process exit code (0 = success, 1 = error, 2 = cancelled). */\r\n readonly exitCode: ExitCode;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Platform Exports\r\n// ---------------------------------------------------------------------------\r\n\r\nexport * from './platform/index.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Orchestrator Exports\r\n// ---------------------------------------------------------------------------\r\n\r\nexport {\r\n executeInstallation,\r\n executeDryRun,\r\n INSTALLER_VERSION,\r\n WORKFLOW_STEPS,\r\n ErrorHandler,\r\n} from './orchestrator/index.js';\r\n\r\nexport type {\r\n CLIOptions,\r\n ExitCode,\r\n WorkflowStepId,\r\n InstallationConfig,\r\n} from './orchestrator/index.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Installer Entry Point\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Run the AI-DLC framework installer.\r\n *\r\n * This is the main programmatic entry point. The CLI module (`cli.ts`)\r\n * calls this function after parsing command-line flags.\r\n *\r\n * Delegates to the CLI Orchestrator workflow which coordinates platform\r\n * detection, terminal UI, and the installation engine.\r\n *\r\n * @param options - Configuration flags from CLI or programmatic caller.\r\n * @returns A promise resolving to the installation result.\r\n */\r\nexport async function runInstaller(\r\n options: InstallerOptions = {},\r\n): Promise<InstallerResult> {\r\n // Build CLIOptions from InstallerOptions\r\n const cliOptions: CLIOptions = {\r\n command: 'install',\r\n target: options.target ?? null,\r\n force: options.force ?? false,\r\n dryRun: options.dryRun ?? false,\r\n verbose: options.verbose ?? false,\r\n noColor: options.noColor ?? false,\r\n quiet: options.quiet ?? false,\r\n overwrite: options.overwrite ?? [],\r\n custom: options.custom ?? false,\r\n profile: options.profile ?? null,\r\n rawArgs: [],\r\n };\r\n\r\n let exitCode: ExitCode;\r\n\r\n if (cliOptions.dryRun) {\r\n exitCode = await executeDryRun(cliOptions);\r\n } else {\r\n exitCode = await executeInstallation(cliOptions);\r\n }\r\n\r\n return {\r\n success: exitCode === EXIT_SUCCESS,\r\n filesWritten: 0, // Detailed counts are in the workflow output\r\n summary: exitCode === EXIT_SUCCESS\r\n ? 'Installation completed successfully.'\r\n : exitCode === 2\r\n ? 'Installation cancelled by user.'\r\n : 'Installation failed.',\r\n exitCode,\r\n };\r\n}\r\n","/**\r\n * CLI Entry Point for @sixsevenai/ai-dlc-installer\r\n *\r\n * Parses command-line arguments, validates flags, and delegates to\r\n * the orchestrator workflow. Supports the `install` subcommand with\r\n * `--target`, `--force`, `--dry-run`, `--verbose`, `--no-color`,\r\n * and `--quiet` flags.\r\n *\r\n * @module cli\r\n */\r\n\r\nimport { runInstaller, type InstallerOptions } from './index.js';\r\nimport { INSTALLER_VERSION } from './orchestrator/index.js';\r\nimport { resolveCategories } from './engine/category-filter.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface CliFlags {\r\n readonly version: boolean;\r\n readonly help: boolean;\r\n readonly verbose: boolean;\r\n readonly dryRun: boolean;\r\n readonly noColor: boolean;\r\n readonly force: boolean;\r\n readonly quiet: boolean;\r\n readonly custom: boolean;\r\n readonly target: string | null;\r\n readonly profile: string | null;\r\n readonly overwrite: readonly string[];\r\n readonly categories: readonly string[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Constants\r\n// ---------------------------------------------------------------------------\r\n\r\nconst CLI_NAME = 'sixsevenai';\r\n\r\n/** Known flags for fuzzy-match suggestion on typos. */\r\nconst KNOWN_FLAGS = [\r\n '--version', '-v', '--help', '-h', '--verbose',\r\n '--dry-run', '-d', '--no-color', '--force', '-f',\r\n '--quiet', '-q', '--target', '-t', '--overwrite',\r\n '--custom', '--categories', '--profile',\r\n];\r\n\r\n// ---------------------------------------------------------------------------\r\n// Argument Parsing\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction parseArgs(argv: readonly string[]): CliFlags {\r\n const args = argv.slice(2);\r\n\r\n // Filter out 'install' subcommand if present\r\n const filtered = args[0] === 'install' ? args.slice(1) : args;\r\n\r\n let target: string | null = null;\r\n const version = filtered.includes('--version') || filtered.includes('-v');\r\n const help = filtered.includes('--help') || filtered.includes('-h');\r\n const verbose = filtered.includes('--verbose');\r\n const dryRun = filtered.includes('--dry-run') || filtered.includes('-d');\r\n const noColor = filtered.includes('--no-color');\r\n const force = filtered.includes('--force') || filtered.includes('-f');\r\n const quiet = filtered.includes('--quiet') || filtered.includes('-q');\r\n const custom = filtered.includes('--custom');\r\n\r\n // Parse --target / -t with value\r\n for (let i = 0; i < filtered.length; i++) {\r\n const arg = filtered[i]!;\r\n if ((arg === '--target' || arg === '-t') && i + 1 < filtered.length) {\r\n target = filtered[i + 1]!;\r\n i++; // skip the value\r\n }\r\n }\r\n\r\n // Parse --overwrite with value (repeatable)\r\n const overwrite: string[] = [];\r\n for (let i = 0; i < filtered.length; i++) {\r\n const arg = filtered[i]!;\r\n if (arg === '--overwrite' && i + 1 < filtered.length) {\r\n overwrite.push(filtered[i + 1]!);\r\n i++; // skip the value\r\n }\r\n }\r\n\r\n // Parse --categories with comma-separated value\r\n const categories: string[] = [];\r\n for (let i = 0; i < filtered.length; i++) {\r\n const arg = filtered[i]!;\r\n if (arg === '--categories' && i + 1 < filtered.length) {\r\n categories.push(...filtered[i + 1]!.split(',').map((s) => s.trim()).filter(Boolean));\r\n i++;\r\n }\r\n }\r\n\r\n // Parse --profile with value\r\n let profile: string | null = null;\r\n for (let i = 0; i < filtered.length; i++) {\r\n const arg = filtered[i]!;\r\n if (arg === '--profile' && i + 1 < filtered.length) {\r\n profile = filtered[i + 1]!;\r\n i++;\r\n }\r\n }\r\n\r\n // Validate --profile value\r\n const VALID_PROFILES = ['minimal', 'standard', 'enterprise'];\r\n if (profile !== null && !VALID_PROFILES.includes(profile)) {\r\n console.error(`Error: Invalid profile '${profile}'. Valid profiles are: ${VALID_PROFILES.join(', ')}`);\r\n process.exit(1);\r\n }\r\n\r\n // Validate --categories against known category IDs\r\n if (categories.length > 0) {\r\n try {\r\n resolveCategories(categories);\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n }\r\n\r\n // If no --target but there's a positional arg that isn't a flag, treat as target\r\n if (target === null) {\r\n for (const arg of filtered) {\r\n if (!arg.startsWith('-') && arg !== 'install') {\r\n target = arg;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n // Validate mutually exclusive flags\r\n if (verbose && quiet) {\r\n console.error('Error: Cannot use --verbose and --quiet together.');\r\n process.exit(1);\r\n }\r\n\r\n // Check for unknown flags\r\n for (const arg of filtered) {\r\n if (arg.startsWith('-') && !KNOWN_FLAGS.includes(arg) && arg !== target) {\r\n // Skip flag values (e.g., the path after --target or --overwrite)\r\n const prevIdx = filtered.indexOf(arg) - 1;\r\n if (prevIdx >= 0 && (filtered[prevIdx] === '--target' || filtered[prevIdx] === '-t' || filtered[prevIdx] === '--overwrite' || filtered[prevIdx] === '--categories' || filtered[prevIdx] === '--profile')) {\r\n continue;\r\n }\r\n\r\n const suggestion = findClosestFlag(arg);\r\n const suggestionText = suggestion ? ` Did you mean ${suggestion}?` : '';\r\n console.error(`Error: Unknown flag: ${arg}.${suggestionText}`);\r\n process.exit(1);\r\n }\r\n }\r\n\r\n return { version, help, verbose, dryRun, noColor, force, quiet, custom, target, profile, overwrite, categories };\r\n}\r\n\r\n/**\r\n * Find the closest known flag using simple Levenshtein distance.\r\n */\r\nfunction findClosestFlag(input: string): string | null {\r\n let bestMatch: string | null = null;\r\n let bestDistance = Infinity;\r\n\r\n for (const flag of KNOWN_FLAGS) {\r\n const dist = levenshteinDistance(input, flag);\r\n if (dist < bestDistance && dist <= 3) {\r\n bestDistance = dist;\r\n bestMatch = flag;\r\n }\r\n }\r\n\r\n return bestMatch;\r\n}\r\n\r\nfunction levenshteinDistance(a: string, b: string): number {\r\n const m = a.length;\r\n const n = b.length;\r\n const dp: number[][] = Array.from({ length: m + 1 }, () =>\r\n Array.from({ length: n + 1 }, () => 0),\r\n );\r\n\r\n for (let i = 0; i <= m; i++) dp[i]![0] = i;\r\n for (let j = 0; j <= n; j++) dp[0]![j] = j;\r\n\r\n for (let i = 1; i <= m; i++) {\r\n for (let j = 1; j <= n; j++) {\r\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\r\n dp[i]![j] = Math.min(\r\n dp[i - 1]![j]! + 1,\r\n dp[i]![j - 1]! + 1,\r\n dp[i - 1]![j - 1]! + cost,\r\n );\r\n }\r\n }\r\n\r\n return dp[m]![n]!;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Help Text\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction printHelp(): void {\r\n const help = `\r\nUsage: ${CLI_NAME} install [target-directory] [options]\r\n\r\nInteractive terminal installer for the AI-DLC framework.\r\n\r\nArguments:\r\n target-directory Target project directory (default: current directory)\r\n\r\nOptions:\r\n --target, -t <dir> Target project directory (overrides positional arg)\r\n --force, -f Overwrite existing files without prompting\r\n --dry-run, -d Preview changes without writing to disk\r\n --verbose Enable verbose logging to stderr\r\n --no-color Disable colored output (also respects NO_COLOR env)\r\n --overwrite <category> Overwrite specific categories only (repeatable)\r\n --custom Enable selective installation mode\r\n --categories <ids> Comma-separated category IDs to install (e.g., agents,skills)\r\n --profile <name> Auto-select categories from profile (minimal|standard|enterprise)\r\n --quiet, -q Suppress non-error output (mutually exclusive with --verbose)\r\n -h, --help Show this help message\r\n -v, --version Show version number\r\n\r\nExit Codes:\r\n 0 Installation completed successfully\r\n 1 Installation failed\r\n 2 Installation cancelled by user\r\n\r\nExamples:\r\n ${CLI_NAME} install\r\n ${CLI_NAME} install --target /home/user/my-project --force\r\n ${CLI_NAME} install --dry-run --verbose\r\n ${CLI_NAME} install --overwrite agents --overwrite skills\r\n ${CLI_NAME} install /path/to/project --dry-run > preview.txt\r\n`;\r\n console.log(help.trim());\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Main\r\n// ---------------------------------------------------------------------------\r\n\r\nasync function main(): Promise<void> {\r\n const flags = parseArgs(process.argv);\r\n\r\n if (flags.version) {\r\n console.log(`${CLI_NAME} v${INSTALLER_VERSION}`);\r\n return;\r\n }\r\n\r\n if (flags.help) {\r\n printHelp();\r\n return;\r\n }\r\n\r\n // Disable color if requested\r\n if (flags.noColor) {\r\n process.env['NO_COLOR'] = '1';\r\n }\r\n\r\n const options: InstallerOptions = {\r\n verbose: flags.verbose,\r\n dryRun: flags.dryRun,\r\n force: flags.force,\r\n quiet: flags.quiet,\r\n noColor: flags.noColor,\r\n target: flags.target ?? undefined,\r\n overwrite: flags.overwrite.length > 0 ? flags.overwrite : undefined,\r\n custom: flags.custom,\r\n categories: flags.categories.length > 0 ? flags.categories : undefined,\r\n profile: flags.profile ?? undefined,\r\n };\r\n\r\n const result = await runInstaller(options);\r\n\r\n process.exit(result.exitCode);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Bootstrap with error handling\r\n// ---------------------------------------------------------------------------\r\n\r\nprocess.title = CLI_NAME;\r\n\r\nmain().catch((error: unknown) => {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(`\\nFatal error: ${message}`);\r\n\r\n if (error instanceof Error && error.stack && process.env['DEBUG']) {\r\n console.error(error.stack);\r\n }\r\n\r\n process.exit(1);\r\n});\r\n"],"mappings":"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","names":["path","mkdir","readFile","stat","stat","text","text","version","seconds","text","stat","text","stripAnsi","text","stripAnsi","stat","version","version","release","path","os","fs","stat","path","os","fs","version","execSync","execSync","version","path","fs","path","stat","fs","stat","sourceHash","fs","path","resolve","fs","path","fs","path","stat","os","stat","readFile","mkdir","version"]}
1
+ {"version":3,"sources":["../src/orchestrator/workflow.ts","../src/orchestrator/types.ts","../src/orchestrator/config.ts","../src/ui/theme.ts","../src/ui/banner.ts","../src/ui/progress.ts","../src/ui/types.ts","../src/ui/prompts.ts","../src/ui/error-display.ts","../src/engine/category-filter.ts","../src/ui/summary.ts","../src/ui/sixseven-animation.ts","../src/orchestrator/error-handler.ts","../src/platform/types.ts","../src/platform/detector.ts","../src/platform/paths.ts","../src/platform/permissions.ts","../src/platform/terminal.ts","../src/platform/shell.ts","../src/platform/runtime.ts","../src/platform/facade.ts","../src/engine/manifest.ts","../src/engine/conflict-detector.ts","../src/engine/file-copier.ts","../src/engine/rollback.ts","../src/engine/validator.ts","../src/index.ts","../src/cli.ts"],"sourcesContent":["/**\r\n * CLI Orchestrator - Installation Workflow\r\n *\r\n * The core orchestration logic that drives the 12-step installation\r\n * workflow. Delegates to platform, UI, and engine subsystems through\r\n * their public APIs. Manages workflow state, error recovery, and\r\n * cancellation handling.\r\n *\r\n * @module orchestrator/workflow\r\n */\r\n\r\nimport * as path from 'node:path';\r\nimport { mkdir, writeFile, readFile, stat } from 'node:fs/promises';\r\n\r\nimport type {\r\n CLIOptions,\r\n ExitCode,\r\n InstallationContext,\r\n InstallationConfig,\r\n OverwriteMode,\r\n WorkflowState,\r\n WorkflowStepId,\r\n WorkflowStepState,\r\n StepOutput,\r\n DryRunReport,\r\n DryRunStepDetail,\r\n} from './types.js';\r\nimport { EXIT_SUCCESS, EXIT_CANCELLED } from './types.js';\r\n\r\nimport {\r\n WORKFLOW_STEPS,\r\n INSTALLER_VERSION,\r\n CLAUDE_DIRECTORY_NAME,\r\n shouldSkipStep,\r\n resolveConfig,\r\n resolveSourceDirectory,\r\n resolveAiDlcSourceDirectory,\r\n} from './config.js';\r\n\r\nimport { ErrorHandler } from './error-handler.js';\r\n\r\n// -- Platform imports\r\nimport {\r\n PlatformFacade,\r\n type PlatformEnvironment,\r\n} from '../platform/index.js';\r\n\r\n// -- UI imports\r\nimport {\r\n ThemeEngine,\r\n renderBanner,\r\n ProgressTracker,\r\n renderError,\r\n renderSummary,\r\n getDefaultNextSteps,\r\n promptDirectorySelection,\r\n promptConfirmation,\r\n promptOverwriteMode,\r\n promptCategorySelection,\r\n promptRetry,\r\n promptIntro,\r\n promptOutro,\r\n UserCancellationError,\r\n SixSevenSpinner,\r\n formatDuration,\r\n mapColorSupport,\r\n type TerminalCapabilities,\r\n type DirectoryOption,\r\n type ErrorPanelContent,\r\n type InstallationSummary,\r\n} from '../ui/index.js';\r\n\r\n// -- Engine imports\r\nimport {\r\n scanSourceDirectory,\r\n detectConflicts,\r\n copyFiles,\r\n createBackup,\r\n restoreFromBackup,\r\n validateInstallation,\r\n resolveCategories,\r\n filterMappingsByCategories,\r\n INSTALL_CATEGORIES,\r\n type ComponentManifest,\r\n type ConflictReport,\r\n type FileMapping,\r\n type BackupManifest,\r\n} from '../engine/index.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Workflow State Factory\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction createInitialState(): WorkflowState {\r\n return {\r\n status: 'pending',\r\n steps: WORKFLOW_STEPS.map(def => ({\r\n def,\r\n status: 'pending',\r\n output: null,\r\n error: null,\r\n startedAt: null,\r\n completedAt: null,\r\n })),\r\n currentStepId: null,\r\n startedAt: null,\r\n completedAt: null,\r\n cancellationReason: null,\r\n };\r\n}\r\n\r\nfunction createInitialContext(sourceDirectory: string): InstallationContext {\r\n return {\r\n platformEnv: null,\r\n terminalCapabilities: null,\r\n runtimeReport: null,\r\n targetDirectory: null,\r\n claudeDirectory: null,\r\n sourceDirectory,\r\n manifest: null,\r\n conflictReport: null,\r\n backupManifest: null,\r\n installationResult: null,\r\n validationReport: null,\r\n fileMappings: [],\r\n overwriteMode: null,\r\n selectedCategories: [],\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helper: Terminal Capabilities from Platform\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction buildTerminalCapabilities(env: PlatformEnvironment): TerminalCapabilities {\r\n return {\r\n colorSupport: mapColorSupport(env.terminal.colorSupport),\r\n unicodeSupport: env.terminal.unicodeSupport.supported,\r\n width: env.terminal.dimensions.columns,\r\n height: env.terminal.dimensions.rows,\r\n isInteractive: env.terminal.interactivity.isInteractive,\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helper: Build File Mappings\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction buildFileMappings(\r\n manifest: ComponentManifest,\r\n sourceDirectory: string,\r\n claudeDirectory: string,\r\n): FileMapping[] {\r\n return manifest.entries.map(entry => ({\r\n relativePath: entry.relativePath,\r\n sourcePath: path.join(sourceDirectory, entry.relativePath),\r\n destinationPath: path.join(claudeDirectory, entry.relativePath),\r\n componentType: entry.componentType,\r\n fileName: entry.fileName,\r\n sizeBytes: entry.sizeBytes,\r\n }));\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helper: Build Installation Summary\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction buildInstallationSummary(\r\n ctx: InstallationContext,\r\n workflow: WorkflowState,\r\n): InstallationSummary {\r\n const elapsed = workflow.completedAt && workflow.startedAt\r\n ? workflow.completedAt - workflow.startedAt\r\n : 0;\r\n\r\n const result = ctx.installationResult;\r\n\r\n // Count from the files that were actually installed, not the full source manifest\r\n const counts = { agents: 0, skills: 0, commands: 0, cli: 0, workflows: 0, metadata: 0 };\r\n for (const m of ctx.fileMappings) {\r\n counts[m.componentType]++;\r\n }\r\n\r\n return {\r\n success: result?.success ?? false,\r\n targetDirectory: ctx.targetDirectory ?? 'unknown',\r\n componentCounts: {\r\n agents: counts.agents,\r\n skills: counts.skills,\r\n commands: counts.commands,\r\n cliFiles: counts.cli,\r\n other: counts.workflows + counts.metadata,\r\n },\r\n totalDuration: formatDuration(elapsed),\r\n totalFilesCopied: result?.copiedCount ?? 0,\r\n totalFilesSkipped: result?.skippedCount ?? 0,\r\n totalFilesFailed: result?.errors.length ?? 0,\r\n installerVersion: INSTALLER_VERSION,\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helper: Build Directory Options\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction buildDirectoryOptions(env: PlatformEnvironment): DirectoryOption[] {\r\n const cwd = process.cwd();\r\n const home = env.platform.homeDirectory.path;\r\n\r\n const options: DirectoryOption[] = [\r\n {\r\n path: cwd,\r\n label: cwd,\r\n isDefault: true,\r\n exists: true,\r\n },\r\n ];\r\n\r\n if (home !== cwd) {\r\n options.push({\r\n path: home,\r\n label: home,\r\n isDefault: false,\r\n exists: true,\r\n });\r\n }\r\n\r\n return options;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Verbose Logger\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction verboseLog(verbose: boolean, ...args: unknown[]): void {\r\n if (verbose) {\r\n console.error('[verbose]', ...args);\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Main Workflow Execution\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Execute the full installation workflow.\r\n *\r\n * This is the core orchestration function that drives the 10-step\r\n * installation pipeline. It delegates to platform, UI, and engine\r\n * subsystems, manages state transitions, and handles errors with\r\n * recovery/rollback.\r\n *\r\n * @param options - Parsed CLI options\r\n * @returns Process exit code (0 = success, 1 = error, 2 = cancelled)\r\n */\r\nexport async function executeInstallation(options: CLIOptions): Promise<ExitCode> {\r\n const errorHandler = new ErrorHandler();\r\n const workflow = createInitialState();\r\n let sourceDirectory: string;\r\n\r\n // Resolve source directory before starting workflow\r\n try {\r\n sourceDirectory = await resolveSourceDirectory();\r\n } catch (error) {\r\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\r\n return EXIT_CANCELLED;\r\n }\r\n\r\n const ctx = createInitialContext(sourceDirectory);\r\n\r\n // Register SIGINT handler for graceful cancellation\r\n let cancelled = false;\r\n const sigintHandler = () => {\r\n cancelled = true;\r\n workflow.status = 'cancelled';\r\n workflow.cancellationReason = 'User pressed Ctrl+C';\r\n };\r\n process.on('SIGINT', sigintHandler);\r\n\r\n // Start workflow\r\n workflow.status = 'running';\r\n workflow.startedAt = Date.now();\r\n\r\n let theme: ThemeEngine | null = null;\r\n\r\n try {\r\n for (const stepState of workflow.steps) {\r\n // Check for cancellation between steps\r\n if (cancelled) {\r\n break;\r\n }\r\n\r\n const stepId = stepState.def.id;\r\n const isInteractive = ctx.terminalCapabilities?.isInteractive ?? true;\r\n\r\n // Check if step should be skipped\r\n if (stepState.def.isSkippable && shouldSkipStep(stepId, options, isInteractive)) {\r\n stepState.status = 'skipped';\r\n verboseLog(options.verbose, `Skipping step: ${stepState.def.name}`);\r\n continue;\r\n }\r\n\r\n // Mark step as running\r\n stepState.status = 'running';\r\n stepState.startedAt = Date.now();\r\n workflow.currentStepId = stepId;\r\n verboseLog(options.verbose, `Starting step: ${stepState.def.name}`);\r\n\r\n try {\r\n const output = await executeStep(stepId, options, ctx, theme, errorHandler);\r\n stepState.status = 'completed';\r\n stepState.output = output;\r\n stepState.completedAt = Date.now();\r\n\r\n // Update theme after platform detection\r\n if (stepId === 'detect-platform' && ctx.terminalCapabilities) {\r\n theme = ThemeEngine.initialize(ctx.terminalCapabilities, {\r\n forceNoColor: options.noColor,\r\n forceColor: false,\r\n });\r\n }\r\n\r\n verboseLog(\r\n options.verbose,\r\n `Completed step: ${stepState.def.name} (${stepState.completedAt - (stepState.startedAt ?? 0)}ms)`,\r\n );\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n\r\n // Handle user cancellation\r\n if (err instanceof UserCancellationError) {\r\n workflow.status = 'cancelled';\r\n workflow.cancellationReason = err.message;\r\n break;\r\n }\r\n\r\n // Classify error and determine recovery\r\n const recovery = errorHandler.handleError(err, stepId);\r\n stepState.status = 'failed';\r\n stepState.error = err;\r\n stepState.completedAt = Date.now();\r\n\r\n verboseLog(options.verbose, `Step failed: ${stepState.def.name} - ${err.message}`);\r\n verboseLog(options.verbose, `Recovery strategy: ${recovery.strategy}`);\r\n\r\n // Execute recovery strategy\r\n if (recovery.strategy === 'PromptUser' && isInteractive && theme) {\r\n // Show error and ask to retry\r\n const errorContent: ErrorPanelContent = {\r\n title: 'Installation Error',\r\n message: recovery.userGuidance,\r\n cause: err.message,\r\n suggestedActions: recovery.platformGuidance\r\n ? [{ step: 1, instruction: recovery.platformGuidance, command: null }]\r\n : [],\r\n retryAvailable: true,\r\n errorCode: null,\r\n };\r\n const lines = renderError(errorContent, theme);\r\n for (const line of lines) {\r\n console.log(line);\r\n }\r\n\r\n const shouldRetry = await promptRetry();\r\n if (shouldRetry && errorHandler.canRetry(stepId)) {\r\n errorHandler.recordRetry(stepId);\r\n // Reset step state for retry\r\n stepState.status = 'running';\r\n stepState.error = null;\r\n stepState.startedAt = Date.now();\r\n stepState.completedAt = null;\r\n\r\n try {\r\n const output = await executeStep(stepId, options, ctx, theme, errorHandler);\r\n stepState.status = 'completed';\r\n stepState.output = output;\r\n stepState.completedAt = Date.now();\r\n continue;\r\n } catch (retryError) {\r\n const retryErr = retryError instanceof Error ? retryError : new Error(String(retryError));\r\n stepState.status = 'failed';\r\n stepState.error = retryErr;\r\n stepState.completedAt = Date.now();\r\n errorHandler.handleError(retryErr, stepId);\r\n }\r\n }\r\n // Fall through to abort\r\n workflow.status = 'failed';\r\n break;\r\n }\r\n\r\n if (recovery.strategy === 'RollbackAndAbort' || recovery.strategy === 'AbortImmediately') {\r\n // Attempt rollback if we have a backup\r\n await attemptRollback(ctx, options);\r\n\r\n // Show error if we have a theme\r\n if (theme) {\r\n const errorContent: ErrorPanelContent = {\r\n title: 'Installation Failed',\r\n message: recovery.userGuidance,\r\n cause: err.message,\r\n suggestedActions: recovery.platformGuidance\r\n ? [{ step: 1, instruction: recovery.platformGuidance, command: null }]\r\n : [],\r\n retryAvailable: false,\r\n errorCode: null,\r\n };\r\n const lines = renderError(errorContent, theme);\r\n for (const line of lines) {\r\n console.log(line);\r\n }\r\n } else {\r\n console.error(`\\nError: ${err.message}`);\r\n console.error(recovery.userGuidance);\r\n }\r\n\r\n workflow.status = 'failed';\r\n break;\r\n }\r\n\r\n // SkipAndContinue\r\n if (recovery.strategy === 'SkipAndContinue' && stepState.def.isSkippable) {\r\n stepState.status = 'skipped';\r\n continue;\r\n }\r\n\r\n // Default: fail workflow\r\n workflow.status = 'failed';\r\n break;\r\n }\r\n }\r\n\r\n // Finalize workflow\r\n if (workflow.status === 'running') {\r\n workflow.status = 'completed';\r\n }\r\n workflow.completedAt = Date.now();\r\n\r\n // Handle cancellation cleanup\r\n if (workflow.status === 'cancelled') {\r\n await attemptRollback(ctx, options);\r\n if (theme) {\r\n promptOutro('Installation cancelled. All changes have been rolled back.');\r\n } else {\r\n console.log('\\nInstallation cancelled. All changes have been rolled back.');\r\n }\r\n }\r\n } finally {\r\n // Remove SIGINT handler\r\n process.removeListener('SIGINT', sigintHandler);\r\n }\r\n\r\n return errorHandler.getExitCode(workflow);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Dry Run Execution\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Execute a dry run of the installation workflow.\r\n *\r\n * Runs the full pipeline without writing any files. Reports what\r\n * would happen if the installation were executed for real.\r\n *\r\n * @param options - Parsed CLI options\r\n * @returns Process exit code\r\n */\r\nexport async function executeDryRun(options: CLIOptions): Promise<ExitCode> {\r\n let sourceDirectory: string;\r\n\r\n try {\r\n sourceDirectory = await resolveSourceDirectory();\r\n } catch (error) {\r\n console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);\r\n return EXIT_CANCELLED;\r\n }\r\n\r\n const ctx = createInitialContext(sourceDirectory);\r\n const details: DryRunStepDetail[] = [];\r\n\r\n console.log('\\n[dry-run] Simulating installation workflow...\\n');\r\n\r\n // Step 1: Detect platform\r\n try {\r\n const facade = new PlatformFacade();\r\n ctx.platformEnv = await facade.detectAll();\r\n ctx.terminalCapabilities = buildTerminalCapabilities(ctx.platformEnv);\r\n details.push({\r\n stepId: 'detect-platform',\r\n stepName: 'Detect Platform',\r\n result: `${ctx.platformEnv.platform.os.family} ${ctx.platformEnv.platform.os.architecture.name}`,\r\n warnings: [],\r\n });\r\n } catch (error) {\r\n console.error(`Platform detection failed: ${error instanceof Error ? error.message : String(error)}`);\r\n return EXIT_CANCELLED;\r\n }\r\n\r\n // Step 2: Check prerequisites\r\n const prereqWarnings: string[] = [];\r\n if (!ctx.platformEnv!.runtime.allRequirementsMet) {\r\n for (const err of ctx.platformEnv!.runtime.errors) {\r\n prereqWarnings.push(err.message);\r\n }\r\n }\r\n details.push({\r\n stepId: 'check-prerequisites',\r\n stepName: 'Check Prerequisites',\r\n result: prereqWarnings.length === 0 ? 'All prerequisites met' : `${prereqWarnings.length} issue(s)`,\r\n warnings: prereqWarnings,\r\n });\r\n\r\n // Resolve target directory\r\n const targetDir = options.target ?? process.cwd();\r\n ctx.targetDirectory = targetDir;\r\n ctx.claudeDirectory = path.join(targetDir, CLAUDE_DIRECTORY_NAME);\r\n\r\n details.push({\r\n stepId: 'select-directory',\r\n stepName: 'Select Target Directory',\r\n result: `Target: ${targetDir}`,\r\n warnings: [],\r\n });\r\n\r\n // Step 5: Scan source\r\n try {\r\n ctx.manifest = await scanSourceDirectory(sourceDirectory);\r\n details.push({\r\n stepId: 'scan-source',\r\n stepName: 'Scan Source Components',\r\n result: `${ctx.manifest.totalCount} components found`,\r\n warnings: [],\r\n });\r\n } catch (error) {\r\n console.error(`Source scan failed: ${error instanceof Error ? error.message : String(error)}`);\r\n return EXIT_CANCELLED;\r\n }\r\n\r\n // Step 6: Detect conflicts\r\n try {\r\n ctx.conflictReport = await detectConflicts(ctx.manifest, sourceDirectory, ctx.claudeDirectory!);\r\n const conflictWarnings: string[] = [];\r\n if (ctx.conflictReport.hasConflicts) {\r\n conflictWarnings.push(`${ctx.conflictReport.modifiedCount} file(s) differ from source`);\r\n }\r\n details.push({\r\n stepId: 'detect-conflicts',\r\n stepName: 'Detect Conflicts',\r\n result: ctx.conflictReport.hasConflicts\r\n ? `${ctx.conflictReport.modifiedCount} conflict(s) detected`\r\n : 'No conflicts',\r\n warnings: conflictWarnings,\r\n });\r\n } catch (error) {\r\n details.push({\r\n stepId: 'detect-conflicts',\r\n stepName: 'Detect Conflicts',\r\n result: `Could not check: ${error instanceof Error ? error.message : 'unknown'}`,\r\n warnings: [],\r\n });\r\n }\r\n\r\n // Build dry-run report\r\n const report: DryRunReport = {\r\n filesToInstall: ctx.manifest.totalCount,\r\n filesToOverwrite: ctx.conflictReport?.modifiedCount ?? 0,\r\n conflictsDetected: ctx.conflictReport?.modifiedCount ?? 0,\r\n wouldSucceed: prereqWarnings.length === 0,\r\n details,\r\n };\r\n\r\n // Print dry-run report\r\n console.log('[dry-run] Installation Preview');\r\n console.log('─'.repeat(50));\r\n console.log(` Files to install: ${report.filesToInstall}`);\r\n console.log(` Files to overwrite: ${report.filesToOverwrite}`);\r\n console.log(` Conflicts detected: ${report.conflictsDetected}`);\r\n console.log(` Would succeed: ${report.wouldSucceed ? 'yes' : 'no'}`);\r\n console.log('');\r\n\r\n for (const detail of report.details) {\r\n console.log(` ${detail.stepName}: ${detail.result}`);\r\n for (const warning of detail.warnings) {\r\n console.log(` ! ${warning}`);\r\n }\r\n }\r\n\r\n console.log('');\r\n console.log('[dry-run] No files were modified.');\r\n\r\n return EXIT_SUCCESS;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Step Executor\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Execute a single workflow step by delegating to the appropriate subsystem.\r\n */\r\nasync function executeStep(\r\n stepId: WorkflowStepId,\r\n options: CLIOptions,\r\n ctx: InstallationContext,\r\n theme: ThemeEngine | null,\r\n errorHandler: ErrorHandler,\r\n): Promise<StepOutput> {\r\n switch (stepId) {\r\n case 'detect-platform':\r\n return executeDetectPlatform(ctx, options);\r\n\r\n case 'check-prerequisites':\r\n return executeCheckPrerequisites(ctx, options);\r\n\r\n case 'show-banner':\r\n return executeShowBanner(ctx, options, theme);\r\n\r\n case 'select-directory':\r\n return executeSelectDirectory(ctx, options, theme);\r\n\r\n case 'scan-source':\r\n return executeScanSource(ctx, options);\r\n\r\n case 'detect-conflicts':\r\n return executeDetectConflicts(ctx, options, theme);\r\n\r\n case 'select-overwrite-mode':\r\n return executeSelectOverwriteMode(ctx, options, theme);\r\n\r\n case 'select-categories':\r\n return executeSelectCategories(ctx, options, theme);\r\n\r\n case 'confirm-installation':\r\n return executeConfirmInstallation(ctx, options, theme);\r\n\r\n case 'execute-installation':\r\n return executeInstallFiles(ctx, options, theme);\r\n\r\n case 'validate-installation':\r\n return executeValidateInstallation(ctx, options);\r\n\r\n case 'show-summary':\r\n return executeShowSummary(ctx, options, theme);\r\n\r\n default: {\r\n const _exhaustive: never = stepId;\r\n throw new Error(`Unknown step: ${_exhaustive}`);\r\n }\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Step Implementations\r\n// ---------------------------------------------------------------------------\r\n\r\nasync function executeDetectPlatform(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n): Promise<StepOutput> {\r\n const facade = new PlatformFacade();\r\n ctx.platformEnv = await facade.detectAll();\r\n ctx.terminalCapabilities = buildTerminalCapabilities(ctx.platformEnv);\r\n ctx.runtimeReport = ctx.platformEnv.runtime;\r\n\r\n const os = ctx.platformEnv.platform.os;\r\n\r\n return {\r\n data: { os: os.family, arch: os.architecture.name, version: os.version },\r\n summary: `Platform: ${os.family} ${os.architecture.name} (${os.version})`,\r\n };\r\n}\r\n\r\nasync function executeCheckPrerequisites(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n): Promise<StepOutput> {\r\n const runtime = ctx.runtimeReport ?? ctx.platformEnv?.runtime;\r\n\r\n if (!runtime) {\r\n throw new Error('Platform detection must complete before prerequisite check.');\r\n }\r\n\r\n if (!runtime.allRequirementsMet) {\r\n const errorMessages = runtime.errors.map(e => e.message);\r\n const fixMessages = runtime.errors.map(e => e.fix);\r\n\r\n throw new Error(\r\n 'Runtime requirements not met:\\n' +\r\n errorMessages.map((msg, i) => ` - ${msg}\\n Fix: ${fixMessages[i]}`).join('\\n'),\r\n );\r\n }\r\n\r\n const nodeVersion = runtime.node.version.raw;\r\n const npmVersion = runtime.npm?.version.raw ?? 'not detected';\r\n\r\n return {\r\n data: { nodeVersion, npmVersion },\r\n summary: `Node.js ${nodeVersion}, npm ${npmVersion}`,\r\n };\r\n}\r\n\r\nasync function executeShowBanner(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n if (!theme) {\r\n // No theme means we're in plain mode\r\n console.log('\\n SixSevenAI - AI-DLC Framework Installer\\n');\r\n return { data: {}, summary: 'Banner displayed (plain)' };\r\n }\r\n\r\n const lines = renderBanner(INSTALLER_VERSION, theme);\r\n for (const line of lines) {\r\n console.log(line);\r\n }\r\n\r\n promptIntro(`SixSevenAI Installer v${INSTALLER_VERSION}`);\r\n\r\n return { data: {}, summary: 'Banner displayed' };\r\n}\r\n\r\nasync function executeSelectDirectory(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n // If --target was provided, use it\r\n if (options.target) {\r\n ctx.targetDirectory = path.resolve(options.target);\r\n ctx.claudeDirectory = path.join(ctx.targetDirectory, CLAUDE_DIRECTORY_NAME);\r\n return {\r\n data: { targetDirectory: ctx.targetDirectory },\r\n summary: `Target: ${ctx.targetDirectory} (from --target)`,\r\n };\r\n }\r\n\r\n // Interactive directory selection\r\n if (!ctx.platformEnv) {\r\n throw new Error('Platform detection must complete before directory selection.');\r\n }\r\n\r\n if (!theme) {\r\n // Non-interactive fallback: use current directory\r\n ctx.targetDirectory = process.cwd();\r\n ctx.claudeDirectory = path.join(ctx.targetDirectory, CLAUDE_DIRECTORY_NAME);\r\n return {\r\n data: { targetDirectory: ctx.targetDirectory },\r\n summary: `Target: ${ctx.targetDirectory} (default)`,\r\n };\r\n }\r\n\r\n const dirOptions = buildDirectoryOptions(ctx.platformEnv);\r\n const selection = await promptDirectorySelection(dirOptions, theme);\r\n\r\n ctx.targetDirectory = path.resolve(selection.path);\r\n ctx.claudeDirectory = path.join(ctx.targetDirectory, CLAUDE_DIRECTORY_NAME);\r\n\r\n return {\r\n data: { targetDirectory: ctx.targetDirectory, isCustom: selection.isCustom },\r\n summary: `Target: ${ctx.targetDirectory}`,\r\n };\r\n}\r\n\r\nasync function executeScanSource(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n): Promise<StepOutput> {\r\n const spinner = new SixSevenSpinner({ quiet: options.quiet });\r\n spinner.start('Scanning source components...');\r\n\r\n ctx.manifest = await scanSourceDirectory(ctx.sourceDirectory);\r\n\r\n spinner.stop(`${ctx.manifest.totalCount} components found`);\r\n\r\n verboseLog(options.verbose, `Scanned ${ctx.manifest.totalCount} components from ${ctx.sourceDirectory}`);\r\n verboseLog(options.verbose, ` Agents: ${ctx.manifest.countsByType.agents}`);\r\n verboseLog(options.verbose, ` Skills: ${ctx.manifest.countsByType.skills}`);\r\n verboseLog(options.verbose, ` Commands: ${ctx.manifest.countsByType.commands}`);\r\n\r\n return {\r\n data: {\r\n totalCount: ctx.manifest.totalCount,\r\n countsByType: ctx.manifest.countsByType,\r\n },\r\n summary: `${ctx.manifest.totalCount} components scanned`,\r\n };\r\n}\r\n\r\nasync function executeDetectConflicts(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n if (!ctx.manifest || !ctx.claudeDirectory) {\r\n throw new Error('Source scan and directory selection must complete before conflict detection.');\r\n }\r\n\r\n // T2.3.1: Fresh install with --custom — skip conflict detection entirely\r\n if (options.custom) {\r\n let claudeDirExists = false;\r\n try {\r\n await stat(ctx.claudeDirectory);\r\n claudeDirExists = true;\r\n } catch {\r\n claudeDirExists = false;\r\n }\r\n if (!claudeDirExists) {\r\n verboseLog(options.verbose, 'Fresh install with --custom, skipping conflict detection');\r\n return {\r\n data: { skipped: true, reason: 'fresh-install-custom' },\r\n summary: 'Conflict detection skipped (fresh install with --custom)',\r\n };\r\n }\r\n }\r\n\r\n const spinner = new SixSevenSpinner({ quiet: options.quiet });\r\n spinner.start('Checking for existing files...');\r\n\r\n ctx.conflictReport = await detectConflicts(\r\n ctx.manifest,\r\n ctx.sourceDirectory,\r\n ctx.claudeDirectory,\r\n );\r\n\r\n spinner.stop(\r\n ctx.conflictReport.hasConflicts\r\n ? `${ctx.conflictReport.modifiedCount} modified, ${ctx.conflictReport.identicalCount} unchanged, ${ctx.conflictReport.newCount} new`\r\n : ctx.conflictReport.identicalCount > 0\r\n ? `${ctx.conflictReport.identicalCount} files up to date, ${ctx.conflictReport.newCount} new`\r\n : `${ctx.conflictReport.newCount} new files to install`,\r\n );\r\n\r\n return {\r\n data: {\r\n hasConflicts: ctx.conflictReport.hasConflicts,\r\n newCount: ctx.conflictReport.newCount,\r\n identicalCount: ctx.conflictReport.identicalCount,\r\n modifiedCount: ctx.conflictReport.modifiedCount,\r\n },\r\n summary: ctx.conflictReport.hasConflicts\r\n ? `${ctx.conflictReport.modifiedCount} conflict(s) found`\r\n : 'No conflicts',\r\n };\r\n}\r\n\r\nasync function executeSelectOverwriteMode(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n if (!ctx.claudeDirectory) {\r\n throw new Error('Directory selection must complete before overwrite mode selection.');\r\n }\r\n\r\n // T2.3.1: Fresh install with --custom — no existing .claude/, skip overwrite mode\r\n let claudeDirExists = false;\r\n try {\r\n await stat(ctx.claudeDirectory);\r\n claudeDirExists = true;\r\n } catch {\r\n claudeDirExists = false;\r\n }\r\n\r\n if (!claudeDirExists && options.custom) {\r\n ctx.overwriteMode = 'all';\r\n return {\r\n data: { mode: 'all', reason: 'fresh-install-custom' },\r\n summary: 'Fresh install with --custom, no overwrite needed',\r\n };\r\n }\r\n\r\n // T2.3.2: Non-interactive --overwrite array provided via CLI\r\n if (options.overwrite.length > 0) {\r\n ctx.selectedCategories = resolveCategories(options.overwrite as string[]);\r\n ctx.overwriteMode = 'choose';\r\n return {\r\n data: { mode: 'choose', categories: ctx.selectedCategories },\r\n summary: `Overwrite mode: choose (${ctx.selectedCategories.length} categories from CLI)`,\r\n };\r\n }\r\n\r\n // T2.3.4: --categories provided via CLI\r\n if (options.categories.length > 0) {\r\n ctx.selectedCategories = resolveCategories(options.categories as string[]);\r\n ctx.overwriteMode = 'choose';\r\n return {\r\n data: { mode: 'choose', categories: ctx.selectedCategories },\r\n summary: `Overwrite mode: choose (${ctx.selectedCategories.length} categories from --categories)`,\r\n };\r\n }\r\n\r\n // T2.3.3: --profile provided — load profile and map to category IDs\r\n if (options.profile) {\r\n const profileCategories = await loadProfileCategories(options.profile);\r\n ctx.selectedCategories = profileCategories;\r\n ctx.overwriteMode = 'choose';\r\n return {\r\n data: { mode: 'choose', profile: options.profile, categories: profileCategories },\r\n summary: `Overwrite mode: choose (profile \"${options.profile}\", ${profileCategories.length} categories)`,\r\n };\r\n }\r\n\r\n // No conflict report yet means detect-conflicts was skipped (e.g. fresh install)\r\n if (!ctx.conflictReport) {\r\n ctx.overwriteMode = 'all';\r\n return {\r\n data: { mode: 'all', reason: 'no-conflicts-detected' },\r\n summary: 'No conflicts detected, installing all',\r\n };\r\n }\r\n\r\n // All existing files identical — prompt to continue\r\n if (ctx.conflictReport.identicalCount > 0 && !ctx.conflictReport.hasConflicts) {\r\n if (theme) {\r\n const totalExisting = ctx.conflictReport.identicalCount;\r\n const newCount = ctx.conflictReport.newCount;\r\n const continueInstall = await promptConfirmation(\r\n `All ${totalExisting} existing files are up to date. No changes detected.${newCount > 0 ? ` ${newCount} new file(s) to install.` : ''} Continue?`,\r\n newCount > 0,\r\n );\r\n if (!continueInstall) {\r\n throw new UserCancellationError('User declined to continue — no changes needed.');\r\n }\r\n }\r\n ctx.overwriteMode = 'all';\r\n return {\r\n data: { mode: 'all', reason: 'all-identical' },\r\n summary: 'All existing files up to date',\r\n };\r\n }\r\n\r\n // Modified files detected — prompt for overwrite strategy\r\n if (ctx.conflictReport.hasConflicts && theme) {\r\n const mode: OverwriteMode = await promptOverwriteMode(ctx.claudeDirectory);\r\n ctx.overwriteMode = mode;\r\n\r\n // Create backup when mode is 'all' or 'choose'\r\n if (mode === 'all' || mode === 'choose') {\r\n try {\r\n ctx.backupManifest = await createBackup(\r\n ctx.claudeDirectory,\r\n ctx.conflictReport.modifiedFiles,\r\n );\r\n if (ctx.backupManifest) {\r\n verboseLog(\r\n options.verbose,\r\n `Backed up ${ctx.backupManifest.files.length} files to ${ctx.backupManifest.backupDirectory}`,\r\n );\r\n }\r\n } catch (backupError) {\r\n verboseLog(options.verbose, `Backup warning: ${backupError instanceof Error ? backupError.message : String(backupError)}`);\r\n }\r\n }\r\n\r\n return {\r\n data: { mode },\r\n summary: `Overwrite mode: ${mode}`,\r\n };\r\n }\r\n\r\n // Default: overwrite all (non-interactive or no conflicts)\r\n ctx.overwriteMode = 'all';\r\n return {\r\n data: { mode: 'all', reason: 'default' },\r\n summary: 'Overwrite mode: all (default)',\r\n };\r\n}\r\n\r\nasync function executeSelectCategories(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n // T2.3.2: Non-interactive --overwrite already resolved categories in select-overwrite-mode\r\n if (options.overwrite.length > 0 && ctx.selectedCategories.length > 0) {\r\n // Categories already set, apply filtering\r\n ctx.fileMappings = applySelectedCategoryFilter(ctx);\r\n return {\r\n data: { categories: ctx.selectedCategories, source: 'cli-overwrite' },\r\n summary: `${ctx.selectedCategories.length} categories selected via --overwrite`,\r\n };\r\n }\r\n\r\n // T2.3.3: --profile already resolved categories in select-overwrite-mode\r\n if (options.profile && ctx.selectedCategories.length > 0) {\r\n ctx.fileMappings = applySelectedCategoryFilter(ctx);\r\n return {\r\n data: { categories: ctx.selectedCategories, source: 'profile' },\r\n summary: `${ctx.selectedCategories.length} categories selected via --profile \"${options.profile}\"`,\r\n };\r\n }\r\n\r\n // T2.3.4: --categories already resolved in select-overwrite-mode\r\n if (options.categories.length > 0 && ctx.selectedCategories.length > 0) {\r\n ctx.fileMappings = applySelectedCategoryFilter(ctx);\r\n return {\r\n data: { categories: ctx.selectedCategories, source: 'cli-categories' },\r\n summary: `${ctx.selectedCategories.length} categories selected via --categories`,\r\n };\r\n }\r\n\r\n // If overwrite mode is not 'choose', no category selection needed\r\n if (ctx.overwriteMode !== 'choose') {\r\n return {\r\n data: { skipped: true, reason: `overwrite-mode-${ctx.overwriteMode ?? 'null'}` },\r\n summary: `Category selection skipped (mode: ${ctx.overwriteMode ?? 'all'})`,\r\n };\r\n }\r\n\r\n // Interactive category selection\r\n if (!theme) {\r\n return {\r\n data: { skipped: true, reason: 'non-interactive' },\r\n summary: 'Category selection skipped (non-interactive)',\r\n };\r\n }\r\n\r\n // Determine which categories have modified files\r\n const modifiedSet = new Set(\r\n (ctx.conflictReport?.modifiedFiles ?? []).map((p) => p.replace(/\\\\/g, '/')),\r\n );\r\n\r\n const modifiedCategoryIds: string[] = INSTALL_CATEGORIES\r\n .filter((cat) =>\r\n [...modifiedSet].some((fp) => fp.startsWith(cat.pathPrefix)),\r\n )\r\n .map((cat) => cat.id);\r\n\r\n const categoryOptions = INSTALL_CATEGORIES.map((cat) => ({\r\n value: cat.id,\r\n label: cat.label,\r\n hint: cat.hint,\r\n }));\r\n\r\n ctx.selectedCategories = await promptCategorySelection(\r\n categoryOptions,\r\n modifiedCategoryIds,\r\n );\r\n\r\n // T2.2.3 / T2.4.1: Apply category filter to build filtered mappings\r\n ctx.fileMappings = applySelectedCategoryFilter(ctx);\r\n\r\n return {\r\n data: { categories: ctx.selectedCategories, count: ctx.fileMappings.length },\r\n summary: `${ctx.selectedCategories.length} categories selected, ${ctx.fileMappings.length} files to install`,\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helper: Apply Category Filter to File Mappings\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Build and filter file mappings based on selected categories.\r\n * Stores the filtered result in ctx.fileMappings.\r\n */\r\nfunction applySelectedCategoryFilter(ctx: InstallationContext): FileMapping[] {\r\n if (!ctx.manifest || !ctx.claudeDirectory) {\r\n return [];\r\n }\r\n\r\n const allMappings = buildFileMappings(ctx.manifest, ctx.sourceDirectory, ctx.claudeDirectory);\r\n return filterMappingsByCategories(allMappings, ctx.selectedCategories);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helper: Load Profile Categories\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Load a profile from tools/installer/profiles.json and map its component\r\n * lists to install category IDs.\r\n */\r\nasync function loadProfileCategories(profileName: string): Promise<string[]> {\r\n // Try multiple locations for profiles.json\r\n const candidatePaths = [\r\n path.resolve(process.cwd(), 'tools', 'installer', 'profiles.json'),\r\n path.resolve(process.cwd(), 'profiles.json'),\r\n ];\r\n\r\n let profileData: Record<string, unknown> | null = null;\r\n for (const candidate of candidatePaths) {\r\n try {\r\n const raw = await readFile(candidate, 'utf-8');\r\n profileData = JSON.parse(raw) as Record<string, unknown>;\r\n break;\r\n } catch {\r\n continue;\r\n }\r\n }\r\n\r\n if (!profileData) {\r\n throw new Error(\r\n `Could not locate profiles.json. Searched: ${candidatePaths.join(', ')}`,\r\n );\r\n }\r\n\r\n const profiles = profileData['profiles'] as Record<string, Record<string, unknown>> | undefined;\r\n if (!profiles || !profiles[profileName]) {\r\n const available = profiles ? Object.keys(profiles).join(', ') : 'none';\r\n throw new Error(\r\n `Unknown profile \"${profileName}\". Available profiles: ${available}`,\r\n );\r\n }\r\n\r\n const profile = profiles[profileName];\r\n const categoryIds: string[] = [];\r\n\r\n // Map profile component keys to install category IDs\r\n // A wildcard \"*\" means include the category\r\n // An array means the category has specific items (still include it)\r\n const keyToCategoryMap: Record<string, string> = {\r\n agents: 'agents',\r\n skills: 'skills',\r\n templates: 'templates',\r\n docs: 'docs',\r\n };\r\n\r\n for (const [key, catId] of Object.entries(keyToCategoryMap)) {\r\n const value = profile[key];\r\n if (value === '*' || (Array.isArray(value) && value.length > 0)) {\r\n categoryIds.push(catId);\r\n }\r\n }\r\n\r\n // Commands are split into sub-categories in INSTALL_CATEGORIES\r\n const commands = profile['commands'];\r\n if (commands === '*') {\r\n // Include all command categories\r\n for (const cat of INSTALL_CATEGORIES) {\r\n if (cat.id.startsWith('commands/') && !categoryIds.includes(cat.id)) {\r\n categoryIds.push(cat.id);\r\n }\r\n }\r\n } else if (Array.isArray(commands) && commands.length > 0) {\r\n // Include all command categories (profile lists command names, not sub-paths)\r\n for (const cat of INSTALL_CATEGORIES) {\r\n if (cat.id.startsWith('commands/') && !categoryIds.includes(cat.id)) {\r\n categoryIds.push(cat.id);\r\n }\r\n }\r\n }\r\n\r\n // Include ai-dlc core and memory if referenced\r\n if (profile['metadata'] === '*' || profile['workflows'] === '*') {\r\n if (!categoryIds.includes('ai-dlc')) {\r\n categoryIds.push('ai-dlc');\r\n }\r\n }\r\n\r\n if (profile['rules'] === '*') {\r\n // Rules don't have a separate category in INSTALL_CATEGORIES but\r\n // we include scripts as a proxy for rule-related files\r\n if (!categoryIds.includes('scripts')) {\r\n categoryIds.push('scripts');\r\n }\r\n }\r\n\r\n return categoryIds;\r\n}\r\n\r\nasync function executeConfirmInstallation(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n if (!ctx.manifest) {\r\n throw new Error('Source scan must complete before confirmation.');\r\n }\r\n\r\n const target = ctx.claudeDirectory ?? ctx.targetDirectory ?? 'unknown';\r\n\r\n // Show accurate count: use pre-filtered mappings when available\r\n let fileCount: number;\r\n if (ctx.fileMappings.length > 0 && (ctx.overwriteMode === 'choose' || ctx.selectedCategories.length > 0)) {\r\n // Mappings were already filtered in select-categories step\r\n fileCount = ctx.fileMappings.length;\r\n } else if (ctx.overwriteMode === 'choose' && ctx.selectedCategories.length > 0) {\r\n const previewMappings = buildFileMappings(ctx.manifest, ctx.sourceDirectory, ctx.claudeDirectory ?? target);\r\n fileCount = filterMappingsByCategories(previewMappings, ctx.selectedCategories).length;\r\n } else if (ctx.overwriteMode === 'none' && ctx.conflictReport) {\r\n fileCount = ctx.manifest.totalCount - ctx.conflictReport.existingFiles.length;\r\n } else {\r\n fileCount = ctx.manifest.totalCount;\r\n }\r\n\r\n const confirmed = await promptConfirmation(\r\n `Install ${fileCount} files to ${target}?`,\r\n true,\r\n );\r\n\r\n if (!confirmed) {\r\n throw new UserCancellationError('User declined installation.');\r\n }\r\n\r\n return {\r\n data: { confirmed: true },\r\n summary: 'Installation confirmed',\r\n };\r\n}\r\n\r\nasync function executeInstallFiles(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n if (!ctx.manifest || !ctx.claudeDirectory) {\r\n throw new Error('Source scan and directory selection must complete before installation.');\r\n }\r\n\r\n // T2.4.2: Use pre-filtered mappings from select-categories when available\r\n if (ctx.fileMappings.length > 0 && (ctx.overwriteMode === 'choose' || (options.custom && ctx.selectedCategories.length > 0))) {\r\n // Mappings were already filtered in executeSelectCategories — use as-is\r\n verboseLog(options.verbose, `Using ${ctx.fileMappings.length} pre-filtered file mappings`);\r\n } else {\r\n // Build file mappings from full manifest\r\n ctx.fileMappings = buildFileMappings(ctx.manifest, ctx.sourceDirectory, ctx.claudeDirectory);\r\n\r\n // Apply overwrite-mode filtering before copying\r\n if (ctx.overwriteMode === 'none' && ctx.conflictReport) {\r\n // Keep only new files — filter out everything that already exists at target\r\n const existingSet = new Set(\r\n ctx.conflictReport.existingFiles.map((p) => p.replace(/\\\\/g, '/')),\r\n );\r\n ctx.fileMappings = ctx.fileMappings.filter(\r\n (m) => !existingSet.has(m.relativePath.replace(/\\\\/g, '/')),\r\n );\r\n } else if (ctx.overwriteMode === 'choose' && ctx.selectedCategories.length > 0) {\r\n // Only install files matching the selected categories\r\n ctx.fileMappings = filterMappingsByCategories(\r\n ctx.fileMappings,\r\n ctx.selectedCategories,\r\n );\r\n }\r\n // 'all' or null: no filtering needed — keep all mappings\r\n }\r\n\r\n if (options.dryRun) {\r\n return {\r\n data: { dryRun: true, fileCount: ctx.fileMappings.length },\r\n summary: `[dry-run] Would install ${ctx.fileMappings.length} files`,\r\n };\r\n }\r\n\r\n // Create spinner for animated progress feedback\r\n const spinner = new SixSevenSpinner({ quiet: options.quiet });\r\n\r\n // Create progress tracker if theme available\r\n let progressTracker: ProgressTracker | null = null;\r\n if (theme && !options.quiet) {\r\n progressTracker = new ProgressTracker();\r\n progressTracker.addStep({ id: 'copy-files', label: `Installing ${ctx.fileMappings.length} files` });\r\n progressTracker.start();\r\n progressTracker.startStep('copy-files');\r\n }\r\n\r\n // Execute file copy\r\n spinner.start('Installing AI-DLC framework...');\r\n\r\n const result = await copyFiles(ctx.fileMappings, {\r\n concurrency: 16,\r\n onProgress: (event) => {\r\n spinner.updateProgress(event.current, event.total, event.fileName);\r\n verboseLog(\r\n options.verbose,\r\n ` [${event.current}/${event.total}] ${event.fileName}`,\r\n );\r\n },\r\n });\r\n\r\n spinner.stop('Framework files installed');\r\n\r\n // Track merged totals (since InstallationResult is readonly)\r\n let totalCopied = result.copiedCount;\r\n let totalSkipped = result.skippedCount;\r\n const allErrors = [...result.errors];\r\n let overallSuccess = result.success;\r\n\r\n // Also install .ai-dlc framework files\r\n // Skip ai-dlc config files when overwrite mode is 'none' or 'choose' —\r\n // these are infrastructure config files that don't belong to any user-selectable category.\r\n // Only copy them on fresh install (null) or when overwriting everything ('all').\r\n const shouldCopyAiDlcFiles = ctx.overwriteMode === null || ctx.overwriteMode === 'all';\r\n const aiDlcSourceDir = shouldCopyAiDlcFiles ? await resolveAiDlcSourceDirectory() : null;\r\n if (aiDlcSourceDir) {\r\n const targetRoot = path.dirname(ctx.claudeDirectory!);\r\n const aiDlcTargetDir = path.join(targetRoot, '.ai-dlc');\r\n\r\n const aiDlcManifest = await scanSourceDirectory(aiDlcSourceDir);\r\n const aiDlcMappings: FileMapping[] = aiDlcManifest.entries.map(entry => ({\r\n relativePath: entry.relativePath,\r\n sourcePath: path.join(aiDlcSourceDir, entry.relativePath),\r\n destinationPath: path.join(aiDlcTargetDir, entry.relativePath),\r\n componentType: entry.componentType,\r\n fileName: entry.fileName,\r\n sizeBytes: entry.sizeBytes,\r\n }));\r\n\r\n spinner.start('Installing .ai-dlc configuration...');\r\n\r\n const aiDlcResult = await copyFiles(aiDlcMappings, {\r\n concurrency: 16,\r\n onProgress: (event) => {\r\n spinner.updateProgress(event.current, event.total, event.fileName);\r\n verboseLog(options.verbose, ` [ai-dlc ${event.current}/${event.total}] ${event.fileName}`);\r\n },\r\n });\r\n\r\n spinner.stop('Configuration files installed');\r\n\r\n // Merge results\r\n totalCopied += aiDlcResult.copiedCount;\r\n totalSkipped += aiDlcResult.skippedCount;\r\n allErrors.push(...aiDlcResult.errors);\r\n if (!aiDlcResult.success) {\r\n overallSuccess = false;\r\n }\r\n\r\n // Add to file mappings for validation\r\n ctx.fileMappings.push(...aiDlcMappings);\r\n }\r\n\r\n // Build merged result for context\r\n ctx.installationResult = {\r\n success: overallSuccess,\r\n copiedCount: totalCopied,\r\n skippedCount: totalSkipped,\r\n warnings: result.warnings,\r\n errors: allErrors,\r\n durationMs: result.durationMs,\r\n componentCounts: result.componentCounts,\r\n };\r\n\r\n // Generate ai-dlc-installation.json metadata\r\n if (overallSuccess) {\r\n try {\r\n const targetRoot = path.dirname(ctx.claudeDirectory!);\r\n const aiDlcDir = path.join(targetRoot, '.ai-dlc');\r\n await mkdir(aiDlcDir, { recursive: true });\r\n\r\n // Extract component lists from file mappings\r\n const agentNames = ctx.fileMappings\r\n .filter(m => m.relativePath.match(/^agents[/\\\\][^/\\\\]+\\.md$/))\r\n .map(m => path.basename(m.fileName, '.md'))\r\n .sort();\r\n\r\n const skillNames = [...new Set(\r\n ctx.fileMappings\r\n .filter(m => m.relativePath.match(/^skills[/\\\\]/))\r\n .map(m => m.relativePath.replace(/\\\\/g, '/').split('/')[1])\r\n )].sort();\r\n\r\n const commandNames = ctx.fileMappings\r\n .filter(m => m.relativePath.match(/^commands[/\\\\].*\\.md$/))\r\n .map(m => {\r\n const parts = m.relativePath.replace(/\\\\/g, '/').split('/');\r\n if (parts.length === 3) {\r\n return `${parts[1]}:${path.basename(parts[2], '.md')}`;\r\n }\r\n return path.basename(m.fileName, '.md');\r\n })\r\n .sort();\r\n\r\n const totalSizeBytes = ctx.fileMappings.reduce((sum, m) => sum + m.sizeBytes, 0);\r\n\r\n const installationMetadata = {\r\n installation: {\r\n version: INSTALLER_VERSION,\r\n installedBy: 'sixsevenai-installer',\r\n sourceRoot: 'npm:@sixsevenai/ai-dlc-installer',\r\n profile: 'npm-global',\r\n backupLocation: '',\r\n projectRoot: ctx.targetDirectory ?? targetRoot,\r\n installedDate: new Date().toISOString(),\r\n },\r\n components: {\r\n commands: { count: commandNames.length, installed: commandNames },\r\n agents: { count: agentNames.length, installed: agentNames },\r\n skills: { count: skillNames.length, installed: skillNames },\r\n },\r\n statistics: {\r\n filesSkipped: totalSkipped,\r\n totalSizeBytes,\r\n totalSizeMB: Math.round(totalSizeBytes / (1024 * 1024) * 100) / 100,\r\n filesProcessed: totalCopied,\r\n },\r\n };\r\n\r\n const metadataPath = path.join(aiDlcDir, 'ai-dlc-installation.json');\r\n await writeFile(metadataPath, JSON.stringify(installationMetadata, null, 2), 'utf-8');\r\n verboseLog(options.verbose, `Installation metadata written to ${metadataPath}`);\r\n } catch (metadataError) {\r\n // Non-fatal: log warning but don't fail the installation\r\n verboseLog(\r\n options.verbose,\r\n `Warning: Could not write installation metadata: ${metadataError instanceof Error ? metadataError.message : String(metadataError)}`,\r\n );\r\n }\r\n }\r\n\r\n // Complete progress\r\n if (progressTracker) {\r\n if (overallSuccess) {\r\n progressTracker.completeStep('copy-files');\r\n } else {\r\n progressTracker.failStep('copy-files', { message: 'File copy failed', cause: null });\r\n }\r\n progressTracker.finish();\r\n }\r\n\r\n if (!overallSuccess) {\r\n const errorMessages = allErrors.map(e => e.message).join('; ');\r\n throw new Error(`File installation failed: ${errorMessages}`);\r\n }\r\n\r\n return {\r\n data: {\r\n copiedCount: totalCopied,\r\n skippedCount: totalSkipped,\r\n errorCount: allErrors.length,\r\n },\r\n summary: `${totalCopied} files installed, ${totalSkipped} skipped`,\r\n };\r\n}\r\n\r\nasync function executeValidateInstallation(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n): Promise<StepOutput> {\r\n if (!ctx.fileMappings || ctx.fileMappings.length === 0) {\r\n // Skip validation if dry-run or no files were copied\r\n return {\r\n data: { valid: true, skipped: true },\r\n summary: 'Validation skipped (no files to validate)',\r\n };\r\n }\r\n\r\n ctx.validationReport = await validateInstallation(ctx.fileMappings);\r\n\r\n if (!ctx.validationReport.valid) {\r\n const missing = ctx.validationReport.missingFiles;\r\n const invalid = ctx.validationReport.invalidFiles;\r\n throw new Error(\r\n `Installation validation failed: ` +\r\n `${missing.length} missing file(s), ` +\r\n `${invalid.length} invalid file(s)`,\r\n );\r\n }\r\n\r\n return {\r\n data: {\r\n valid: true,\r\n totalChecked: ctx.validationReport.totalChecked,\r\n validCount: ctx.validationReport.validCount,\r\n },\r\n summary: `${ctx.validationReport.validCount} files validated`,\r\n };\r\n}\r\n\r\nasync function executeShowSummary(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n theme: ThemeEngine | null,\r\n): Promise<StepOutput> {\r\n // Build summary using actual workflow results\r\n // We use a simplified state here since we don't track full WorkflowState in scope\r\n const elapsed = Date.now() - (ctx.installationResult ? Date.now() : Date.now());\r\n\r\n const summary: InstallationSummary = {\r\n success: ctx.installationResult?.success ?? true,\r\n targetDirectory: ctx.targetDirectory ?? 'unknown',\r\n componentCounts: {\r\n agents: ctx.manifest?.countsByType.agents ?? 0,\r\n skills: ctx.manifest?.countsByType.skills ?? 0,\r\n commands: ctx.manifest?.countsByType.commands ?? 0,\r\n cliFiles: ctx.manifest?.countsByType.cli ?? 0,\r\n other: (ctx.manifest?.countsByType.workflows ?? 0) + (ctx.manifest?.countsByType.metadata ?? 0),\r\n },\r\n totalDuration: formatDuration(0), // Will be updated by caller\r\n totalFilesCopied: ctx.installationResult?.copiedCount ?? 0,\r\n totalFilesSkipped: ctx.installationResult?.skippedCount ?? 0,\r\n totalFilesFailed: ctx.installationResult?.errors.length ?? 0,\r\n installerVersion: INSTALLER_VERSION,\r\n };\r\n\r\n const nextSteps = getDefaultNextSteps(summary.success);\r\n\r\n if (theme && !options.quiet) {\r\n const lines = renderSummary(summary, nextSteps, theme);\r\n for (const line of lines) {\r\n console.log(line);\r\n }\r\n\r\n if (summary.success) {\r\n promptOutro('Installation complete!');\r\n }\r\n } else if (!options.quiet) {\r\n // Plain text summary\r\n console.log('\\n--- Installation Summary ---');\r\n console.log(` Status: ${summary.success ? 'Success' : 'Failed'}`);\r\n console.log(` Files installed: ${summary.totalFilesCopied}`);\r\n console.log(` Files skipped: ${summary.totalFilesSkipped}`);\r\n console.log(` Target: ${summary.targetDirectory}`);\r\n if (summary.success) {\r\n console.log('\\n Next steps:');\r\n for (const step of nextSteps) {\r\n console.log(` ${step.order}. ${step.title}`);\r\n if (step.command) {\r\n console.log(` $ ${step.command}`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return {\r\n data: { success: summary.success },\r\n summary: summary.success ? 'Installation successful' : 'Installation completed with errors',\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Rollback Helper\r\n// ---------------------------------------------------------------------------\r\n\r\nasync function attemptRollback(\r\n ctx: InstallationContext,\r\n options: CLIOptions,\r\n): Promise<void> {\r\n if (!ctx.backupManifest || !ctx.claudeDirectory) {\r\n verboseLog(options.verbose, 'No backup available for rollback.');\r\n return;\r\n }\r\n\r\n try {\r\n verboseLog(options.verbose, 'Rolling back installation...');\r\n const rollbackResult = await restoreFromBackup(ctx.backupManifest, ctx.claudeDirectory);\r\n if (rollbackResult.success) {\r\n verboseLog(options.verbose, `Rollback complete: ${rollbackResult.restoredCount} files restored.`);\r\n } else {\r\n const errorMessages = rollbackResult.errors.map(e => e.message).join('; ');\r\n console.error(`Rollback encountered errors: ${errorMessages}`);\r\n }\r\n } catch (error) {\r\n console.error(\r\n `Rollback failed: ${error instanceof Error ? error.message : String(error)}`,\r\n );\r\n }\r\n}\r\n","/**\r\n * CLI Orchestrator - Shared Types\r\n *\r\n * Workflow state, installation context, error classification, and\r\n * configuration types used by the orchestration layer.\r\n *\r\n * @module orchestrator/types\r\n */\r\n\r\nimport type {\r\n ComponentManifest,\r\n ConflictReport,\r\n BackupManifest,\r\n InstallationResult,\r\n ValidationReport,\r\n FileMapping,\r\n} from '../engine/index.js';\r\n\r\nimport type {\r\n PlatformEnvironment,\r\n RuntimeReport,\r\n} from '../platform/index.js';\r\n\r\nimport type {\r\n TerminalCapabilities,\r\n InstallationSummary,\r\n Duration,\r\n} from '../ui/index.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Overwrite Mode\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Controls how existing files are handled during installation. */\r\nexport type OverwriteMode = 'all' | 'none' | 'choose';\r\n\r\n// ---------------------------------------------------------------------------\r\n// CLI Options\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Parsed and validated CLI options. */\r\nexport interface CLIOptions {\r\n readonly command: CLICommand;\r\n readonly target: string | null;\r\n readonly force: boolean;\r\n readonly dryRun: boolean;\r\n readonly verbose: boolean;\r\n readonly noColor: boolean;\r\n readonly quiet: boolean;\r\n readonly overwrite: readonly string[];\r\n readonly custom: boolean;\r\n readonly profile: string | null;\r\n readonly categories: readonly string[];\r\n readonly rawArgs: readonly string[];\r\n}\r\n\r\n/** Top-level CLI command type. */\r\nexport type CLICommand = 'install' | 'help' | 'version';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Exit Codes\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Process exit codes with defined semantics. */\r\nexport type ExitCode = 0 | 1 | 2;\r\n\r\nexport const EXIT_SUCCESS: ExitCode = 0;\r\nexport const EXIT_ERROR: ExitCode = 1;\r\nexport const EXIT_CANCELLED: ExitCode = 2;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Workflow Status\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Lifecycle status of the installation workflow. */\r\nexport type WorkflowStatus =\r\n | 'pending'\r\n | 'running'\r\n | 'completed'\r\n | 'failed'\r\n | 'cancelled';\r\n\r\n/** Lifecycle status of a single workflow step. */\r\nexport type StepStatus =\r\n | 'pending'\r\n | 'running'\r\n | 'completed'\r\n | 'failed'\r\n | 'skipped';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Workflow Step Definitions\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Identifier for a workflow step. */\r\nexport type WorkflowStepId =\r\n | 'detect-platform'\r\n | 'check-prerequisites'\r\n | 'show-banner'\r\n | 'select-directory'\r\n | 'scan-source'\r\n | 'detect-conflicts'\r\n | 'select-overwrite-mode'\r\n | 'select-categories'\r\n | 'confirm-installation'\r\n | 'execute-installation'\r\n | 'validate-installation'\r\n | 'show-summary';\r\n\r\n/** Definition of a single workflow step. */\r\nexport interface WorkflowStepDef {\r\n readonly id: WorkflowStepId;\r\n readonly name: string;\r\n readonly order: number;\r\n readonly isSkippable: boolean;\r\n}\r\n\r\n/** Runtime state of a single workflow step. */\r\nexport interface WorkflowStepState {\r\n readonly def: WorkflowStepDef;\r\n status: StepStatus;\r\n output: StepOutput | null;\r\n error: Error | null;\r\n startedAt: number | null;\r\n completedAt: number | null;\r\n}\r\n\r\n/** Output produced by a completed step. */\r\nexport interface StepOutput {\r\n readonly data: Record<string, unknown>;\r\n readonly summary: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Workflow State\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Complete state of the installation workflow. */\r\nexport interface WorkflowState {\r\n status: WorkflowStatus;\r\n readonly steps: WorkflowStepState[];\r\n currentStepId: WorkflowStepId | null;\r\n startedAt: number | null;\r\n completedAt: number | null;\r\n cancellationReason: string | null;\r\n}\r\n\r\n/** Progress metrics for the workflow. */\r\nexport interface WorkflowProgress {\r\n readonly completedSteps: number;\r\n readonly totalSteps: number;\r\n readonly percentage: number;\r\n readonly currentStepName: string;\r\n readonly elapsedTime: Duration;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Installation Context (accumulated during workflow)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Runtime context assembled during workflow execution. */\r\nexport interface InstallationContext {\r\n platformEnv: PlatformEnvironment | null;\r\n terminalCapabilities: TerminalCapabilities | null;\r\n runtimeReport: RuntimeReport | null;\r\n targetDirectory: string | null;\r\n claudeDirectory: string | null;\r\n sourceDirectory: string;\r\n manifest: ComponentManifest | null;\r\n conflictReport: ConflictReport | null;\r\n backupManifest: BackupManifest | null;\r\n installationResult: InstallationResult | null;\r\n validationReport: ValidationReport | null;\r\n fileMappings: FileMapping[];\r\n overwriteMode: OverwriteMode | null;\r\n selectedCategories: string[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Installation Config\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Resolved configuration for the installation. */\r\nexport interface InstallationConfig {\r\n readonly targetDirectory: string;\r\n readonly claudeDirectory: string;\r\n readonly sourceDirectory: string;\r\n readonly forceOverwrite: boolean;\r\n readonly dryRunMode: boolean;\r\n readonly verboseLogging: boolean;\r\n readonly colorEnabled: boolean;\r\n readonly interactiveMode: boolean;\r\n readonly maxConcurrency: number;\r\n readonly backupEnabled: boolean;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Error Classification\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Categories of errors that can occur during installation. */\r\nexport type ErrorCategory =\r\n | 'Permission'\r\n | 'DiskSpace'\r\n | 'InvalidPath'\r\n | 'RuntimeVersion'\r\n | 'ConflictResolution'\r\n | 'ValidationFailure'\r\n | 'IntegrityError'\r\n | 'InternalError'\r\n | 'Cancellation';\r\n\r\n/** Severity levels for classified errors. */\r\nexport type ErrorSeverity = 'Warning' | 'Recoverable' | 'Fatal';\r\n\r\n/** Recovery strategy for handling errors. */\r\nexport type RecoveryStrategy =\r\n | 'Retry'\r\n | 'RollbackAndAbort'\r\n | 'SkipAndContinue'\r\n | 'PromptUser'\r\n | 'AbortImmediately';\r\n\r\n/** An error classified with category, severity, and recovery strategy. */\r\nexport interface ClassifiedError {\r\n readonly errorId: string;\r\n readonly originalError: Error;\r\n readonly category: ErrorCategory;\r\n readonly severity: ErrorSeverity;\r\n readonly sourceStep: WorkflowStepId;\r\n readonly recoveryStrategy: RecoveryStrategy;\r\n readonly retryCount: number;\r\n readonly timestamp: Date;\r\n readonly userMessage: string;\r\n readonly technicalDetail: string;\r\n}\r\n\r\n/** Action to take when recovering from an error. */\r\nexport interface RecoveryAction {\r\n readonly strategy: RecoveryStrategy;\r\n readonly stepId: WorkflowStepId;\r\n readonly userGuidance: string;\r\n readonly platformGuidance: string | null;\r\n}\r\n\r\n/** Summary of all errors accumulated during the workflow. */\r\nexport interface ErrorSummaryInfo {\r\n readonly totalErrors: number;\r\n readonly fatalCount: number;\r\n readonly recoverableCount: number;\r\n readonly warningCount: number;\r\n readonly messages: readonly string[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Dry Run\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Report produced by dry-run mode. */\r\nexport interface DryRunReport {\r\n readonly filesToInstall: number;\r\n readonly filesToOverwrite: number;\r\n readonly conflictsDetected: number;\r\n readonly wouldSucceed: boolean;\r\n readonly details: readonly DryRunStepDetail[];\r\n}\r\n\r\n/** Detail for a single step in dry-run mode. */\r\nexport interface DryRunStepDetail {\r\n readonly stepId: string;\r\n readonly stepName: string;\r\n readonly result: string;\r\n readonly warnings: readonly string[];\r\n}\r\n","/**\r\n * CLI Orchestrator - Configuration\r\n *\r\n * Default configuration values, source directory resolution, and\r\n * the standard workflow step definitions.\r\n *\r\n * @module orchestrator/config\r\n */\r\n\r\nimport * as path from 'node:path';\r\nimport * as fs from 'node:fs/promises';\r\nimport { readFileSync } from 'node:fs';\r\nimport { fileURLToPath } from 'node:url';\r\n\r\nimport type {\r\n InstallationConfig,\r\n WorkflowStepDef,\r\n WorkflowStepId,\r\n CLIOptions,\r\n} from './types.js';\r\n\r\nimport type { PlatformEnvironment } from '../platform/index.js';\r\nimport type { TerminalCapabilities } from '../ui/index.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Package Version\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Installer version, dynamically read from package.json to stay in sync automatically. */\r\nexport const INSTALLER_VERSION: string = (() => {\r\n try {\r\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\r\n const pkgPath = path.resolve(__dirname, '../package.json');\r\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as { version: string };\r\n return pkg.version;\r\n } catch {\r\n return '0.0.0-unknown';\r\n }\r\n})();\r\n\r\n// ---------------------------------------------------------------------------\r\n// Default Configuration Values\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Default max parallel file copy operations. */\r\nexport const DEFAULT_MAX_CONCURRENCY = 16;\r\n\r\n/** Default target subdirectory name within the project. */\r\nexport const CLAUDE_DIRECTORY_NAME = '.claude';\r\n\r\n/**\r\n * Source library relative path from the compiled CLI entry point.\r\n * The bundled library is at `library/` in the package root.\r\n * Since the built CLI is at `dist/cli.js`, the relative path is `../library`.\r\n */\r\nconst SOURCE_LIBRARY_RELATIVE = '../library';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Source Directory Resolution\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Resolve the absolute path to the AI-DLC library source directory.\r\n *\r\n * Resolution order:\r\n * 1. AIDLC_SOURCE_DIR environment variable\r\n * 2. Relative path from this package root\r\n *\r\n * @returns Absolute path to the source library directory\r\n */\r\nexport async function resolveSourceDirectory(): Promise<string> {\r\n // Check environment variable first\r\n const envSource = process.env['AIDLC_SOURCE_DIR'];\r\n if (envSource) {\r\n try {\r\n const stat = await fs.stat(envSource);\r\n if (stat.isDirectory()) {\r\n return path.resolve(envSource);\r\n }\r\n } catch {\r\n // Fall through to default resolution\r\n }\r\n }\r\n\r\n // Resolve relative to this file's location\r\n const thisFile = fileURLToPath(import.meta.url);\r\n const thisDir = path.dirname(thisFile);\r\n const resolved = path.resolve(thisDir, SOURCE_LIBRARY_RELATIVE);\r\n\r\n try {\r\n const stat = await fs.stat(resolved);\r\n if (stat.isDirectory()) {\r\n return resolved;\r\n }\r\n } catch {\r\n // Fall through\r\n }\r\n\r\n // Fallback: try from current working directory (for development)\r\n const cwdSource = path.resolve(process.cwd(), 'src', 'installer', 'library');\r\n try {\r\n const stat = await fs.stat(cwdSource);\r\n if (stat.isDirectory()) {\r\n return cwdSource;\r\n }\r\n } catch {\r\n // Fall through\r\n }\r\n\r\n throw new Error(\r\n 'Cannot locate AI-DLC library source directory. ' +\r\n 'Set the AIDLC_SOURCE_DIR environment variable to the library path, ' +\r\n 'or ensure the library/ directory exists in the package root.',\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// AI-DLC Source Directory Resolution\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Resolve the absolute path to the AI-DLC framework source directory\r\n * (the .ai-dlc bundle shipped alongside the library).\r\n *\r\n * Resolution order:\r\n * 1. AIDLC_FRAMEWORK_DIR environment variable\r\n * 2. Relative path from this package root (../library-aidlc)\r\n * 3. CWD fallback for development\r\n *\r\n * @returns Absolute path to the ai-dlc framework directory, or null if not found\r\n */\r\nexport async function resolveAiDlcSourceDirectory(): Promise<string | null> {\r\n const envSource = process.env['AIDLC_FRAMEWORK_DIR'];\r\n if (envSource) {\r\n try {\r\n const stat = await fs.stat(envSource);\r\n if (stat.isDirectory()) return path.resolve(envSource);\r\n } catch { /* fall through */ }\r\n }\r\n\r\n const thisFile = fileURLToPath(import.meta.url);\r\n const thisDir = path.dirname(thisFile);\r\n const resolved = path.resolve(thisDir, '../library-aidlc');\r\n\r\n try {\r\n const stat = await fs.stat(resolved);\r\n if (stat.isDirectory()) return resolved;\r\n } catch { /* fall through */ }\r\n\r\n // CWD fallback\r\n const cwdFallback = path.resolve(process.cwd(), 'src', 'installer', 'library-aidlc');\r\n try {\r\n const stat = await fs.stat(cwdFallback);\r\n if (stat.isDirectory()) return cwdFallback;\r\n } catch { /* fall through */ }\r\n\r\n return null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Workflow Step Definitions\r\n// ---------------------------------------------------------------------------\r\n\r\n/** The ordered sequence of installation workflow steps. */\r\nexport const WORKFLOW_STEPS: readonly WorkflowStepDef[] = [\r\n { id: 'detect-platform', name: 'Detect Platform', order: 1, isSkippable: false },\r\n { id: 'check-prerequisites', name: 'Check Prerequisites', order: 2, isSkippable: false },\r\n { id: 'show-banner', name: 'Show Banner', order: 3, isSkippable: true },\r\n { id: 'select-directory', name: 'Select Target Directory', order: 4, isSkippable: true },\r\n { id: 'scan-source', name: 'Scan Source Components', order: 5, isSkippable: false },\r\n { id: 'detect-conflicts', name: 'Detect Conflicts', order: 6, isSkippable: true },\r\n { id: 'select-overwrite-mode', name: 'Select Overwrite Mode', order: 7, isSkippable: true },\r\n { id: 'select-categories', name: 'Select Categories', order: 8, isSkippable: true },\r\n { id: 'confirm-installation', name: 'Confirm Installation', order: 9, isSkippable: true },\r\n { id: 'execute-installation', name: 'Install Files', order: 10, isSkippable: false },\r\n { id: 'validate-installation', name: 'Validate Installation', order: 11, isSkippable: false },\r\n { id: 'show-summary', name: 'Show Summary', order: 12, isSkippable: false },\r\n];\r\n\r\n// ---------------------------------------------------------------------------\r\n// Step Skip Conditions\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Determine whether a step should be skipped given the current options\r\n * and capabilities.\r\n */\r\nexport function shouldSkipStep(\r\n stepId: WorkflowStepId,\r\n options: CLIOptions,\r\n isInteractive: boolean,\r\n): boolean {\r\n switch (stepId) {\r\n case 'show-banner':\r\n return !isInteractive || options.quiet;\r\n\r\n case 'select-directory':\r\n // Never skip — the step itself handles --target with a fast path\r\n // that sets ctx.targetDirectory and ctx.claudeDirectory without prompting.\r\n return false;\r\n\r\n case 'detect-conflicts':\r\n return options.force;\r\n\r\n case 'select-overwrite-mode':\r\n return options.force;\r\n\r\n case 'select-categories':\r\n return false;\r\n\r\n case 'confirm-installation':\r\n return options.force || !isInteractive;\r\n\r\n default:\r\n return false;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Configuration Resolution\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Resolve the complete installation configuration from CLI options,\r\n * platform environment, and terminal capabilities.\r\n *\r\n * Priority: CLI flags > environment variables > platform-detected > defaults\r\n */\r\nexport function resolveConfig(\r\n options: CLIOptions,\r\n platformEnv: PlatformEnvironment,\r\n capabilities: TerminalCapabilities,\r\n sourceDirectory: string,\r\n targetDirectory: string,\r\n): InstallationConfig {\r\n const claudeDirectory = path.join(targetDirectory, CLAUDE_DIRECTORY_NAME);\r\n\r\n const noColorEnv = process.env['NO_COLOR'] !== undefined;\r\n const colorEnabled = !options.noColor && !noColorEnv && capabilities.colorSupport !== 'none';\r\n\r\n const interactiveMode = capabilities.isInteractive && !options.force && !options.quiet;\r\n\r\n return {\r\n targetDirectory,\r\n claudeDirectory,\r\n sourceDirectory,\r\n forceOverwrite: options.force,\r\n dryRunMode: options.dryRun,\r\n verboseLogging: options.verbose,\r\n colorEnabled,\r\n interactiveMode,\r\n maxConcurrency: DEFAULT_MAX_CONCURRENCY,\r\n backupEnabled: !options.force,\r\n };\r\n}\r\n","/**\r\n * Theme Engine - Color palette, symbol sets, and rendering tier management.\r\n *\r\n * Centralizes all visual styling decisions. Selects the appropriate\r\n * rendering tier based on terminal capabilities and provides color/symbol\r\n * helpers to all other UI components.\r\n *\r\n * @module ui/theme\r\n */\r\n\r\nimport chalk from 'chalk';\r\nimport gradientString from 'gradient-string';\r\n\r\nimport type {\r\n ColorScheme,\r\n GradientSpec,\r\n RenderingTier,\r\n SymbolSet,\r\n TerminalCapabilities,\r\n ThemeColor,\r\n ThemeInitParams,\r\n CLIColorOverrides,\r\n} from './types.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Predefined Color Schemes\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Truecolor (24-bit) color scheme using hex values via chalk. */\r\nconst TRUECOLOR_SCHEME: ColorScheme = {\r\n header: '#3B82F6',\r\n accent: '#06B6D4',\r\n success: '#10B981',\r\n error: '#EF4444',\r\n warning: '#F59E0B',\r\n muted: '#6B7280',\r\n};\r\n\r\n/** Basic (16-color ANSI) color scheme. */\r\nconst BASIC_SCHEME: ColorScheme = {\r\n header: 'blue',\r\n accent: 'cyan',\r\n success: 'green',\r\n error: 'red',\r\n warning: 'yellow',\r\n muted: 'gray',\r\n};\r\n\r\n/** Plain (no color) scheme -- all empty strings. */\r\nconst PLAIN_SCHEME: ColorScheme = {\r\n header: '',\r\n accent: '',\r\n success: '',\r\n error: '',\r\n warning: '',\r\n muted: '',\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Predefined Symbol Sets\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Unicode symbol set for Full and Basic tiers. */\r\nconst UNICODE_SYMBOLS: SymbolSet = {\r\n pending: '\\u25CB', // White circle\r\n running: '\\u25CF', // Filled circle\r\n completed: '\\u2713', // Checkmark\r\n failed: '\\u2717', // Cross\r\n skipped: '\\u2500', // Horizontal line\r\n bullet: '\\u2022', // Bullet\r\n arrow: '\\u25B8', // Right-pointing triangle\r\n boxTopLeft: '\\u250C',\r\n boxTopRight: '\\u2510',\r\n boxBottomLeft: '\\u2514',\r\n boxBottomRight: '\\u2518',\r\n boxHorizontal: '\\u2500',\r\n boxVertical: '\\u2502',\r\n boxDividerLeft: '\\u251C',\r\n boxDividerRight: '\\u2524',\r\n doubleTopLeft: '\\u2554',\r\n doubleTopRight: '\\u2557',\r\n doubleBottomLeft: '\\u255A',\r\n doubleBottomRight: '\\u255D',\r\n doubleHorizontal: '\\u2550',\r\n doubleVertical: '\\u2551',\r\n};\r\n\r\n/** ASCII symbol set for Plain tier. */\r\nconst ASCII_SYMBOLS: SymbolSet = {\r\n pending: 'o',\r\n running: '*',\r\n completed: '+',\r\n failed: 'x',\r\n skipped: '-',\r\n bullet: '*',\r\n arrow: '>',\r\n boxTopLeft: '+',\r\n boxTopRight: '+',\r\n boxBottomLeft: '+',\r\n boxBottomRight: '+',\r\n boxHorizontal: '-',\r\n boxVertical: '|',\r\n boxDividerLeft: '+',\r\n boxDividerRight: '+',\r\n doubleTopLeft: '+',\r\n doubleTopRight: '+',\r\n doubleBottomLeft: '+',\r\n doubleBottomRight: '+',\r\n doubleHorizontal: '=',\r\n doubleVertical: '|',\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Tier Selection\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Determine the rendering tier from terminal capabilities and overrides.\r\n *\r\n * Selection rules:\r\n * - forceNoColor -> Plain\r\n * - truecolor + Unicode -> Full\r\n * - (basic | 256) + Unicode -> Basic\r\n * - all other -> Plain\r\n */\r\nfunction selectTier(\r\n capabilities: TerminalCapabilities,\r\n overrides: CLIColorOverrides,\r\n): RenderingTier {\r\n if (overrides.forceNoColor) {\r\n return 'plain';\r\n }\r\n\r\n if (!capabilities.unicodeSupport) {\r\n return 'plain';\r\n }\r\n\r\n if (capabilities.colorSupport === 'none') {\r\n return 'plain';\r\n }\r\n\r\n if (capabilities.colorSupport === 'truecolor') {\r\n return 'full';\r\n }\r\n\r\n // basic or 256 with Unicode\r\n return 'basic';\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// ThemeEngine\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * ThemeEngine manages rendering tier, color scheme, symbol set, and\r\n * terminal width for the entire UI layer. Must be initialized before\r\n * any component calls render().\r\n */\r\nexport class ThemeEngine {\r\n private _tier: RenderingTier;\r\n private _colorScheme: ColorScheme;\r\n private _symbolSet: SymbolSet;\r\n private _terminalWidth: number;\r\n private _forceNoColor: boolean;\r\n\r\n private constructor(params: ThemeInitParams) {\r\n this._tier = params.tier;\r\n this._colorScheme = params.colorScheme;\r\n this._symbolSet = params.symbolSet;\r\n this._terminalWidth = params.terminalWidth;\r\n this._forceNoColor = params.forceNoColor;\r\n }\r\n\r\n /** Current rendering tier. */\r\n get tier(): RenderingTier {\r\n return this._tier;\r\n }\r\n\r\n /** Active color scheme. */\r\n get colorScheme(): ColorScheme {\r\n return this._colorScheme;\r\n }\r\n\r\n /** Active symbol set. */\r\n get symbolSet(): SymbolSet {\r\n return this._symbolSet;\r\n }\r\n\r\n /** Detected or default terminal width. */\r\n get terminalWidth(): number {\r\n return this._terminalWidth;\r\n }\r\n\r\n /** Whether color output is forcibly disabled. */\r\n get forceNoColor(): boolean {\r\n return this._forceNoColor;\r\n }\r\n\r\n /**\r\n * Apply a semantic color to text. Returns unmodified text for Plain tier.\r\n */\r\n colorize(text: string, color: ThemeColor): string {\r\n if (this._tier === 'plain') {\r\n return text;\r\n }\r\n\r\n const colorValue = this._colorScheme[color];\r\n if (!colorValue) {\r\n return text;\r\n }\r\n\r\n if (this._tier === 'full') {\r\n return chalk.hex(colorValue)(text);\r\n }\r\n\r\n // Basic tier: use named colors\r\n const chalkFn = this.getBasicChalkFn(color);\r\n return chalkFn(text);\r\n }\r\n\r\n /**\r\n * Apply bold styling to text. Returns unmodified text for Plain tier.\r\n */\r\n bold(text: string): string {\r\n if (this._tier === 'plain') {\r\n return text;\r\n }\r\n return chalk.bold(text);\r\n }\r\n\r\n /**\r\n * Apply dim styling to text. Returns unmodified text for Plain tier.\r\n */\r\n dim(text: string): string {\r\n if (this._tier === 'plain') {\r\n return text;\r\n }\r\n return chalk.dim(text);\r\n }\r\n\r\n /**\r\n * Apply underline styling to text. Returns unmodified text for Plain tier.\r\n */\r\n underline(text: string): string {\r\n if (this._tier === 'plain') {\r\n return text;\r\n }\r\n return chalk.underline(text);\r\n }\r\n\r\n /**\r\n * Apply gradient coloring to text. Full tier uses gradient-string.\r\n * Basic tier applies a single accent color. Plain tier returns unmodified text.\r\n */\r\n applyGradient(text: string, gradient?: GradientSpec): string {\r\n if (this._tier === 'plain') {\r\n return text;\r\n }\r\n\r\n if (this._tier === 'full') {\r\n const colors = gradient?.colors ?? ['#4F46E5', '#06B6D4'];\r\n const grad = gradientString(...(colors as [string, string, ...string[]]));\r\n return grad(text);\r\n }\r\n\r\n // Basic tier: single accent color\r\n return chalk.blue(text);\r\n }\r\n\r\n /**\r\n * Get the status symbol for a step status, colorized for the active tier.\r\n */\r\n statusSymbol(status: 'pending' | 'running' | 'completed' | 'failed' | 'skipped'): string {\r\n const symbol = this._symbolSet[status];\r\n\r\n if (this._tier === 'plain') {\r\n return `[${symbol}]`;\r\n }\r\n\r\n switch (status) {\r\n case 'completed':\r\n return this.colorize(symbol, 'success');\r\n case 'failed':\r\n return this.colorize(symbol, 'error');\r\n case 'running':\r\n return this.colorize(symbol, 'accent');\r\n case 'skipped':\r\n return this.colorize(symbol, 'muted');\r\n case 'pending':\r\n return this.colorize(symbol, 'muted');\r\n default:\r\n return symbol;\r\n }\r\n }\r\n\r\n /**\r\n * Get a chalk function for basic (16-color) mode.\r\n */\r\n private getBasicChalkFn(color: ThemeColor): (text: string) => string {\r\n switch (color) {\r\n case 'header': return chalk.blue;\r\n case 'accent': return chalk.cyan;\r\n case 'success': return chalk.green;\r\n case 'error': return chalk.red;\r\n case 'warning': return chalk.yellow;\r\n case 'muted': return chalk.gray;\r\n default: return (t: string) => t;\r\n }\r\n }\r\n\r\n /**\r\n * Create and initialize a ThemeEngine from terminal capabilities and overrides.\r\n */\r\n static initialize(\r\n capabilities: TerminalCapabilities,\r\n overrides: CLIColorOverrides = { forceNoColor: false, forceColor: false },\r\n ): ThemeEngine {\r\n const tier = selectTier(capabilities, overrides);\r\n\r\n let colorScheme: ColorScheme;\r\n let symbolSet: SymbolSet;\r\n\r\n switch (tier) {\r\n case 'full':\r\n colorScheme = TRUECOLOR_SCHEME;\r\n symbolSet = UNICODE_SYMBOLS;\r\n break;\r\n case 'basic':\r\n colorScheme = BASIC_SCHEME;\r\n symbolSet = UNICODE_SYMBOLS;\r\n break;\r\n case 'plain':\r\n default:\r\n colorScheme = PLAIN_SCHEME;\r\n symbolSet = ASCII_SYMBOLS;\r\n break;\r\n }\r\n\r\n const terminalWidth = capabilities.width > 0 ? capabilities.width : 80;\r\n\r\n return new ThemeEngine({\r\n tier,\r\n colorScheme,\r\n symbolSet,\r\n terminalWidth,\r\n forceNoColor: overrides.forceNoColor,\r\n });\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Convenience Exports\r\n// ---------------------------------------------------------------------------\r\n\r\nexport { TRUECOLOR_SCHEME, BASIC_SCHEME, PLAIN_SCHEME };\r\nexport { UNICODE_SYMBOLS, ASCII_SYMBOLS };\r\n","/**\r\n * Banner Component - ASCII art banner with gradient coloring.\r\n *\r\n * Renders the \"SixSevenAI\" product name as ASCII art using figlet,\r\n * applies gradient coloring for Full tier, single color for Basic tier,\r\n * and plain text for Plain tier. Includes subtitle and version.\r\n *\r\n * @module ui/banner\r\n */\r\n\r\nimport figlet from 'figlet';\r\n\r\nimport type { BannerConfig, FigletFont, GradientSpec, RenderOptions } from './types.js';\r\nimport { ThemeEngine } from './theme.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Default Configuration\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Default gradient for the Full tier banner. */\r\nconst DEFAULT_GRADIENT: GradientSpec = {\r\n colors: ['#4F46E5', '#06B6D4'],\r\n direction: 'horizontal',\r\n};\r\n\r\n/** Default figlet font for wide terminals. */\r\nconst DEFAULT_FONT: FigletFont = 'ANSI Shadow';\r\n\r\n/** Narrow figlet font for terminals < 80 columns. */\r\nconst NARROW_FONT: FigletFont = 'Small';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Banner Rendering\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Generate ASCII art text using figlet.\r\n *\r\n * Returns null if figlet rendering fails, allowing the caller\r\n * to fall back to plain text.\r\n */\r\nfunction generateFigletText(text: string, font: FigletFont): string | null {\r\n try {\r\n const result = figlet.textSync(text, {\r\n font: font as never,\r\n horizontalLayout: 'default',\r\n verticalLayout: 'default',\r\n });\r\n return result;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Render the plain text fallback banner when figlet is unavailable\r\n * or the terminal is too narrow.\r\n */\r\nfunction renderFallbackBanner(version: string, theme: ThemeEngine): string[] {\r\n const separator = '='.repeat(Math.min(43, theme.terminalWidth - 4));\r\n const lines: string[] = [];\r\n\r\n lines.push(` ${separator}`);\r\n lines.push(' SixSevenAI - AI-DLC Framework');\r\n lines.push(` Installer ${version}`);\r\n lines.push(` ${separator}`);\r\n lines.push('');\r\n\r\n return lines;\r\n}\r\n\r\n/**\r\n * Render the ASCII art banner with tier-appropriate styling.\r\n *\r\n * Full tier: figlet + gradient coloring + styled subtitle\r\n * Basic tier: figlet + single blue color + styled subtitle\r\n * Plain tier: figlet (simple font) or fallback + plain subtitle\r\n *\r\n * @param version - Semantic version string (e.g., \"v1.0.0\")\r\n * @param theme - Initialized ThemeEngine for color/symbol decisions\r\n * @param config - Optional banner configuration override\r\n * @returns Array of output lines ready for terminal writing\r\n */\r\nexport function renderBanner(\r\n version: string,\r\n theme: ThemeEngine,\r\n config?: Partial<BannerConfig>,\r\n): string[] {\r\n const title = config?.title ?? 'SixSevenAI';\r\n const subtitle = config?.subtitle ?? 'AI-DLC Framework Installer';\r\n const tier = theme.tier;\r\n const width = theme.terminalWidth;\r\n\r\n // Select font based on terminal width\r\n let font: FigletFont;\r\n if (tier === 'plain') {\r\n font = config?.font ?? 'Standard';\r\n } else {\r\n font = config?.font ?? (width >= 80 ? DEFAULT_FONT : NARROW_FONT);\r\n }\r\n\r\n // Generate ASCII art\r\n const figletText = generateFigletText(title, font);\r\n\r\n // If figlet fails, use fallback\r\n if (!figletText) {\r\n return renderFallbackBanner(version, theme);\r\n }\r\n\r\n // Check if the figlet output fits the terminal width\r\n const figletLines = figletText.split('\\n').filter((line) => line.trim().length > 0);\r\n const maxLineWidth = Math.max(...figletLines.map((line) => line.length));\r\n\r\n // If too wide, try narrow font or fall back\r\n if (maxLineWidth > width - 4) {\r\n if (font !== NARROW_FONT) {\r\n const narrowText = generateFigletText(title, NARROW_FONT);\r\n if (narrowText) {\r\n const narrowLines = narrowText.split('\\n').filter((line) => line.trim().length > 0);\r\n const narrowMax = Math.max(...narrowLines.map((line) => line.length));\r\n if (narrowMax <= width - 4) {\r\n return buildBannerOutput(narrowLines, subtitle, version, theme);\r\n }\r\n }\r\n }\r\n return renderFallbackBanner(version, theme);\r\n }\r\n\r\n return buildBannerOutput(figletLines, subtitle, version, theme);\r\n}\r\n\r\n/**\r\n * Assemble the final banner output with ASCII art, subtitle, and version.\r\n */\r\nfunction buildBannerOutput(\r\n artLines: string[],\r\n subtitle: string,\r\n version: string,\r\n theme: ThemeEngine,\r\n): string[] {\r\n const lines: string[] = [];\r\n\r\n // Apply tier-appropriate coloring to the ASCII art\r\n for (const artLine of artLines) {\r\n const indented = ` ${artLine}`;\r\n switch (theme.tier) {\r\n case 'full':\r\n lines.push(theme.applyGradient(indented, DEFAULT_GRADIENT));\r\n break;\r\n case 'basic':\r\n lines.push(theme.colorize(indented, 'header'));\r\n break;\r\n case 'plain':\r\n default:\r\n lines.push(indented);\r\n break;\r\n }\r\n }\r\n\r\n // Blank line after art\r\n lines.push('');\r\n\r\n // Subtitle with version\r\n const versionStr = version.startsWith('v') ? version : `v${version}`;\r\n const subtitleLine = ` ${subtitle} ${versionStr}`;\r\n\r\n switch (theme.tier) {\r\n case 'full': {\r\n const styledSubtitle = theme.dim(subtitle);\r\n const styledVersion = theme.bold(theme.colorize(versionStr, 'accent'));\r\n lines.push(` ${styledSubtitle} ${styledVersion}`);\r\n break;\r\n }\r\n case 'basic': {\r\n const styledSubtitle = theme.dim(subtitle);\r\n const styledVersion = theme.colorize(versionStr, 'accent');\r\n lines.push(` ${styledSubtitle} ${styledVersion}`);\r\n break;\r\n }\r\n case 'plain':\r\n default:\r\n lines.push(subtitleLine);\r\n break;\r\n }\r\n\r\n // Trailing blank line\r\n lines.push('');\r\n\r\n return lines;\r\n}\r\n","/**\r\n * Progress Tracker Component - Hierarchical step tracking with live updates.\r\n *\r\n * Tracks multiple installation steps with status lifecycle management,\r\n * elapsed time display, and tier-appropriate symbol/color rendering.\r\n * The ProgressTracker produces string[] output; actual terminal I/O\r\n * is handled by the render service.\r\n *\r\n * @module ui/progress\r\n */\r\n\r\nimport ora, { type Ora } from 'ora';\r\n\r\nimport type {\r\n CompletionRatio,\r\n Duration,\r\n ErrorDetail,\r\n ProgressStep,\r\n StepStatus,\r\n} from './types.js';\r\nimport { formatDuration } from './types.js';\r\nimport { ThemeEngine } from './theme.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Valid State Transitions\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Map of valid transitions from each status to allowed target statuses. */\r\nconst VALID_TRANSITIONS: Record<StepStatus, readonly StepStatus[]> = {\r\n pending: ['running', 'skipped'],\r\n running: ['completed', 'failed'],\r\n completed: [],\r\n failed: [],\r\n skipped: [],\r\n};\r\n\r\n/**\r\n * Check whether a status transition is valid.\r\n */\r\nfunction isValidTransition(from: StepStatus, to: StepStatus): boolean {\r\n return VALID_TRANSITIONS[from].includes(to);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// ProgressTracker\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Manages a hierarchical tree of installation steps with status lifecycle\r\n * tracking, elapsed time computation, and rendering.\r\n *\r\n * Usage:\r\n * ```typescript\r\n * const tracker = new ProgressTracker();\r\n * tracker.addStep({ id: 'detect', label: 'Detect platform' });\r\n * tracker.addStep({ id: 'install', label: 'Install components', children: [\r\n * { id: 'agents', label: 'Copy agents' },\r\n * { id: 'skills', label: 'Copy skills' },\r\n * ]});\r\n * tracker.start();\r\n * tracker.startStep('detect');\r\n * tracker.completeStep('detect');\r\n * ```\r\n */\r\nexport class ProgressTracker {\r\n private readonly _steps: ProgressStep[] = [];\r\n private _startTime: number | null = null;\r\n private _endTime: number | null = null;\r\n private _isActive: boolean = false;\r\n private _spinner: Ora | null = null;\r\n\r\n /** Ordered list of top-level steps. */\r\n get steps(): readonly ProgressStep[] {\r\n return this._steps;\r\n }\r\n\r\n /** Whether tracking is in progress. */\r\n get isActive(): boolean {\r\n return this._isActive;\r\n }\r\n\r\n /**\r\n * Append a top-level step. Throws if tracker is already finished.\r\n */\r\n addStep(config: {\r\n id: string;\r\n label: string;\r\n children?: Array<{ id: string; label: string }>;\r\n }): void {\r\n if (this._endTime !== null) {\r\n throw new Error('Cannot add steps to a finished tracker.');\r\n }\r\n\r\n // Check for duplicate IDs\r\n if (this.findStep(config.id)) {\r\n throw new Error(`Duplicate step ID: \"${config.id}\".`);\r\n }\r\n\r\n const children: ProgressStep[] = (config.children ?? []).map((child) => {\r\n if (this.findStep(child.id)) {\r\n throw new Error(`Duplicate step ID: \"${child.id}\".`);\r\n }\r\n return {\r\n id: child.id,\r\n label: child.label,\r\n status: 'pending' as StepStatus,\r\n children: [],\r\n startTime: null,\r\n endTime: null,\r\n error: null,\r\n };\r\n });\r\n\r\n this._steps.push({\r\n id: config.id,\r\n label: config.label,\r\n status: 'pending',\r\n children,\r\n startTime: null,\r\n endTime: null,\r\n error: null,\r\n });\r\n }\r\n\r\n /**\r\n * Mark the tracker as active and record the start time.\r\n */\r\n start(): void {\r\n this._startTime = Date.now();\r\n this._isActive = true;\r\n }\r\n\r\n /**\r\n * Transition a step from Pending to Running.\r\n */\r\n startStep(stepId: string): void {\r\n const step = this.requireStep(stepId);\r\n this.transitionStep(step, 'running');\r\n step.startTime = Date.now();\r\n }\r\n\r\n /**\r\n * Transition a step from Running to Completed.\r\n */\r\n completeStep(stepId: string): void {\r\n const step = this.requireStep(stepId);\r\n this.transitionStep(step, 'completed');\r\n step.endTime = Date.now();\r\n }\r\n\r\n /**\r\n * Transition a step from Running to Failed with error details.\r\n */\r\n failStep(stepId: string, error: ErrorDetail): void {\r\n const step = this.requireStep(stepId);\r\n this.transitionStep(step, 'failed');\r\n step.endTime = Date.now();\r\n step.error = error;\r\n }\r\n\r\n /**\r\n * Transition a step from Pending to Skipped.\r\n */\r\n skipStep(stepId: string, _reason: string): void {\r\n const step = this.requireStep(stepId);\r\n this.transitionStep(step, 'skipped');\r\n }\r\n\r\n /**\r\n * Mark the tracker as finished. Throws if any steps are still Running.\r\n */\r\n finish(): void {\r\n const runningSteps = this.flattenSteps().filter((s) => s.status === 'running');\r\n if (runningSteps.length > 0) {\r\n const ids = runningSteps.map((s) => s.id).join(', ');\r\n throw new Error(`Cannot finish tracker while steps are running: ${ids}`);\r\n }\r\n\r\n this._endTime = Date.now();\r\n this._isActive = false;\r\n this.stopSpinner();\r\n }\r\n\r\n /**\r\n * Get the elapsed time since tracking started.\r\n */\r\n getElapsedTime(): Duration {\r\n if (this._startTime === null) {\r\n return { milliseconds: 0, formatted: '0ms' };\r\n }\r\n const end = this._endTime ?? Date.now();\r\n return formatDuration(end - this._startTime);\r\n }\r\n\r\n /**\r\n * Get the completion ratio across all steps (including children).\r\n */\r\n getCompletionRatio(): CompletionRatio {\r\n const allSteps = this.flattenSteps();\r\n const completed = allSteps.filter(\r\n (s) => s.status === 'completed' || s.status === 'skipped',\r\n ).length;\r\n const total = allSteps.length;\r\n const percentage = total > 0 ? Math.round((completed / total) * 100) : 0;\r\n\r\n return { completed, total, percentage };\r\n }\r\n\r\n /**\r\n * Render the current progress state as terminal output lines.\r\n *\r\n * @param theme - ThemeEngine for colors and symbols\r\n * @returns Array of output lines\r\n */\r\n render(theme: ThemeEngine): string[] {\r\n const lines: string[] = [];\r\n const width = theme.terminalWidth;\r\n\r\n for (const step of this._steps) {\r\n lines.push(this.renderStep(step, 0, theme, width));\r\n\r\n for (const child of step.children) {\r\n lines.push(this.renderStep(child, 1, theme, width));\r\n }\r\n }\r\n\r\n return lines;\r\n }\r\n\r\n /**\r\n * Start the ora spinner for the currently running step.\r\n * Used by the render service for animated Running indicators.\r\n */\r\n startSpinner(text?: string): Ora | null {\r\n if (this._spinner) {\r\n this._spinner.stop();\r\n }\r\n\r\n const runningStep = this.flattenSteps().find((s) => s.status === 'running');\r\n if (!runningStep) {\r\n return null;\r\n }\r\n\r\n this._spinner = ora({\r\n text: text ?? runningStep.label,\r\n spinner: 'dots',\r\n });\r\n this._spinner.start();\r\n return this._spinner;\r\n }\r\n\r\n /**\r\n * Stop the ora spinner if one is running.\r\n */\r\n stopSpinner(): void {\r\n if (this._spinner) {\r\n this._spinner.stop();\r\n this._spinner = null;\r\n }\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Private Helpers\r\n // -------------------------------------------------------------------------\r\n\r\n /**\r\n * Find a step by ID across all levels of the hierarchy.\r\n */\r\n private findStep(stepId: string): ProgressStep | null {\r\n for (const step of this._steps) {\r\n if (step.id === stepId) return step;\r\n for (const child of step.children) {\r\n if (child.id === stepId) return child;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * Find a step by ID, throwing if not found.\r\n */\r\n private requireStep(stepId: string): ProgressStep {\r\n const step = this.findStep(stepId);\r\n if (!step) {\r\n throw new Error(`Step not found: \"${stepId}\".`);\r\n }\r\n return step;\r\n }\r\n\r\n /**\r\n * Enforce valid status transitions.\r\n */\r\n private transitionStep(step: ProgressStep, to: StepStatus): void {\r\n if (!isValidTransition(step.status, to)) {\r\n throw new Error(\r\n `Invalid transition for step \"${step.id}\": ${step.status} -> ${to}. ` +\r\n `Allowed: [${VALID_TRANSITIONS[step.status].join(', ')}].`,\r\n );\r\n }\r\n step.status = to;\r\n }\r\n\r\n /**\r\n * Flatten all steps (parents + children) into a single array.\r\n */\r\n private flattenSteps(): ProgressStep[] {\r\n const result: ProgressStep[] = [];\r\n for (const step of this._steps) {\r\n result.push(step);\r\n result.push(...step.children);\r\n }\r\n return result;\r\n }\r\n\r\n /**\r\n * Render a single step line with indentation, symbol, label, and elapsed time.\r\n */\r\n private renderStep(\r\n step: ProgressStep,\r\n depth: number,\r\n theme: ThemeEngine,\r\n terminalWidth: number,\r\n ): string {\r\n const tier = theme.tier;\r\n\r\n // Indentation: 2 spaces per depth level for Unicode, 4 for Plain\r\n const indentSize = tier === 'plain' ? 4 : 2;\r\n const indent = ' '.repeat(2 + depth * indentSize);\r\n\r\n // Status symbol\r\n const symbol = theme.statusSymbol(step.status);\r\n\r\n // Elapsed time (only if started)\r\n let elapsed = '';\r\n if (step.startTime !== null) {\r\n const end = step.endTime ?? Date.now();\r\n const duration = formatDuration(end - step.startTime);\r\n elapsed = duration.formatted;\r\n }\r\n\r\n // Compose the line\r\n const labelPart = `${indent}${symbol} ${step.label}`;\r\n\r\n if (!elapsed) {\r\n return labelPart;\r\n }\r\n\r\n // Right-align the elapsed time\r\n const elapsedDisplay = theme.dim(elapsed);\r\n const rawLabelLength = stripAnsi(labelPart).length;\r\n const rawElapsedLength = elapsed.length;\r\n const padding = Math.max(4, terminalWidth - rawLabelLength - rawElapsedLength - 2);\r\n\r\n return `${labelPart}${' '.repeat(padding)}${elapsedDisplay}`;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Utility\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Strip ANSI escape codes from a string for accurate length calculation.\r\n */\r\nfunction stripAnsi(text: string): string {\r\n // eslint-disable-next-line no-control-regex\r\n return text.replace(/\\x1b\\[[0-9;]*m/g, '');\r\n}\r\n","/**\r\n * Terminal UI Components - Shared Types\r\n *\r\n * All value objects, enumerations, and interfaces used throughout\r\n * the terminal UI subsystem. Mirrors the domain model from\r\n * domain-model-unit-terminal-ui-20260213-001.md.\r\n *\r\n * @module ui/types\r\n */\r\n\r\nimport type { ColorSupportLevel, TerminalProfile } from '../platform/types.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Rendering Tier\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Discrete rendering fidelity level, selected based on terminal capabilities.\r\n *\r\n * - Full: truecolor + Unicode -- gradient colors, box-drawing, rich symbols\r\n * - Basic: 16/256-color + Unicode -- single ANSI colors, box-drawing, rich symbols\r\n * - Plain: no color or no Unicode -- uncolored text, ASCII-only symbols\r\n */\r\nexport type RenderingTier = 'full' | 'basic' | 'plain';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Step Status\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Lifecycle state of a progress step.\r\n *\r\n * Valid transitions:\r\n * Pending -> Running\r\n * Pending -> Skipped\r\n * Running -> Completed\r\n * Running -> Failed\r\n *\r\n * Completed, Failed, and Skipped are terminal states.\r\n */\r\nexport type StepStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Progress Step\r\n// ---------------------------------------------------------------------------\r\n\r\n/** A single trackable item in the progress hierarchy. */\r\nexport interface ProgressStep {\r\n readonly id: string;\r\n readonly label: string;\r\n status: StepStatus;\r\n readonly children: ProgressStep[];\r\n startTime: number | null;\r\n endTime: number | null;\r\n error: ErrorDetail | null;\r\n}\r\n\r\n/** Error information associated with a failed step. */\r\nexport interface ErrorDetail {\r\n readonly message: string;\r\n readonly cause: string | null;\r\n}\r\n\r\n/** Ratio of completed steps to total steps. */\r\nexport interface CompletionRatio {\r\n readonly completed: number;\r\n readonly total: number;\r\n readonly percentage: number;\r\n}\r\n\r\n/** Human-readable duration value object. */\r\nexport interface Duration {\r\n readonly milliseconds: number;\r\n readonly formatted: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Color Scheme\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Color palette used across all components. */\r\nexport interface ColorScheme {\r\n readonly header: string;\r\n readonly accent: string;\r\n readonly success: string;\r\n readonly error: string;\r\n readonly warning: string;\r\n readonly muted: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Symbol Set\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Set of status indicator glyphs for rendering. */\r\nexport interface SymbolSet {\r\n readonly pending: string;\r\n readonly running: string;\r\n readonly completed: string;\r\n readonly failed: string;\r\n readonly skipped: string;\r\n readonly bullet: string;\r\n readonly arrow: string;\r\n readonly boxTopLeft: string;\r\n readonly boxTopRight: string;\r\n readonly boxBottomLeft: string;\r\n readonly boxBottomRight: string;\r\n readonly boxHorizontal: string;\r\n readonly boxVertical: string;\r\n readonly boxDividerLeft: string;\r\n readonly boxDividerRight: string;\r\n readonly doubleTopLeft: string;\r\n readonly doubleTopRight: string;\r\n readonly doubleBottomLeft: string;\r\n readonly doubleBottomRight: string;\r\n readonly doubleHorizontal: string;\r\n readonly doubleVertical: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Render Options\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Options that control rendering behavior, derived from terminal capabilities. */\r\nexport interface RenderOptions {\r\n readonly tier: RenderingTier;\r\n readonly unicodeSupport: boolean;\r\n readonly width: number;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Theme Color (semantic color names)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Semantic color names that map to the active ColorScheme fields. */\r\nexport type ThemeColor = 'header' | 'accent' | 'success' | 'error' | 'warning' | 'muted';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Banner Config\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Configuration for the ASCII art banner component. */\r\nexport interface BannerConfig {\r\n readonly title: string;\r\n readonly subtitle: string;\r\n readonly version: string;\r\n readonly font: FigletFont;\r\n}\r\n\r\n/** Recognized figlet font names. */\r\nexport type FigletFont = 'ANSI Shadow' | 'Standard' | 'Slant' | 'Small' | 'Banner3';\r\n\r\n/** Gradient color specification for banner rendering. */\r\nexport interface GradientSpec {\r\n readonly colors: readonly string[];\r\n readonly direction: 'horizontal' | 'vertical';\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Error Display\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Content for an error panel. */\r\nexport interface ErrorPanelContent {\r\n readonly title: string;\r\n readonly message: string;\r\n readonly cause: string | null;\r\n readonly suggestedActions: readonly SuggestedAction[];\r\n readonly retryAvailable: boolean;\r\n readonly errorCode: string | null;\r\n}\r\n\r\n/** Content for a warning panel. */\r\nexport interface WarningPanelContent {\r\n readonly title: string;\r\n readonly message: string;\r\n readonly suggestedActions: readonly SuggestedAction[];\r\n readonly continueAvailable: boolean;\r\n}\r\n\r\n/** A numbered remediation step shown in error/warning panels. */\r\nexport interface SuggestedAction {\r\n readonly step: number;\r\n readonly instruction: string;\r\n readonly command: string | null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Summary Screen\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Post-installation summary data. */\r\nexport interface InstallationSummary {\r\n readonly success: boolean;\r\n readonly targetDirectory: string;\r\n readonly componentCounts: ComponentCounts;\r\n readonly totalDuration: Duration;\r\n readonly totalFilesCopied: number;\r\n readonly totalFilesSkipped: number;\r\n readonly totalFilesFailed: number;\r\n readonly installerVersion: string;\r\n}\r\n\r\n/** Breakdown of installed component counts. */\r\nexport interface ComponentCounts {\r\n readonly agents: number;\r\n readonly skills: number;\r\n readonly commands: number;\r\n readonly cliFiles: number;\r\n readonly other: number;\r\n}\r\n\r\n/** Post-installation guidance step. */\r\nexport interface NextStep {\r\n readonly order: number;\r\n readonly title: string;\r\n readonly instruction: string;\r\n readonly command: string | null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Directory Selector\r\n// ---------------------------------------------------------------------------\r\n\r\n/** A selectable directory option in the directory selector. */\r\nexport interface DirectoryOption {\r\n readonly path: string;\r\n readonly label: string;\r\n readonly isDefault: boolean;\r\n readonly exists: boolean;\r\n}\r\n\r\n/** Confirmed directory selection result. */\r\nexport interface DirectorySelection {\r\n readonly path: string;\r\n readonly isCustom: boolean;\r\n}\r\n\r\n/** Path validation result. */\r\nexport interface PathValidation {\r\n readonly isValid: boolean;\r\n readonly path: string;\r\n readonly errors: readonly ValidationError[];\r\n readonly warnings: readonly ValidationWarning[];\r\n}\r\n\r\n/** A specific validation error for a path. */\r\nexport interface ValidationError {\r\n readonly code: string;\r\n readonly message: string;\r\n}\r\n\r\n/** A non-blocking validation warning for a path. */\r\nexport interface ValidationWarning {\r\n readonly code: string;\r\n readonly message: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Terminal Capabilities (consumed from platform context)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Terminal capabilities consumed from the cross-platform context.\r\n * Maps to the platform module's TerminalProfile type.\r\n */\r\nexport interface TerminalCapabilities {\r\n readonly colorSupport: 'none' | 'basic' | '256' | 'truecolor';\r\n readonly unicodeSupport: boolean;\r\n readonly width: number;\r\n readonly height: number;\r\n readonly isInteractive: boolean;\r\n}\r\n\r\n/** CLI-level color overrides (e.g., --no-color flag). */\r\nexport interface CLIColorOverrides {\r\n readonly forceNoColor: boolean;\r\n readonly forceColor: boolean;\r\n}\r\n\r\n/** Parameters for initializing the ThemeEngine. */\r\nexport interface ThemeInitParams {\r\n readonly tier: RenderingTier;\r\n readonly colorScheme: ColorScheme;\r\n readonly symbolSet: SymbolSet;\r\n readonly terminalWidth: number;\r\n readonly forceNoColor: boolean;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Component Counts Utility\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Calculate the total from a ComponentCounts value. */\r\nexport function totalComponentCount(counts: ComponentCounts): number {\r\n return counts.agents + counts.skills + counts.commands + counts.cliFiles + counts.other;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Duration Utility\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Format a duration in milliseconds to a human-readable string. */\r\nexport function formatDuration(ms: number): Duration {\r\n if (ms < 1000) {\r\n return { milliseconds: ms, formatted: `${ms}ms` };\r\n }\r\n if (ms < 60_000) {\r\n const seconds = (ms / 1000).toFixed(1);\r\n return { milliseconds: ms, formatted: `${seconds}s` };\r\n }\r\n const minutes = Math.floor(ms / 60_000);\r\n const seconds = Math.round((ms % 60_000) / 1000);\r\n return { milliseconds: ms, formatted: `${minutes}m ${seconds}s` };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Color Support Mapping\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Map the platform module's ColorSupportLevel enum to the UI-local\r\n * TerminalCapabilities color support string.\r\n */\r\nexport function mapColorSupport(level: ColorSupportLevel): TerminalCapabilities['colorSupport'] {\r\n switch (level) {\r\n case 0: return 'none';\r\n case 1: return 'basic';\r\n case 2: return '256';\r\n case 3: return 'truecolor';\r\n default: return 'none';\r\n }\r\n}\r\n","/**\r\n * Prompts Component - Interactive terminal prompts using @clack/prompts.\r\n *\r\n * Provides directory selection, confirmation, component selection, and\r\n * text input prompts. Falls back to non-interactive defaults when the\r\n * terminal does not support interactive input.\r\n *\r\n * @module ui/prompts\r\n */\r\n\r\nimport * as clack from '@clack/prompts';\r\n\r\nimport type { DirectoryOption, DirectorySelection } from './types.js';\r\nimport type { OverwriteMode } from '../orchestrator/types.js';\r\nimport type { CategoryConflictSummary } from '../engine/conflict-detector.js';\r\nimport { ThemeEngine } from './theme.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Directory Selection\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Prompt the user to select an installation directory from a list of options.\r\n *\r\n * Uses @clack/prompts.select() with domain-specific options and a \"Custom path\"\r\n * entry. If the user selects \"Custom path\", a text prompt collects the path.\r\n *\r\n * @param options - Suggested directory options\r\n * @param theme - ThemeEngine for styling (used in message formatting)\r\n * @returns The selected directory or throws on cancellation\r\n */\r\nexport async function promptDirectorySelection(\r\n options: readonly DirectoryOption[],\r\n theme: ThemeEngine,\r\n): Promise<DirectorySelection> {\r\n const selectOptions = options.map((opt) => ({\r\n value: opt.path,\r\n label: opt.path,\r\n hint: opt.isDefault ? '(default)' : opt.exists ? '(exists)' : '(will be created)',\r\n }));\r\n\r\n // Add custom path option\r\n selectOptions.push({\r\n value: '__custom__',\r\n label: 'Custom path...',\r\n hint: 'Enter a custom directory path',\r\n });\r\n\r\n const selected = await clack.select({\r\n message: 'Select installation directory:',\r\n options: selectOptions,\r\n initialValue: options.find((o) => o.isDefault)?.path ?? options[0]?.path,\r\n });\r\n\r\n if (clack.isCancel(selected)) {\r\n throw new UserCancellationError('Directory selection cancelled.');\r\n }\r\n\r\n // Custom path entry\r\n if (selected === '__custom__') {\r\n const customPath = await clack.text({\r\n message: 'Enter installation directory path:',\r\n placeholder: process.cwd(),\r\n validate: (value) => {\r\n if (!value || value.trim().length === 0) {\r\n return 'Path cannot be empty.';\r\n }\r\n // Basic absolute path check\r\n const isAbsolute = /^[A-Za-z]:[\\\\/]/.test(value) || value.startsWith('/');\r\n if (!isAbsolute) {\r\n return 'Path must be absolute (e.g., C:\\\\dev\\\\project or /home/user/project).';\r\n }\r\n return undefined;\r\n },\r\n });\r\n\r\n if (clack.isCancel(customPath)) {\r\n throw new UserCancellationError('Custom path entry cancelled.');\r\n }\r\n\r\n return {\r\n path: customPath as string,\r\n isCustom: true,\r\n };\r\n }\r\n\r\n return {\r\n path: selected as string,\r\n isCustom: false,\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Confirmation Prompt\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Display a yes/no confirmation prompt.\r\n *\r\n * @param message - The question to display\r\n * @param defaultValue - Default answer if the user presses Enter\r\n * @returns true for yes, false for no\r\n */\r\nexport async function promptConfirmation(\r\n message: string,\r\n defaultValue: boolean = true,\r\n): Promise<boolean> {\r\n const result = await clack.confirm({\r\n message,\r\n initialValue: defaultValue,\r\n });\r\n\r\n if (clack.isCancel(result)) {\r\n throw new UserCancellationError('Confirmation cancelled.');\r\n }\r\n\r\n return result as boolean;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Overwrite Existing Prompt\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Prompt whether to overwrite an existing installation.\r\n *\r\n * @param targetPath - The directory that already contains files\r\n * @returns true to overwrite, false to cancel\r\n */\r\nexport async function promptOverwriteExisting(\r\n targetPath: string,\r\n): Promise<boolean> {\r\n const result = await clack.confirm({\r\n message: `Directory \"${targetPath}\" already contains AI-DLC files. Overwrite?`,\r\n initialValue: false,\r\n });\r\n\r\n if (clack.isCancel(result)) {\r\n throw new UserCancellationError('Overwrite confirmation cancelled.');\r\n }\r\n\r\n return result as boolean;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Component Selection Prompt\r\n// ---------------------------------------------------------------------------\r\n\r\n/** A selectable component category for installation. */\r\nexport interface ComponentOption {\r\n readonly value: string;\r\n readonly label: string;\r\n readonly hint?: string;\r\n}\r\n\r\n/**\r\n * Prompt the user to select which components to install.\r\n *\r\n * @param components - Available component categories\r\n * @returns Array of selected component values\r\n */\r\nexport async function promptComponentSelection(\r\n components: readonly ComponentOption[],\r\n): Promise<string[]> {\r\n const result = await clack.multiselect({\r\n message: 'Select components to install:',\r\n options: components.map((c) => ({\r\n value: c.value,\r\n label: c.label,\r\n hint: c.hint,\r\n })),\r\n required: true,\r\n });\r\n\r\n if (clack.isCancel(result)) {\r\n throw new UserCancellationError('Component selection cancelled.');\r\n }\r\n\r\n return result as string[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Retry Prompt\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Prompt the user whether to retry a failed operation.\r\n *\r\n * @returns true to retry, false to abort\r\n */\r\nexport async function promptRetry(): Promise<boolean> {\r\n const result = await clack.confirm({\r\n message: 'Would you like to retry?',\r\n initialValue: true,\r\n });\r\n\r\n if (clack.isCancel(result)) {\r\n return false;\r\n }\r\n\r\n return result as boolean;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Overwrite Mode Prompt\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Prompt the user to select how existing files should be handled.\r\n *\r\n * Offers three strategies: overwrite all, skip existing, or choose by category.\r\n *\r\n * @param targetPath - The directory that already contains files\r\n * @returns The selected overwrite mode\r\n */\r\nexport async function promptOverwriteMode(\r\n targetPath: string,\r\n): Promise<OverwriteMode> {\r\n const result = await clack.select({\r\n message: `Directory \"${targetPath}\" already contains AI-DLC files. How should existing files be handled?`,\r\n options: [\r\n { value: 'all' as const, label: 'Overwrite all', hint: 'Replace all existing files with latest versions' },\r\n { value: 'none' as const, label: 'Skip existing', hint: 'Only install new files, keep all existing' },\r\n { value: 'choose' as const, label: 'Choose categories', hint: 'Select which component categories to overwrite' },\r\n ],\r\n });\r\n\r\n if (clack.isCancel(result)) {\r\n throw new UserCancellationError('Overwrite mode selection cancelled.');\r\n }\r\n\r\n return result as OverwriteMode;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Category Selection Prompt\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Prompt the user to select which component categories to overwrite.\r\n *\r\n * Categories that have been modified since the last installation are annotated\r\n * with \"(modified)\" in their hint text. When conflict stats are provided,\r\n * file counts and modification counts are shown in the hint.\r\n *\r\n * @param categories - Available categories with value, label, and hint\r\n * @param modifiedCategories - Category values that have local modifications\r\n * @param conflictStats - Optional per-category conflict summaries for file count display\r\n * @returns Array of selected category values (may be empty)\r\n */\r\nexport async function promptCategorySelection(\r\n categories: Array<{ value: string; label: string; hint: string }>,\r\n modifiedCategories: string[],\r\n conflictStats?: CategoryConflictSummary[],\r\n): Promise<string[]> {\r\n const statsMap = new Map<string, CategoryConflictSummary>();\r\n if (conflictStats) {\r\n for (const stat of conflictStats) {\r\n statsMap.set(stat.categoryId, stat);\r\n }\r\n }\r\n\r\n const options = categories.map((cat) => {\r\n let hint = cat.hint;\r\n const stat = statsMap.get(cat.value);\r\n\r\n // Append file count and modification info when stats are available\r\n if (stat) {\r\n const parts: string[] = [`${stat.totalFiles} files`];\r\n if (stat.modifiedFiles > 0) {\r\n parts.push(`${stat.modifiedFiles} modified`);\r\n }\r\n if (stat.newFiles > 0) {\r\n parts.push(`${stat.newFiles} new`);\r\n }\r\n hint = `${hint} (${parts.join(', ')})`;\r\n } else if (modifiedCategories.includes(cat.value)) {\r\n hint = `${hint} (modified)`;\r\n }\r\n\r\n return {\r\n value: cat.value,\r\n label: cat.label,\r\n hint,\r\n };\r\n });\r\n\r\n const result = await clack.multiselect({\r\n message: 'Select categories to overwrite:',\r\n options,\r\n required: false,\r\n });\r\n\r\n if (clack.isCancel(result)) {\r\n throw new UserCancellationError('Category selection cancelled.');\r\n }\r\n\r\n return result as string[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Clack Lifecycle Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Display the @clack/prompts intro banner.\r\n * Should be called once at the start of the interactive session.\r\n */\r\nexport function promptIntro(title: string): void {\r\n clack.intro(title);\r\n}\r\n\r\n/**\r\n * Display the @clack/prompts outro banner.\r\n * Should be called once at the end of the interactive session.\r\n */\r\nexport function promptOutro(message: string): void {\r\n clack.outro(message);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// User Cancellation Error\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Error thrown when the user cancels an interactive prompt (Ctrl+C or Escape).\r\n * The CLI orchestrator should catch this and exit with code 2.\r\n */\r\nexport class UserCancellationError extends Error {\r\n readonly code = 'USER_CANCELLED';\r\n\r\n constructor(message: string = 'Operation cancelled by user.') {\r\n super(message);\r\n this.name = 'UserCancellationError';\r\n }\r\n}\r\n","/**\r\n * Error Display Component - Styled error and warning panels.\r\n *\r\n * Renders error and warning information in bordered terminal panels\r\n * with colored borders, structured details, and actionable remediation\r\n * suggestions. Adapts panel style to the active rendering tier.\r\n *\r\n * @module ui/error-display\r\n */\r\n\r\nimport type { ErrorPanelContent, SuggestedAction, WarningPanelContent } from './types.js';\r\nimport { ThemeEngine } from './theme.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Error Panel Rendering\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render an error panel with red border, title, message, cause, and\r\n * suggested remediation actions.\r\n *\r\n * @param content - Error panel content\r\n * @param theme - ThemeEngine for colors, symbols, and terminal width\r\n * @returns Array of output lines\r\n */\r\nexport function renderError(\r\n content: ErrorPanelContent,\r\n theme: ThemeEngine,\r\n): string[] {\r\n return renderPanel(content, 'error', theme);\r\n}\r\n\r\n/**\r\n * Render a warning panel with yellow border, title, message, and\r\n * suggested actions.\r\n *\r\n * @param content - Warning panel content\r\n * @param theme - ThemeEngine for colors, symbols, and terminal width\r\n * @returns Array of output lines\r\n */\r\nexport function renderWarning(\r\n content: WarningPanelContent,\r\n theme: ThemeEngine,\r\n): string[] {\r\n return renderPanel(content, 'warning', theme);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Panel Rendering Core\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render a styled panel (error or warning) with the appropriate border\r\n * color and structure.\r\n */\r\nfunction renderPanel(\r\n content: ErrorPanelContent | WarningPanelContent,\r\n panelType: 'error' | 'warning',\r\n theme: ThemeEngine,\r\n): string[] {\r\n const symbols = theme.symbolSet;\r\n const width = Math.min(theme.terminalWidth - 4, 75);\r\n const innerWidth = width - 4; // 2 for border + 1 space padding each side\r\n const tier = theme.tier;\r\n\r\n // Select colorize function based on panel type\r\n const colorFn = (text: string): string => {\r\n return theme.colorize(text, panelType === 'error' ? 'error' : 'warning');\r\n };\r\n\r\n const lines: string[] = [];\r\n\r\n // Top border\r\n const topBorder = buildHorizontalBorder(\r\n symbols.boxTopLeft,\r\n symbols.boxHorizontal,\r\n symbols.boxTopRight,\r\n width,\r\n );\r\n lines.push(` ${colorFn(topBorder)}`);\r\n\r\n // Title line\r\n const statusSymbol = panelType === 'error'\r\n ? theme.statusSymbol('failed')\r\n : (tier === 'plain' ? '[!]' : '\\u26A0');\r\n const titleText = `${statusSymbol} ${content.title}`;\r\n lines.push(buildContentLine(titleText, symbols.boxVertical, innerWidth, colorFn, theme));\r\n\r\n // Divider\r\n const divider = buildHorizontalBorder(\r\n symbols.boxDividerLeft,\r\n symbols.boxHorizontal,\r\n symbols.boxDividerRight,\r\n width,\r\n );\r\n lines.push(` ${colorFn(divider)}`);\r\n\r\n // Blank line\r\n lines.push(buildEmptyLine(symbols.boxVertical, innerWidth, colorFn));\r\n\r\n // Message\r\n const messageLines = wordWrap(content.message, innerWidth - 2);\r\n for (const msgLine of messageLines) {\r\n lines.push(buildContentLine(` ${msgLine}`, symbols.boxVertical, innerWidth, colorFn, theme));\r\n }\r\n\r\n // Cause (error panels only)\r\n if ('cause' in content && content.cause) {\r\n lines.push(buildEmptyLine(symbols.boxVertical, innerWidth, colorFn));\r\n const causePrefix = theme.bold('Cause:');\r\n const causeLines = wordWrap(`${content.cause}`, innerWidth - 9);\r\n lines.push(\r\n buildContentLine(` ${causePrefix} ${causeLines[0] ?? ''}`, symbols.boxVertical, innerWidth, colorFn, theme),\r\n );\r\n for (let i = 1; i < causeLines.length; i++) {\r\n lines.push(\r\n buildContentLine(` ${causeLines[i]}`, symbols.boxVertical, innerWidth, colorFn, theme),\r\n );\r\n }\r\n }\r\n\r\n // Suggested actions\r\n if (content.suggestedActions.length > 0) {\r\n lines.push(buildEmptyLine(symbols.boxVertical, innerWidth, colorFn));\r\n lines.push(\r\n buildContentLine(' Suggested actions:', symbols.boxVertical, innerWidth, colorFn, theme),\r\n );\r\n lines.push(buildEmptyLine(symbols.boxVertical, innerWidth, colorFn));\r\n\r\n for (const action of content.suggestedActions) {\r\n lines.push(...renderSuggestedAction(action, symbols.boxVertical, innerWidth, colorFn, theme));\r\n }\r\n }\r\n\r\n // Blank line before close\r\n lines.push(buildEmptyLine(symbols.boxVertical, innerWidth, colorFn));\r\n\r\n // Bottom border\r\n const bottomBorder = buildHorizontalBorder(\r\n symbols.boxBottomLeft,\r\n symbols.boxHorizontal,\r\n symbols.boxBottomRight,\r\n width,\r\n );\r\n lines.push(` ${colorFn(bottomBorder)}`);\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Line Builders\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Build a horizontal border line (top, bottom, or divider).\r\n */\r\nfunction buildHorizontalBorder(\r\n left: string,\r\n horizontal: string,\r\n right: string,\r\n totalWidth: number,\r\n): string {\r\n const fill = horizontal.repeat(totalWidth - 2);\r\n return `${left}${fill}${right}`;\r\n}\r\n\r\n/**\r\n * Build a content line with vertical borders and inner padding.\r\n */\r\nfunction buildContentLine(\r\n content: string,\r\n vertical: string,\r\n innerWidth: number,\r\n colorFn: (text: string) => string,\r\n theme: ThemeEngine,\r\n): string {\r\n const strippedLength = stripAnsi(content).length;\r\n const padding = Math.max(0, innerWidth - strippedLength);\r\n return ` ${colorFn(vertical)} ${content}${' '.repeat(padding)}${colorFn(vertical)}`;\r\n}\r\n\r\n/**\r\n * Build an empty line with vertical borders.\r\n */\r\nfunction buildEmptyLine(\r\n vertical: string,\r\n innerWidth: number,\r\n colorFn: (text: string) => string,\r\n): string {\r\n return ` ${colorFn(vertical)}${' '.repeat(innerWidth + 2)}${colorFn(vertical)}`;\r\n}\r\n\r\n/**\r\n * Render a suggested action as one or more lines.\r\n */\r\nfunction renderSuggestedAction(\r\n action: SuggestedAction,\r\n vertical: string,\r\n innerWidth: number,\r\n colorFn: (text: string) => string,\r\n theme: ThemeEngine,\r\n): string[] {\r\n const lines: string[] = [];\r\n\r\n // Numbered instruction\r\n const numberPrefix = ` ${action.step}. `;\r\n const instructionLines = wordWrap(action.instruction, innerWidth - numberPrefix.length - 2);\r\n\r\n lines.push(\r\n buildContentLine(\r\n `${numberPrefix}${instructionLines[0] ?? ''}`,\r\n vertical,\r\n innerWidth,\r\n colorFn,\r\n theme,\r\n ),\r\n );\r\n\r\n // Continuation lines\r\n const continuationIndent = ' '.repeat(numberPrefix.length);\r\n for (let i = 1; i < instructionLines.length; i++) {\r\n lines.push(\r\n buildContentLine(\r\n `${continuationIndent}${instructionLines[i]}`,\r\n vertical,\r\n innerWidth,\r\n colorFn,\r\n theme,\r\n ),\r\n );\r\n }\r\n\r\n // Command (if present)\r\n if (action.command) {\r\n const commandText = theme.colorize(action.command, 'accent');\r\n lines.push(\r\n buildContentLine(\r\n `${continuationIndent}${commandText}`,\r\n vertical,\r\n innerWidth,\r\n colorFn,\r\n theme,\r\n ),\r\n );\r\n }\r\n\r\n // Blank line between actions\r\n lines.push(buildEmptyLine(vertical, innerWidth, colorFn));\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Utility\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Word wrap text to fit within a maximum width.\r\n */\r\nfunction wordWrap(text: string, maxWidth: number): string[] {\r\n if (maxWidth <= 0) return [text];\r\n\r\n const words = text.split(' ');\r\n const lines: string[] = [];\r\n let currentLine = '';\r\n\r\n for (const word of words) {\r\n if (currentLine.length === 0) {\r\n currentLine = word;\r\n } else if (currentLine.length + 1 + word.length <= maxWidth) {\r\n currentLine += ` ${word}`;\r\n } else {\r\n lines.push(currentLine);\r\n currentLine = word;\r\n }\r\n }\r\n\r\n if (currentLine.length > 0) {\r\n lines.push(currentLine);\r\n }\r\n\r\n return lines.length > 0 ? lines : [''];\r\n}\r\n\r\n/**\r\n * Strip ANSI escape codes from a string for accurate length calculation.\r\n */\r\nfunction stripAnsi(text: string): string {\r\n // eslint-disable-next-line no-control-regex\r\n return text.replace(/\\x1b\\[[0-9;]*m/g, '');\r\n}\r\n","/**\r\n * Installation Engine - Category Filter\r\n *\r\n * Defines install categories and provides functions to filter file mappings\r\n * by category selection, supporting the granular `--overwrite` workflow.\r\n *\r\n * @module engine/category-filter\r\n */\r\n\r\nimport type { FileMapping } from './types.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Install Category Type\r\n// ---------------------------------------------------------------------------\r\n\r\n/** A category of installable files. */\r\nexport interface InstallCategory {\r\n /** Unique identifier used in `--overwrite` flags. */\r\n readonly id: string;\r\n /** Human-readable label for UI display. */\r\n readonly label: string;\r\n /** Short description shown alongside the label. */\r\n readonly hint: string;\r\n /** Path prefix used to match file mappings to this category. */\r\n readonly pathPrefix: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Install Categories\r\n// ---------------------------------------------------------------------------\r\n\r\n/** All recognised install categories with their path prefixes. */\r\nexport const INSTALL_CATEGORIES: readonly InstallCategory[] = [\r\n { id: 'agents', pathPrefix: 'agents/', label: 'Agents', hint: 'AI agent definitions' },\r\n { id: 'commands/ai-dlc', pathPrefix: 'commands/ai-dlc/', label: 'Commands: AI-DLC', hint: 'AI-DLC lifecycle commands' },\r\n { id: 'commands/brn', pathPrefix: 'commands/brn/', label: 'Commands: Brownfield', hint: 'Brownfield refactoring commands' },\r\n { id: 'commands/docs', pathPrefix: 'commands/docs/', label: 'Commands: Docs', hint: 'Documentation commands' },\r\n { id: 'commands/elicit', pathPrefix: 'commands/elicit/', label: 'Commands: Elicit', hint: 'Elicitation commands' },\r\n { id: 'commands/git', pathPrefix: 'commands/git/', label: 'Commands: Git', hint: 'Git workflow commands' },\r\n { id: 'commands/spec', pathPrefix: 'commands/spec/', label: 'Commands: Spec', hint: 'Specification commands' },\r\n { id: 'commands/task', pathPrefix: 'commands/task/', label: 'Commands: Task', hint: 'Task management commands' },\r\n { id: 'commands/worktree', pathPrefix: 'commands/worktree/', label: 'Commands: Worktree', hint: 'Worktree management commands' },\r\n { id: 'skills', pathPrefix: 'skills/', label: 'Skills', hint: 'Reusable skill definitions' },\r\n { id: 'templates', pathPrefix: 'templates/', label: 'Templates', hint: 'Project templates' },\r\n { id: 'scripts', pathPrefix: 'scripts/', label: 'Scripts', hint: 'Utility scripts' },\r\n { id: 'docs', pathPrefix: 'docs/', label: 'Documentation', hint: 'Framework documentation' },\r\n { id: 'ai-dlc', pathPrefix: 'ai-dlc/', label: 'AI-DLC Core', hint: 'Core AI-DLC framework files' },\r\n { id: 'memory', pathPrefix: 'memory/', label: 'Memory', hint: 'Memory templates' },\r\n] as const;\r\n\r\n// ---------------------------------------------------------------------------\r\n// Filter Functions\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Filters file mappings to only include files belonging to the specified\r\n * categories. A file matches a category when its `relativePath` (normalised\r\n * to forward slashes) starts with the category's `pathPrefix`.\r\n *\r\n * @param mappings - The full set of file mappings from the source scan.\r\n * @param categories - Category IDs to include (must match `InstallCategory.id`).\r\n * @returns A subset of `mappings` whose relative paths match a selected category.\r\n */\r\nexport function filterMappingsByCategories(\r\n mappings: FileMapping[],\r\n categories: string[],\r\n): FileMapping[] {\r\n const prefixes = INSTALL_CATEGORIES\r\n .filter((cat) => categories.includes(cat.id))\r\n .map((cat) => cat.pathPrefix);\r\n\r\n if (prefixes.length === 0) {\r\n return [];\r\n }\r\n\r\n return mappings.filter((mapping) => {\r\n const normalised = mapping.relativePath.replace(/\\\\/g, '/');\r\n return prefixes.some((prefix) => normalised.startsWith(prefix));\r\n });\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Resolution / Validation\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Validates `--overwrite` flag values against known categories and returns\r\n * the resolved list of category IDs.\r\n *\r\n * @param overwriteFlags - Raw values passed via `--overwrite` CLI flags.\r\n * @returns An array of validated category IDs.\r\n * @throws {Error} If any flag value does not match a known category ID.\r\n */\r\nexport function resolveCategories(overwriteFlags: string[]): string[] {\r\n const validIds = INSTALL_CATEGORIES.map((cat) => cat.id);\r\n const unknown = overwriteFlags.filter((flag) => !validIds.includes(flag));\r\n\r\n if (unknown.length > 0) {\r\n throw new Error(\r\n `Unknown overwrite categories: ${unknown.join(', ')}. ` +\r\n `Valid categories are: ${validIds.join(', ')}`,\r\n );\r\n }\r\n\r\n return [...overwriteFlags];\r\n}\r\n","/**\r\n * Summary Screen Component - Post-installation summary display.\r\n *\r\n * Renders installation results with a success/failure header, component\r\n * counts, file statistics, elapsed time, and numbered next-step guidance.\r\n * Adapts layout and styling to the active rendering tier.\r\n *\r\n * @module ui/summary\r\n */\r\n\r\nimport type {\r\n ComponentCounts,\r\n Duration,\r\n InstallationSummary,\r\n NextStep,\r\n} from './types.js';\r\nimport { totalComponentCount } from './types.js';\r\nimport { ThemeEngine } from './theme.js';\r\nimport type { CategoryConflictSummary } from '../engine/conflict-detector.js';\r\nimport { INSTALL_CATEGORIES } from '../engine/category-filter.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Summary Rendering\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Optional category installation details for the summary screen. */\r\nexport interface CategoryInstallInfo {\r\n /** IDs of categories that were selected for installation. */\r\n readonly installedCategories: string[];\r\n /** Per-category file statistics (from conflict detection). */\r\n readonly categoryStats?: CategoryConflictSummary[];\r\n}\r\n\r\n/**\r\n * Render the post-installation summary screen.\r\n *\r\n * @param summary - Installation result data\r\n * @param nextSteps - Ordered list of next-step guidance\r\n * @param theme - ThemeEngine for colors, symbols, and terminal width\r\n * @param categoryInfo - Optional category installation details\r\n * @returns Array of output lines\r\n */\r\nexport function renderSummary(\r\n summary: InstallationSummary,\r\n nextSteps: readonly NextStep[],\r\n theme: ThemeEngine,\r\n categoryInfo?: CategoryInstallInfo,\r\n): string[] {\r\n const width = theme.terminalWidth;\r\n const lines: string[] = [];\r\n\r\n // Header box\r\n lines.push(...renderHeaderBox(summary, theme, width));\r\n lines.push('');\r\n\r\n // Target directory\r\n const dirLabel = summary.success ? 'Installed to:' : 'Target directory:';\r\n lines.push(` ${dirLabel} ${theme.colorize(summary.targetDirectory, 'accent')}`);\r\n lines.push('');\r\n\r\n // Installed categories (when selective installation was used)\r\n if (categoryInfo && categoryInfo.installedCategories.length > 0) {\r\n lines.push(...renderInstalledCategories(categoryInfo, theme));\r\n lines.push('');\r\n }\r\n\r\n // Component counts (only on success or partial success)\r\n if (summary.success || summary.totalFilesCopied > 0) {\r\n lines.push(...renderComponentCounts(summary.componentCounts, theme));\r\n lines.push('');\r\n }\r\n\r\n // File statistics\r\n lines.push(...renderFileStatistics(summary, theme));\r\n lines.push('');\r\n\r\n // Total time\r\n lines.push(` Total time: ${theme.bold(summary.totalDuration.formatted)}`);\r\n lines.push('');\r\n\r\n // Divider\r\n lines.push(renderDivider(theme, width));\r\n lines.push('');\r\n\r\n // Next steps\r\n if (nextSteps.length > 0) {\r\n lines.push(...renderNextSteps(nextSteps, theme));\r\n lines.push('');\r\n lines.push(renderDivider(theme, width));\r\n }\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Header Box\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render the success/failure header box with double-line borders.\r\n */\r\nfunction renderHeaderBox(\r\n summary: InstallationSummary,\r\n theme: ThemeEngine,\r\n width: number,\r\n): string[] {\r\n const symbols = theme.symbolSet;\r\n const boxWidth = Math.min(width - 4, 72);\r\n const innerWidth = boxWidth - 4;\r\n\r\n // Determine header content and color\r\n let statusSymbol: string;\r\n let title: string;\r\n let colorName: 'success' | 'error' | 'warning';\r\n\r\n if (summary.success && summary.totalFilesFailed === 0) {\r\n statusSymbol = theme.statusSymbol('completed');\r\n title = 'Installation Complete!';\r\n colorName = 'success';\r\n } else if (summary.success && summary.totalFilesFailed > 0) {\r\n statusSymbol = theme.tier === 'plain' ? '[!]' : '\\u26A0';\r\n title = 'Installation Completed with Warnings';\r\n colorName = 'warning';\r\n } else {\r\n statusSymbol = theme.statusSymbol('failed');\r\n title = 'Installation Failed';\r\n colorName = 'error';\r\n }\r\n\r\n const colorFn = (text: string): string => theme.colorize(text, colorName);\r\n\r\n const lines: string[] = [];\r\n\r\n // Top border\r\n const topBorder = `${symbols.doubleTopLeft}${symbols.doubleHorizontal.repeat(boxWidth - 2)}${symbols.doubleTopRight}`;\r\n lines.push(` ${colorFn(topBorder)}`);\r\n\r\n // Empty line\r\n const emptyLine = `${symbols.doubleVertical}${' '.repeat(boxWidth - 2)}${symbols.doubleVertical}`;\r\n lines.push(` ${colorFn(emptyLine)}`);\r\n\r\n // Title line (centered)\r\n const titleContent = `${statusSymbol} ${theme.bold(colorFn(title))}`;\r\n const strippedTitleLength = stripAnsi(titleContent).length;\r\n const leftPad = Math.max(0, Math.floor((innerWidth - strippedTitleLength) / 2));\r\n const rightPad = Math.max(0, innerWidth - strippedTitleLength - leftPad);\r\n const titleLine = `${symbols.doubleVertical} ${' '.repeat(leftPad)}${titleContent}${' '.repeat(rightPad)} ${symbols.doubleVertical}`;\r\n lines.push(` ${colorFn(symbols.doubleVertical)} ${' '.repeat(leftPad)}${titleContent}${' '.repeat(rightPad)} ${colorFn(symbols.doubleVertical)}`);\r\n\r\n // Empty line\r\n lines.push(` ${colorFn(emptyLine)}`);\r\n\r\n // Bottom border\r\n const bottomBorder = `${symbols.doubleBottomLeft}${symbols.doubleHorizontal.repeat(boxWidth - 2)}${symbols.doubleBottomRight}`;\r\n lines.push(` ${colorFn(bottomBorder)}`);\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Component Counts\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render component counts as a bulleted list.\r\n */\r\nfunction renderComponentCounts(\r\n counts: ComponentCounts,\r\n theme: ThemeEngine,\r\n): string[] {\r\n const bullet = theme.symbolSet.bullet;\r\n const lines: string[] = [];\r\n\r\n lines.push(` ${theme.bold(theme.colorize('Components installed:', 'header'))}`);\r\n\r\n const items: Array<{ label: string; count: number }> = [\r\n { label: 'agents', count: counts.agents },\r\n { label: 'skill files', count: counts.skills },\r\n { label: 'commands', count: counts.commands },\r\n { label: 'TypeScript CLI files', count: counts.cliFiles },\r\n { label: 'other files', count: counts.other },\r\n ];\r\n\r\n for (const item of items) {\r\n if (item.count > 0) {\r\n const countStr = theme.colorize(String(item.count), 'accent');\r\n lines.push(` ${bullet} ${countStr} ${item.label}`);\r\n }\r\n }\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Installed Categories\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render installed categories as a bulleted list with file counts.\r\n */\r\nfunction renderInstalledCategories(\r\n categoryInfo: CategoryInstallInfo,\r\n theme: ThemeEngine,\r\n): string[] {\r\n const bullet = theme.symbolSet.bullet;\r\n const lines: string[] = [];\r\n\r\n lines.push(` ${theme.bold(theme.colorize('Categories installed:', 'header'))}`);\r\n\r\n // Build a stats lookup from the optional conflict summaries\r\n const statsMap = new Map<string, CategoryConflictSummary>();\r\n if (categoryInfo.categoryStats) {\r\n for (const stat of categoryInfo.categoryStats) {\r\n statsMap.set(stat.categoryId, stat);\r\n }\r\n }\r\n\r\n for (const catId of categoryInfo.installedCategories) {\r\n // Find the category definition for its label\r\n const catDef = INSTALL_CATEGORIES.find((c) => c.id === catId);\r\n const label = catDef?.label ?? catId;\r\n\r\n const stat = statsMap.get(catId);\r\n if (stat) {\r\n const countStr = theme.colorize(String(stat.totalFiles), 'accent');\r\n lines.push(` ${bullet} ${label}: ${countStr} files`);\r\n } else {\r\n lines.push(` ${bullet} ${label}`);\r\n }\r\n }\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// File Statistics\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render file copy statistics with status symbols.\r\n */\r\nfunction renderFileStatistics(\r\n summary: InstallationSummary,\r\n theme: ThemeEngine,\r\n): string[] {\r\n const lines: string[] = [];\r\n\r\n lines.push(` ${theme.bold(theme.colorize('File statistics:', 'header'))}`);\r\n\r\n // Copied\r\n const copiedSymbol = theme.statusSymbol('completed');\r\n lines.push(` ${copiedSymbol} ${summary.totalFilesCopied} files copied successfully`);\r\n\r\n // Skipped\r\n const skippedSymbol = theme.statusSymbol('skipped');\r\n if (summary.totalFilesSkipped > 0) {\r\n lines.push(\r\n ` ${skippedSymbol} ${summary.totalFilesSkipped} files skipped (already up-to-date)`,\r\n );\r\n }\r\n\r\n // Failed\r\n const failedSymbol = theme.statusSymbol('failed');\r\n const failedText = summary.totalFilesFailed > 0\r\n ? `${summary.totalFilesFailed} files failed`\r\n : '0 files failed';\r\n lines.push(` ${failedSymbol} ${failedText}`);\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Next Steps\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render numbered next-step guidance with optional copyable commands.\r\n */\r\nfunction renderNextSteps(\r\n steps: readonly NextStep[],\r\n theme: ThemeEngine,\r\n): string[] {\r\n const lines: string[] = [];\r\n\r\n lines.push(` ${theme.bold(theme.colorize('Next steps:', 'header'))}`);\r\n lines.push('');\r\n\r\n for (const step of steps) {\r\n // Numbered title\r\n lines.push(` ${step.order}. ${step.title}:`);\r\n\r\n // Instruction or command\r\n if (step.command) {\r\n lines.push(` ${theme.colorize(step.command, 'accent')}`);\r\n } else {\r\n lines.push(` ${step.instruction}`);\r\n }\r\n\r\n lines.push('');\r\n }\r\n\r\n return lines;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Divider\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Render a horizontal divider line.\r\n */\r\nfunction renderDivider(theme: ThemeEngine, width: number): string {\r\n const dividerWidth = Math.min(width - 4, 72);\r\n const char = theme.symbolSet.boxHorizontal;\r\n return ` ${theme.dim(char.repeat(dividerWidth))}`;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Utility\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Strip ANSI escape codes from a string for accurate length calculation.\r\n */\r\nfunction stripAnsi(text: string): string {\r\n // eslint-disable-next-line no-control-regex\r\n return text.replace(/\\x1b\\[[0-9;]*m/g, '');\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Default Next Steps\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Generate default next-step guidance based on installation result.\r\n */\r\nexport function getDefaultNextSteps(success: boolean): NextStep[] {\r\n if (success) {\r\n return [\r\n {\r\n order: 1,\r\n title: 'Verify the installation',\r\n instruction: 'Run the status command to verify',\r\n command: 'ai-dlc status',\r\n },\r\n {\r\n order: 2,\r\n title: 'Start your first AI-DLC project',\r\n instruction: 'Create an intent to begin',\r\n command: 'ai-dlc start-intent \"Your project idea\"',\r\n },\r\n {\r\n order: 3,\r\n title: 'View available commands',\r\n instruction: 'See all available commands',\r\n command: 'ai-dlc help',\r\n },\r\n {\r\n order: 4,\r\n title: 'Read the documentation',\r\n instruction: 'Visit the documentation site',\r\n command: 'https://github.com/SixSevenAI/ai-dlc/docs',\r\n },\r\n ];\r\n }\r\n\r\n return [\r\n {\r\n order: 1,\r\n title: 'Review the error messages above',\r\n instruction: 'Identify the root cause of the failure',\r\n command: null,\r\n },\r\n {\r\n order: 2,\r\n title: 'Fix the underlying issue',\r\n instruction: 'Address permissions, disk space, or network issues',\r\n command: null,\r\n },\r\n {\r\n order: 3,\r\n title: 'Run the installer again',\r\n instruction: 'Retry the installation',\r\n command: 'npx @sixsevenai/ai-dlc install',\r\n },\r\n {\r\n order: 4,\r\n title: 'Get help',\r\n instruction: 'Report an issue on GitHub',\r\n command: 'https://github.com/SixSevenAI/ai-dlc/issues',\r\n },\r\n ];\r\n}\r\n","/**\r\n * SixSeven Animation Module\r\n *\r\n * Provides a terminal spinner with a bouncing/wave animation between\r\n * the digits 6 and 7 — the SixSevenAI brand motif. Supports plain\r\n * text mode (hidden cursor, frame cycling) and a progress-bar variant\r\n * for long-running file-copy operations.\r\n *\r\n * All output goes to `process.stderr` so it never contaminates stdout\r\n * piping. In non-TTY / quiet mode every method is a silent no-op.\r\n *\r\n * @module ui/sixseven-animation\r\n */\r\n\r\n// ---------------------------------------------------------------------------\r\n// Animation Frames\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Six frames depicting two dots bouncing between the digits 6 and 7.\r\n * Every frame is exactly 15 characters wide so the line stays stable.\r\n */\r\nconst FRAMES = [\r\n ' 6 * 7 ',\r\n ' 6 * 7 ',\r\n ' 6 * 7 ',\r\n ' 6 * 7 ',\r\n ' 6 * 7 ',\r\n ' 6 * 7 ',\r\n];\r\n\r\n// ---------------------------------------------------------------------------\r\n// Progress Bar Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\nconst BAR_WIDTH = 20;\r\n\r\nfunction renderBar(current: number, total: number): string {\r\n const ratio = total > 0 ? Math.min(current / total, 1) : 0;\r\n const filled = Math.round(ratio * BAR_WIDTH);\r\n const empty = BAR_WIDTH - filled;\r\n return '\\u2588'.repeat(filled) + '\\u2591'.repeat(empty);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// SixSevenSpinner\r\n// ---------------------------------------------------------------------------\r\n\r\nexport class SixSevenSpinner {\r\n private intervalId: ReturnType<typeof setInterval> | null = null;\r\n private frameIndex = 0;\r\n private message = '';\r\n private isActive = false;\r\n private readonly isSilent: boolean;\r\n\r\n constructor(options?: { quiet?: boolean }) {\r\n this.isSilent = options?.quiet ?? !process.stderr.isTTY;\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Public API\r\n // -------------------------------------------------------------------------\r\n\r\n /**\r\n * Start the spinner animation with an initial message.\r\n */\r\n start(message: string): void {\r\n if (this.isSilent) return;\r\n if (this.isActive) return;\r\n\r\n this.message = message;\r\n this.frameIndex = 0;\r\n this.isActive = true;\r\n\r\n // Hide cursor\r\n process.stderr.write('\\x1b[?25l');\r\n\r\n this.render();\r\n this.intervalId = setInterval(() => {\r\n this.frameIndex = (this.frameIndex + 1) % FRAMES.length;\r\n this.render();\r\n }, 150);\r\n }\r\n\r\n /**\r\n * Update the message text displayed alongside the animation.\r\n */\r\n update(message: string): void {\r\n if (this.isSilent) return;\r\n this.message = message;\r\n }\r\n\r\n /**\r\n * Update with a progress bar showing current/total and a category label.\r\n *\r\n * Renders: ` 6 * 7 [████░░░░] 12/48 Installing agents...`\r\n */\r\n updateProgress(current: number, total: number, category: string): void {\r\n if (this.isSilent) return;\r\n const bar = renderBar(current, total);\r\n const counter = `${current}/${total}`.padStart(String(total).length * 2 + 1);\r\n this.message = `[${bar}] ${counter} ${category}`;\r\n }\r\n\r\n /**\r\n * Stop the spinner, display a final message with a checkmark, and\r\n * restore the cursor.\r\n */\r\n stop(finalMessage: string): void {\r\n if (this.isSilent) return;\r\n\r\n if (this.intervalId !== null) {\r\n clearInterval(this.intervalId);\r\n this.intervalId = null;\r\n }\r\n\r\n this.isActive = false;\r\n\r\n // Clear line, write final message, restore cursor\r\n process.stderr.write(`\\r\\x1b[K \\x1b[32m\\u2714\\x1b[0m ${finalMessage}\\n`);\r\n process.stderr.write('\\x1b[?25h');\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Internal\r\n // -------------------------------------------------------------------------\r\n\r\n private render(): void {\r\n const frame = FRAMES[this.frameIndex];\r\n process.stderr.write(`\\r\\x1b[K${frame} ${this.message}`);\r\n }\r\n}\r\n","/**\r\n * CLI Orchestrator - Error Handler\r\n *\r\n * Centralized error classification, recovery strategy selection, and\r\n * actionable message generation. Provides rollback coordination when\r\n * fatal errors occur during installation.\r\n *\r\n * @module orchestrator/error-handler\r\n */\r\n\r\nimport type {\r\n ClassifiedError,\r\n ErrorCategory,\r\n ErrorSeverity,\r\n ErrorSummaryInfo,\r\n ExitCode,\r\n RecoveryAction,\r\n RecoveryStrategy,\r\n WorkflowState,\r\n WorkflowStepId,\r\n} from './types.js';\r\nimport {\r\n EXIT_SUCCESS,\r\n EXIT_ERROR,\r\n EXIT_CANCELLED,\r\n} from './types.js';\r\n\r\nimport { UserCancellationError } from '../ui/index.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Constants\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Maximum number of retries per step. */\r\nconst MAX_RETRIES = 2;\r\n\r\n/** Counter for generating unique error IDs. */\r\nlet errorCounter = 0;\r\n\r\n// ---------------------------------------------------------------------------\r\n// ErrorHandler\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Centralized error classification and recovery coordinator.\r\n *\r\n * Catches errors from any subsystem, classifies them by category and\r\n * severity, determines the appropriate recovery strategy, and produces\r\n * actionable user-facing messages.\r\n */\r\nexport class ErrorHandler {\r\n private readonly errors: ClassifiedError[] = [];\r\n private readonly retryCounts: Map<WorkflowStepId, number> = new Map();\r\n\r\n /**\r\n * Classify an error and determine the recovery action.\r\n *\r\n * @param error - Raw error from any subsystem\r\n * @param stepId - The workflow step where the error occurred\r\n * @returns Recovery action to take\r\n */\r\n handleError(error: Error, stepId: WorkflowStepId): RecoveryAction {\r\n const category = classifyCategory(error);\r\n const severity = classifySeverity(category);\r\n const recoveryStrategy = selectRecoveryStrategy(category, severity, this.canRetry(stepId));\r\n\r\n const classified: ClassifiedError = {\r\n errorId: `err-${++errorCounter}`,\r\n originalError: error,\r\n category,\r\n severity,\r\n sourceStep: stepId,\r\n recoveryStrategy,\r\n retryCount: this.getRetryCount(stepId),\r\n timestamp: new Date(),\r\n userMessage: buildUserMessage(category, error),\r\n technicalDetail: error.stack ?? error.message,\r\n };\r\n\r\n this.errors.push(classified);\r\n\r\n return {\r\n strategy: recoveryStrategy,\r\n stepId,\r\n userGuidance: buildUserGuidance(category, error),\r\n platformGuidance: buildPlatformGuidance(category),\r\n };\r\n }\r\n\r\n /**\r\n * Check whether the specified step can be retried.\r\n */\r\n canRetry(stepId: WorkflowStepId): boolean {\r\n return this.getRetryCount(stepId) < MAX_RETRIES;\r\n }\r\n\r\n /**\r\n * Record a retry attempt for a step.\r\n */\r\n recordRetry(stepId: WorkflowStepId): void {\r\n const current = this.retryCounts.get(stepId) ?? 0;\r\n this.retryCounts.set(stepId, current + 1);\r\n }\r\n\r\n /**\r\n * Get the current retry count for a step.\r\n */\r\n getRetryCount(stepId: WorkflowStepId): number {\r\n return this.retryCounts.get(stepId) ?? 0;\r\n }\r\n\r\n /**\r\n * Check if the workflow should abort due to accumulated errors.\r\n */\r\n shouldAbort(): boolean {\r\n return this.errors.some(e => e.severity === 'Fatal');\r\n }\r\n\r\n /**\r\n * Get a summary of all accumulated errors.\r\n */\r\n getErrorSummary(): ErrorSummaryInfo {\r\n const fatalCount = this.errors.filter(e => e.severity === 'Fatal').length;\r\n const recoverableCount = this.errors.filter(e => e.severity === 'Recoverable').length;\r\n const warningCount = this.errors.filter(e => e.severity === 'Warning').length;\r\n\r\n return {\r\n totalErrors: this.errors.length,\r\n fatalCount,\r\n recoverableCount,\r\n warningCount,\r\n messages: this.errors.map(e => e.userMessage),\r\n };\r\n }\r\n\r\n /**\r\n * Determine the appropriate exit code based on workflow state and errors.\r\n */\r\n getExitCode(workflow: WorkflowState): ExitCode {\r\n if (workflow.status === 'cancelled') {\r\n return EXIT_CANCELLED;\r\n }\r\n\r\n if (workflow.status === 'failed') {\r\n return EXIT_ERROR;\r\n }\r\n\r\n if (this.errors.some(e => e.severity === 'Fatal')) {\r\n return EXIT_ERROR;\r\n }\r\n\r\n return EXIT_SUCCESS;\r\n }\r\n\r\n /**\r\n * Get all classified errors for inspection.\r\n */\r\n getErrors(): readonly ClassifiedError[] {\r\n return this.errors;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Classification Functions\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Classify the error category based on error type and message patterns.\r\n */\r\nfunction classifyCategory(error: Error): ErrorCategory {\r\n if (error instanceof UserCancellationError || error.name === 'UserCancellationError') {\r\n return 'Cancellation';\r\n }\r\n\r\n const message = error.message.toLowerCase();\r\n const code = (error as NodeJS.ErrnoException).code;\r\n\r\n // Permission errors\r\n if (code === 'EACCES' || code === 'EPERM' || message.includes('permission denied')) {\r\n return 'Permission';\r\n }\r\n\r\n // Disk space errors\r\n if (code === 'ENOSPC' || message.includes('disk full') || message.includes('no space')) {\r\n return 'DiskSpace';\r\n }\r\n\r\n // Path errors\r\n if (\r\n code === 'ENOENT' ||\r\n code === 'ENOTDIR' ||\r\n message.includes('invalid path') ||\r\n message.includes('not a directory') ||\r\n message.includes('does not exist')\r\n ) {\r\n return 'InvalidPath';\r\n }\r\n\r\n // Runtime version\r\n if (\r\n message.includes('node.js') ||\r\n message.includes('node version') ||\r\n message.includes('npm') ||\r\n message.includes('minimum required')\r\n ) {\r\n return 'RuntimeVersion';\r\n }\r\n\r\n // Validation failures\r\n if (\r\n message.includes('validation') ||\r\n message.includes('missing files') ||\r\n message.includes('corrupt')\r\n ) {\r\n return 'ValidationFailure';\r\n }\r\n\r\n // Integrity errors\r\n if (\r\n message.includes('integrity') ||\r\n message.includes('hash') ||\r\n message.includes('source directory')\r\n ) {\r\n return 'IntegrityError';\r\n }\r\n\r\n // Conflict resolution\r\n if (message.includes('conflict') || message.includes('overwrite')) {\r\n return 'ConflictResolution';\r\n }\r\n\r\n return 'InternalError';\r\n}\r\n\r\n/**\r\n * Map error category to severity level.\r\n */\r\nfunction classifySeverity(category: ErrorCategory): ErrorSeverity {\r\n switch (category) {\r\n case 'Cancellation':\r\n return 'Fatal';\r\n case 'DiskSpace':\r\n return 'Fatal';\r\n case 'IntegrityError':\r\n return 'Fatal';\r\n case 'RuntimeVersion':\r\n return 'Fatal';\r\n case 'Permission':\r\n return 'Recoverable';\r\n case 'InvalidPath':\r\n return 'Recoverable';\r\n case 'ConflictResolution':\r\n return 'Recoverable';\r\n case 'ValidationFailure':\r\n return 'Fatal';\r\n case 'InternalError':\r\n return 'Fatal';\r\n }\r\n}\r\n\r\n/**\r\n * Select the appropriate recovery strategy.\r\n */\r\nfunction selectRecoveryStrategy(\r\n category: ErrorCategory,\r\n severity: ErrorSeverity,\r\n canRetry: boolean,\r\n): RecoveryStrategy {\r\n if (category === 'Cancellation') {\r\n return 'AbortImmediately';\r\n }\r\n\r\n if (severity === 'Fatal') {\r\n return 'RollbackAndAbort';\r\n }\r\n\r\n if (severity === 'Recoverable' && canRetry) {\r\n return 'PromptUser';\r\n }\r\n\r\n if (severity === 'Recoverable') {\r\n return 'RollbackAndAbort';\r\n }\r\n\r\n return 'SkipAndContinue';\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Message Builders\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction buildUserMessage(category: ErrorCategory, error: Error): string {\r\n switch (category) {\r\n case 'Permission':\r\n return `Permission denied: ${error.message}`;\r\n case 'DiskSpace':\r\n return `Insufficient disk space: ${error.message}`;\r\n case 'InvalidPath':\r\n return `Invalid path: ${error.message}`;\r\n case 'RuntimeVersion':\r\n return `Runtime requirement not met: ${error.message}`;\r\n case 'ValidationFailure':\r\n return `Installation validation failed: ${error.message}`;\r\n case 'IntegrityError':\r\n return `Source integrity error: ${error.message}`;\r\n case 'ConflictResolution':\r\n return `Conflict resolution failed: ${error.message}`;\r\n case 'Cancellation':\r\n return 'Installation cancelled by user.';\r\n case 'InternalError':\r\n return `Unexpected error: ${error.message}`;\r\n }\r\n}\r\n\r\nfunction buildUserGuidance(category: ErrorCategory, error: Error): string {\r\n switch (category) {\r\n case 'Permission':\r\n return 'Run the installer with elevated permissions or choose a different target directory.';\r\n case 'DiskSpace':\r\n return 'Free up disk space and try again.';\r\n case 'InvalidPath':\r\n return 'Check that the target directory path is valid and the parent directory exists.';\r\n case 'RuntimeVersion':\r\n return 'Upgrade Node.js to version 18 or later. Visit https://nodejs.org/';\r\n case 'ValidationFailure':\r\n return 'Try running the installer again. If the problem persists, check file permissions.';\r\n case 'IntegrityError':\r\n return 'The AI-DLC library source may be corrupted. Re-clone the repository or re-install the package.';\r\n case 'ConflictResolution':\r\n return 'Use --force to overwrite existing files, or manually resolve conflicts.';\r\n case 'Cancellation':\r\n return 'Installation was cancelled. No changes were made.';\r\n case 'InternalError':\r\n return 'This is an unexpected error. Please report it with the --verbose output.';\r\n }\r\n}\r\n\r\nfunction buildPlatformGuidance(category: ErrorCategory): string | null {\r\n switch (category) {\r\n case 'Permission':\r\n return process.platform === 'win32'\r\n ? 'Right-click your terminal and select \"Run as Administrator\".'\r\n : 'Prefix the command with sudo: sudo sixsevenai install';\r\n default:\r\n return null;\r\n }\r\n}\r\n","/**\r\n * Platform Abstraction Layer - Shared Types\r\n *\r\n * All immutable value objects, enumerations, branded types, and interfaces\r\n * used throughout the platform detection subsystem.\r\n *\r\n * @module platform/types\r\n */\r\n\r\n// ---------------------------------------------------------------------------\r\n// Branded Type: NormalizedPath\r\n// ---------------------------------------------------------------------------\r\n\r\ndeclare const NormalizedPathBrand: unique symbol;\r\n\r\n/**\r\n * A branded string type representing a normalized file system path.\r\n * Internally always uses forward slashes. Created only through\r\n * PathNormalizer methods to enforce normalization invariants.\r\n */\r\nexport type NormalizedPath = string & {\r\n readonly [NormalizedPathBrand]: typeof NormalizedPathBrand;\r\n};\r\n\r\n/**\r\n * Cast a raw string to NormalizedPath. Use only in factory methods\r\n * or tests where you know the string is already normalized.\r\n */\r\nexport function createNormalizedPath(value: string): NormalizedPath {\r\n return value as NormalizedPath;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Operating System\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Supported OS family identifiers. */\r\nexport type OsFamily = 'windows' | 'macos' | 'linux';\r\n\r\n/** Supported CPU architectures. */\r\nexport type ArchitectureName = 'x64' | 'arm64' | 'x86';\r\n\r\n/** CPU architecture value object. */\r\nexport interface Architecture {\r\n readonly name: ArchitectureName;\r\n}\r\n\r\n/** Operating system value object. */\r\nexport interface OperatingSystem {\r\n readonly family: OsFamily;\r\n readonly version: string;\r\n readonly release: string;\r\n readonly architecture: Architecture;\r\n}\r\n\r\n/** Resolved user home directory. */\r\nexport interface HomeDirectory {\r\n readonly path: string;\r\n readonly source: 'USERPROFILE' | 'HOME' | 'os.homedir';\r\n}\r\n\r\n/** System temp directory. */\r\nexport interface TempDirectory {\r\n readonly path: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Platform Snapshot\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Complete, immutable snapshot of the host platform. */\r\nexport interface PlatformSnapshot {\r\n readonly os: OperatingSystem;\r\n readonly homeDirectory: HomeDirectory;\r\n readonly tempDirectory: TempDirectory;\r\n readonly detectedAt: Date;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Shell\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Recognized shell types. */\r\nexport type ShellType =\r\n | 'powershell'\r\n | 'cmd'\r\n | 'bash'\r\n | 'zsh'\r\n | 'fish'\r\n | 'unknown';\r\n\r\n/** Basic shell information included in PlatformSnapshot. */\r\nexport interface ShellInfo {\r\n readonly type: ShellType;\r\n readonly version: string | null;\r\n readonly profilePath: string | null;\r\n readonly executablePath: string;\r\n}\r\n\r\n/** Complete shell detection result. */\r\nexport interface ShellEnvironment {\r\n readonly type: ShellType;\r\n readonly version: string | null;\r\n readonly executablePath: string;\r\n readonly profilePath: NormalizedPath | null;\r\n readonly profileExists: boolean;\r\n readonly pathSeparator: ';' | ':';\r\n readonly pathModificationCommand: string | null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Terminal\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Color support tiers, ordered by capability. */\r\nexport enum ColorSupportLevel {\r\n /** No color support (piped output, NO_COLOR set, non-TTY). */\r\n None = 0,\r\n /** 16 colors (basic ANSI). */\r\n Basic = 1,\r\n /** 256 colors (xterm-256color). */\r\n Extended = 2,\r\n /** 16 million colors (24-bit true color). */\r\n TrueColor = 3,\r\n}\r\n\r\n/** Terminal viewport dimensions. */\r\nexport interface TerminalDimensions {\r\n readonly columns: number;\r\n readonly rows: number;\r\n}\r\n\r\n/** Unicode rendering capability. */\r\nexport interface UnicodeSupport {\r\n readonly supported: boolean;\r\n readonly detectionMethod: 'locale' | 'env' | 'terminal' | 'default';\r\n}\r\n\r\n/** Terminal interactivity mode. */\r\nexport interface InteractivityMode {\r\n readonly isInteractive: boolean;\r\n readonly isTTY: boolean;\r\n readonly supportsRawMode: boolean;\r\n}\r\n\r\n/** Identified terminal emulator. */\r\nexport interface TerminalEmulator {\r\n readonly name: string | null;\r\n readonly version: string | null;\r\n readonly isKnown: boolean;\r\n}\r\n\r\n/** Complete terminal capability profile. */\r\nexport interface TerminalProfile {\r\n readonly colorSupport: ColorSupportLevel;\r\n readonly dimensions: TerminalDimensions;\r\n readonly unicodeSupport: UnicodeSupport;\r\n readonly interactivity: InteractivityMode;\r\n readonly emulator: TerminalEmulator;\r\n readonly detectedAt: Date;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Permissions\r\n// ---------------------------------------------------------------------------\r\n\r\n/** File access modes for permission checking. */\r\nexport enum AccessMode {\r\n Read = 'read',\r\n Write = 'write',\r\n Execute = 'execute',\r\n ReadWrite = 'readwrite',\r\n}\r\n\r\n/** Platform-specific guidance for obtaining elevated privileges. */\r\nexport interface ElevationInstructions {\r\n readonly platform: OsFamily;\r\n readonly command: string;\r\n readonly description: string;\r\n readonly shellSpecificHint: string | null;\r\n}\r\n\r\n/** Result of a permission check on a specific path. */\r\nexport interface PermissionResult {\r\n readonly targetPath: NormalizedPath;\r\n readonly canRead: boolean;\r\n readonly canWrite: boolean;\r\n readonly canExecute: boolean;\r\n readonly exists: boolean;\r\n readonly isDirectory: boolean;\r\n readonly requiresElevation: boolean;\r\n readonly elevationInstructions: ElevationInstructions | null;\r\n readonly checkedAt: Date;\r\n}\r\n\r\n/** Symlink creation capability. */\r\nexport interface SymlinkCapability {\r\n readonly supported: boolean;\r\n readonly requiresDeveloperMode: boolean;\r\n readonly requiresElevation: boolean;\r\n readonly instructions: string | null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Runtime Validation\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Parsed semantic version for comparison. */\r\nexport interface SemVer {\r\n readonly major: number;\r\n readonly minor: number;\r\n readonly patch: number;\r\n readonly raw: string;\r\n}\r\n\r\n/** A detected runtime tool with its version. */\r\nexport interface RuntimeVersion {\r\n readonly tool: 'node' | 'npm' | 'npx' | 'git';\r\n readonly version: SemVer;\r\n readonly executablePath: string;\r\n readonly meetsMinimum: boolean;\r\n readonly minimumRequired: SemVer;\r\n}\r\n\r\n/** The directory where npm installs global package executables. */\r\nexport interface GlobalBinDirectory {\r\n readonly path: NormalizedPath;\r\n readonly isOnPath: boolean;\r\n readonly pathFixCommand: string | null;\r\n}\r\n\r\n/** Runtime validation error types. */\r\nexport type RuntimeErrorType = 'not_found' | 'version_too_low' | 'not_on_path';\r\n\r\n/** A specific runtime validation failure. */\r\nexport interface RuntimeError {\r\n readonly tool: string;\r\n readonly errorType: RuntimeErrorType;\r\n readonly message: string;\r\n readonly fix: string;\r\n}\r\n\r\n/** Complete runtime validation result. */\r\nexport interface RuntimeReport {\r\n readonly node: RuntimeVersion;\r\n readonly npm: RuntimeVersion | null;\r\n readonly git: RuntimeVersion | null;\r\n readonly globalBinDir: GlobalBinDirectory | null;\r\n readonly allRequirementsMet: boolean;\r\n readonly errors: readonly RuntimeError[];\r\n readonly validatedAt: Date;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Composite: PlatformEnvironment\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Complete platform environment returned by IPlatformFacade.detectAll(). */\r\nexport interface PlatformEnvironment {\r\n readonly platform: PlatformSnapshot;\r\n readonly terminal: TerminalProfile;\r\n readonly shell: ShellEnvironment;\r\n readonly runtime: RuntimeReport;\r\n readonly permissions: {\r\n checkWriteAccess(path: NormalizedPath): Promise<PermissionResult>;\r\n checkDirectoryCreatable(path: NormalizedPath): Promise<PermissionResult>;\r\n };\r\n readonly paths: IPathNormalizer;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Disposable\r\n// ---------------------------------------------------------------------------\r\n\r\n/** A resource that can be disposed to release subscriptions. */\r\nexport interface Disposable {\r\n dispose(): void;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Interfaces (Ports)\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Detects the host operating system, architecture, and directories. */\r\nexport interface IPlatformDetector {\r\n detect(): PlatformSnapshot;\r\n}\r\n\r\n/** Stateless path manipulation utility. */\r\nexport interface IPathNormalizer {\r\n normalize(rawPath: string, os: OperatingSystem): NormalizedPath;\r\n toNative(path: NormalizedPath, os: OperatingSystem): string;\r\n resolveHome(path: string, homeDir: HomeDirectory): NormalizedPath;\r\n toAbsolute(path: NormalizedPath, basePath: NormalizedPath): NormalizedPath;\r\n toRelative(path: NormalizedPath, basePath: NormalizedPath): NormalizedPath;\r\n join(base: NormalizedPath, ...segments: string[]): NormalizedPath;\r\n parent(path: NormalizedPath): NormalizedPath | null;\r\n extension(path: NormalizedPath): string | null;\r\n getDefaultClaudeDir(homeDir: HomeDirectory, os: OperatingSystem): NormalizedPath;\r\n}\r\n\r\n/** Checks file system permissions and elevation status. */\r\nexport interface IPermissionChecker {\r\n checkAccess(\r\n path: NormalizedPath,\r\n desiredAccess: AccessMode,\r\n platform: PlatformSnapshot,\r\n ): Promise<PermissionResult>;\r\n checkWriteAccess(\r\n path: NormalizedPath,\r\n platform: PlatformSnapshot,\r\n ): Promise<PermissionResult>;\r\n checkDirectoryCreatable(\r\n path: NormalizedPath,\r\n platform: PlatformSnapshot,\r\n ): Promise<PermissionResult>;\r\n detectElevation(platform: PlatformSnapshot): Promise<boolean>;\r\n checkSymlinkCapability(\r\n platform: PlatformSnapshot,\r\n ): Promise<SymlinkCapability>;\r\n}\r\n\r\n/** Detects terminal rendering and interaction capabilities. */\r\nexport interface ITerminalDetector {\r\n detectProfile(): TerminalProfile;\r\n detectColorSupport(): ColorSupportLevel;\r\n detectDimensions(): TerminalDimensions;\r\n onResize(callback: (dimensions: TerminalDimensions) => void): Disposable;\r\n}\r\n\r\n/** Identifies the active shell and its configuration. */\r\nexport interface IShellDetector {\r\n detectShell(platform: PlatformSnapshot): Promise<ShellEnvironment>;\r\n getPathModificationCommand(\r\n shell: ShellEnvironment,\r\n directory: NormalizedPath,\r\n ): string;\r\n getProfileEditCommand(shell: ShellEnvironment): string | null;\r\n}\r\n\r\n/** Validates Node.js and npm runtime versions and paths. */\r\nexport interface IRuntimeValidator {\r\n validate(minimumNode: SemVer, minimumNpm: SemVer): Promise<RuntimeReport>;\r\n checkNodeVersion(minimum: SemVer): RuntimeVersion;\r\n checkNpmVersion(minimum: SemVer): Promise<RuntimeVersion>;\r\n resolveGlobalBinDir(\r\n shell: ShellEnvironment,\r\n ): Promise<GlobalBinDirectory>;\r\n checkToolAvailable(\r\n toolName: string,\r\n ): Promise<{ available: boolean; path: string | null }>;\r\n}\r\n\r\n/** High-level entry point for all platform detection. */\r\nexport interface IPlatformFacade {\r\n detectAll(): Promise<PlatformEnvironment>;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Error Types\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Error codes for platform detection failures. */\r\nexport type PlatformErrorCode =\r\n | 'UNSUPPORTED_PLATFORM'\r\n | 'DETECTION_FAILED'\r\n | 'INVALID_PATH'\r\n | 'PERMISSION_ERROR'\r\n | 'RUNTIME_NOT_FOUND'\r\n | 'RUNTIME_VERSION_LOW'\r\n | 'CHILD_PROCESS_TIMEOUT'\r\n | 'CHILD_PROCESS_ERROR';\r\n\r\n/** Base error for all platform detection failures. */\r\nexport class PlatformError extends Error {\r\n readonly code: PlatformErrorCode;\r\n readonly component: string;\r\n readonly context?: Record<string, unknown>;\r\n\r\n constructor(\r\n code: PlatformErrorCode,\r\n component: string,\r\n message: string,\r\n context?: Record<string, unknown>,\r\n ) {\r\n super(message);\r\n this.name = 'PlatformError';\r\n this.code = code;\r\n this.component = component;\r\n this.context = context;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// SemVer Utilities\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Parse a version string like \"20.11.0\" or \"v20.11.0\" into a SemVer object.\r\n * Returns null if parsing fails.\r\n */\r\nexport function parseSemVer(versionString: string): SemVer | null {\r\n const cleaned = versionString.trim().replace(/^v/i, '');\r\n const match = /^(\\d+)\\.(\\d+)\\.(\\d+)/.exec(cleaned);\r\n if (!match) {\r\n return null;\r\n }\r\n return {\r\n major: parseInt(match[1], 10),\r\n minor: parseInt(match[2], 10),\r\n patch: parseInt(match[3], 10),\r\n raw: versionString.trim(),\r\n };\r\n}\r\n\r\n/**\r\n * Check if `version` satisfies the minimum requirement (>=).\r\n */\r\nexport function semVerSatisfiesMinimum(\r\n version: SemVer,\r\n minimum: SemVer,\r\n): boolean {\r\n if (version.major !== minimum.major) {\r\n return version.major > minimum.major;\r\n }\r\n if (version.minor !== minimum.minor) {\r\n return version.minor > minimum.minor;\r\n }\r\n return version.patch >= minimum.patch;\r\n}\r\n\r\n/**\r\n * Compare two SemVer values. Returns -1, 0, or 1.\r\n */\r\nexport function semVerCompare(a: SemVer, b: SemVer): -1 | 0 | 1 {\r\n if (a.major !== b.major) return a.major < b.major ? -1 : 1;\r\n if (a.minor !== b.minor) return a.minor < b.minor ? -1 : 1;\r\n if (a.patch !== b.patch) return a.patch < b.patch ? -1 : 1;\r\n return 0;\r\n}\r\n\r\n/**\r\n * Create a SemVer from explicit version numbers. Useful for defining constants.\r\n */\r\nexport function semVer(\r\n major: number,\r\n minor: number,\r\n patch: number,\r\n): SemVer {\r\n return {\r\n major,\r\n minor,\r\n patch,\r\n raw: `${major}.${minor}.${patch}`,\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// CI Environment Detection\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Known CI environment variables. */\r\nexport interface CIEnvironment {\r\n readonly isCI: boolean;\r\n readonly name: string | null;\r\n}\r\n","/**\r\n * Platform Detection - Detects OS, architecture, home directory, and temp directory.\r\n *\r\n * This is the primary entry point for platform identification. It produces\r\n * a PlatformSnapshot value object consumed by all other platform subsystems.\r\n *\r\n * @module platform/detector\r\n */\r\n\r\nimport * as os from 'node:os';\r\n\r\nimport {\r\n type Architecture,\r\n type ArchitectureName,\r\n type HomeDirectory,\r\n type IPlatformDetector,\r\n type OperatingSystem,\r\n type OsFamily,\r\n type PlatformSnapshot,\r\n PlatformError,\r\n type TempDirectory,\r\n} from './types.js';\r\n\r\n/**\r\n * Map process.platform values to OsFamily. Only win32, darwin, and linux\r\n * are supported. All other values produce an UNSUPPORTED_PLATFORM error.\r\n */\r\nfunction resolveOsFamily(platform: string): OsFamily {\r\n switch (platform) {\r\n case 'win32':\r\n return 'windows';\r\n case 'darwin':\r\n return 'macos';\r\n case 'linux':\r\n return 'linux';\r\n default:\r\n throw new PlatformError(\r\n 'UNSUPPORTED_PLATFORM',\r\n 'PlatformDetector',\r\n `Unsupported platform: \"${platform}\". Only Windows, macOS, and Linux are supported.`,\r\n { platform },\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Map process.arch values to ArchitectureName.\r\n * Supported: x64, arm64, ia32 (mapped to x86).\r\n * All other values default to x64 with a warning logged to stderr.\r\n */\r\nfunction resolveArchitecture(arch: string): Architecture {\r\n const archMap: Record<string, ArchitectureName> = {\r\n x64: 'x64',\r\n arm64: 'arm64',\r\n ia32: 'x86',\r\n x86: 'x86',\r\n };\r\n\r\n const name = archMap[arch];\r\n if (name) {\r\n return { name };\r\n }\r\n\r\n // Fallback for unknown architectures -- default to x64\r\n return { name: 'x64' };\r\n}\r\n\r\n/**\r\n * Build a human-readable OS release name from os.type(), os.release(),\r\n * and os.version() where available.\r\n */\r\nfunction resolveReleaseName(family: OsFamily, version: string): string {\r\n switch (family) {\r\n case 'windows': {\r\n // os.version() returns something like \"Windows 10 Pro\" or \"Windows 11 Home\"\r\n // os.release() returns the NT version like \"10.0.22621\"\r\n try {\r\n const osVersion = os.version();\r\n if (osVersion) {\r\n return osVersion;\r\n }\r\n } catch {\r\n // os.version() not available on older Node versions\r\n }\r\n return `Windows NT ${version}`;\r\n }\r\n case 'macos': {\r\n // Map major version to macOS marketing name\r\n const majorMinor = version.split('.').slice(0, 2).join('.');\r\n const macVersionNames: Record<string, string> = {\r\n '24': 'Sequoia',\r\n '23': 'Sonoma',\r\n '22': 'Ventura',\r\n '21': 'Monterey',\r\n '20': 'Big Sur',\r\n '19': 'Catalina',\r\n };\r\n const major = version.split('.')[0];\r\n const name = macVersionNames[major];\r\n return name ? `macOS ${name} ${majorMinor}` : `macOS ${majorMinor}`;\r\n }\r\n case 'linux': {\r\n try {\r\n const osVersion = os.version();\r\n if (osVersion) {\r\n return osVersion;\r\n }\r\n } catch {\r\n // os.version() not available on older Node versions\r\n }\r\n return `Linux ${version}`;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Resolve the user home directory with platform-specific fallbacks.\r\n *\r\n * Priority:\r\n * 1. Windows: USERPROFILE env var\r\n * 2. Unix: HOME env var\r\n * 3. Fallback: os.homedir()\r\n */\r\nfunction resolveHomeDirectory(family: OsFamily): HomeDirectory {\r\n if (family === 'windows') {\r\n const userProfile = process.env['USERPROFILE'];\r\n if (userProfile) {\r\n return { path: userProfile, source: 'USERPROFILE' };\r\n }\r\n }\r\n\r\n const home = process.env['HOME'];\r\n if (home) {\r\n return { path: home, source: 'HOME' };\r\n }\r\n\r\n return { path: os.homedir(), source: 'os.homedir' };\r\n}\r\n\r\n/**\r\n * Resolve the system temp directory.\r\n */\r\nfunction resolveTempDirectory(): TempDirectory {\r\n return { path: os.tmpdir() };\r\n}\r\n\r\n/**\r\n * PlatformDetector implementation.\r\n *\r\n * Detects the host operating system, CPU architecture, home directory,\r\n * and temp directory. All operations are synchronous since they read\r\n * from process globals and the os module.\r\n */\r\nexport class PlatformDetector implements IPlatformDetector {\r\n /**\r\n * Detect platform information and return an immutable PlatformSnapshot.\r\n *\r\n * @throws PlatformError with code UNSUPPORTED_PLATFORM if the OS is not\r\n * win32, darwin, or linux.\r\n */\r\n detect(): PlatformSnapshot {\r\n const family = resolveOsFamily(process.platform);\r\n const version = os.release();\r\n const release = resolveReleaseName(family, version);\r\n const architecture = resolveArchitecture(process.arch);\r\n\r\n const operatingSystem: OperatingSystem = {\r\n family,\r\n version,\r\n release,\r\n architecture,\r\n };\r\n\r\n const homeDirectory = resolveHomeDirectory(family);\r\n const tempDirectory = resolveTempDirectory();\r\n\r\n return {\r\n os: operatingSystem,\r\n homeDirectory,\r\n tempDirectory,\r\n detectedAt: new Date(),\r\n };\r\n }\r\n}\r\n","/**\r\n * Path Normalization - Cross-platform path manipulation utility.\r\n *\r\n * All internal paths use forward slashes. This module provides conversion\r\n * between platform-native and normalized representations, home directory\r\n * expansion, and path manipulation operations.\r\n *\r\n * @module platform/paths\r\n */\r\n\r\nimport {\r\n type HomeDirectory,\r\n type IPathNormalizer,\r\n type NormalizedPath,\r\n type OperatingSystem,\r\n PlatformError,\r\n createNormalizedPath,\r\n} from './types.js';\r\n\r\n/**\r\n * Check if a path starts with a Windows drive letter pattern (e.g., C:/ or C:\\).\r\n */\r\nfunction hasDriveLetter(path: string): boolean {\r\n return /^[a-zA-Z]:[/\\\\]/.test(path);\r\n}\r\n\r\n/**\r\n * Check if a path is a UNC path (\\\\server\\share or //server/share).\r\n */\r\nfunction isUncPath(path: string): boolean {\r\n return /^[/\\\\]{2}[^/\\\\]/.test(path);\r\n}\r\n\r\n/**\r\n * Resolve `.` and `..` segments in a path.\r\n * Does not access the filesystem -- purely string-based resolution.\r\n */\r\nfunction resolveSegments(segments: string[]): string[] {\r\n const resolved: string[] = [];\r\n\r\n for (const segment of segments) {\r\n if (segment === '.' || segment === '') {\r\n continue;\r\n }\r\n if (segment === '..') {\r\n if (resolved.length > 0) {\r\n resolved.pop();\r\n }\r\n continue;\r\n }\r\n resolved.push(segment);\r\n }\r\n\r\n return resolved;\r\n}\r\n\r\n/**\r\n * PathNormalizer implementation.\r\n *\r\n * Stateless utility for cross-platform path handling. All methods are\r\n * pure functions -- they take an OperatingSystem or HomeDirectory value\r\n * object as context rather than reading from process or os modules.\r\n */\r\nexport class PathNormalizer implements IPathNormalizer {\r\n /**\r\n * Convert a platform-native path to normalized internal form (forward slashes).\r\n *\r\n * Rules:\r\n * 1. Replace all backslashes with forward slashes\r\n * 2. Uppercase Windows drive letters (c:/ -> C:/)\r\n * 3. Preserve UNC path prefix (\\\\server\\share -> //server/share)\r\n * 4. Resolve . and .. segments\r\n * 5. Strip trailing separator (except root paths like / or C:/)\r\n * 6. Collapse double separators (except UNC prefix)\r\n *\r\n * @throws PlatformError with code INVALID_PATH for empty input\r\n */\r\n normalize(rawPath: string, os: OperatingSystem): NormalizedPath {\r\n if (!rawPath || rawPath.trim().length === 0) {\r\n throw new PlatformError(\r\n 'INVALID_PATH',\r\n 'PathNormalizer',\r\n 'Path cannot be empty',\r\n { rawPath },\r\n );\r\n }\r\n\r\n let path = rawPath;\r\n\r\n // Replace all backslashes with forward slashes\r\n path = path.replace(/\\\\/g, '/');\r\n\r\n // Handle UNC paths: preserve the // prefix\r\n let uncPrefix = '';\r\n if (isUncPath(rawPath)) {\r\n uncPrefix = '//';\r\n path = path.slice(2);\r\n }\r\n\r\n // Uppercase Windows drive letter\r\n if (os.family === 'windows' && hasDriveLetter(path)) {\r\n path = path[0].toUpperCase() + path.slice(1);\r\n }\r\n\r\n // Split into segments\r\n const segments = path.split('/');\r\n\r\n // Extract root prefix (drive letter or leading /)\r\n let root = '';\r\n if (uncPrefix) {\r\n // UNC path: first two segments are server and share\r\n const server = segments[0];\r\n const share = segments[1];\r\n root = `${uncPrefix}${server}/${share}`;\r\n segments.splice(0, 2);\r\n } else if (hasDriveLetter(path)) {\r\n root = segments[0] + '/';\r\n segments.splice(0, 1);\r\n } else if (path.startsWith('/')) {\r\n root = '/';\r\n segments.splice(0, 1);\r\n }\r\n\r\n // Resolve . and .. segments\r\n const resolved = resolveSegments(segments);\r\n\r\n // Reassemble the path\r\n let normalized = root + resolved.join('/');\r\n\r\n // Collapse double slashes (but not in UNC prefix or after drive letter)\r\n if (!uncPrefix) {\r\n normalized = normalized.replace(/\\/{2,}/g, '/');\r\n }\r\n\r\n // Strip trailing separator unless it is a root path\r\n if (normalized.length > 1 && normalized.endsWith('/')) {\r\n const isRootPath =\r\n normalized === '/' ||\r\n /^[A-Z]:\\/$/.test(normalized) ||\r\n /^\\/\\/[^/]+\\/[^/]+\\/?$/.test(normalized);\r\n if (!isRootPath) {\r\n normalized = normalized.replace(/\\/+$/, '');\r\n }\r\n }\r\n\r\n return createNormalizedPath(normalized);\r\n }\r\n\r\n /**\r\n * Convert a normalized path back to platform-native form for OS API calls.\r\n * On Windows, replaces forward slashes with backslashes.\r\n * On Unix, returns as-is.\r\n */\r\n toNative(path: NormalizedPath, os: OperatingSystem): string {\r\n if (os.family === 'windows') {\r\n return path.replace(/\\//g, '\\\\');\r\n }\r\n return path;\r\n }\r\n\r\n /**\r\n * Replace home directory tokens (~, $HOME, %USERPROFILE%) with the\r\n * actual home directory path.\r\n *\r\n * Token expansion happens before normalization:\r\n * - ~ or ~/ at the start of the path\r\n * - $HOME at the start of the path\r\n * - %USERPROFILE% at the start of the path\r\n *\r\n * @throws PlatformError with code INVALID_PATH for empty input\r\n */\r\n resolveHome(path: string, homeDir: HomeDirectory): NormalizedPath {\r\n if (!path || path.trim().length === 0) {\r\n throw new PlatformError(\r\n 'INVALID_PATH',\r\n 'PathNormalizer',\r\n 'Path cannot be empty',\r\n { path },\r\n );\r\n }\r\n\r\n let resolved = path;\r\n\r\n // Normalize the home directory path (forward slashes)\r\n const normalizedHome = homeDir.path.replace(/\\\\/g, '/');\r\n\r\n // Expand ~ or ~/ at the start\r\n if (resolved === '~') {\r\n resolved = normalizedHome;\r\n } else if (resolved.startsWith('~/') || resolved.startsWith('~\\\\')) {\r\n resolved = normalizedHome + '/' + resolved.slice(2);\r\n }\r\n\r\n // Expand $HOME at the start\r\n if (resolved === '$HOME') {\r\n resolved = normalizedHome;\r\n } else if (\r\n resolved.startsWith('$HOME/') ||\r\n resolved.startsWith('$HOME\\\\')\r\n ) {\r\n resolved = normalizedHome + '/' + resolved.slice(6);\r\n }\r\n\r\n // Expand %USERPROFILE% at the start\r\n if (resolved === '%USERPROFILE%') {\r\n resolved = normalizedHome;\r\n } else if (\r\n resolved.startsWith('%USERPROFILE%/') ||\r\n resolved.startsWith('%USERPROFILE%\\\\')\r\n ) {\r\n resolved = normalizedHome + '/' + resolved.slice(14);\r\n }\r\n\r\n // Normalize the result\r\n const family = normalizedHome.match(/^[A-Z]:/i) ? 'windows' : 'linux';\r\n const os: OperatingSystem = {\r\n family: family as 'windows' | 'linux',\r\n version: '',\r\n release: '',\r\n architecture: { name: 'x64' },\r\n };\r\n\r\n return this.normalize(resolved, os);\r\n }\r\n\r\n /**\r\n * Convert a relative path to absolute using the given base path.\r\n * If the path is already absolute, returns it unchanged.\r\n */\r\n toAbsolute(\r\n path: NormalizedPath,\r\n basePath: NormalizedPath,\r\n ): NormalizedPath {\r\n if (this.isAbsolute(path)) {\r\n return path;\r\n }\r\n return createNormalizedPath(\r\n this.stripTrailing(basePath) + '/' + path,\r\n );\r\n }\r\n\r\n /**\r\n * Convert an absolute path to relative from the given base path.\r\n * If the path is not under the base, returns the original absolute path.\r\n */\r\n toRelative(\r\n path: NormalizedPath,\r\n basePath: NormalizedPath,\r\n ): NormalizedPath {\r\n const normalBase = this.stripTrailing(basePath);\r\n const normalPath = this.stripTrailing(path);\r\n\r\n if (!normalPath.startsWith(normalBase + '/') && normalPath !== normalBase) {\r\n // Path is not under base, split both and compute relative\r\n const pathParts = normalPath.split('/');\r\n const baseParts = normalBase.split('/');\r\n\r\n // Find common prefix length\r\n let commonLength = 0;\r\n while (\r\n commonLength < pathParts.length &&\r\n commonLength < baseParts.length &&\r\n pathParts[commonLength] === baseParts[commonLength]\r\n ) {\r\n commonLength++;\r\n }\r\n\r\n // Build relative path\r\n const upCount = baseParts.length - commonLength;\r\n const upSegments = Array(upCount).fill('..');\r\n const downSegments = pathParts.slice(commonLength);\r\n const relativeParts = [...upSegments, ...downSegments];\r\n\r\n return createNormalizedPath(\r\n relativeParts.length > 0 ? relativeParts.join('/') : '.',\r\n );\r\n }\r\n\r\n if (normalPath === normalBase) {\r\n return createNormalizedPath('.');\r\n }\r\n\r\n return createNormalizedPath(normalPath.slice(normalBase.length + 1));\r\n }\r\n\r\n /**\r\n * Join path segments, normalizing the result.\r\n * The base path is used as the starting point.\r\n */\r\n join(base: NormalizedPath, ...segments: string[]): NormalizedPath {\r\n const allSegments = [base, ...segments].filter(Boolean);\r\n const joined = allSegments.join('/');\r\n\r\n // Determine OS context from the base path\r\n const isWindows = /^[A-Z]:/i.test(base);\r\n const os: OperatingSystem = {\r\n family: isWindows ? 'windows' : 'linux',\r\n version: '',\r\n release: '',\r\n architecture: { name: 'x64' },\r\n };\r\n\r\n return this.normalize(joined, os);\r\n }\r\n\r\n /**\r\n * Return the parent directory path, or null for root paths.\r\n */\r\n parent(path: NormalizedPath): NormalizedPath | null {\r\n const stripped = this.stripTrailing(path);\r\n\r\n // Check if this is a root path\r\n if (stripped === '/' || /^[A-Z]:\\/?$/i.test(stripped)) {\r\n return null;\r\n }\r\n\r\n // UNC root (//server/share)\r\n if (/^\\/\\/[^/]+\\/[^/]+\\/?$/.test(stripped)) {\r\n return null;\r\n }\r\n\r\n const lastSlash = stripped.lastIndexOf('/');\r\n if (lastSlash === -1) {\r\n return null;\r\n }\r\n\r\n // If the parent is the root\r\n if (lastSlash === 0) {\r\n return createNormalizedPath('/');\r\n }\r\n\r\n // If the parent ends with a drive letter colon\r\n const parentStr = stripped.slice(0, lastSlash);\r\n if (/^[A-Z]:$/i.test(parentStr)) {\r\n return createNormalizedPath(parentStr + '/');\r\n }\r\n\r\n return createNormalizedPath(parentStr);\r\n }\r\n\r\n /**\r\n * Extract file extension (without leading dot), or null if none.\r\n */\r\n extension(path: NormalizedPath): string | null {\r\n const stripped = this.stripTrailing(path);\r\n const lastSlash = stripped.lastIndexOf('/');\r\n const filename = lastSlash >= 0 ? stripped.slice(lastSlash + 1) : stripped;\r\n\r\n // No extension for dotfiles like .gitignore (unless they have a second dot)\r\n if (filename.startsWith('.') && filename.indexOf('.', 1) === -1) {\r\n return null;\r\n }\r\n\r\n const lastDot = filename.lastIndexOf('.');\r\n if (lastDot <= 0) {\r\n return null;\r\n }\r\n\r\n return filename.slice(lastDot + 1);\r\n }\r\n\r\n /**\r\n * Get the default .claude directory path for the given home directory.\r\n */\r\n getDefaultClaudeDir(\r\n homeDir: HomeDirectory,\r\n os: OperatingSystem,\r\n ): NormalizedPath {\r\n const homePath = this.normalize(homeDir.path, os);\r\n return this.join(homePath, '.claude');\r\n }\r\n\r\n /**\r\n * Check if a normalized path is absolute.\r\n */\r\n private isAbsolute(path: string): boolean {\r\n return (\r\n path.startsWith('/') ||\r\n /^[A-Z]:\\//i.test(path) ||\r\n path.startsWith('//')\r\n );\r\n }\r\n\r\n /**\r\n * Strip trailing slash from a path (preserving root paths).\r\n */\r\n private stripTrailing(path: string): string {\r\n if (\r\n path === '/' ||\r\n /^[A-Z]:\\/$/.test(path) ||\r\n /^\\/\\/[^/]+\\/[^/]+\\/$/.test(path)\r\n ) {\r\n return path;\r\n }\r\n return path.replace(/\\/+$/, '');\r\n }\r\n}\r\n","/**\r\n * Permission Checking - File system permission queries and elevation detection.\r\n *\r\n * Checks read/write/execute access to paths, detects elevated privilege status,\r\n * and provides platform-specific elevation guidance. Never modifies permissions\r\n * or attempts to elevate -- only detects and advises.\r\n *\r\n * @module platform/permissions\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport { execSync } from 'node:child_process';\r\n\r\nimport {\r\n AccessMode,\r\n type ElevationInstructions,\r\n type IPermissionChecker,\r\n type NormalizedPath,\r\n type PermissionResult,\r\n type PlatformSnapshot,\r\n type SymlinkCapability,\r\n} from './types.js';\r\nimport { PathNormalizer } from './paths.js';\r\n\r\n/**\r\n * Map AccessMode to fs.constants flags.\r\n */\r\nfunction accessModeToFlags(mode: AccessMode): number {\r\n const mapping: Record<AccessMode, number> = {\r\n [AccessMode.Read]: fs.constants.R_OK,\r\n [AccessMode.Write]: fs.constants.W_OK,\r\n [AccessMode.Execute]: fs.constants.X_OK,\r\n [AccessMode.ReadWrite]: fs.constants.R_OK | fs.constants.W_OK,\r\n };\r\n return mapping[mode];\r\n}\r\n\r\n// Ensure accessModeToFlags is referenced (prevents dead-code lint warnings)\r\nvoid accessModeToFlags;\r\n\r\n/**\r\n * Check if a path exists and whether it is a directory.\r\n */\r\nasync function statPath(\r\n nativePath: string,\r\n): Promise<{ exists: boolean; isDirectory: boolean }> {\r\n try {\r\n const stat = await fs.promises.stat(nativePath);\r\n return { exists: true, isDirectory: stat.isDirectory() };\r\n } catch {\r\n return { exists: false, isDirectory: false };\r\n }\r\n}\r\n\r\n/**\r\n * Check specific access permission on a path using fs.access.\r\n */\r\nasync function checkPermission(\r\n nativePath: string,\r\n flag: number,\r\n): Promise<boolean> {\r\n try {\r\n await fs.promises.access(nativePath, flag);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Build platform-specific elevation instructions.\r\n */\r\nfunction buildElevationInstructions(\r\n platform: PlatformSnapshot,\r\n targetPath: string,\r\n): ElevationInstructions {\r\n const family = platform.os.family;\r\n\r\n switch (family) {\r\n case 'windows':\r\n return {\r\n platform: 'windows',\r\n command: 'Run terminal as Administrator',\r\n description:\r\n \"Right-click your terminal and select 'Run as Administrator', then re-run the command.\",\r\n shellSpecificHint:\r\n 'In PowerShell: Start-Process pwsh -Verb RunAs',\r\n };\r\n case 'macos':\r\n return {\r\n platform: 'macos',\r\n command: `sudo sixsevenai install --target \"${targetPath}\"`,\r\n description:\r\n 'Prefix the command with sudo to run with root privileges.',\r\n shellSpecificHint: null,\r\n };\r\n case 'linux':\r\n return {\r\n platform: 'linux',\r\n command: `sudo sixsevenai install --target \"${targetPath}\"`,\r\n description:\r\n 'Prefix the command with sudo to run with root privileges.',\r\n shellSpecificHint: null,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Find the nearest existing parent directory for a path.\r\n * Used for checking directory creatability when the target does not exist.\r\n */\r\nfunction findNearestExistingParent(nativePath: string): string {\r\n let current = nativePath;\r\n\r\n // Walk up the directory tree until we find one that exists\r\n // eslint-disable-next-line no-constant-condition\r\n while (true) {\r\n try {\r\n const stat = fs.statSync(current);\r\n if (stat.isDirectory()) {\r\n return current;\r\n }\r\n } catch {\r\n // Directory does not exist, try parent\r\n }\r\n\r\n const parent = getParentNative(current);\r\n if (!parent || parent === current) {\r\n return current;\r\n }\r\n current = parent;\r\n }\r\n}\r\n\r\n/**\r\n * Get the native parent path. Handles both forward and backslash separators.\r\n */\r\nfunction getParentNative(nativePath: string): string | null {\r\n // Normalize separators for comparison\r\n const normalized = nativePath.replace(/\\\\/g, '/');\r\n const lastSlash = normalized.lastIndexOf('/');\r\n\r\n if (lastSlash <= 0) {\r\n return null;\r\n }\r\n\r\n // Check if this is already a root\r\n if (/^[A-Z]:\\/?$/i.test(normalized)) {\r\n return null;\r\n }\r\n\r\n const parent = normalized.slice(0, lastSlash);\r\n if (/^[A-Z]:$/i.test(parent)) {\r\n return parent + '/';\r\n }\r\n\r\n return parent || '/';\r\n}\r\n\r\n/**\r\n * PermissionChecker implementation.\r\n *\r\n * All methods return PermissionResult value objects and never throw.\r\n * Elevation detection reads OS state but never attempts to elevate.\r\n */\r\nexport class PermissionChecker implements IPermissionChecker {\r\n private readonly pathNormalizer = new PathNormalizer();\r\n\r\n /**\r\n * Check access to a path with the specified access mode.\r\n * Never throws -- returns a PermissionResult with appropriate flags.\r\n */\r\n async checkAccess(\r\n path: NormalizedPath,\r\n desiredAccess: AccessMode,\r\n platform: PlatformSnapshot,\r\n ): Promise<PermissionResult> {\r\n const nativePath = this.pathNormalizer.toNative(path, platform.os);\r\n const now = new Date();\r\n\r\n try {\r\n const { exists, isDirectory } = await statPath(nativePath);\r\n\r\n if (!exists) {\r\n return {\r\n targetPath: path,\r\n canRead: false,\r\n canWrite: false,\r\n canExecute: false,\r\n exists: false,\r\n isDirectory: false,\r\n requiresElevation: false,\r\n elevationInstructions: null,\r\n checkedAt: now,\r\n };\r\n }\r\n\r\n const canRead = await checkPermission(nativePath, fs.constants.R_OK);\r\n const canWrite = await checkPermission(nativePath, fs.constants.W_OK);\r\n const canExecute = await checkPermission(nativePath, fs.constants.X_OK);\r\n\r\n // Determine if elevation is needed based on desired access\r\n let needsElevation = false;\r\n switch (desiredAccess) {\r\n case 'read':\r\n needsElevation = !canRead;\r\n break;\r\n case 'write':\r\n needsElevation = !canWrite;\r\n break;\r\n case 'execute':\r\n needsElevation = !canExecute;\r\n break;\r\n case 'readwrite':\r\n needsElevation = !canRead || !canWrite;\r\n break;\r\n }\r\n\r\n const elevationInstructions = needsElevation\r\n ? buildElevationInstructions(platform, nativePath)\r\n : null;\r\n\r\n return {\r\n targetPath: path,\r\n canRead,\r\n canWrite,\r\n canExecute,\r\n exists,\r\n isDirectory,\r\n requiresElevation: needsElevation,\r\n elevationInstructions,\r\n checkedAt: now,\r\n };\r\n } catch {\r\n // Unexpected error -- return safe defaults\r\n return {\r\n targetPath: path,\r\n canRead: false,\r\n canWrite: false,\r\n canExecute: false,\r\n exists: false,\r\n isDirectory: false,\r\n requiresElevation: false,\r\n elevationInstructions: null,\r\n checkedAt: now,\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Convenience method: check write access to a path.\r\n */\r\n async checkWriteAccess(\r\n path: NormalizedPath,\r\n platform: PlatformSnapshot,\r\n ): Promise<PermissionResult> {\r\n return this.checkAccess(path, 'write' as AccessMode, platform);\r\n }\r\n\r\n /**\r\n * Check whether a directory can be created at the given path.\r\n * If the path does not exist, checks permissions on the nearest\r\n * existing parent directory.\r\n */\r\n async checkDirectoryCreatable(\r\n path: NormalizedPath,\r\n platform: PlatformSnapshot,\r\n ): Promise<PermissionResult> {\r\n const nativePath = this.pathNormalizer.toNative(path, platform.os);\r\n const now = new Date();\r\n\r\n try {\r\n // Check if the path already exists\r\n const { exists, isDirectory } = await statPath(nativePath);\r\n\r\n if (exists) {\r\n if (isDirectory) {\r\n // Directory already exists, check write access on it\r\n return this.checkAccess(path, 'write' as AccessMode, platform);\r\n }\r\n // A file exists at this path, cannot create directory\r\n return {\r\n targetPath: path,\r\n canRead: false,\r\n canWrite: false,\r\n canExecute: false,\r\n exists: true,\r\n isDirectory: false,\r\n requiresElevation: false,\r\n elevationInstructions: null,\r\n checkedAt: now,\r\n };\r\n }\r\n\r\n // Path does not exist, check nearest existing parent\r\n const nearestParent = findNearestExistingParent(nativePath);\r\n const canWriteParent = await checkPermission(\r\n nearestParent,\r\n fs.constants.W_OK,\r\n );\r\n\r\n const needsElevation = !canWriteParent;\r\n const elevationInstructions = needsElevation\r\n ? buildElevationInstructions(platform, nativePath)\r\n : null;\r\n\r\n return {\r\n targetPath: path,\r\n canRead: false,\r\n canWrite: canWriteParent,\r\n canExecute: false,\r\n exists: false,\r\n isDirectory: false,\r\n requiresElevation: needsElevation,\r\n elevationInstructions,\r\n checkedAt: now,\r\n };\r\n } catch {\r\n return {\r\n targetPath: path,\r\n canRead: false,\r\n canWrite: false,\r\n canExecute: false,\r\n exists: false,\r\n isDirectory: false,\r\n requiresElevation: false,\r\n elevationInstructions: null,\r\n checkedAt: now,\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Detect whether the current process is running with elevated privileges.\r\n *\r\n * - Unix: checks process.getuid() === 0\r\n * - Windows: executes `net session` via child_process.execSync\r\n *\r\n * Never throws. Returns false on detection failure.\r\n */\r\n async detectElevation(platform: PlatformSnapshot): Promise<boolean> {\r\n try {\r\n if (platform.os.family === 'windows') {\r\n return this.detectWindowsElevation();\r\n }\r\n return this.detectUnixElevation();\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Detect whether symbolic links can be created on the current platform.\r\n *\r\n * - Unix: always supported (no restrictions)\r\n * - Windows: depends on Developer Mode and/or elevation status\r\n */\r\n async checkSymlinkCapability(\r\n platform: PlatformSnapshot,\r\n ): Promise<SymlinkCapability> {\r\n if (platform.os.family !== 'windows') {\r\n return {\r\n supported: true,\r\n requiresDeveloperMode: false,\r\n requiresElevation: false,\r\n instructions: null,\r\n };\r\n }\r\n\r\n // Windows symlink capability\r\n const isElevated = await this.detectElevation(platform);\r\n\r\n if (isElevated) {\r\n return {\r\n supported: true,\r\n requiresDeveloperMode: false,\r\n requiresElevation: false,\r\n instructions: null,\r\n };\r\n }\r\n\r\n // Check if Developer Mode is enabled via registry\r\n const hasDeveloperMode = this.checkWindowsDeveloperMode();\r\n\r\n if (hasDeveloperMode) {\r\n return {\r\n supported: true,\r\n requiresDeveloperMode: false,\r\n requiresElevation: false,\r\n instructions: null,\r\n };\r\n }\r\n\r\n return {\r\n supported: false,\r\n requiresDeveloperMode: true,\r\n requiresElevation: true,\r\n instructions:\r\n 'Enable Developer Mode in Windows Settings > For developers, or run the installer as Administrator.',\r\n };\r\n }\r\n\r\n /**\r\n * Detect Windows elevation by running `net session`.\r\n * If it succeeds, the process is elevated. If it fails with exit code 5\r\n * (Access denied), the process is not elevated.\r\n */\r\n private detectWindowsElevation(): boolean {\r\n try {\r\n execSync('net session', {\r\n stdio: 'pipe',\r\n timeout: 5000,\r\n });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Detect Unix elevation by checking the effective user ID.\r\n */\r\n private detectUnixElevation(): boolean {\r\n if (typeof process.getuid === 'function') {\r\n return process.getuid() === 0;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Check if Windows Developer Mode is enabled by reading the registry.\r\n */\r\n private checkWindowsDeveloperMode(): boolean {\r\n try {\r\n const result = execSync(\r\n 'reg query \"HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\AppModelUnlock\" /v AllowDevelopmentWithoutDevLicense',\r\n { stdio: 'pipe', timeout: 5000 },\r\n ).toString();\r\n return result.includes('0x1');\r\n } catch {\r\n return false;\r\n }\r\n }\r\n}\r\n","/**\r\n * Terminal Capability Detection - Color support, Unicode, dimensions, interactivity.\r\n *\r\n * Detects the rendering and interaction capabilities of the current terminal\r\n * environment. Follows the NO_COLOR standard (https://no-color.org/) and\r\n * uses well-known environment variable conventions for detection.\r\n *\r\n * @module platform/terminal\r\n */\r\n\r\nimport * as os from 'node:os';\r\n\r\nimport {\r\n type CIEnvironment,\r\n ColorSupportLevel,\r\n type Disposable,\r\n type ITerminalDetector,\r\n type InteractivityMode,\r\n type TerminalDimensions,\r\n type TerminalEmulator,\r\n type TerminalProfile,\r\n type UnicodeSupport,\r\n} from './types.js';\r\n\r\n/**\r\n * Detect the CI environment, if any.\r\n */\r\nfunction detectCIEnvironment(): CIEnvironment {\r\n const env = process.env;\r\n\r\n // Check common CI environment variables\r\n if (env['CI'] || env['CONTINUOUS_INTEGRATION'] || env['BUILD_NUMBER']) {\r\n // Try to identify the specific CI service\r\n if (env['GITHUB_ACTIONS']) return { isCI: true, name: 'GitHub Actions' };\r\n if (env['AZURE_PIPELINES'] || env['TF_BUILD']) return { isCI: true, name: 'Azure Pipelines' };\r\n if (env['GITLAB_CI']) return { isCI: true, name: 'GitLab CI' };\r\n if (env['CIRCLECI']) return { isCI: true, name: 'CircleCI' };\r\n if (env['TRAVIS']) return { isCI: true, name: 'Travis CI' };\r\n if (env['JENKINS_URL']) return { isCI: true, name: 'Jenkins' };\r\n if (env['CODEBUILD_BUILD_ID']) return { isCI: true, name: 'AWS CodeBuild' };\r\n if (env['TEAMCITY_VERSION']) return { isCI: true, name: 'TeamCity' };\r\n if (env['BITBUCKET_BUILD_NUMBER']) return { isCI: true, name: 'Bitbucket Pipelines' };\r\n\r\n return { isCI: true, name: 'Unknown CI' };\r\n }\r\n\r\n return { isCI: false, name: null };\r\n}\r\n\r\n/**\r\n * Detect the terminal emulator from environment variables.\r\n */\r\nfunction detectEmulator(): TerminalEmulator {\r\n const env = process.env;\r\n\r\n // Windows Terminal\r\n if (env['WT_SESSION']) {\r\n return {\r\n name: 'Windows Terminal',\r\n version: env['WT_SESSION'] ?? null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // VS Code integrated terminal\r\n if (env['TERM_PROGRAM'] === 'vscode') {\r\n return {\r\n name: 'VS Code Terminal',\r\n version: env['TERM_PROGRAM_VERSION'] ?? null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // iTerm2\r\n if (env['TERM_PROGRAM'] === 'iTerm.app') {\r\n return {\r\n name: 'iTerm2',\r\n version: env['TERM_PROGRAM_VERSION'] ?? null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // Apple Terminal\r\n if (env['TERM_PROGRAM'] === 'Apple_Terminal') {\r\n return {\r\n name: 'Apple Terminal',\r\n version: env['TERM_PROGRAM_VERSION'] ?? null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // ConEmu / Cmder\r\n if (env['ConEmuPID'] || env['ConEmuANSI']) {\r\n return {\r\n name: 'ConEmu',\r\n version: null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // GNOME Terminal\r\n if (env['GNOME_TERMINAL_SERVICE'] || env['GNOME_TERMINAL_SCREEN']) {\r\n return {\r\n name: 'GNOME Terminal',\r\n version: null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // Hyper\r\n if (env['TERM_PROGRAM'] === 'Hyper') {\r\n return {\r\n name: 'Hyper',\r\n version: env['TERM_PROGRAM_VERSION'] ?? null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // Alacritty\r\n if (env['TERM_PROGRAM'] === 'Alacritty' || env['ALACRITTY_LOG']) {\r\n return {\r\n name: 'Alacritty',\r\n version: null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // Kitty\r\n if (env['TERM'] === 'xterm-kitty' || env['KITTY_WINDOW_ID']) {\r\n return {\r\n name: 'Kitty',\r\n version: null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // WezTerm\r\n if (env['TERM_PROGRAM'] === 'WezTerm') {\r\n return {\r\n name: 'WezTerm',\r\n version: env['TERM_PROGRAM_VERSION'] ?? null,\r\n isKnown: true,\r\n };\r\n }\r\n\r\n // Generic TERM_PROGRAM\r\n if (env['TERM_PROGRAM']) {\r\n return {\r\n name: env['TERM_PROGRAM'],\r\n version: env['TERM_PROGRAM_VERSION'] ?? null,\r\n isKnown: false,\r\n };\r\n }\r\n\r\n // Fallback to TERM\r\n if (env['TERM'] && env['TERM'] !== 'dumb') {\r\n return {\r\n name: env['TERM'],\r\n version: null,\r\n isKnown: false,\r\n };\r\n }\r\n\r\n return {\r\n name: null,\r\n version: null,\r\n isKnown: false,\r\n };\r\n}\r\n\r\n/**\r\n * Parse the FORCE_COLOR environment variable into a ColorSupportLevel.\r\n * Follows the convention: 0=None, 1=Basic, 2=Extended, 3=TrueColor.\r\n */\r\nfunction parseForcedColor(value: string): ColorSupportLevel | null {\r\n switch (value) {\r\n case '0':\r\n return ColorSupportLevel.None;\r\n case '1':\r\n case 'true':\r\n case '':\r\n return ColorSupportLevel.Basic;\r\n case '2':\r\n return ColorSupportLevel.Extended;\r\n case '3':\r\n return ColorSupportLevel.TrueColor;\r\n default:\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * TerminalDetector implementation.\r\n *\r\n * Detects terminal capabilities using environment variables, process\r\n * stream properties, and well-known terminal emulator conventions.\r\n * All detection methods are synchronous (no child process calls).\r\n */\r\nexport class TerminalDetector implements ITerminalDetector {\r\n /**\r\n * Detect all terminal capabilities and return a complete profile.\r\n */\r\n detectProfile(): TerminalProfile {\r\n return {\r\n colorSupport: this.detectColorSupport(),\r\n dimensions: this.detectDimensions(),\r\n unicodeSupport: this.detectUnicodeSupport(),\r\n interactivity: this.detectInteractivity(),\r\n emulator: detectEmulator(),\r\n detectedAt: new Date(),\r\n };\r\n }\r\n\r\n /**\r\n * Detect the color support level of the current terminal.\r\n *\r\n * Priority chain:\r\n * 1. NO_COLOR env var set -> None\r\n * 2. FORCE_COLOR env var set -> forced level\r\n * 3. stdout is not a TTY -> None\r\n * 4. COLORTERM = \"truecolor\" or \"24bit\" -> TrueColor\r\n * 5. Known terminal emulator -> emulator-specific level\r\n * 6. TERM = \"xterm-256color\" -> Extended\r\n * 7. TERM contains \"color\" -> Basic\r\n * 8. Windows version >= 10.0.14393 -> Extended minimum\r\n * 9. Default -> Basic\r\n */\r\n detectColorSupport(): ColorSupportLevel {\r\n const env = process.env;\r\n\r\n // 1. NO_COLOR standard (https://no-color.org/)\r\n if ('NO_COLOR' in env) {\r\n return ColorSupportLevel.None;\r\n }\r\n\r\n // 2. FORCE_COLOR override\r\n if ('FORCE_COLOR' in env) {\r\n const forced = parseForcedColor(env['FORCE_COLOR'] ?? '');\r\n if (forced !== null) {\r\n return forced;\r\n }\r\n }\r\n\r\n // 3. Non-TTY check\r\n if (!process.stdout.isTTY) {\r\n return ColorSupportLevel.None;\r\n }\r\n\r\n // 4. COLORTERM environment variable\r\n const colorTerm = env['COLORTERM'];\r\n if (colorTerm === 'truecolor' || colorTerm === '24bit') {\r\n return ColorSupportLevel.TrueColor;\r\n }\r\n\r\n // 5. Known terminal emulators\r\n const termProgram = env['TERM_PROGRAM'];\r\n\r\n // Windows Terminal -> TrueColor\r\n if (env['WT_SESSION']) {\r\n return ColorSupportLevel.TrueColor;\r\n }\r\n\r\n // VS Code -> TrueColor\r\n if (termProgram === 'vscode') {\r\n return ColorSupportLevel.TrueColor;\r\n }\r\n\r\n // iTerm2 -> TrueColor\r\n if (termProgram === 'iTerm.app') {\r\n return ColorSupportLevel.TrueColor;\r\n }\r\n\r\n // Apple Terminal -> Extended\r\n if (termProgram === 'Apple_Terminal') {\r\n return ColorSupportLevel.Extended;\r\n }\r\n\r\n // ConEmu -> Extended\r\n if (env['ConEmuANSI'] === 'ON') {\r\n return ColorSupportLevel.Extended;\r\n }\r\n\r\n // GNOME Terminal -> Extended\r\n if (env['GNOME_TERMINAL_SERVICE']) {\r\n return ColorSupportLevel.Extended;\r\n }\r\n\r\n // Kitty, Alacritty, WezTerm, Hyper -> TrueColor\r\n if (\r\n env['TERM'] === 'xterm-kitty' ||\r\n env['KITTY_WINDOW_ID'] ||\r\n termProgram === 'Alacritty' ||\r\n termProgram === 'WezTerm' ||\r\n termProgram === 'Hyper'\r\n ) {\r\n return ColorSupportLevel.TrueColor;\r\n }\r\n\r\n // 6. TERM = xterm-256color\r\n const term = env['TERM'];\r\n if (term === 'xterm-256color' || term === 'screen-256color') {\r\n return ColorSupportLevel.Extended;\r\n }\r\n\r\n // 7. TERM contains \"color\"\r\n if (term && /color/i.test(term)) {\r\n return ColorSupportLevel.Basic;\r\n }\r\n\r\n // 8. Windows version check (>= 10.0.14393 supports ANSI escape codes)\r\n if (process.platform === 'win32') {\r\n const osRelease = os.release();\r\n const versionParts = osRelease.split('.');\r\n const major = parseInt(versionParts[0], 10);\r\n const build = parseInt(versionParts[2], 10);\r\n\r\n if (major >= 10 && build >= 14393) {\r\n return ColorSupportLevel.Extended;\r\n }\r\n }\r\n\r\n // 9. Default\r\n return ColorSupportLevel.Basic;\r\n }\r\n\r\n /**\r\n * Detect terminal dimensions (columns x rows).\r\n * Falls back to 80x24 if detection fails.\r\n */\r\n detectDimensions(): TerminalDimensions {\r\n const columns = process.stdout.columns;\r\n const rows = process.stdout.rows;\r\n\r\n return {\r\n columns: columns && columns > 0 ? columns : 80,\r\n rows: rows && rows > 0 ? rows : 24,\r\n };\r\n }\r\n\r\n /**\r\n * Subscribe to terminal resize events.\r\n * Returns a Disposable to unsubscribe.\r\n */\r\n onResize(\r\n callback: (dimensions: TerminalDimensions) => void,\r\n ): Disposable {\r\n const handler = (): void => {\r\n callback(this.detectDimensions());\r\n };\r\n\r\n process.stdout.on('resize', handler);\r\n\r\n return {\r\n dispose: (): void => {\r\n process.stdout.removeListener('resize', handler);\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Detect Unicode support in the terminal.\r\n *\r\n * Detection methods:\r\n * 1. Check LANG, LC_ALL, LC_CTYPE for UTF-8 reference\r\n * 2. Check for modern terminal emulators (WT_SESSION, TERM_PROGRAM)\r\n * 3. On Windows, check if running in a modern terminal\r\n * 4. Default to true on macOS/Linux, false on Windows CMD\r\n */\r\n private detectUnicodeSupport(): UnicodeSupport {\r\n const env = process.env;\r\n\r\n // Check locale environment variables for UTF-8\r\n const localeVars = [env['LC_ALL'], env['LC_CTYPE'], env['LANG']];\r\n for (const localeVar of localeVars) {\r\n if (localeVar && /utf-?8/i.test(localeVar)) {\r\n return { supported: true, detectionMethod: 'locale' };\r\n }\r\n }\r\n\r\n // Check for known modern terminal emulators\r\n if (\r\n env['WT_SESSION'] ||\r\n env['TERM_PROGRAM'] === 'vscode' ||\r\n env['TERM_PROGRAM'] === 'iTerm.app' ||\r\n env['TERM_PROGRAM'] === 'Hyper' ||\r\n env['TERM_PROGRAM'] === 'Alacritty' ||\r\n env['TERM_PROGRAM'] === 'WezTerm' ||\r\n env['KITTY_WINDOW_ID'] ||\r\n env['TERM'] === 'xterm-kitty'\r\n ) {\r\n return { supported: true, detectionMethod: 'terminal' };\r\n }\r\n\r\n // ConEmu/Cmder supports Unicode\r\n if (env['ConEmuANSI'] === 'ON') {\r\n return { supported: true, detectionMethod: 'env' };\r\n }\r\n\r\n // Platform defaults\r\n if (process.platform === 'darwin') {\r\n // macOS defaults to UTF-8\r\n return { supported: true, detectionMethod: 'default' };\r\n }\r\n\r\n if (process.platform === 'linux') {\r\n // Most modern Linux distros default to UTF-8\r\n return { supported: true, detectionMethod: 'default' };\r\n }\r\n\r\n if (process.platform === 'win32') {\r\n // Windows: only modern terminals support Unicode well\r\n // If we reach here, the user is in a legacy terminal (CMD without WT)\r\n return { supported: false, detectionMethod: 'default' };\r\n }\r\n\r\n return { supported: true, detectionMethod: 'default' };\r\n }\r\n\r\n /**\r\n * Detect terminal interactivity mode.\r\n */\r\n private detectInteractivity(): InteractivityMode {\r\n const isTTY = !!process.stdout.isTTY;\r\n const isInteractive = !!process.stdin.isTTY;\r\n\r\n // Raw mode is available when stdin is a TTY and setRawMode exists\r\n const supportsRawMode =\r\n isInteractive &&\r\n typeof (process.stdin as NodeJS.ReadStream).setRawMode === 'function';\r\n\r\n return {\r\n isInteractive,\r\n isTTY,\r\n supportsRawMode,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Detect CI environment. Exported for use by other modules.\r\n */\r\nexport { detectCIEnvironment };\r\n","/**\r\n * Shell Detection - Identifies the active shell and its configuration.\r\n *\r\n * Detects the current shell (PowerShell, CMD, bash, zsh, fish) from\r\n * environment variables, locates profile files, and generates shell-specific\r\n * PATH modification commands.\r\n *\r\n * @module platform/shell\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\n\r\nimport {\r\n type IShellDetector,\r\n type NormalizedPath,\r\n type PlatformSnapshot,\r\n type ShellEnvironment,\r\n type ShellType,\r\n createNormalizedPath,\r\n} from './types.js';\r\nimport { PathNormalizer } from './paths.js';\r\n\r\n/**\r\n * Resolve the shell type from environment variables.\r\n *\r\n * Detection order:\r\n * 1. PSModulePath (PowerShell -- works across platforms)\r\n * 2. SHELL (Unix -- bash, zsh, fish)\r\n * 3. MSYSTEM (Git Bash on Windows)\r\n * 4. ComSpec (Windows CMD fallback)\r\n * 5. Default based on platform\r\n */\r\nfunction resolveShellType(env: NodeJS.ProcessEnv, platform: 'windows' | 'macos' | 'linux'): {\r\n type: ShellType;\r\n executablePath: string;\r\n} {\r\n // Check for PowerShell (cross-platform)\r\n if (env['PSModulePath']) {\r\n // Determine executable name: pwsh (PowerShell Core) or powershell (Windows PowerShell)\r\n const psPath = env['PSModulePath'] ?? '';\r\n const isPwshCore = psPath.includes('PowerShell') && !psPath.includes('WindowsPowerShell');\r\n\r\n if (platform === 'windows') {\r\n return {\r\n type: 'powershell',\r\n executablePath: isPwshCore ? 'pwsh.exe' : 'powershell.exe',\r\n };\r\n }\r\n return {\r\n type: 'powershell',\r\n executablePath: 'pwsh',\r\n };\r\n }\r\n\r\n // Check SHELL environment variable (Unix systems)\r\n const shell = env['SHELL'];\r\n if (shell) {\r\n const shellName = shell.split('/').pop()?.toLowerCase() ?? '';\r\n\r\n if (shellName.includes('zsh')) {\r\n return { type: 'zsh', executablePath: shell };\r\n }\r\n if (shellName.includes('bash')) {\r\n return { type: 'bash', executablePath: shell };\r\n }\r\n if (shellName.includes('fish')) {\r\n return { type: 'fish', executablePath: shell };\r\n }\r\n }\r\n\r\n // Check for Git Bash on Windows (MSYSTEM indicates MSYS2/Git Bash)\r\n if (env['MSYSTEM']) {\r\n const bashPath = env['SHELL'] ?? 'bash';\r\n return { type: 'bash', executablePath: bashPath };\r\n }\r\n\r\n // Check ComSpec for Windows CMD\r\n if (platform === 'windows') {\r\n const comspec = env['ComSpec'];\r\n if (comspec && comspec.toLowerCase().endsWith('cmd.exe')) {\r\n return { type: 'cmd', executablePath: comspec };\r\n }\r\n // Default to PowerShell on modern Windows\r\n return { type: 'powershell', executablePath: 'pwsh.exe' };\r\n }\r\n\r\n // Default based on platform\r\n if (platform === 'macos') {\r\n // zsh is the default since macOS Catalina\r\n return { type: 'zsh', executablePath: '/bin/zsh' };\r\n }\r\n\r\n // Linux default\r\n return { type: 'bash', executablePath: '/bin/bash' };\r\n}\r\n\r\n/**\r\n * Resolve the profile file path for a given shell type.\r\n * Returns null for shells without profile files (CMD, unknown).\r\n */\r\nfunction resolveProfilePath(\r\n shellType: ShellType,\r\n platform: 'windows' | 'macos' | 'linux',\r\n homePath: string,\r\n): string | null {\r\n const home = homePath.replace(/\\\\/g, '/');\r\n\r\n switch (shellType) {\r\n case 'powershell': {\r\n if (platform === 'windows') {\r\n // PowerShell Core: Documents/PowerShell/Microsoft.PowerShell_profile.ps1\r\n // Windows PowerShell: Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1\r\n // Default to PowerShell Core path\r\n return `${home}/Documents/PowerShell/Microsoft.PowerShell_profile.ps1`;\r\n }\r\n // Cross-platform PowerShell on Unix\r\n return `${home}/.config/powershell/Microsoft.PowerShell_profile.ps1`;\r\n }\r\n case 'bash': {\r\n if (platform === 'macos') {\r\n // macOS uses .bash_profile for login shells\r\n return `${home}/.bash_profile`;\r\n }\r\n // Linux uses .bashrc\r\n return `${home}/.bashrc`;\r\n }\r\n case 'zsh':\r\n return `${home}/.zshrc`;\r\n case 'fish':\r\n return `${home}/.config/fish/config.fish`;\r\n case 'cmd':\r\n // CMD uses registry, not profile files\r\n return null;\r\n case 'unknown':\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Generate a shell-specific command to add a directory to PATH.\r\n */\r\nfunction buildPathModificationCommand(\r\n shellType: ShellType,\r\n directory: string,\r\n profilePath: string | null,\r\n): string | null {\r\n switch (shellType) {\r\n case 'powershell':\r\n return `$env:PATH = \"${directory}\" + [System.IO.Path]::PathSeparator + $env:PATH`;\r\n case 'bash':\r\n case 'zsh':\r\n return `export PATH=\"${directory}:$PATH\"`;\r\n case 'fish':\r\n return `set -gx PATH \"${directory}\" $PATH`;\r\n case 'cmd':\r\n return `set PATH=${directory};%PATH%`;\r\n case 'unknown':\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Generate a persistent PATH modification command (for writing to profile).\r\n */\r\nfunction buildPersistentPathCommand(\r\n shellType: ShellType,\r\n directory: string,\r\n profilePath: string | null,\r\n): string | null {\r\n if (!profilePath) return null;\r\n\r\n switch (shellType) {\r\n case 'powershell':\r\n return `Add-Content -Path \"${profilePath}\" -Value '$env:PATH = \"${directory}\" + [System.IO.Path]::PathSeparator + $env:PATH'`;\r\n case 'bash':\r\n case 'zsh':\r\n return `echo 'export PATH=\"${directory}:$PATH\"' >> \"${profilePath}\"`;\r\n case 'fish':\r\n return `echo 'set -gx PATH \"${directory}\" $PATH' >> \"${profilePath}\"`;\r\n case 'cmd':\r\n return `setx PATH \"${directory};%PATH%\"`;\r\n case 'unknown':\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Detect the shell version by checking for version-related environment variables.\r\n * Does not execute child processes -- uses only environment variables.\r\n */\r\nfunction detectShellVersion(\r\n shellType: ShellType,\r\n env: NodeJS.ProcessEnv,\r\n): string | null {\r\n switch (shellType) {\r\n case 'bash': {\r\n // BASH_VERSION is set by bash\r\n return env['BASH_VERSION'] ?? null;\r\n }\r\n case 'zsh': {\r\n // ZSH_VERSION is set by zsh\r\n return env['ZSH_VERSION'] ?? null;\r\n }\r\n case 'fish': {\r\n // FISH_VERSION is set by fish\r\n return env['FISH_VERSION'] ?? null;\r\n }\r\n case 'powershell': {\r\n // No standard env var for PowerShell version detection\r\n // PSVersionTable is available inside PowerShell but not as an env var\r\n return null;\r\n }\r\n default:\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * ShellDetector implementation.\r\n *\r\n * Identifies the active shell from environment variables, locates\r\n * profile files, and generates shell-specific commands. Uses environment\r\n * variable detection as the primary mechanism per ADR-003.\r\n */\r\nexport class ShellDetector implements IShellDetector {\r\n private readonly pathNormalizer = new PathNormalizer();\r\n\r\n /**\r\n * Detect the active shell and its profile configuration.\r\n */\r\n async detectShell(platform: PlatformSnapshot): Promise<ShellEnvironment> {\r\n const osFamily = platform.os.family;\r\n const env = process.env;\r\n\r\n // Resolve shell type\r\n const { type, executablePath } = resolveShellType(env, osFamily);\r\n\r\n // Resolve profile path\r\n const rawProfilePath = resolveProfilePath(\r\n type,\r\n osFamily,\r\n platform.homeDirectory.path,\r\n );\r\n\r\n // Normalize profile path\r\n let profilePath: NormalizedPath | null = null;\r\n let profileExists = false;\r\n\r\n if (rawProfilePath) {\r\n profilePath = this.pathNormalizer.normalize(rawProfilePath, platform.os);\r\n const nativePath = this.pathNormalizer.toNative(profilePath, platform.os);\r\n try {\r\n profileExists = fs.existsSync(nativePath);\r\n } catch {\r\n profileExists = false;\r\n }\r\n }\r\n\r\n // Detect shell version\r\n const version = detectShellVersion(type, env);\r\n\r\n // Build PATH modification command for the default global npm bin dir\r\n const pathModCommand = buildPathModificationCommand(\r\n type,\r\n '{directory}',\r\n rawProfilePath,\r\n );\r\n\r\n // Determine PATH separator\r\n const pathSeparator: ';' | ':' = osFamily === 'windows' ? ';' : ':';\r\n\r\n return {\r\n type,\r\n version,\r\n executablePath,\r\n profilePath,\r\n profileExists,\r\n pathSeparator,\r\n pathModificationCommand: pathModCommand,\r\n };\r\n }\r\n\r\n /**\r\n * Generate a shell-specific command to add a directory to PATH.\r\n * The returned command can be run immediately in the current session.\r\n */\r\n getPathModificationCommand(\r\n shell: ShellEnvironment,\r\n directory: NormalizedPath,\r\n ): string {\r\n const nativeDir =\r\n shell.pathSeparator === ';'\r\n ? directory.replace(/\\//g, '\\\\')\r\n : (directory as string);\r\n\r\n const command = buildPathModificationCommand(\r\n shell.type,\r\n nativeDir,\r\n shell.profilePath,\r\n );\r\n\r\n return command ?? `# Unable to generate PATH command for ${shell.type} shell`;\r\n }\r\n\r\n /**\r\n * Generate a command to open the shell's profile file for editing.\r\n * Returns null if the shell has no profile file.\r\n */\r\n getProfileEditCommand(shell: ShellEnvironment): string | null {\r\n if (!shell.profilePath) {\r\n return null;\r\n }\r\n\r\n const profileStr = shell.profilePath as string;\r\n\r\n switch (shell.type) {\r\n case 'powershell':\r\n return `code \"${profileStr}\" # or notepad \"${profileStr}\"`;\r\n case 'bash':\r\n case 'zsh':\r\n case 'fish':\r\n return `${process.env['EDITOR'] ?? 'nano'} \"${profileStr}\"`;\r\n case 'cmd':\r\n return null;\r\n case 'unknown':\r\n return null;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Exported for testing and reuse by other modules.\r\n */\r\nexport { buildPersistentPathCommand, resolveShellType, resolveProfilePath };\r\n","/**\r\n * Runtime Validation - Node.js, npm, and git version checking.\r\n *\r\n * Validates that required runtime tools meet minimum version requirements\r\n * and resolves the global npm binary directory. Provides actionable\r\n * error messages for all validation failures.\r\n *\r\n * @module platform/runtime\r\n */\r\n\r\nimport { execSync } from 'node:child_process';\r\n\r\nimport {\r\n type GlobalBinDirectory,\r\n type IRuntimeValidator,\r\n type NormalizedPath,\r\n type RuntimeError,\r\n type RuntimeReport,\r\n type RuntimeVersion,\r\n type SemVer,\r\n type ShellEnvironment,\r\n createNormalizedPath,\r\n parseSemVer,\r\n semVer,\r\n semVerSatisfiesMinimum,\r\n} from './types.js';\r\n\r\n/** Default minimum Node.js version requirement. */\r\nexport const MINIMUM_NODE_VERSION: SemVer = semVer(18, 0, 0);\r\n\r\n/** Default minimum npm version requirement. */\r\nexport const MINIMUM_NPM_VERSION: SemVer = semVer(9, 0, 0);\r\n\r\n/** Timeout for child process commands (10 seconds). */\r\nconst COMMAND_TIMEOUT_MS = 10_000;\r\n\r\n/**\r\n * Execute a command and return its trimmed stdout, or null on failure.\r\n */\r\nfunction execCommand(command: string): string | null {\r\n try {\r\n const result = execSync(command, {\r\n encoding: 'utf-8',\r\n stdio: ['pipe', 'pipe', 'pipe'],\r\n timeout: COMMAND_TIMEOUT_MS,\r\n });\r\n return result.trim();\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Resolve the executable path for a tool using `which` (Unix) or `where` (Windows).\r\n */\r\nfunction resolveExecutablePath(toolName: string): string | null {\r\n const isWindows = process.platform === 'win32';\r\n const command = isWindows ? `where ${toolName}` : `which ${toolName}`;\r\n\r\n const result = execCommand(command);\r\n if (!result) return null;\r\n\r\n // `where` on Windows may return multiple lines; take the first\r\n return result.split(/\\r?\\n/)[0].trim();\r\n}\r\n\r\n/**\r\n * RuntimeValidator implementation.\r\n *\r\n * Validates Node.js and npm versions, resolves the global npm binary\r\n * directory, and checks for arbitrary tool availability. Uses child_process\r\n * for npm and git commands with a 10-second timeout.\r\n */\r\nexport class RuntimeValidator implements IRuntimeValidator {\r\n /**\r\n * Run all runtime validation checks and return a complete RuntimeReport.\r\n */\r\n async validate(\r\n minimumNode: SemVer,\r\n minimumNpm: SemVer,\r\n ): Promise<RuntimeReport> {\r\n const errors: RuntimeError[] = [];\r\n\r\n // Check Node.js version (synchronous -- already running in Node)\r\n const node = this.checkNodeVersion(minimumNode);\r\n if (!node.meetsMinimum) {\r\n errors.push({\r\n tool: 'node',\r\n errorType: 'version_too_low',\r\n message: `Node.js ${node.version.raw} is below the minimum required ${minimumNode.raw}.`,\r\n fix: `Upgrade Node.js to ${minimumNode.raw} or later. Visit https://nodejs.org/ or use nvm: nvm install ${minimumNode.major}`,\r\n });\r\n }\r\n\r\n // Check npm version (async -- child process)\r\n let npm: RuntimeVersion | null = null;\r\n try {\r\n npm = await this.checkNpmVersion(minimumNpm);\r\n if (!npm.meetsMinimum) {\r\n errors.push({\r\n tool: 'npm',\r\n errorType: 'version_too_low',\r\n message: `npm ${npm.version.raw} is below the minimum required ${minimumNpm.raw}.`,\r\n fix: `Upgrade npm: npm install -g npm@latest`,\r\n });\r\n }\r\n } catch {\r\n errors.push({\r\n tool: 'npm',\r\n errorType: 'not_found',\r\n message: 'npm is not installed or not available on PATH.',\r\n fix: 'Install Node.js (which includes npm) from https://nodejs.org/ or install npm separately.',\r\n });\r\n }\r\n\r\n // Check git availability (optional but reported)\r\n let git: RuntimeVersion | null = null;\r\n try {\r\n const gitResult = await this.checkGitVersion();\r\n git = gitResult;\r\n } catch {\r\n // git is optional, do not add to errors\r\n }\r\n\r\n // Resolve global bin directory\r\n let globalBinDir: GlobalBinDirectory | null = null;\r\n if (npm) {\r\n try {\r\n globalBinDir = await this.resolveGlobalBinDir({\r\n type: 'unknown',\r\n version: null,\r\n executablePath: '',\r\n profilePath: null,\r\n profileExists: false,\r\n pathSeparator: process.platform === 'win32' ? ';' : ':',\r\n pathModificationCommand: null,\r\n });\r\n\r\n if (!globalBinDir.isOnPath) {\r\n errors.push({\r\n tool: 'npm',\r\n errorType: 'not_on_path',\r\n message: `npm global bin directory (${globalBinDir.path}) is not on PATH.`,\r\n fix: globalBinDir.pathFixCommand ??\r\n `Add ${globalBinDir.path} to your PATH environment variable.`,\r\n });\r\n }\r\n } catch {\r\n // Non-fatal: global bin dir resolution failed\r\n }\r\n }\r\n\r\n const allRequirementsMet =\r\n node.meetsMinimum &&\r\n (npm?.meetsMinimum ?? false) &&\r\n (globalBinDir?.isOnPath ?? false);\r\n\r\n return {\r\n node,\r\n npm,\r\n git,\r\n globalBinDir,\r\n allRequirementsMet,\r\n errors,\r\n validatedAt: new Date(),\r\n };\r\n }\r\n\r\n /**\r\n * Check Node.js version against the minimum requirement.\r\n * This is synchronous since we read from process.version.\r\n */\r\n checkNodeVersion(minimum: SemVer): RuntimeVersion {\r\n const rawVersion = process.version; // e.g., \"v20.11.0\"\r\n const version = parseSemVer(rawVersion);\r\n\r\n if (!version) {\r\n return {\r\n tool: 'node',\r\n version: semVer(0, 0, 0),\r\n executablePath: process.execPath,\r\n meetsMinimum: false,\r\n minimumRequired: minimum,\r\n };\r\n }\r\n\r\n return {\r\n tool: 'node',\r\n version,\r\n executablePath: process.execPath,\r\n meetsMinimum: semVerSatisfiesMinimum(version, minimum),\r\n minimumRequired: minimum,\r\n };\r\n }\r\n\r\n /**\r\n * Check npm version against the minimum requirement.\r\n * Executes `npm --version` via child_process.\r\n */\r\n async checkNpmVersion(minimum: SemVer): Promise<RuntimeVersion> {\r\n const rawVersion = execCommand('npm --version');\r\n\r\n if (!rawVersion) {\r\n throw new Error('npm is not available');\r\n }\r\n\r\n const version = parseSemVer(rawVersion);\r\n if (!version) {\r\n throw new Error(`Unable to parse npm version: ${rawVersion}`);\r\n }\r\n\r\n const executablePath = resolveExecutablePath('npm') ?? 'npm';\r\n\r\n return {\r\n tool: 'npm',\r\n version,\r\n executablePath,\r\n meetsMinimum: semVerSatisfiesMinimum(version, minimum),\r\n minimumRequired: minimum,\r\n };\r\n }\r\n\r\n /**\r\n * Check git version. Git is not strictly required but is reported.\r\n */\r\n private async checkGitVersion(): Promise<RuntimeVersion> {\r\n const rawVersion = execCommand('git --version');\r\n\r\n if (!rawVersion) {\r\n throw new Error('git is not available');\r\n }\r\n\r\n // git --version returns \"git version 2.43.0\" or similar\r\n const versionMatch = /(\\d+\\.\\d+\\.\\d+)/.exec(rawVersion);\r\n if (!versionMatch) {\r\n throw new Error(`Unable to parse git version: ${rawVersion}`);\r\n }\r\n\r\n const version = parseSemVer(versionMatch[1]);\r\n if (!version) {\r\n throw new Error(`Unable to parse git version: ${versionMatch[1]}`);\r\n }\r\n\r\n const executablePath = resolveExecutablePath('git') ?? 'git';\r\n\r\n // git minimum is not enforced, so meetsMinimum is always true\r\n return {\r\n tool: 'git',\r\n version,\r\n executablePath,\r\n meetsMinimum: true,\r\n minimumRequired: semVer(0, 0, 0),\r\n };\r\n }\r\n\r\n /**\r\n * Resolve the npm global bin directory and check if it is on PATH.\r\n *\r\n * On Unix: `npm config get prefix` returns the prefix, bin dir is `{prefix}/bin`\r\n * On Windows: `npm config get prefix` returns the prefix, which IS the bin dir\r\n */\r\n async resolveGlobalBinDir(\r\n shell: ShellEnvironment,\r\n ): Promise<GlobalBinDirectory> {\r\n const prefix = execCommand('npm config get prefix');\r\n\r\n if (!prefix) {\r\n throw new Error('Unable to resolve npm global bin directory');\r\n }\r\n\r\n const isWindows = process.platform === 'win32';\r\n const binDir = isWindows\r\n ? prefix.replace(/\\\\/g, '/')\r\n : prefix.replace(/\\\\/g, '/') + '/bin';\r\n\r\n const normalizedBinDir = createNormalizedPath(binDir);\r\n\r\n // Check if the bin directory is on PATH\r\n const pathEnv = process.env['PATH'] ?? process.env['Path'] ?? '';\r\n const pathDirs = pathEnv.split(shell.pathSeparator);\r\n\r\n const isOnPath = pathDirs.some((dir) => {\r\n const normalizedDir = dir.replace(/\\\\/g, '/').replace(/\\/+$/, '');\r\n return (\r\n normalizedDir.toLowerCase() === binDir.toLowerCase() ||\r\n normalizedDir.toLowerCase() === binDir.replace(/\\/bin$/, '').toLowerCase()\r\n );\r\n });\r\n\r\n let pathFixCommand: string | null = null;\r\n if (!isOnPath) {\r\n if (isWindows) {\r\n pathFixCommand = `$env:PATH = \"${binDir.replace(/\\//g, '\\\\')}\" + \";\" + $env:PATH`;\r\n } else {\r\n pathFixCommand = `export PATH=\"${binDir}:$PATH\"`;\r\n }\r\n }\r\n\r\n return {\r\n path: normalizedBinDir,\r\n isOnPath,\r\n pathFixCommand,\r\n };\r\n }\r\n\r\n /**\r\n * Check if an arbitrary tool is available on PATH.\r\n */\r\n async checkToolAvailable(\r\n toolName: string,\r\n ): Promise<{ available: boolean; path: string | null }> {\r\n const executablePath = resolveExecutablePath(toolName);\r\n return {\r\n available: executablePath !== null,\r\n path: executablePath,\r\n };\r\n }\r\n}\r\n","/**\r\n * Platform Facade - High-level entry point for all platform detection.\r\n *\r\n * Orchestrates all detection subsystems into a single detectAll() call.\r\n * Returns a complete PlatformEnvironment value object. Handles partial\r\n * failures gracefully -- only PlatformDetector failure is fatal.\r\n *\r\n * @module platform/facade\r\n */\r\n\r\nimport {\r\n ColorSupportLevel,\r\n type IPlatformFacade,\r\n type NormalizedPath,\r\n type PlatformEnvironment,\r\n PlatformError,\r\n type RuntimeReport,\r\n type ShellEnvironment,\r\n type TerminalProfile,\r\n semVer,\r\n} from './types.js';\r\nimport { PlatformDetector } from './detector.js';\r\nimport { PathNormalizer } from './paths.js';\r\nimport { PermissionChecker } from './permissions.js';\r\nimport { TerminalDetector } from './terminal.js';\r\nimport { ShellDetector } from './shell.js';\r\nimport { RuntimeValidator, MINIMUM_NODE_VERSION, MINIMUM_NPM_VERSION } from './runtime.js';\r\n\r\n/**\r\n * Safe defaults for terminal profile when detection fails.\r\n */\r\nfunction safeTerminalProfile(): TerminalProfile {\r\n return {\r\n colorSupport: ColorSupportLevel.None,\r\n dimensions: { columns: 80, rows: 24 },\r\n unicodeSupport: { supported: false, detectionMethod: 'default' },\r\n interactivity: { isInteractive: false, isTTY: false, supportsRawMode: false },\r\n emulator: { name: null, version: null, isKnown: false },\r\n detectedAt: new Date(),\r\n };\r\n}\r\n\r\n/**\r\n * Safe defaults for shell environment when detection fails.\r\n */\r\nfunction safeShellEnvironment(): ShellEnvironment {\r\n return {\r\n type: 'unknown',\r\n version: null,\r\n executablePath: '',\r\n profilePath: null,\r\n profileExists: false,\r\n pathSeparator: process.platform === 'win32' ? ';' : ':',\r\n pathModificationCommand: null,\r\n };\r\n}\r\n\r\n/**\r\n * Safe defaults for runtime report when validation fails.\r\n */\r\nfunction safeRuntimeReport(): RuntimeReport {\r\n return {\r\n node: {\r\n tool: 'node',\r\n version: semVer(0, 0, 0),\r\n executablePath: process.execPath,\r\n meetsMinimum: false,\r\n minimumRequired: MINIMUM_NODE_VERSION,\r\n },\r\n npm: null,\r\n git: null,\r\n globalBinDir: null,\r\n allRequirementsMet: false,\r\n errors: [\r\n {\r\n tool: 'runtime',\r\n errorType: 'not_found',\r\n message: 'Runtime validation failed unexpectedly.',\r\n fix: 'Ensure Node.js >= 18.0.0 and npm >= 9.0.0 are installed.',\r\n },\r\n ],\r\n validatedAt: new Date(),\r\n };\r\n}\r\n\r\n/**\r\n * PlatformFacade implementation.\r\n *\r\n * Orchestrates all platform detection subsystems. Called once at installer\r\n * startup by unit-cli-orchestrator. Follows graceful degradation per ADR-007:\r\n * only PlatformDetector failure is fatal.\r\n */\r\nexport class PlatformFacade implements IPlatformFacade {\r\n private readonly platformDetector: PlatformDetector;\r\n private readonly pathNormalizer: PathNormalizer;\r\n private readonly permissionChecker: PermissionChecker;\r\n private readonly terminalDetector: TerminalDetector;\r\n private readonly shellDetector: ShellDetector;\r\n private readonly runtimeValidator: RuntimeValidator;\r\n\r\n constructor() {\r\n this.platformDetector = new PlatformDetector();\r\n this.pathNormalizer = new PathNormalizer();\r\n this.permissionChecker = new PermissionChecker();\r\n this.terminalDetector = new TerminalDetector();\r\n this.shellDetector = new ShellDetector();\r\n this.runtimeValidator = new RuntimeValidator();\r\n }\r\n\r\n /**\r\n * Detect all platform capabilities in a single coordinated call.\r\n *\r\n * Detection flow:\r\n * 1. PlatformDetector.detect() -- FATAL on failure\r\n * 2. TerminalDetector.detectProfile() -- parallel with step 3\r\n * 3. ShellDetector.detectShell(snapshot) -- parallel with step 2\r\n * 4. RuntimeValidator.validate() -- depends on step 3\r\n * 5. Assemble PlatformEnvironment\r\n *\r\n * @throws PlatformError with code UNSUPPORTED_PLATFORM if OS detection fails\r\n */\r\n async detectAll(): Promise<PlatformEnvironment> {\r\n // Step 1: Platform detection (synchronous, FATAL on failure)\r\n const platform = this.platformDetector.detect();\r\n\r\n // Steps 2 & 3: Terminal and Shell detection (parallel)\r\n const [terminal, shell] = await Promise.all([\r\n this.safeDetectTerminal(),\r\n this.safeDetectShell(platform),\r\n ]);\r\n\r\n // Step 4: Runtime validation (depends on shell)\r\n const runtime = await this.safeValidateRuntime();\r\n\r\n // Step 5: Assemble PlatformEnvironment\r\n const permissionChecker = this.permissionChecker;\r\n const pathNormalizer = this.pathNormalizer;\r\n\r\n return {\r\n platform,\r\n terminal,\r\n shell,\r\n runtime,\r\n permissions: {\r\n checkWriteAccess: (path: NormalizedPath) =>\r\n permissionChecker.checkWriteAccess(path, platform),\r\n checkDirectoryCreatable: (path: NormalizedPath) =>\r\n permissionChecker.checkDirectoryCreatable(path, platform),\r\n },\r\n paths: pathNormalizer,\r\n };\r\n }\r\n\r\n /**\r\n * Safely detect terminal profile. Returns safe defaults on failure.\r\n */\r\n private async safeDetectTerminal(): Promise<TerminalProfile> {\r\n try {\r\n return this.terminalDetector.detectProfile();\r\n } catch {\r\n return safeTerminalProfile();\r\n }\r\n }\r\n\r\n /**\r\n * Safely detect shell environment. Returns safe defaults on failure.\r\n */\r\n private async safeDetectShell(\r\n platform: ReturnType<PlatformDetector['detect']>,\r\n ): Promise<ShellEnvironment> {\r\n try {\r\n return await this.shellDetector.detectShell(platform);\r\n } catch {\r\n return safeShellEnvironment();\r\n }\r\n }\r\n\r\n /**\r\n * Safely validate runtime. Returns safe defaults on failure.\r\n */\r\n private async safeValidateRuntime(): Promise<RuntimeReport> {\r\n try {\r\n return await this.runtimeValidator.validate(\r\n MINIMUM_NODE_VERSION,\r\n MINIMUM_NPM_VERSION,\r\n );\r\n } catch {\r\n return safeRuntimeReport();\r\n }\r\n }\r\n}\r\n","/**\r\n * Component Manifest - Source directory scanning and component classification.\r\n *\r\n * Walks the source directory tree, classifies files into categories based on\r\n * directory structure conventions, and produces an immutable ComponentManifest.\r\n * Uses fs/promises exclusively for all I/O operations.\r\n *\r\n * @module engine/manifest\r\n */\r\n\r\nimport * as fs from 'node:fs/promises';\r\nimport * as path from 'node:path';\r\n\r\nimport type {\r\n ComponentEntry,\r\n ComponentManifest,\r\n ComponentType,\r\n} from './types.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Classification Rules\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Directory patterns mapped to component types.\r\n * Order matters: first match wins for classification.\r\n */\r\nconst CATEGORY_RULES: ReadonlyArray<{\r\n readonly pattern: RegExp;\r\n readonly type: ComponentType;\r\n}> = [\r\n { pattern: /^agents[/\\\\]/, type: 'agents' },\r\n { pattern: /^skills[/\\\\]/, type: 'skills' },\r\n { pattern: /^commands[/\\\\]/, type: 'commands' },\r\n { pattern: /^cli[/\\\\]/, type: 'cli' },\r\n { pattern: /^typescript[/\\\\]/, type: 'cli' },\r\n { pattern: /^workflows[/\\\\]/, type: 'workflows' },\r\n { pattern: /^metadata[/\\\\]/, type: 'metadata' },\r\n];\r\n\r\n/**\r\n * Directories to ignore during scanning.\r\n * These are never recursed into.\r\n */\r\nconst IGNORED_DIRECTORIES: ReadonlySet<string> = new Set([\r\n 'node_modules',\r\n '.git',\r\n 'dist',\r\n 'build',\r\n 'out',\r\n '.next',\r\n '__pycache__',\r\n 'coverage',\r\n]);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Classification Logic\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Classify a file's relative path into a ComponentType.\r\n * Falls back to 'metadata' for files that do not match any rule.\r\n */\r\nfunction classifyComponent(relativePath: string): ComponentType {\r\n // Normalize to forward slashes for pattern matching\r\n const normalized = relativePath.replace(/\\\\/g, '/');\r\n\r\n for (const rule of CATEGORY_RULES) {\r\n if (rule.pattern.test(normalized)) {\r\n return rule.type;\r\n }\r\n }\r\n\r\n return 'metadata';\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Directory Walking\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Recursively walk a directory and collect all file entries.\r\n * Skips ignored directories and hidden directories (except conventions\r\n * like .claude/ that may appear within the source).\r\n *\r\n * @param rootDir - Absolute path to the root directory being scanned.\r\n * @param currentDir - Absolute path to the current directory being processed.\r\n * @returns Array of ComponentEntry objects for all discovered files.\r\n */\r\nasync function walkDirectory(\r\n rootDir: string,\r\n currentDir: string,\r\n): Promise<ComponentEntry[]> {\r\n const entries: ComponentEntry[] = [];\r\n let dirEntries: import('fs').Dirent[];\r\n\r\n try {\r\n dirEntries = await fs.readdir(currentDir, { withFileTypes: true });\r\n } catch {\r\n // If we cannot read the directory, skip it silently\r\n return entries;\r\n }\r\n\r\n for (const dirEntry of dirEntries) {\r\n const fullPath = path.join(currentDir, dirEntry.name);\r\n\r\n if (dirEntry.isDirectory()) {\r\n // Skip ignored directories\r\n if (IGNORED_DIRECTORIES.has(dirEntry.name)) {\r\n continue;\r\n }\r\n\r\n // Recurse into subdirectories\r\n const subEntries = await walkDirectory(rootDir, fullPath);\r\n entries.push(...subEntries);\r\n } else if (dirEntry.isFile()) {\r\n const relativePath = path.relative(rootDir, fullPath);\r\n const componentType = classifyComponent(relativePath);\r\n\r\n try {\r\n const stat = await fs.stat(fullPath);\r\n entries.push({\r\n relativePath,\r\n fileName: dirEntry.name,\r\n componentType,\r\n sizeBytes: stat.size,\r\n });\r\n } catch {\r\n // If we cannot stat the file, skip it\r\n continue;\r\n }\r\n }\r\n }\r\n\r\n return entries;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Scan a source directory and build a ComponentManifest.\r\n *\r\n * Walks the entire directory tree, classifies each file into a category\r\n * based on its directory path, and returns an immutable manifest with\r\n * component counts.\r\n *\r\n * @param sourceDirectory - Absolute path to the source AI-DLC library directory.\r\n * @returns A fully populated ComponentManifest.\r\n * @throws Error if the source directory does not exist or is not readable.\r\n */\r\nexport async function scanSourceDirectory(\r\n sourceDirectory: string,\r\n): Promise<ComponentManifest> {\r\n // Validate source directory exists\r\n try {\r\n const stat = await fs.stat(sourceDirectory);\r\n if (!stat.isDirectory()) {\r\n throw new Error(\r\n `Source path is not a directory: ${sourceDirectory}`,\r\n );\r\n }\r\n } catch (error) {\r\n if (error instanceof Error && error.message.startsWith('Source path')) {\r\n throw error;\r\n }\r\n throw new Error(\r\n `Source directory does not exist or is not accessible: ${sourceDirectory}`,\r\n );\r\n }\r\n\r\n const entries = await walkDirectory(sourceDirectory, sourceDirectory);\r\n\r\n const countsByType = countComponentsByType(entries);\r\n\r\n return {\r\n entries,\r\n totalCount: entries.length,\r\n countsByType,\r\n };\r\n}\r\n\r\n/**\r\n * Filter manifest entries by one or more component types.\r\n *\r\n * @param manifest - The manifest to filter.\r\n * @param types - One or more ComponentType values to include.\r\n * @returns A new array containing only entries matching the specified types.\r\n */\r\nexport function filterByComponentType(\r\n manifest: ComponentManifest,\r\n ...types: ComponentType[]\r\n): readonly ComponentEntry[] {\r\n const typeSet = new Set(types);\r\n return manifest.entries.filter((entry) => typeSet.has(entry.componentType));\r\n}\r\n\r\n/**\r\n * Count components grouped by type.\r\n *\r\n * @param entries - Array of ComponentEntry objects.\r\n * @returns A record mapping each ComponentType to its count.\r\n */\r\nexport function countComponentsByType(\r\n entries: readonly ComponentEntry[],\r\n): Record<ComponentType, number> {\r\n const counts: Record<ComponentType, number> = {\r\n agents: 0,\r\n skills: 0,\r\n commands: 0,\r\n cli: 0,\r\n workflows: 0,\r\n metadata: 0,\r\n };\r\n\r\n for (const entry of entries) {\r\n counts[entry.componentType]++;\r\n }\r\n\r\n return counts;\r\n}\r\n","/**\r\n * Conflict Detector - Detect conflicts between source and target directories.\r\n *\r\n * Compares a ComponentManifest against the existing contents of a target\r\n * directory. Classifies every file as new, identical, or modified using\r\n * SHA-256 content hashes. Detects partial installations and existing\r\n * .claude/ directories.\r\n *\r\n * Uses fs/promises and node:crypto exclusively. No external dependencies.\r\n *\r\n * @module engine/conflict-detector\r\n */\r\n\r\nimport * as fs from 'node:fs/promises';\r\nimport * as crypto from 'node:crypto';\r\nimport * as nodePath from 'node:path';\r\n\r\nimport type {\r\n ComponentManifest,\r\n ConflictFileEntry,\r\n ConflictReport,\r\n FileConflictStatus,\r\n} from './types.js';\r\n\r\nimport { INSTALL_CATEGORIES } from './category-filter.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Hashing\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Compute the SHA-256 hash of a file using streaming reads.\r\n * Reads the file in chunks to avoid loading entire contents into memory.\r\n *\r\n * @param filePath - Absolute path to the file.\r\n * @returns Hex-encoded SHA-256 hash string.\r\n */\r\nasync function computeFileHash(filePath: string): Promise<string> {\r\n const content = await fs.readFile(filePath);\r\n return crypto.createHash('sha256').update(content).digest('hex');\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Target Directory Detection\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Check if a directory exists at the given path.\r\n *\r\n * @param dirPath - Absolute path to check.\r\n * @returns True if the path exists and is a directory.\r\n */\r\nasync function directoryExists(dirPath: string): Promise<boolean> {\r\n try {\r\n const stat = await fs.stat(dirPath);\r\n return stat.isDirectory();\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Check if a file exists at the given path.\r\n *\r\n * @param filePath - Absolute path to check.\r\n * @returns True if the path exists and is a file.\r\n */\r\nasync function fileExists(filePath: string): Promise<boolean> {\r\n try {\r\n const stat = await fs.stat(filePath);\r\n return stat.isFile();\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Detect conflicts between a source component manifest and a target directory.\r\n *\r\n * For each component entry in the manifest:\r\n * 1. If the target file does not exist: status = 'new'\r\n * 2. If the target file exists: compute SHA-256 hashes of both source and target\r\n * - If hashes match: status = 'identical'\r\n * - If hashes differ: status = 'modified'\r\n *\r\n * Also detects whether the target .claude/ directory exists (indicating a\r\n * brownfield / existing installation).\r\n *\r\n * @param manifest - The ComponentManifest describing all source files.\r\n * @param sourceDirectory - Absolute path to the source library directory.\r\n * @param targetDirectory - Absolute path to the target .claude/ directory.\r\n * @returns A ConflictReport with all file statuses and conflict summary.\r\n */\r\nexport async function detectConflicts(\r\n manifest: ComponentManifest,\r\n sourceDirectory: string,\r\n targetDirectory: string,\r\n): Promise<ConflictReport> {\r\n const isExistingInstallation = await directoryExists(targetDirectory);\r\n\r\n const files: ConflictFileEntry[] = [];\r\n const existingFiles: string[] = [];\r\n const modifiedFiles: string[] = [];\r\n let newCount = 0;\r\n let identicalCount = 0;\r\n let modifiedCount = 0;\r\n\r\n for (const entry of manifest.entries) {\r\n const sourcePath = nodePath.join(sourceDirectory, entry.relativePath);\r\n const targetPath = nodePath.join(targetDirectory, entry.relativePath);\r\n\r\n const targetFileExists = await fileExists(targetPath);\r\n\r\n if (!targetFileExists) {\r\n // File does not exist at target -- always a new file\r\n const sourceHash = await computeFileHash(sourcePath);\r\n files.push({\r\n relativePath: entry.relativePath,\r\n status: 'new' as FileConflictStatus,\r\n sourceHash,\r\n targetHash: null,\r\n });\r\n newCount++;\r\n continue;\r\n }\r\n\r\n // File exists at target -- compute hashes and compare\r\n existingFiles.push(entry.relativePath);\r\n\r\n const [sourceHash, targetHash] = await Promise.all([\r\n computeFileHash(sourcePath),\r\n computeFileHash(targetPath),\r\n ]);\r\n\r\n if (sourceHash === targetHash) {\r\n files.push({\r\n relativePath: entry.relativePath,\r\n status: 'identical' as FileConflictStatus,\r\n sourceHash,\r\n targetHash,\r\n });\r\n identicalCount++;\r\n } else {\r\n files.push({\r\n relativePath: entry.relativePath,\r\n status: 'modified' as FileConflictStatus,\r\n sourceHash,\r\n targetHash,\r\n });\r\n modifiedFiles.push(entry.relativePath);\r\n modifiedCount++;\r\n }\r\n }\r\n\r\n return {\r\n files,\r\n existingFiles,\r\n modifiedFiles,\r\n newCount,\r\n identicalCount,\r\n modifiedCount,\r\n hasConflicts: modifiedCount > 0,\r\n isExistingInstallation,\r\n };\r\n}\r\n\r\n/**\r\n * List existing files in a target directory that would be affected\r\n * by installation. Returns relative paths of all files found.\r\n *\r\n * @param targetDirectory - Absolute path to the target .claude/ directory.\r\n * @returns Array of relative file paths, or empty array if directory does not exist.\r\n */\r\nexport async function listExistingFiles(\r\n targetDirectory: string,\r\n): Promise<readonly string[]> {\r\n const exists = await directoryExists(targetDirectory);\r\n if (!exists) {\r\n return [];\r\n }\r\n\r\n const results: string[] = [];\r\n\r\n async function walk(dir: string): Promise<void> {\r\n let entries: import('fs').Dirent[];\r\n try {\r\n entries = await fs.readdir(dir, { withFileTypes: true });\r\n } catch {\r\n return;\r\n }\r\n\r\n for (const entry of entries) {\r\n const fullPath = nodePath.join(dir, entry.name);\r\n if (entry.isDirectory()) {\r\n await walk(fullPath);\r\n } else if (entry.isFile()) {\r\n results.push(nodePath.relative(targetDirectory, fullPath));\r\n }\r\n }\r\n }\r\n\r\n await walk(targetDirectory);\r\n return results;\r\n}\r\n\r\n/**\r\n * Detect whether an installation is partial by checking if the target\r\n * directory exists but contains fewer files than the source manifest.\r\n *\r\n * @param manifest - The ComponentManifest describing all source files.\r\n * @param targetDirectory - Absolute path to the target .claude/ directory.\r\n * @returns True if the target exists but has fewer files than the source.\r\n */\r\nexport async function isPartialInstallation(\r\n manifest: ComponentManifest,\r\n targetDirectory: string,\r\n): Promise<boolean> {\r\n const exists = await directoryExists(targetDirectory);\r\n if (!exists) {\r\n return false;\r\n }\r\n\r\n const existing = await listExistingFiles(targetDirectory);\r\n\r\n // Partial: target exists with some files but fewer than expected\r\n return existing.length > 0 && existing.length < manifest.totalCount;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Category Conflict Analysis\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Per-category conflict statistics. */\r\nexport interface CategoryConflictSummary {\r\n /** Category identifier matching InstallCategory.id. */\r\n readonly categoryId: string;\r\n /** Total number of files in this category. */\r\n readonly totalFiles: number;\r\n /** Number of files that have been modified since the last install. */\r\n readonly modifiedFiles: number;\r\n /** Number of files that are new (do not exist at target). */\r\n readonly newFiles: number;\r\n}\r\n\r\n/**\r\n * Map conflicting (modified) files back to their category IDs.\r\n *\r\n * For each modified file in the conflict report, determines which\r\n * install category it belongs to based on path prefix matching.\r\n *\r\n * @param conflicts - The conflict report from `detectConflicts`.\r\n * @returns Array of unique category IDs that contain modified files.\r\n */\r\nexport function getModifiedCategories(conflicts: ConflictReport): string[] {\r\n const categoryIds = new Set<string>();\r\n\r\n for (const filePath of conflicts.modifiedFiles) {\r\n const normalised = filePath.replace(/\\\\/g, '/');\r\n for (const cat of INSTALL_CATEGORIES) {\r\n if (normalised.startsWith(cat.pathPrefix)) {\r\n categoryIds.add(cat.id);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n return [...categoryIds];\r\n}\r\n\r\n/**\r\n * Build per-category conflict statistics from a conflict report.\r\n *\r\n * Each category in `INSTALL_CATEGORIES` is checked against the conflict\r\n * report's file entries. Only categories with at least one file are included.\r\n *\r\n * @param conflicts - The conflict report from `detectConflicts`.\r\n * @returns Array of per-category summaries, ordered by INSTALL_CATEGORIES order.\r\n */\r\nexport function getCategorySummary(conflicts: ConflictReport): CategoryConflictSummary[] {\r\n const summaries: CategoryConflictSummary[] = [];\r\n\r\n for (const cat of INSTALL_CATEGORIES) {\r\n let totalFiles = 0;\r\n let modifiedFiles = 0;\r\n let newFiles = 0;\r\n\r\n for (const file of conflicts.files) {\r\n const normalised = file.relativePath.replace(/\\\\/g, '/');\r\n if (normalised.startsWith(cat.pathPrefix)) {\r\n totalFiles++;\r\n if (file.status === 'modified') {\r\n modifiedFiles++;\r\n } else if (file.status === 'new') {\r\n newFiles++;\r\n }\r\n }\r\n }\r\n\r\n if (totalFiles > 0) {\r\n summaries.push({ categoryId: cat.id, totalFiles, modifiedFiles, newFiles });\r\n }\r\n }\r\n\r\n return summaries;\r\n}\r\n","/**\r\n * File Copier - Parallel file copy with bounded concurrency.\r\n *\r\n * Copies files from source to destination according to an InstallationPlan.\r\n * Uses a semaphore-based work queue to limit concurrent I/O operations,\r\n * preventing file descriptor exhaustion. Reports progress via callback\r\n * after each completed operation.\r\n *\r\n * Uses fs/promises exclusively. No external dependencies.\r\n *\r\n * @module engine/file-copier\r\n */\r\n\r\nimport * as fs from 'node:fs/promises';\r\nimport * as path from 'node:path';\r\n\r\nimport type {\r\n ComponentType,\r\n FileMapping,\r\n InstallationError,\r\n InstallationResult,\r\n InstallationWarning,\r\n ProgressCallback,\r\n} from './types.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Semaphore - Bounded Concurrency Control\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * A counting semaphore for limiting concurrent async operations.\r\n * Uses a FIFO queue: when all permits are taken, new acquirers wait\r\n * in order. When a permit is released, the next waiter is woken.\r\n */\r\nclass Semaphore {\r\n private permits: number;\r\n private readonly queue: Array<() => void> = [];\r\n\r\n constructor(maxConcurrent: number) {\r\n this.permits = maxConcurrent;\r\n }\r\n\r\n /** Acquire a permit. Resolves immediately if available, else waits. */\r\n async acquire(): Promise<void> {\r\n if (this.permits > 0) {\r\n this.permits--;\r\n return;\r\n }\r\n return new Promise<void>((resolve) => this.queue.push(resolve));\r\n }\r\n\r\n /** Release a permit. Wakes the next waiter if any. */\r\n release(): void {\r\n const next = this.queue.shift();\r\n if (next) {\r\n next();\r\n } else {\r\n this.permits++;\r\n }\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Directory Creation\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Collect all unique parent directories from file mappings\r\n * and create them. Deduplicates and sorts to ensure parents\r\n * are created before children.\r\n */\r\nasync function ensureDirectories(files: readonly FileMapping[]): Promise<void> {\r\n const dirs = new Set<string>();\r\n\r\n for (const file of files) {\r\n const dir = path.dirname(file.destinationPath);\r\n dirs.add(dir);\r\n }\r\n\r\n // Sort so that shorter (parent) paths are created first\r\n const sorted = Array.from(dirs).sort((a, b) => a.length - b.length);\r\n\r\n for (const dir of sorted) {\r\n await fs.mkdir(dir, { recursive: true });\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Single File Copy\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Copy a single file from source to destination.\r\n * Uses fs.copyFile which leverages the most efficient platform mechanism\r\n * (sendfile on Linux, COPYFILE_FICLONE on macOS).\r\n */\r\nasync function copySingleFile(\r\n sourcePath: string,\r\n destinationPath: string,\r\n): Promise<void> {\r\n await fs.copyFile(sourcePath, destinationPath);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Default concurrency limit for parallel file copy. */\r\nexport const DEFAULT_CONCURRENCY = 10;\r\n\r\n/** Minimum allowed concurrency limit. */\r\nexport const MIN_CONCURRENCY = 1;\r\n\r\n/** Maximum allowed concurrency limit. */\r\nexport const MAX_CONCURRENCY = 64;\r\n\r\n/**\r\n * Copy files from source to destination according to file mappings.\r\n *\r\n * Creates all necessary directories, then copies files in parallel\r\n * up to the configured concurrency limit. Reports progress via\r\n * callback after each file completes. Implements fail-fast: on\r\n * any copy failure, stops dispatching new work (in-flight copies\r\n * are allowed to complete).\r\n *\r\n * @param files - Array of FileMapping objects describing source/destination pairs.\r\n * @param options - Configuration options.\r\n * @param options.concurrency - Maximum parallel copy operations (default: 10, range: 1-64).\r\n * @param options.onProgress - Callback invoked after each file completes.\r\n * @returns InstallationResult with success status, counts, and any errors.\r\n */\r\nexport async function copyFiles(\r\n files: readonly FileMapping[],\r\n options: {\r\n concurrency?: number;\r\n onProgress?: ProgressCallback;\r\n } = {},\r\n): Promise<InstallationResult> {\r\n const startTime = Date.now();\r\n\r\n // Clamp concurrency to valid range\r\n const concurrency = Math.max(\r\n MIN_CONCURRENCY,\r\n Math.min(MAX_CONCURRENCY, options.concurrency ?? DEFAULT_CONCURRENCY),\r\n );\r\n\r\n const onProgress = options.onProgress ?? (() => {});\r\n const total = files.length;\r\n\r\n if (total === 0) {\r\n return buildResult(true, 0, 0, [], [], startTime, {});\r\n }\r\n\r\n // Create all target directories up front\r\n await ensureDirectories(files);\r\n\r\n // Track results\r\n const errors: InstallationError[] = [];\r\n const warnings: InstallationWarning[] = [];\r\n const componentCounts: Record<ComponentType, number> = {\r\n agents: 0,\r\n skills: 0,\r\n commands: 0,\r\n cli: 0,\r\n workflows: 0,\r\n metadata: 0,\r\n };\r\n\r\n let copiedCount = 0;\r\n let skippedCount = 0;\r\n let completedCount = 0;\r\n let hasFailed = false;\r\n\r\n const semaphore = new Semaphore(concurrency);\r\n\r\n // Launch all copy tasks. The semaphore limits actual parallelism.\r\n const tasks = files.map(async (file) => {\r\n await semaphore.acquire();\r\n\r\n try {\r\n // If a previous file failed, skip remaining work\r\n if (hasFailed) {\r\n skippedCount++;\r\n return;\r\n }\r\n\r\n await copySingleFile(file.sourcePath, file.destinationPath);\r\n copiedCount++;\r\n componentCounts[file.componentType]++;\r\n } catch (error) {\r\n hasFailed = true;\r\n const message =\r\n error instanceof Error ? error.message : String(error);\r\n errors.push({\r\n code: 'COPY_FAILED',\r\n message: `Failed to copy ${file.relativePath}: ${message}`,\r\n filePath: file.relativePath,\r\n originalError: message,\r\n });\r\n } finally {\r\n completedCount++;\r\n try {\r\n onProgress({\r\n fileName: file.fileName,\r\n current: completedCount,\r\n total,\r\n });\r\n } catch {\r\n // Progress callback errors must not halt installation\r\n }\r\n semaphore.release();\r\n }\r\n });\r\n\r\n await Promise.all(tasks);\r\n\r\n const success = errors.length === 0;\r\n\r\n return buildResult(\r\n success,\r\n copiedCount,\r\n skippedCount,\r\n warnings,\r\n errors,\r\n startTime,\r\n componentCounts,\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Result Builder\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Build an InstallationResult from the provided metrics.\r\n */\r\nfunction buildResult(\r\n success: boolean,\r\n copiedCount: number,\r\n skippedCount: number,\r\n warnings: readonly InstallationWarning[],\r\n errors: readonly InstallationError[],\r\n startTime: number,\r\n componentCounts: Record<string, number>,\r\n): InstallationResult {\r\n return {\r\n success,\r\n copiedCount,\r\n skippedCount,\r\n warnings,\r\n errors,\r\n durationMs: Date.now() - startTime,\r\n componentCounts: {\r\n agents: componentCounts['agents'] ?? 0,\r\n skills: componentCounts['skills'] ?? 0,\r\n commands: componentCounts['commands'] ?? 0,\r\n cli: componentCounts['cli'] ?? 0,\r\n workflows: componentCounts['workflows'] ?? 0,\r\n metadata: componentCounts['metadata'] ?? 0,\r\n },\r\n };\r\n}\r\n","/**\r\n * Rollback - Backup creation, restoration, and cleanup.\r\n *\r\n * Creates timestamped backup directories before overwriting existing files.\r\n * Provides rollback restoration on installation failure and cleanup on\r\n * success. Backup directory naming follows the convention:\r\n * .ai-dlc-backup/{ISO-timestamp}/\r\n *\r\n * Uses fs/promises exclusively. No external dependencies.\r\n *\r\n * @module engine/rollback\r\n */\r\n\r\nimport * as fs from 'node:fs/promises';\r\nimport * as path from 'node:path';\r\n\r\nimport type {\r\n BackedUpFile,\r\n BackupManifest,\r\n InstallationError,\r\n RollbackResult,\r\n} from './types.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Constants\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Directory name prefix for backup directories within the target.\r\n * Full path: {targetDirectory}/.ai-dlc-backup/{timestamp}/\r\n */\r\nconst BACKUP_ROOT_DIR = '.ai-dlc-backup';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Timestamp\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Generate a filesystem-safe ISO 8601 timestamp.\r\n * Replaces colons with hyphens for Windows compatibility.\r\n *\r\n * @returns A string like \"2026-02-13T163000Z\"\r\n */\r\nfunction generateTimestamp(): string {\r\n return new Date()\r\n .toISOString()\r\n .replace(/:/g, '')\r\n .replace(/\\.\\d+Z$/, 'Z');\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Create a timestamped backup directory and copy files that will be\r\n * overwritten during installation.\r\n *\r\n * @param targetDirectory - Absolute path to the target .claude/ directory.\r\n * @param filesToBackup - Relative paths (from targetDirectory) of files to back up.\r\n * @returns A BackupManifest describing the backup, or null if no files needed backup.\r\n */\r\nexport async function createBackup(\r\n targetDirectory: string,\r\n filesToBackup: readonly string[],\r\n): Promise<BackupManifest | null> {\r\n if (filesToBackup.length === 0) {\r\n return null;\r\n }\r\n\r\n const timestamp = generateTimestamp();\r\n const backupDirectory = path.join(\r\n targetDirectory,\r\n BACKUP_ROOT_DIR,\r\n timestamp,\r\n );\r\n\r\n // Create the backup directory\r\n await fs.mkdir(backupDirectory, { recursive: true });\r\n\r\n const backedUpFiles: BackedUpFile[] = [];\r\n\r\n for (const relativePath of filesToBackup) {\r\n const sourcePath = path.join(targetDirectory, relativePath);\r\n const backupPath = path.join(backupDirectory, relativePath);\r\n\r\n try {\r\n // Check the source file exists before attempting backup\r\n await fs.access(sourcePath);\r\n\r\n // Create parent directory in backup location\r\n await fs.mkdir(path.dirname(backupPath), { recursive: true });\r\n\r\n // Copy the file to backup\r\n await fs.copyFile(sourcePath, backupPath);\r\n\r\n backedUpFiles.push({\r\n originalRelativePath: relativePath,\r\n backupPath,\r\n });\r\n } catch {\r\n // If we cannot back up a file (e.g., it was deleted between\r\n // conflict detection and backup), skip it. This is not fatal.\r\n continue;\r\n }\r\n }\r\n\r\n return {\r\n backupDirectory,\r\n files: backedUpFiles,\r\n createdAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\n/**\r\n * Restore all backed-up files to their original locations in the\r\n * target directory. This is the rollback operation invoked on\r\n * installation failure.\r\n *\r\n * Rollback is designed to be idempotent: calling it multiple times\r\n * produces the same result.\r\n *\r\n * @param backup - The BackupManifest from a prior createBackup call.\r\n * @param targetDirectory - Absolute path to the target .claude/ directory.\r\n * @returns A RollbackResult with success status and restore counts.\r\n */\r\nexport async function restoreFromBackup(\r\n backup: BackupManifest,\r\n targetDirectory: string,\r\n): Promise<RollbackResult> {\r\n const errors: InstallationError[] = [];\r\n let restoredCount = 0;\r\n\r\n for (const file of backup.files) {\r\n const restorePath = path.join(targetDirectory, file.originalRelativePath);\r\n\r\n try {\r\n // Ensure the parent directory exists (it may have been modified)\r\n await fs.mkdir(path.dirname(restorePath), { recursive: true });\r\n\r\n // Copy the backed-up file back to its original location\r\n await fs.copyFile(file.backupPath, restorePath);\r\n restoredCount++;\r\n } catch (error) {\r\n const message =\r\n error instanceof Error ? error.message : String(error);\r\n errors.push({\r\n code: 'ROLLBACK_RESTORE_FAILED',\r\n message: `Failed to restore ${file.originalRelativePath}: ${message}`,\r\n filePath: file.originalRelativePath,\r\n originalError: message,\r\n });\r\n }\r\n }\r\n\r\n return {\r\n success: errors.length === 0,\r\n restoredCount,\r\n errors,\r\n };\r\n}\r\n\r\n/**\r\n * Delete the backup directory after a successful installation.\r\n * Removes the entire backup directory tree.\r\n *\r\n * Cleanup failure is non-fatal: the backup directory simply remains\r\n * on disk and can be manually deleted.\r\n *\r\n * @param backup - The BackupManifest to clean up.\r\n */\r\nexport async function cleanupBackup(backup: BackupManifest): Promise<void> {\r\n try {\r\n await fs.rm(backup.backupDirectory, { recursive: true, force: true });\r\n } catch {\r\n // Cleanup failure is non-fatal. The backup directory remains\r\n // on disk but does not affect the installation.\r\n }\r\n}\r\n\r\n/**\r\n * List all existing backup directories under the target directory.\r\n * Returns absolute paths sorted by name (which are timestamps,\r\n * so sorting is chronological).\r\n *\r\n * @param targetDirectory - Absolute path to the target .claude/ directory.\r\n * @returns Array of absolute paths to backup directories.\r\n */\r\nexport async function listBackups(\r\n targetDirectory: string,\r\n): Promise<readonly string[]> {\r\n const backupRoot = path.join(targetDirectory, BACKUP_ROOT_DIR);\r\n\r\n try {\r\n const entries = await fs.readdir(backupRoot, { withFileTypes: true });\r\n return entries\r\n .filter((entry) => entry.isDirectory())\r\n .map((entry) => path.join(backupRoot, entry.name))\r\n .sort();\r\n } catch {\r\n // If the backup root does not exist, there are no backups\r\n return [];\r\n }\r\n}\r\n","/**\r\n * Validator - Post-installation integrity verification.\r\n *\r\n * Verifies that all expected files exist at their destination paths\r\n * and have non-zero file sizes. Produces a ValidationReport that\r\n * the orchestrator uses to determine installation success.\r\n *\r\n * Uses fs/promises exclusively. No external dependencies.\r\n *\r\n * @module engine/validator\r\n */\r\n\r\nimport * as fs from 'node:fs/promises';\r\nimport * as path from 'node:path';\r\n\r\nimport type {\r\n FileMapping,\r\n InvalidFile,\r\n ValidationReport,\r\n} from './types.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Single File Validation\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Validate that a single file exists at its expected destination\r\n * and has a non-zero file size.\r\n *\r\n * @param destinationPath - Absolute path where the file should exist.\r\n * @param relativePath - Relative path for reporting purposes.\r\n * @returns null if valid, or an InvalidFile describing the issue.\r\n */\r\nasync function validateSingleFile(\r\n destinationPath: string,\r\n relativePath: string,\r\n): Promise<InvalidFile | null> {\r\n try {\r\n const stat = await fs.stat(destinationPath);\r\n\r\n if (!stat.isFile()) {\r\n return {\r\n relativePath,\r\n reason: 'Path exists but is not a regular file',\r\n };\r\n }\r\n\r\n if (stat.size === 0) {\r\n return {\r\n relativePath,\r\n reason: 'File exists but has zero size',\r\n };\r\n }\r\n\r\n return null;\r\n } catch (error) {\r\n // File does not exist or is not accessible\r\n const code =\r\n error instanceof Error && 'code' in error\r\n ? (error as NodeJS.ErrnoException).code\r\n : undefined;\r\n\r\n if (code === 'ENOENT') {\r\n return {\r\n relativePath,\r\n reason: 'File does not exist at destination',\r\n };\r\n }\r\n\r\n const message =\r\n error instanceof Error ? error.message : String(error);\r\n return {\r\n relativePath,\r\n reason: `Cannot access file: ${message}`,\r\n };\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Public API\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Validate that all files in the installation plan exist at their\r\n * destination and have non-zero file sizes.\r\n *\r\n * @param files - Array of FileMapping objects that were copied.\r\n * @returns A ValidationReport with pass/fail status and details.\r\n */\r\nexport async function validateInstallation(\r\n files: readonly FileMapping[],\r\n): Promise<ValidationReport> {\r\n if (files.length === 0) {\r\n return {\r\n valid: true,\r\n totalChecked: 0,\r\n validCount: 0,\r\n missingFiles: [],\r\n invalidFiles: [],\r\n };\r\n }\r\n\r\n const missingFiles: string[] = [];\r\n const invalidFiles: InvalidFile[] = [];\r\n let validCount = 0;\r\n\r\n // Validate each file\r\n for (const file of files) {\r\n const issue = await validateSingleFile(\r\n file.destinationPath,\r\n file.relativePath,\r\n );\r\n\r\n if (issue === null) {\r\n validCount++;\r\n } else if (issue.reason.includes('does not exist')) {\r\n missingFiles.push(file.relativePath);\r\n invalidFiles.push(issue);\r\n } else {\r\n invalidFiles.push(issue);\r\n }\r\n }\r\n\r\n return {\r\n valid: missingFiles.length === 0 && invalidFiles.length === 0,\r\n totalChecked: files.length,\r\n validCount,\r\n missingFiles,\r\n invalidFiles,\r\n };\r\n}\r\n\r\n/**\r\n * Validate that a target directory exists and contains the expected\r\n * number of files. A lightweight check that does not inspect individual\r\n * file contents.\r\n *\r\n * @param targetDirectory - Absolute path to the target .claude/ directory.\r\n * @param expectedFileCount - Number of files expected in the directory tree.\r\n * @returns A ValidationReport with pass/fail status.\r\n */\r\nexport async function validateTargetDirectory(\r\n targetDirectory: string,\r\n expectedFileCount: number,\r\n): Promise<ValidationReport> {\r\n try {\r\n const stat = await fs.stat(targetDirectory);\r\n if (!stat.isDirectory()) {\r\n return {\r\n valid: false,\r\n totalChecked: 0,\r\n validCount: 0,\r\n missingFiles: [],\r\n invalidFiles: [\r\n {\r\n relativePath: targetDirectory,\r\n reason: 'Target path exists but is not a directory',\r\n },\r\n ],\r\n };\r\n }\r\n } catch {\r\n return {\r\n valid: false,\r\n totalChecked: 0,\r\n validCount: 0,\r\n missingFiles: [targetDirectory],\r\n invalidFiles: [\r\n {\r\n relativePath: targetDirectory,\r\n reason: 'Target directory does not exist',\r\n },\r\n ],\r\n };\r\n }\r\n\r\n // Count all files recursively\r\n const actualCount = await countFilesRecursive(targetDirectory);\r\n\r\n if (actualCount < expectedFileCount) {\r\n return {\r\n valid: false,\r\n totalChecked: actualCount,\r\n validCount: actualCount,\r\n missingFiles: [],\r\n invalidFiles: [\r\n {\r\n relativePath: targetDirectory,\r\n reason: `Expected ${expectedFileCount} files but found ${actualCount}`,\r\n },\r\n ],\r\n };\r\n }\r\n\r\n return {\r\n valid: true,\r\n totalChecked: actualCount,\r\n validCount: actualCount,\r\n missingFiles: [],\r\n invalidFiles: [],\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Recursively count all files in a directory tree.\r\n *\r\n * @param directory - Absolute path to the directory.\r\n * @returns Total number of regular files found.\r\n */\r\nasync function countFilesRecursive(directory: string): Promise<number> {\r\n let count = 0;\r\n\r\n let entries: import('fs').Dirent[];\r\n try {\r\n entries = await fs.readdir(directory, { withFileTypes: true });\r\n } catch {\r\n return 0;\r\n }\r\n\r\n for (const entry of entries) {\r\n const fullPath = path.join(directory, entry.name);\r\n if (entry.isDirectory()) {\r\n count += await countFilesRecursive(fullPath);\r\n } else if (entry.isFile()) {\r\n count++;\r\n }\r\n }\r\n\r\n return count;\r\n}\r\n","/**\r\n * @sixsevenai/ai-dlc-installer - Public API\r\n *\r\n * Re-exports the core installer entry point and shared types\r\n * for programmatic use and CLI bootstrapping.\r\n *\r\n * @module index\r\n */\r\n\r\nimport {\r\n executeInstallation,\r\n executeDryRun,\r\n type CLIOptions,\r\n type ExitCode,\r\n EXIT_SUCCESS,\r\n} from './orchestrator/index.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type { CliFlags } from './cli.js';\r\n\r\n/**\r\n * Options accepted by the installer's programmatic entry point.\r\n */\r\nexport interface InstallerOptions {\r\n /** Enable verbose logging during installation. */\r\n readonly verbose?: boolean;\r\n /** Preview changes without modifying the file system. */\r\n readonly dryRun?: boolean;\r\n /** Overwrite existing files without confirmation prompts. */\r\n readonly force?: boolean;\r\n /** Suppress non-error output. */\r\n readonly quiet?: boolean;\r\n /** Disable colored output. */\r\n readonly noColor?: boolean;\r\n /** Target directory for installation. */\r\n readonly target?: string;\r\n /** Category names to selectively overwrite (from `--overwrite` flags). */\r\n readonly overwrite?: readonly string[];\r\n /** Enable selective installation mode. */\r\n readonly custom?: boolean;\r\n /** Comma-separated category IDs to install. */\r\n readonly categories?: readonly string[];\r\n /** Auto-select categories from a named profile. */\r\n readonly profile?: string;\r\n}\r\n\r\n/**\r\n * Result returned after an installation run completes.\r\n */\r\nexport interface InstallerResult {\r\n /** Whether the installation completed successfully. */\r\n readonly success: boolean;\r\n /** Number of files written to disk. */\r\n readonly filesWritten: number;\r\n /** Human-readable summary of what was done. */\r\n readonly summary: string;\r\n /** Process exit code (0 = success, 1 = error, 2 = cancelled). */\r\n readonly exitCode: ExitCode;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Platform Exports\r\n// ---------------------------------------------------------------------------\r\n\r\nexport * from './platform/index.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Orchestrator Exports\r\n// ---------------------------------------------------------------------------\r\n\r\nexport {\r\n executeInstallation,\r\n executeDryRun,\r\n INSTALLER_VERSION,\r\n WORKFLOW_STEPS,\r\n ErrorHandler,\r\n} from './orchestrator/index.js';\r\n\r\nexport type {\r\n CLIOptions,\r\n ExitCode,\r\n WorkflowStepId,\r\n InstallationConfig,\r\n} from './orchestrator/index.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Installer Entry Point\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Run the AI-DLC framework installer.\r\n *\r\n * This is the main programmatic entry point. The CLI module (`cli.ts`)\r\n * calls this function after parsing command-line flags.\r\n *\r\n * Delegates to the CLI Orchestrator workflow which coordinates platform\r\n * detection, terminal UI, and the installation engine.\r\n *\r\n * @param options - Configuration flags from CLI or programmatic caller.\r\n * @returns A promise resolving to the installation result.\r\n */\r\nexport async function runInstaller(\r\n options: InstallerOptions = {},\r\n): Promise<InstallerResult> {\r\n // Build CLIOptions from InstallerOptions\r\n const cliOptions: CLIOptions = {\r\n command: 'install',\r\n target: options.target ?? null,\r\n force: options.force ?? false,\r\n dryRun: options.dryRun ?? false,\r\n verbose: options.verbose ?? false,\r\n noColor: options.noColor ?? false,\r\n quiet: options.quiet ?? false,\r\n overwrite: options.overwrite ?? [],\r\n custom: options.custom ?? false,\r\n profile: options.profile ?? null,\r\n categories: options.categories ?? [],\r\n rawArgs: [],\r\n };\r\n\r\n let exitCode: ExitCode;\r\n\r\n if (cliOptions.dryRun) {\r\n exitCode = await executeDryRun(cliOptions);\r\n } else {\r\n exitCode = await executeInstallation(cliOptions);\r\n }\r\n\r\n return {\r\n success: exitCode === EXIT_SUCCESS,\r\n filesWritten: 0, // Detailed counts are in the workflow output\r\n summary: exitCode === EXIT_SUCCESS\r\n ? 'Installation completed successfully.'\r\n : exitCode === 2\r\n ? 'Installation cancelled by user.'\r\n : 'Installation failed.',\r\n exitCode,\r\n };\r\n}\r\n","/**\r\n * CLI Entry Point for @sixsevenai/ai-dlc-installer\r\n *\r\n * Parses command-line arguments, validates flags, and delegates to\r\n * the orchestrator workflow. Supports the `install` subcommand with\r\n * `--target`, `--force`, `--dry-run`, `--verbose`, `--no-color`,\r\n * and `--quiet` flags.\r\n *\r\n * @module cli\r\n */\r\n\r\nimport { runInstaller, type InstallerOptions } from './index.js';\r\nimport { INSTALLER_VERSION } from './orchestrator/index.js';\r\nimport { resolveCategories } from './engine/category-filter.js';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface CliFlags {\r\n readonly version: boolean;\r\n readonly help: boolean;\r\n readonly verbose: boolean;\r\n readonly dryRun: boolean;\r\n readonly noColor: boolean;\r\n readonly force: boolean;\r\n readonly quiet: boolean;\r\n readonly custom: boolean;\r\n readonly target: string | null;\r\n readonly profile: string | null;\r\n readonly overwrite: readonly string[];\r\n readonly categories: readonly string[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Constants\r\n// ---------------------------------------------------------------------------\r\n\r\nconst CLI_NAME = 'sixsevenai';\r\n\r\n/** Known flags for fuzzy-match suggestion on typos. */\r\nconst KNOWN_FLAGS = [\r\n '--version', '-v', '--help', '-h', '--verbose',\r\n '--dry-run', '-d', '--no-color', '--force', '-f',\r\n '--quiet', '-q', '--target', '-t', '--overwrite',\r\n '--custom', '--categories', '--profile',\r\n];\r\n\r\n// ---------------------------------------------------------------------------\r\n// Argument Parsing\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction parseArgs(argv: readonly string[]): CliFlags {\r\n const args = argv.slice(2);\r\n\r\n // Filter out 'install' subcommand if present\r\n const filtered = args[0] === 'install' ? args.slice(1) : args;\r\n\r\n let target: string | null = null;\r\n const version = filtered.includes('--version') || filtered.includes('-v');\r\n const help = filtered.includes('--help') || filtered.includes('-h');\r\n const verbose = filtered.includes('--verbose');\r\n const dryRun = filtered.includes('--dry-run') || filtered.includes('-d');\r\n const noColor = filtered.includes('--no-color');\r\n const force = filtered.includes('--force') || filtered.includes('-f');\r\n const quiet = filtered.includes('--quiet') || filtered.includes('-q');\r\n const custom = filtered.includes('--custom');\r\n\r\n // Parse --target / -t with value\r\n for (let i = 0; i < filtered.length; i++) {\r\n const arg = filtered[i]!;\r\n if ((arg === '--target' || arg === '-t') && i + 1 < filtered.length) {\r\n target = filtered[i + 1]!;\r\n i++; // skip the value\r\n }\r\n }\r\n\r\n // Parse --overwrite with value (repeatable)\r\n const overwrite: string[] = [];\r\n for (let i = 0; i < filtered.length; i++) {\r\n const arg = filtered[i]!;\r\n if (arg === '--overwrite' && i + 1 < filtered.length) {\r\n overwrite.push(filtered[i + 1]!);\r\n i++; // skip the value\r\n }\r\n }\r\n\r\n // Parse --categories with comma-separated value\r\n const categories: string[] = [];\r\n for (let i = 0; i < filtered.length; i++) {\r\n const arg = filtered[i]!;\r\n if (arg === '--categories' && i + 1 < filtered.length) {\r\n categories.push(...filtered[i + 1]!.split(',').map((s) => s.trim()).filter(Boolean));\r\n i++;\r\n }\r\n }\r\n\r\n // Parse --profile with value\r\n let profile: string | null = null;\r\n for (let i = 0; i < filtered.length; i++) {\r\n const arg = filtered[i]!;\r\n if (arg === '--profile' && i + 1 < filtered.length) {\r\n profile = filtered[i + 1]!;\r\n i++;\r\n }\r\n }\r\n\r\n // Validate --profile value\r\n const VALID_PROFILES = ['minimal', 'standard', 'enterprise'];\r\n if (profile !== null && !VALID_PROFILES.includes(profile)) {\r\n console.error(`Error: Invalid profile '${profile}'. Valid profiles are: ${VALID_PROFILES.join(', ')}`);\r\n process.exit(1);\r\n }\r\n\r\n // Validate --categories against known category IDs\r\n if (categories.length > 0) {\r\n try {\r\n resolveCategories(categories);\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n }\r\n\r\n // If no --target but there's a positional arg that isn't a flag, treat as target\r\n if (target === null) {\r\n for (const arg of filtered) {\r\n if (!arg.startsWith('-') && arg !== 'install') {\r\n target = arg;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n // Validate mutually exclusive flags\r\n if (verbose && quiet) {\r\n console.error('Error: Cannot use --verbose and --quiet together.');\r\n process.exit(1);\r\n }\r\n\r\n // Check for unknown flags\r\n for (const arg of filtered) {\r\n if (arg.startsWith('-') && !KNOWN_FLAGS.includes(arg) && arg !== target) {\r\n // Skip flag values (e.g., the path after --target or --overwrite)\r\n const prevIdx = filtered.indexOf(arg) - 1;\r\n if (prevIdx >= 0 && (filtered[prevIdx] === '--target' || filtered[prevIdx] === '-t' || filtered[prevIdx] === '--overwrite' || filtered[prevIdx] === '--categories' || filtered[prevIdx] === '--profile')) {\r\n continue;\r\n }\r\n\r\n const suggestion = findClosestFlag(arg);\r\n const suggestionText = suggestion ? ` Did you mean ${suggestion}?` : '';\r\n console.error(`Error: Unknown flag: ${arg}.${suggestionText}`);\r\n process.exit(1);\r\n }\r\n }\r\n\r\n return { version, help, verbose, dryRun, noColor, force, quiet, custom, target, profile, overwrite, categories };\r\n}\r\n\r\n/**\r\n * Find the closest known flag using simple Levenshtein distance.\r\n */\r\nfunction findClosestFlag(input: string): string | null {\r\n let bestMatch: string | null = null;\r\n let bestDistance = Infinity;\r\n\r\n for (const flag of KNOWN_FLAGS) {\r\n const dist = levenshteinDistance(input, flag);\r\n if (dist < bestDistance && dist <= 3) {\r\n bestDistance = dist;\r\n bestMatch = flag;\r\n }\r\n }\r\n\r\n return bestMatch;\r\n}\r\n\r\nfunction levenshteinDistance(a: string, b: string): number {\r\n const m = a.length;\r\n const n = b.length;\r\n const dp: number[][] = Array.from({ length: m + 1 }, () =>\r\n Array.from({ length: n + 1 }, () => 0),\r\n );\r\n\r\n for (let i = 0; i <= m; i++) dp[i]![0] = i;\r\n for (let j = 0; j <= n; j++) dp[0]![j] = j;\r\n\r\n for (let i = 1; i <= m; i++) {\r\n for (let j = 1; j <= n; j++) {\r\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\r\n dp[i]![j] = Math.min(\r\n dp[i - 1]![j]! + 1,\r\n dp[i]![j - 1]! + 1,\r\n dp[i - 1]![j - 1]! + cost,\r\n );\r\n }\r\n }\r\n\r\n return dp[m]![n]!;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Help Text\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction printHelp(): void {\r\n const help = `\r\nUsage: ${CLI_NAME} install [target-directory] [options]\r\n\r\nInteractive terminal installer for the AI-DLC framework.\r\n\r\nArguments:\r\n target-directory Target project directory (default: current directory)\r\n\r\nOptions:\r\n --target, -t <dir> Target project directory (overrides positional arg)\r\n --force, -f Overwrite existing files without prompting\r\n --dry-run, -d Preview changes without writing to disk\r\n --verbose Enable verbose logging to stderr\r\n --no-color Disable colored output (also respects NO_COLOR env)\r\n --overwrite <category> Overwrite specific categories only (repeatable)\r\n --custom Enable selective installation mode\r\n --categories <ids> Comma-separated category IDs to install (e.g., agents,skills)\r\n --profile <name> Auto-select categories from profile (minimal|standard|enterprise)\r\n --quiet, -q Suppress non-error output (mutually exclusive with --verbose)\r\n -h, --help Show this help message\r\n -v, --version Show version number\r\n\r\nExit Codes:\r\n 0 Installation completed successfully\r\n 1 Installation failed\r\n 2 Installation cancelled by user\r\n\r\nExamples:\r\n ${CLI_NAME} install\r\n ${CLI_NAME} install --target /home/user/my-project --force\r\n ${CLI_NAME} install --dry-run --verbose\r\n ${CLI_NAME} install --overwrite agents --overwrite skills\r\n ${CLI_NAME} install /path/to/project --dry-run > preview.txt\r\n`;\r\n console.log(help.trim());\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Main\r\n// ---------------------------------------------------------------------------\r\n\r\nasync function main(): Promise<void> {\r\n const flags = parseArgs(process.argv);\r\n\r\n if (flags.version) {\r\n console.log(`${CLI_NAME} v${INSTALLER_VERSION}`);\r\n return;\r\n }\r\n\r\n if (flags.help) {\r\n printHelp();\r\n return;\r\n }\r\n\r\n // Disable color if requested\r\n if (flags.noColor) {\r\n process.env['NO_COLOR'] = '1';\r\n }\r\n\r\n const options: InstallerOptions = {\r\n verbose: flags.verbose,\r\n dryRun: flags.dryRun,\r\n force: flags.force,\r\n quiet: flags.quiet,\r\n noColor: flags.noColor,\r\n target: flags.target ?? undefined,\r\n overwrite: flags.overwrite.length > 0 ? flags.overwrite : undefined,\r\n custom: flags.custom,\r\n categories: flags.categories.length > 0 ? flags.categories : undefined,\r\n profile: flags.profile ?? undefined,\r\n };\r\n\r\n const result = await runInstaller(options);\r\n\r\n process.exit(result.exitCode);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Bootstrap with error handling\r\n// ---------------------------------------------------------------------------\r\n\r\nprocess.title = CLI_NAME;\r\n\r\nmain().catch((error: unknown) => {\r\n const message = error instanceof Error ? error.message : String(error);\r\n console.error(`\\nFatal error: ${message}`);\r\n\r\n if (error instanceof Error && error.stack && process.env['DEBUG']) {\r\n console.error(error.stack);\r\n }\r\n\r\n process.exit(1);\r\n});\r\n"],"mappings":"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","names":["path","mkdir","readFile","stat","stat","text","text","version","seconds","text","stat","text","stripAnsi","text","stripAnsi","stat","version","version","release","path","os","fs","stat","path","os","fs","version","execSync","execSync","version","path","fs","path","stat","fs","stat","sourceHash","fs","path","resolve","fs","path","fs","path","stat","os","stat","readFile","mkdir","version"]}