@baton-dx/cli 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["runProjectMode","runGlobalMode","p.multiselect","p.isCancel","p.select","p.spinner","p.multiselect","p.isCancel","formatIdeName","p.select","p.isCancel","p.multiselect","p.confirm","p.isCancel","p.spinner","simpleGit","loadProjectManifestSafe","p.spinner","formatIdeName","formatIdeName","p.multiselect","p.isCancel","p.select","formatIdeName","p.spinner","formatIdeName","p.multiselect","p.isCancel","p.spinner","p.select","p.isCancel","p.multiselect","p.spinner","p.select","p.isCancel","p.confirm","p.select","p.isCancel","p.confirm","p.multiselect","__dirname","p.spinner","p.confirm","p.isCancel","p.confirm","p.isCancel","__dirname","p.text","p.isCancel","p.confirm","Handlebars","simpleGit","p.spinner","p.confirm","p.isCancel","p.spinner","simpleGit"],"sources":["../src/commands/ai-tools/configure.ts","../src/commands/ai-tools/list.ts","../src/commands/ai-tools/scan.ts","../src/commands/ai-tools/index.ts","../src/utils/build-intersection.ts","../src/utils/first-run-preferences.ts","../src/utils/intersection-display.ts","../src/commands/sync-pipeline.ts","../src/commands/apply.ts","../src/commands/config/set.ts","../src/commands/config/index.ts","../src/commands/diff.ts","../src/commands/ides/utils.ts","../src/commands/ides/configure.ts","../src/commands/ides/list.ts","../src/commands/ides/scan.ts","../src/commands/ides/index.ts","../src/utils/profile-selection.ts","../src/utils/run-baton-sync.ts","../src/commands/init.ts","../src/commands/manage.ts","../src/commands/profile/index.ts","../src/commands/self-update.ts","../src/commands/source/connect.ts","../src/commands/source/create.ts","../src/commands/source/disconnect.ts","../src/commands/source/list.ts","../src/commands/source/index.ts","../src/commands/sync.ts","../src/commands/update.ts","../src/index.ts"],"sourcesContent":["import { stat } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport {\n getAllAIToolAdapters,\n getGlobalAiTools,\n readProjectPreferences,\n setGlobalAiTools,\n writeProjectPreferences,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\n\nexport const aiToolsConfigureCommand = defineCommand({\n meta: {\n name: \"configure\",\n description: \"Manually configure which AI tools Baton manages\",\n },\n args: {\n yes: {\n type: \"boolean\",\n alias: \"y\",\n description:\n \"Keep current selection unchanged (no-op), or with --project write useGlobal: true\",\n },\n project: {\n type: \"boolean\",\n description: \"Configure AI tools for this project instead of globally\",\n },\n },\n async run({ args }) {\n if (args.project) {\n await runProjectMode(args.yes ?? false);\n } else {\n await runGlobalMode(args.yes ?? false);\n }\n },\n});\n\nasync function runGlobalMode(nonInteractive: boolean): Promise<void> {\n p.intro(\"Baton - Configure AI Tools\");\n\n const currentTools = await getGlobalAiTools();\n\n // --yes flag is a no-op (keeps current selection unchanged)\n if (nonInteractive) {\n if (currentTools.length > 0) {\n p.log.info(`Current AI tools: ${currentTools.join(\", \")}`);\n } else {\n p.log.info(\"No AI tools currently configured.\");\n }\n p.outro(\"No changes made.\");\n return;\n }\n\n const allAdapters = getAllAIToolAdapters();\n\n const options = allAdapters.map((adapter) => {\n const isSaved = currentTools.includes(adapter.key);\n return {\n value: adapter.key,\n label: isSaved ? `${adapter.name} (currently saved)` : adapter.name,\n };\n });\n\n const selected = await p.multiselect({\n message: \"Select which AI tools to save:\",\n options,\n initialValues: currentTools,\n });\n\n if (p.isCancel(selected)) {\n p.outro(\"No changes made.\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n const hasChanges =\n selectedKeys.length !== currentTools.length ||\n selectedKeys.some((key) => !currentTools.includes(key));\n\n if (hasChanges) {\n await setGlobalAiTools(selectedKeys);\n p.log.success(`Saved ${selectedKeys.length} tool(s) to global config.`);\n } else {\n p.log.info(\"No changes made.\");\n }\n\n p.outro(\"Configuration complete.\");\n}\n\nasync function runProjectMode(nonInteractive: boolean): Promise<void> {\n p.intro(\"Baton - Configure AI Tools (Project)\");\n\n const projectRoot = process.cwd();\n const manifestPath = resolve(projectRoot, \"baton.yaml\");\n\n // Check that baton.yaml exists\n try {\n await stat(manifestPath);\n } catch {\n p.cancel(\"No baton.yaml found in current directory. Run `baton init` first.\");\n process.exit(1);\n }\n\n // --yes with --project writes useGlobal: true\n if (nonInteractive) {\n const existing = await readProjectPreferences(projectRoot);\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: { useGlobal: true, tools: existing?.ai.tools ?? [] },\n ide: existing?.ide ?? { useGlobal: true, platforms: [] },\n });\n p.log.info(\"Set AI tools to use global config for this project.\");\n p.outro(\"Configuration complete.\");\n return;\n }\n\n const existing = await readProjectPreferences(projectRoot);\n const globalTools = await getGlobalAiTools();\n\n // Show current state\n if (globalTools.length > 0) {\n p.log.info(`Global AI tools: ${globalTools.join(\", \")}`);\n }\n\n // Ask useGlobal first\n const mode = await p.select({\n message: \"How should this project resolve AI tools?\",\n options: [\n {\n value: \"global\",\n label: \"Use global config\",\n hint: \"always follows your global AI tools setting\",\n },\n {\n value: \"project\",\n label: \"Customize for this project\",\n hint: \"choose specific tools for this project\",\n },\n ],\n initialValue: existing?.ai.useGlobal === false ? \"project\" : \"global\",\n });\n\n if (p.isCancel(mode)) {\n p.outro(\"No changes made.\");\n return;\n }\n\n if (mode === \"global\") {\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: { useGlobal: true, tools: [] },\n ide: existing?.ide ?? { useGlobal: true, platforms: [] },\n });\n p.log.success(\"Project configured to use global AI tools.\");\n p.outro(\"Configuration complete.\");\n return;\n }\n\n // Customize: show multiselect\n const allAdapters = getAllAIToolAdapters();\n const currentProjectTools = existing?.ai.useGlobal === false ? existing.ai.tools : globalTools;\n\n const options = allAdapters.map((adapter) => {\n const isGlobal = globalTools.includes(adapter.key);\n return {\n value: adapter.key,\n label: isGlobal ? `${adapter.name} (in global config)` : adapter.name,\n };\n });\n\n const selected = await p.multiselect({\n message: \"Select AI tools for this project:\",\n options,\n initialValues: currentProjectTools,\n });\n\n if (p.isCancel(selected)) {\n p.outro(\"No changes made.\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: { useGlobal: false, tools: selectedKeys },\n ide: existing?.ide ?? { useGlobal: true, platforms: [] },\n });\n p.log.success(`Project configured with ${selectedKeys.length} AI tool(s).`);\n p.outro(\"Configuration complete.\");\n}\n","import { readdir, stat } from \"node:fs/promises\";\nimport { getAIToolConfig, getAIToolPath, getAllAIToolKeys } from \"@baton-dx/ai-tool-paths\";\nimport { getGlobalAiTools } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\n\nexport const aiToolsListCommand = defineCommand({\n meta: {\n name: \"list\",\n description: \"Show saved AI tools from global config and their configuration status\",\n },\n args: {\n all: {\n type: \"boolean\",\n alias: \"a\",\n description: \"Show all supported tools, not just saved ones\",\n },\n json: {\n type: \"boolean\",\n description: \"Output machine-readable JSON\",\n alias: \"j\",\n },\n },\n async run({ args }) {\n if (!args.json) {\n p.intro(\"Baton - AI Tools\");\n }\n\n // Load saved tools from global config\n const savedTools = await getGlobalAiTools();\n const allAIToolKeys = getAllAIToolKeys();\n\n // Determine which tools to show\n const keysToShow = args.all\n ? allAIToolKeys\n : savedTools.length > 0\n ? savedTools\n : allAIToolKeys;\n\n const toolStatuses = await Promise.all(\n keysToShow.map(async (toolKey) => {\n const isSaved = savedTools.includes(toolKey);\n\n // Count installed configs for this tool\n let skillCount = 0;\n let ruleCount = 0;\n let aiToolConfigCount = 0;\n let memoryCount = 0;\n let commandCount = 0;\n\n if (isSaved) {\n skillCount = await countConfigs(toolKey, \"skills\", \"project\");\n ruleCount = await countConfigs(toolKey, \"rules\", \"project\");\n aiToolConfigCount = await countConfigs(toolKey, \"agents\", \"project\");\n memoryCount = await countConfigs(toolKey, \"memory\", \"project\");\n commandCount = await countConfigs(toolKey, \"commands\", \"project\");\n }\n\n // Get path locations for each config type\n const paths = {\n skills: getAIToolPath(toolKey, \"skills\", \"project\", \"\"),\n rules: getAIToolPath(toolKey, \"rules\", \"project\", \"\"),\n agents: getAIToolPath(toolKey, \"agents\", \"project\", \"\"),\n memory: getAIToolPath(toolKey, \"memory\", \"project\", \"\"),\n commands: getAIToolPath(toolKey, \"commands\", \"project\", \"\"),\n };\n\n const config = getAIToolConfig(toolKey);\n\n return {\n key: toolKey,\n name: config.name,\n saved: isSaved,\n counts: {\n skills: skillCount,\n rules: ruleCount,\n agents: aiToolConfigCount,\n memory: memoryCount,\n commands: commandCount,\n },\n paths,\n };\n }),\n );\n\n // JSON output\n if (args.json) {\n console.log(JSON.stringify(toolStatuses, null, 2));\n return;\n }\n\n // Formatted output\n if (savedTools.length === 0) {\n p.log.warn(\"No AI tools saved in global config.\");\n p.log.info(\"Run 'baton ai-tools scan' to detect and save your AI tools.\");\n console.log(\"\");\n p.log.info(`All ${allAIToolKeys.length} supported tools:`);\n for (const key of allAIToolKeys) {\n const config = getAIToolConfig(key);\n console.log(` \\x1b[90m- ${config.name}\\x1b[0m`);\n }\n p.outro(\"Run 'baton ai-tools scan' to get started.\");\n return;\n }\n\n console.log(`\\nSaved AI tools (${savedTools.length}):\\n`);\n\n for (const agent of toolStatuses) {\n const statusColor = agent.saved ? \"\\x1b[32m\" : \"\\x1b[90m\";\n const status = agent.saved ? \"✓\" : \"✗\";\n const resetColor = \"\\x1b[0m\";\n\n console.log(`${statusColor}${status}${resetColor} ${agent.name.padEnd(20)}`);\n\n if (agent.saved) {\n const totalConfigs =\n agent.counts.skills +\n agent.counts.rules +\n agent.counts.agents +\n agent.counts.memory +\n agent.counts.commands;\n\n if (totalConfigs > 0) {\n const details = [];\n if (agent.counts.skills > 0) details.push(`${agent.counts.skills} skills`);\n if (agent.counts.rules > 0) details.push(`${agent.counts.rules} rules`);\n if (agent.counts.agents > 0) details.push(`${agent.counts.agents} agents`);\n if (agent.counts.memory > 0) details.push(`${agent.counts.memory} memory`);\n if (agent.counts.commands > 0) details.push(`${agent.counts.commands} commands`);\n\n console.log(` → ${details.join(\", \")}`);\n }\n }\n\n console.log(\"\");\n }\n\n p.outro(\"Manage tools: 'baton ai-tools scan' (detect) | 'baton ai-tools configure' (select)\");\n },\n});\n\n/**\n * Count config files of a given type for a tool\n */\nasync function countConfigs(\n toolKey: string,\n configType: \"skills\" | \"rules\" | \"agents\" | \"memory\" | \"commands\",\n scope: \"project\" | \"global\",\n): Promise<number> {\n try {\n const basePath = getAIToolPath(toolKey, configType, scope, \"\");\n const dirPath = basePath.replace(/{name}.*$/, \"\").replace(/\\/$/, \"\");\n\n const stats = await stat(dirPath);\n if (!stats.isDirectory()) {\n return 0;\n }\n\n const items = await readdir(dirPath);\n return items.length;\n } catch (_error) {\n return 0;\n }\n}\n","import {\n clearAIToolCache,\n detectInstalledAITools,\n getAllAIToolAdapters,\n getGlobalAiTools,\n setGlobalAiTools,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\n\nexport const aiToolsScanCommand = defineCommand({\n meta: {\n name: \"scan\",\n description: \"Scan your system for AI tools and save results to global config\",\n },\n args: {\n yes: {\n type: \"boolean\",\n alias: \"y\",\n description: \"Automatically save detected tools without confirmation\",\n },\n },\n async run({ args }) {\n p.intro(\"Baton - AI Tool Scanner\");\n\n const spinner = p.spinner();\n spinner.start(\"Scanning for AI tools...\");\n\n // Clear cache to force fresh detection\n clearAIToolCache();\n\n const detectedAITools = await detectInstalledAITools();\n const allAdapters = getAllAIToolAdapters();\n const currentTools = await getGlobalAiTools();\n\n spinner.stop(\"Scan complete.\");\n\n if (detectedAITools.length > 0) {\n p.log.success(\n `Found ${detectedAITools.length} AI tool${detectedAITools.length !== 1 ? \"s\" : \"\"} on your system.`,\n );\n } else {\n p.log.warn(\"No AI tools detected on your system.\");\n }\n\n // --yes flag: save only detected tools (preserves current behavior)\n if (args.yes) {\n const detectedKeys = detectedAITools;\n const hasChanges =\n detectedKeys.length !== currentTools.length ||\n detectedKeys.some((key) => !currentTools.includes(key));\n\n if (hasChanges) {\n await setGlobalAiTools(detectedKeys);\n p.log.success(`Saved ${detectedKeys.length} detected tool(s) to global config.`);\n } else {\n p.log.info(\"Global config is already up to date.\");\n }\n\n p.outro(\"Scan finished.\");\n return;\n }\n\n // Interactive: show multiselect with all 14 tools\n const options = allAdapters.map((adapter) => {\n const isDetected = detectedAITools.includes(adapter.key);\n return {\n value: adapter.key,\n label: isDetected ? `${adapter.name} (detected)` : adapter.name,\n };\n });\n\n const selected = await p.multiselect({\n message: \"Select which AI tools to save:\",\n options,\n initialValues: detectedAITools,\n });\n\n if (p.isCancel(selected)) {\n p.outro(\"Scan finished (not saved).\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n const hasChanges =\n selectedKeys.length !== currentTools.length ||\n selectedKeys.some((key) => !currentTools.includes(key));\n\n if (hasChanges) {\n await setGlobalAiTools(selectedKeys);\n p.log.success(`Saved ${selectedKeys.length} tool(s) to global config.`);\n } else {\n p.log.info(\"Global config is already up to date.\");\n }\n\n p.outro(\"Scan finished.\");\n },\n});\n","import { defineCommand } from \"citty\";\nimport { aiToolsConfigureCommand } from \"./configure.js\";\nimport { aiToolsListCommand } from \"./list.js\";\nimport { aiToolsScanCommand } from \"./scan.js\";\n\nexport const aiToolsCommand = defineCommand({\n meta: {\n name: \"ai-tools\",\n description: \"Manage AI tool detection and configuration\",\n },\n subCommands: {\n configure: aiToolsConfigureCommand,\n list: aiToolsListCommand,\n scan: aiToolsScanCommand,\n },\n});\n","import { resolve } from \"node:path\";\nimport type { IntersectionResult, SourceManifest } from \"@baton-dx/core\";\nimport {\n cloneGitSource,\n computeIntersection,\n findSourceManifest,\n loadProfileManifest,\n parseSource,\n resolveProfileSupport,\n} from \"@baton-dx/core\";\nimport { findSourceRoot } from \"./context-detection.js\";\n\n/**\n * Compute the intersection for a single profile source string.\n * Shared utility used by sync, config, and manage commands.\n *\n * @returns IntersectionResult or null if intersection cannot be computed\n */\nexport async function buildIntersection(\n sourceString: string,\n developerTools: { aiTools: string[]; idePlatforms: string[] },\n cwd: string,\n): Promise<IntersectionResult | null> {\n const parsed = parseSource(sourceString);\n\n let repoRoot: string;\n let profileDir: string;\n\n if (parsed.provider === \"github\" || parsed.provider === \"gitlab\") {\n const repoClone = await cloneGitSource({\n url: parsed.url,\n ref: parsed.ref,\n useCache: true,\n });\n repoRoot = repoClone.localPath;\n profileDir = parsed.subpath ? resolve(repoRoot, parsed.subpath) : repoRoot;\n } else if (parsed.provider === \"local\" || parsed.provider === \"file\") {\n const absolutePath = parsed.path.startsWith(\"/\") ? parsed.path : resolve(cwd, parsed.path);\n profileDir = absolutePath;\n repoRoot = (await findSourceRoot(absolutePath, { fallbackToStart: true })) as string;\n } else {\n return null;\n }\n\n // Load source manifest (optional)\n let sourceManifest: SourceManifest;\n try {\n sourceManifest = await findSourceManifest(repoRoot);\n } catch {\n sourceManifest = { name: \"unknown\", version: \"0.0.0\" } as SourceManifest;\n }\n\n // Load profile manifest\n const profileManifestPath = resolve(profileDir, \"baton.profile.yaml\");\n const profileManifest = await loadProfileManifest(profileManifestPath).catch(() => null);\n if (!profileManifest) return null;\n\n const profileSupport = resolveProfileSupport(profileManifest, sourceManifest);\n return computeIntersection(developerTools, profileSupport);\n}\n","import {\n getAllAIToolAdapters,\n getGlobalAiTools,\n getGlobalIdePlatforms,\n getRegisteredIdePlatforms,\n readProjectPreferences,\n writeProjectPreferences,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\n\n/**\n * Format an IDE platform key into a display name.\n * Duplicated here to avoid circular dependency with ides/utils.\n */\nfunction formatIdeName(ideKey: string): string {\n const names: Record<string, string> = {\n vscode: \"VS Code\",\n jetbrains: \"JetBrains\",\n cursor: \"Cursor\",\n windsurf: \"Windsurf\",\n antigravity: \"Antigravity\",\n zed: \"Zed\",\n };\n return names[ideKey] ?? ideKey;\n}\n\n/**\n * Shows the first-run preferences prompt if .baton/preferences.yaml doesn't exist.\n *\n * Asks the user whether to use global config or customize AI tools and IDEs\n * for this project, then writes the preferences file.\n *\n * @param projectRoot - Absolute path to the project root\n * @param nonInteractive - If true, writes useGlobal: true silently\n * @returns true if preferences were written, false if already existed\n */\nexport async function promptFirstRunPreferences(\n projectRoot: string,\n nonInteractive: boolean,\n): Promise<boolean> {\n const existing = await readProjectPreferences(projectRoot);\n if (existing) {\n return false;\n }\n\n // --yes mode: write useGlobal: true silently\n if (nonInteractive) {\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: { useGlobal: true, tools: [] },\n ide: { useGlobal: true, platforms: [] },\n });\n return true;\n }\n\n // AI tools prompt\n const aiMode = await p.select({\n message: \"How do you want to configure AI tools for this project?\",\n options: [\n { value: \"global\", label: \"Use global config\", hint: \"recommended\" },\n { value: \"customize\", label: \"Customize for this project\" },\n ],\n });\n\n if (p.isCancel(aiMode)) {\n return false;\n }\n\n let aiUseGlobal = true;\n let aiTools: string[] = [];\n\n if (aiMode === \"customize\") {\n const globalTools = await getGlobalAiTools();\n const allAdapters = getAllAIToolAdapters();\n\n const selected = await p.multiselect({\n message: \"Select AI tools for this project:\",\n options: allAdapters.map((adapter) => ({\n value: adapter.key,\n label: globalTools.includes(adapter.key)\n ? `${adapter.name} (in global config)`\n : adapter.name,\n })),\n initialValues: globalTools,\n });\n\n if (p.isCancel(selected)) {\n return false;\n }\n\n aiUseGlobal = false;\n aiTools = selected as string[];\n }\n\n // IDE platforms prompt\n const ideMode = await p.select({\n message: \"How do you want to configure IDE platforms for this project?\",\n options: [\n { value: \"global\", label: \"Use global config\", hint: \"recommended\" },\n { value: \"customize\", label: \"Customize for this project\" },\n ],\n });\n\n if (p.isCancel(ideMode)) {\n return false;\n }\n\n let ideUseGlobal = true;\n let idePlatforms: string[] = [];\n\n if (ideMode === \"customize\") {\n const globalPlatforms = await getGlobalIdePlatforms();\n const allIdeKeys = getRegisteredIdePlatforms();\n\n const selected = await p.multiselect({\n message: \"Select IDE platforms for this project:\",\n options: allIdeKeys.map((ideKey) => ({\n value: ideKey,\n label: globalPlatforms.includes(ideKey)\n ? `${formatIdeName(ideKey)} (in global config)`\n : formatIdeName(ideKey),\n })),\n initialValues: globalPlatforms,\n });\n\n if (p.isCancel(selected)) {\n return false;\n }\n\n ideUseGlobal = false;\n idePlatforms = selected as string[];\n }\n\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: { useGlobal: aiUseGlobal, tools: aiTools },\n ide: { useGlobal: ideUseGlobal, platforms: idePlatforms },\n });\n\n return true;\n}\n","import type { DimensionIntersection, IntersectionResult } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\n\n/**\n * Display the intersection between developer tools and profile support.\n * Shows which tools/platforms will be synced, which are unsupported, and which are unavailable.\n *\n * Used by `baton init` (after profile selection) and `baton manage` (overview).\n */\nexport function displayIntersection(intersection: IntersectionResult): void {\n const hasAiData =\n intersection.aiTools.synced.length > 0 ||\n intersection.aiTools.unsupported.length > 0 ||\n intersection.aiTools.unavailable.length > 0;\n\n const hasIdeData =\n intersection.idePlatforms.synced.length > 0 ||\n intersection.idePlatforms.unsupported.length > 0 ||\n intersection.idePlatforms.unavailable.length > 0;\n\n if (!hasAiData && !hasIdeData) {\n p.log.info(\"No tool or IDE intersection data available.\");\n return;\n }\n\n if (hasAiData) {\n displayDimension(\"AI Tools\", intersection.aiTools);\n }\n\n if (hasIdeData) {\n displayDimension(\"IDE Platforms\", intersection.idePlatforms);\n }\n}\n\n/**\n * Display a single dimension (AI tools or IDE platforms) of the intersection.\n */\nfunction displayDimension(label: string, dimension: DimensionIntersection): void {\n const lines: string[] = [];\n\n if (dimension.synced.length > 0) {\n for (const item of dimension.synced) {\n lines.push(` \\u2713 ${item}`);\n }\n }\n\n if (dimension.unavailable.length > 0) {\n for (const item of dimension.unavailable) {\n lines.push(` - ${item} (not installed)`);\n }\n }\n\n if (dimension.unsupported.length > 0) {\n for (const item of dimension.unsupported) {\n lines.push(` ~ ${item} (not supported by profile)`);\n }\n }\n\n if (lines.length > 0) {\n p.note(lines.join(\"\\n\"), label);\n }\n}\n\n/**\n * Format a compact intersection summary for inline display.\n * Example: \"claude-code, cursor (AI) + vscode (IDE)\"\n */\nexport function formatIntersectionSummary(intersection: IntersectionResult): string {\n const parts: string[] = [];\n\n if (intersection.aiTools.synced.length > 0) {\n parts.push(`${intersection.aiTools.synced.join(\", \")} (AI)`);\n }\n\n if (intersection.idePlatforms.synced.length > 0) {\n parts.push(`${intersection.idePlatforms.synced.join(\", \")} (IDE)`);\n }\n\n if (parts.length === 0) {\n return \"No matching tools\";\n }\n\n return parts.join(\" + \");\n}\n","import { mkdir, readFile, readdir, writeFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport {\n type LockFileEntry,\n type ProjectManifest,\n collectComprehensivePatterns,\n ensureBatonDirGitignored,\n generateLock,\n removeGitignoreManagedSection,\n removePlacedFiles,\n updateGitignore,\n writeLock,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\n\nexport type SyncCategory = \"ai\" | \"files\" | \"ide\";\nexport const validCategories: SyncCategory[] = [\"ai\", \"files\", \"ide\"];\n\nexport interface SyncStats {\n created: number;\n errors: number;\n}\n\n/** Get or initialize placed files for a profile, avoiding unsafe `as` casts on Map.get(). */\nexport function getOrCreatePlacedFiles(\n map: Map<string, Record<string, LockFileEntry>>,\n profileName: string,\n): Record<string, LockFileEntry> {\n let files = map.get(profileName);\n if (!files) {\n files = {};\n map.set(profileName, files);\n }\n return files;\n}\n\n/**\n * Recursively copy all files from sourceDir to targetDir.\n * Returns the number of files written (skips identical content).\n */\nexport async function copyDirectoryRecursive(\n sourceDir: string,\n targetDir: string,\n): Promise<number> {\n await mkdir(targetDir, { recursive: true });\n const entries = await readdir(sourceDir, { withFileTypes: true });\n let placed = 0;\n\n for (const entry of entries) {\n const sourcePath = resolve(sourceDir, entry.name);\n const targetPath = resolve(targetDir, entry.name);\n\n if (entry.isDirectory()) {\n placed += await copyDirectoryRecursive(sourcePath, targetPath);\n } else {\n const content = await readFile(sourcePath, \"utf-8\");\n // Idempotency: skip if content is identical\n const existing = await readFile(targetPath, \"utf-8\").catch(() => undefined);\n if (existing !== content) {\n await writeFile(targetPath, content, \"utf-8\");\n placed++;\n }\n }\n }\n\n return placed;\n}\n\n/**\n * Handle .gitignore update based on the project manifest's gitignore setting.\n *\n * When gitignore is enabled (default): writes comprehensive patterns for ALL\n * known AI tools and IDE platforms to ensure stable, dev-independent content.\n * When disabled: removes any existing managed section.\n * Always ensures .baton/ is gitignored regardless of setting.\n */\nexport async function handleGitignoreUpdate(params: {\n projectManifest: ProjectManifest;\n fileMap: Map<string, { source: string; target: string; profileName: string }>;\n projectRoot: string;\n spinner: ReturnType<typeof p.spinner>;\n}): Promise<void> {\n const { projectManifest, fileMap, projectRoot, spinner } = params;\n const gitignoreEnabled = projectManifest.gitignore !== false;\n\n // Always ensure .baton/ is gitignored\n await ensureBatonDirGitignored(projectRoot);\n\n if (gitignoreEnabled) {\n spinner.start(\"Updating .gitignore...\");\n const fileTargets = [...fileMap.values()].map((f) => f.target);\n const patterns = collectComprehensivePatterns({ fileTargets });\n const updated = await updateGitignore(projectRoot, patterns);\n spinner.stop(\n updated ? \"Updated .gitignore with managed patterns\" : \".gitignore already up to date\",\n );\n } else {\n spinner.start(\"Checking .gitignore...\");\n const removed = await removeGitignoreManagedSection(projectRoot);\n spinner.stop(removed ? \"Removed managed section from .gitignore\" : \".gitignore unchanged\");\n }\n}\n\n/**\n * Generate and write the baton.lock lockfile from placed files and profile metadata.\n */\nexport async function writeLockData(params: {\n allProfiles: Array<{ name: string; source: string; manifest: { version: string } }>;\n sourceShas: Map<string, string>;\n placedFiles: Map<string, Record<string, LockFileEntry>>;\n projectRoot: string;\n spinner: ReturnType<typeof p.spinner>;\n}): Promise<void> {\n const { allProfiles, sourceShas, placedFiles, projectRoot, spinner } = params;\n\n spinner.start(\"Updating lockfile...\");\n\n const lockPackages: Record<\n string,\n {\n source: string;\n resolved: string;\n version: string;\n sha: string;\n files: Record<string, string | LockFileEntry>;\n }\n > = {};\n\n for (const profile of allProfiles) {\n lockPackages[profile.name] = {\n source: profile.source,\n resolved: profile.source,\n version: profile.manifest.version,\n sha: sourceShas.get(profile.source) || \"unknown\",\n files: placedFiles.get(profile.name) || {},\n };\n }\n\n const lockData = generateLock(lockPackages);\n await writeLock(lockData, resolve(projectRoot, \"baton.lock\"));\n\n spinner.stop(\"Lockfile updated\");\n}\n\n/**\n * Detect and remove files that were in the previous lockfile but are no longer\n * part of the current sync. Cleans up empty parent directories.\n */\nexport async function cleanupOrphanedFiles(params: {\n previousPaths: Set<string>;\n placedFiles: Map<string, Record<string, LockFileEntry>>;\n projectRoot: string;\n dryRun: boolean;\n autoYes: boolean;\n spinner: ReturnType<typeof p.spinner>;\n}): Promise<void> {\n const { previousPaths, placedFiles, projectRoot, dryRun, autoYes, spinner } = params;\n\n if (previousPaths.size === 0) return;\n\n // Collect all currently placed file paths\n const currentPaths = new Set<string>();\n for (const files of placedFiles.values()) {\n for (const filePath of Object.keys(files)) {\n currentPaths.add(filePath);\n }\n }\n\n // Find orphaned paths (in previous lock but not in current sync)\n const orphanedPaths = [...previousPaths].filter((prev) => !currentPaths.has(prev));\n if (orphanedPaths.length === 0) return;\n\n if (dryRun) {\n p.log.warn(`Would remove ${orphanedPaths.length} orphaned file(s):`);\n for (const orphanedPath of orphanedPaths) {\n p.log.info(` Removed: ${orphanedPath}`);\n }\n return;\n }\n\n p.log.warn(`Found ${orphanedPaths.length} orphaned file(s) to remove:`);\n for (const orphanedPath of orphanedPaths) {\n p.log.info(` Removed: ${orphanedPath}`);\n }\n\n let shouldRemove = autoYes;\n if (!autoYes) {\n const confirmed = await p.confirm({\n message: `Remove ${orphanedPaths.length} orphaned file(s)?`,\n initialValue: true,\n });\n if (p.isCancel(confirmed)) {\n p.log.info(\"Skipped orphan removal.\");\n shouldRemove = false;\n } else {\n shouldRemove = confirmed;\n }\n }\n\n if (!shouldRemove) {\n p.log.info(\"Orphan removal skipped.\");\n return;\n }\n\n spinner.start(\"Removing orphaned files...\");\n const removedCount = await removePlacedFiles(orphanedPaths, projectRoot);\n spinner.stop(`Removed ${removedCount} orphaned file(s)`);\n}\n","import { mkdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, relative, resolve } from \"node:path\";\nimport {\n type AIToolAdapter,\n type AgentEntry,\n type AgentFile,\n type CloneContext,\n FileNotFoundError,\n type LockFile,\n type LockFileEntry,\n type MemoryEntry,\n type MergedSkillItem,\n type ParsedSource,\n type ProjectManifest,\n type RuleEntry,\n type RuleFile,\n type WeightConflictWarning,\n cloneGitSource,\n detectInstalledAITools,\n detectLegacyPaths,\n getAIToolAdaptersForKeys,\n getIdePlatformTargetDir,\n getProfileWeight,\n isKnownIdePlatform,\n isLockedProfile,\n loadProfileManifest,\n loadProjectManifest,\n mergeAgentsWithWarnings,\n mergeContentParts,\n mergeMemoryWithWarnings,\n mergeRulesWithWarnings,\n mergeSkillsWithWarnings,\n parseFrontmatter,\n parseSource,\n placeFile,\n readLock,\n resolvePreferences,\n resolveProfileChain,\n sortProfilesByWeight,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport simpleGit from \"simple-git\";\nimport { buildIntersection } from \"../utils/build-intersection.js\";\nimport { promptFirstRunPreferences } from \"../utils/first-run-preferences.js\";\nimport { displayIntersection, formatIntersectionSummary } from \"../utils/intersection-display.js\";\nimport {\n type SyncCategory,\n type SyncStats,\n cleanupOrphanedFiles,\n copyDirectoryRecursive,\n getOrCreatePlacedFiles,\n handleGitignoreUpdate,\n validCategories,\n writeLockData,\n} from \"./sync-pipeline.js\";\n\n/** Extract the package name from a source string for lockfile lookup. */\nfunction getPackageNameFromSource(source: string, parsed: ParsedSource): string {\n if (parsed.provider === \"github\" || parsed.provider === \"gitlab\") {\n return `${parsed.org}/${parsed.repo}`;\n }\n if (parsed.provider === \"npm\") {\n return parsed.scope ? `${parsed.scope}/${parsed.package}` : parsed.package;\n }\n if (parsed.provider === \"git\") {\n return parsed.url;\n }\n return source;\n}\n\nexport const applyCommand = defineCommand({\n meta: {\n name: \"apply\",\n description: \"Apply locked configurations to the project (deterministic, reproducible)\",\n },\n args: {\n \"dry-run\": {\n type: \"boolean\",\n description: \"Show what would be done without writing files\",\n default: false,\n },\n category: {\n type: \"string\",\n description: \"Apply only a specific category: ai, files, or ide\",\n required: false,\n },\n yes: {\n type: \"boolean\",\n description: \"Run non-interactively (no prompts)\",\n default: false,\n },\n verbose: {\n type: \"boolean\",\n alias: \"v\",\n description: \"Show detailed output for each placed file\",\n default: false,\n },\n fresh: {\n type: \"boolean\",\n description: \"Force cache bypass (re-clone even if cached)\",\n default: false,\n },\n },\n async run({ args }) {\n const dryRun = args[\"dry-run\"];\n const categoryArg = args.category as string | undefined;\n const autoYes = args.yes;\n const verbose = args.verbose;\n const fresh = args.fresh;\n\n // Validate --category flag\n let category: SyncCategory | undefined;\n if (categoryArg) {\n if (!validCategories.includes(categoryArg as SyncCategory)) {\n p.cancel(\n `Invalid category \"${categoryArg}\". Valid categories: ${validCategories.join(\", \")}`,\n );\n process.exit(1);\n }\n category = categoryArg as SyncCategory;\n }\n\n const syncAi = !category || category === \"ai\";\n const syncFiles = !category || category === \"files\";\n const syncIde = !category || category === \"ide\";\n\n p.intro(category ? `📦 Baton Apply (category: ${category})` : \"📦 Baton Apply\");\n\n // Statistics tracking\n const stats: SyncStats = {\n created: 0,\n errors: 0,\n };\n\n try {\n // Step 0: Load project manifest\n const projectRoot = process.cwd();\n const manifestPath = resolve(projectRoot, \"baton.yaml\");\n\n let projectManifest: ProjectManifest;\n try {\n projectManifest = await loadProjectManifest(manifestPath);\n } catch (error) {\n if (error instanceof FileNotFoundError) {\n p.cancel(\"baton.yaml not found. Run `baton init` first.\");\n } else {\n p.cancel(\n `Failed to load baton.yaml: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n process.exit(1);\n }\n\n // Step 0a: First-run preferences check\n await promptFirstRunPreferences(projectRoot, !!args.yes);\n\n // Step 0b: Read lockfile for locked SHAs\n const lockfilePath = resolve(projectRoot, \"baton.lock\");\n let lockfile: LockFile | null = null;\n try {\n lockfile = await readLock(lockfilePath);\n } catch {\n // No lockfile — fall back to manifest versions\n if (verbose) {\n p.log.warn(\"No lockfile found. Falling back to manifest versions.\");\n }\n }\n\n // Step 0c: Compute cache TTL (apply uses cache by default, --fresh bypasses)\n const maxCacheAgeMs = fresh ? 0 : undefined;\n\n // Step 0d: Read existing lockfile to detect orphaned files later\n const previousPaths = new Set<string>();\n if (lockfile) {\n for (const pkg of Object.values(lockfile.packages)) {\n for (const filePath of Object.keys(pkg.integrity)) {\n previousPaths.add(filePath);\n }\n }\n }\n\n // Step 1: Resolve profile chain\n const spinner = p.spinner();\n spinner.start(\"Resolving profile chain...\");\n\n const allProfiles = [];\n // Track SHA per source for lockfile\n const sourceShas = new Map<string, string>();\n for (const profileSource of projectManifest.profiles || []) {\n try {\n if (verbose) {\n p.log.info(`Resolving source: ${profileSource.source}`);\n }\n // Load the profile manifest first\n const parsed = parseSource(profileSource.source);\n\n let manifestPath: string;\n let cloneContext: CloneContext | undefined;\n if (parsed.provider === \"local\" || parsed.provider === \"file\") {\n const absolutePath = parsed.path.startsWith(\"/\")\n ? parsed.path\n : resolve(projectRoot, parsed.path);\n manifestPath = resolve(absolutePath, \"baton.profile.yaml\");\n // Try to get SHA from local git repo, fallback to \"local\"\n try {\n const git = simpleGit(absolutePath);\n await git.checkIsRepo();\n const sha = await git.revparse([\"HEAD\"]);\n sourceShas.set(profileSource.source, sha.trim());\n } catch {\n sourceShas.set(profileSource.source, \"local\");\n }\n } else {\n // For remote sources, clone first\n const url =\n parsed.provider === \"github\" || parsed.provider === \"gitlab\"\n ? parsed.url\n : parsed.provider === \"git\"\n ? parsed.url\n : \"\";\n\n if (!url) {\n throw new Error(`Invalid source: ${profileSource.source}`);\n }\n\n // Determine ref: use locked SHA if available, otherwise profileSource.version\n let ref = profileSource.version;\n if (lockfile) {\n const packageName = getPackageNameFromSource(profileSource.source, parsed);\n const lockedPkg = lockfile.packages[packageName];\n if (lockedPkg?.sha && lockedPkg.sha !== \"unknown\") {\n ref = lockedPkg.sha;\n if (verbose) {\n p.log.info(`Using locked SHA for ${profileSource.source}: ${ref.slice(0, 12)}`);\n }\n }\n }\n\n const cloned = await cloneGitSource({\n url,\n ref,\n subpath: \"subpath\" in parsed ? parsed.subpath : undefined,\n useCache: true,\n maxCacheAgeMs,\n });\n manifestPath = resolve(cloned.localPath, \"baton.profile.yaml\");\n sourceShas.set(profileSource.source, cloned.sha);\n cloneContext = {\n cachePath: cloned.cachePath,\n sparseCheckout: cloned.sparseCheckout,\n };\n }\n\n const manifest = await loadProfileManifest(manifestPath);\n const profileDir = dirname(manifestPath);\n const chain = await resolveProfileChain(\n manifest,\n profileSource.source,\n profileDir,\n cloneContext,\n );\n allProfiles.push(...chain);\n } catch (error) {\n spinner.stop(`Failed to resolve profile ${profileSource.source}: ${error}`);\n stats.errors++;\n }\n }\n\n if (allProfiles.length === 0) {\n spinner.stop(\"No profiles configured\");\n p.outro(\"Nothing to apply. Run `baton manage` to add a profile.\");\n process.exit(2);\n }\n\n spinner.stop(`Resolved ${allProfiles.length} profile(s)`);\n\n // Step 1b: Sort profiles by weight for merge ordering\n const weightSortedProfiles = sortProfilesByWeight(allProfiles);\n\n // Step 2: Merge configurations\n spinner.start(\"Merging configurations...\");\n\n const allWeightWarnings: WeightConflictWarning[] = [];\n\n const skillsResult = mergeSkillsWithWarnings(weightSortedProfiles);\n const mergedSkills: MergedSkillItem[] = skillsResult.skills;\n allWeightWarnings.push(...skillsResult.warnings);\n\n const rulesResult = mergeRulesWithWarnings(weightSortedProfiles);\n const mergedRules: RuleEntry[] = rulesResult.rules;\n allWeightWarnings.push(...rulesResult.warnings);\n\n const agentsResult = mergeAgentsWithWarnings(weightSortedProfiles);\n const mergedAgents: AgentEntry[] = agentsResult.agents;\n allWeightWarnings.push(...agentsResult.warnings);\n\n const memoryResult = mergeMemoryWithWarnings(weightSortedProfiles);\n const mergedMemory: MemoryEntry[] = memoryResult.entries;\n allWeightWarnings.push(...memoryResult.warnings);\n\n // Collect all commands from all profiles (deduplicated by name, last wins)\n const commandMap = new Map<string, string>();\n const lockedCommands = new Set<string>();\n const commandOwner = new Map<string, { profileName: string; weight: number }>();\n for (const profile of weightSortedProfiles) {\n const weight = getProfileWeight(profile);\n const locked = isLockedProfile(profile);\n for (const cmd of profile.manifest.ai?.commands || []) {\n if (lockedCommands.has(cmd)) continue;\n\n const existing = commandOwner.get(cmd);\n if (existing && existing.weight === weight && existing.profileName !== profile.name) {\n allWeightWarnings.push({\n key: cmd,\n category: \"command\",\n profileA: existing.profileName,\n profileB: profile.name,\n weight,\n });\n }\n\n commandMap.set(cmd, profile.name);\n commandOwner.set(cmd, { profileName: profile.name, weight });\n if (locked) lockedCommands.add(cmd);\n }\n }\n const mergedCommandCount = commandMap.size;\n\n // Collect all files from all profiles (deduplicated by target path, last wins)\n const fileMap = new Map<string, { source: string; target: string; profileName: string }>();\n const lockedFiles = new Set<string>();\n const fileOwner = new Map<string, { profileName: string; weight: number }>();\n for (const profile of weightSortedProfiles) {\n const weight = getProfileWeight(profile);\n const locked = isLockedProfile(profile);\n for (const fileConfig of profile.manifest.files || []) {\n const target = fileConfig.target || fileConfig.source;\n if (lockedFiles.has(target)) continue;\n\n const existing = fileOwner.get(target);\n if (existing && existing.weight === weight && existing.profileName !== profile.name) {\n allWeightWarnings.push({\n key: target,\n category: \"file\",\n profileA: existing.profileName,\n profileB: profile.name,\n weight,\n });\n }\n\n fileMap.set(target, { source: fileConfig.source, target, profileName: profile.name });\n fileOwner.set(target, { profileName: profile.name, weight });\n if (locked) lockedFiles.add(target);\n }\n }\n const mergedFileCount = fileMap.size;\n\n // Collect all IDE configs from all profiles\n const ideMap = new Map<\n string,\n { ideKey: string; fileName: string; targetDir: string; profileName: string }\n >();\n const lockedIdeConfigs = new Set<string>();\n const ideOwner = new Map<string, { profileName: string; weight: number }>();\n for (const profile of weightSortedProfiles) {\n if (!profile.manifest.ide) continue;\n const weight = getProfileWeight(profile);\n const locked = isLockedProfile(profile);\n for (const [ideKey, files] of Object.entries(profile.manifest.ide)) {\n if (!files) continue;\n const targetDir = getIdePlatformTargetDir(ideKey);\n if (!targetDir) {\n if (!isKnownIdePlatform(ideKey)) {\n p.log.warn(\n `Unknown IDE platform \"${ideKey}\" in profile \"${profile.name}\" — skipping. Register it in the IDE platform registry.`,\n );\n }\n continue;\n }\n for (const fileName of files) {\n const targetPath = `${targetDir}/${fileName}`;\n if (lockedIdeConfigs.has(targetPath)) continue;\n\n const existing = ideOwner.get(targetPath);\n if (existing && existing.weight === weight && existing.profileName !== profile.name) {\n allWeightWarnings.push({\n key: targetPath,\n category: \"ide\",\n profileA: existing.profileName,\n profileB: profile.name,\n weight,\n });\n }\n\n ideMap.set(targetPath, { ideKey, fileName, targetDir, profileName: profile.name });\n ideOwner.set(targetPath, { profileName: profile.name, weight });\n if (locked) lockedIdeConfigs.add(targetPath);\n }\n }\n }\n const mergedIdeCount = ideMap.size;\n\n spinner.stop(\n `Merged: ${mergedSkills.length} skills, ${mergedRules.length} rules, ${mergedAgents.length} agents, ${mergedMemory.length} memory files, ${mergedCommandCount} commands, ${mergedFileCount} files, ${mergedIdeCount} IDE configs`,\n );\n\n // Emit weight conflict warnings\n if (allWeightWarnings.length > 0) {\n for (const w of allWeightWarnings) {\n p.log.warn(\n `Weight conflict: \"${w.profileA}\" and \"${w.profileB}\" both define ${w.category} \"${w.key}\" with weight ${w.weight}. Last declared wins.`,\n );\n }\n }\n\n // Step 3: Determine which AI tools and IDE platforms to sync (intersection-based)\n spinner.start(\"Computing tool intersection...\");\n\n const prefs = await resolvePreferences(projectRoot);\n const detectedAITools = await detectInstalledAITools();\n\n if (verbose) {\n p.log.info(\n `AI tools: ${prefs.ai.tools.join(\", \") || \"(none)\"} (from ${prefs.ai.source} preferences)`,\n );\n p.log.info(\n `IDE platforms: ${prefs.ide.platforms.join(\", \") || \"(none)\"} (from ${prefs.ide.source} preferences)`,\n );\n }\n\n let syncedAiTools: string[];\n let syncedIdePlatforms: string[] | null = null;\n let allIntersections: Map<string, import(\"@baton-dx/core\").IntersectionResult> | null = null;\n\n if (prefs.ai.tools.length > 0) {\n const developerTools = { aiTools: prefs.ai.tools, idePlatforms: prefs.ide.platforms };\n const aggregatedSyncedAi = new Set<string>();\n const aggregatedSyncedIde = new Set<string>();\n allIntersections = new Map();\n\n for (const profileSource of projectManifest.profiles || []) {\n try {\n const intersection = await buildIntersection(\n profileSource.source,\n developerTools,\n projectRoot,\n );\n if (intersection) {\n allIntersections.set(profileSource.source, intersection);\n for (const tool of intersection.aiTools.synced) {\n aggregatedSyncedAi.add(tool);\n }\n for (const platform of intersection.idePlatforms.synced) {\n aggregatedSyncedIde.add(platform);\n }\n }\n } catch {\n // Best-effort — skip if intersection cannot be computed for this profile\n }\n }\n\n syncedAiTools = aggregatedSyncedAi.size > 0 ? [...aggregatedSyncedAi] : [];\n syncedIdePlatforms = [...aggregatedSyncedIde];\n } else {\n syncedAiTools = detectedAITools;\n syncedIdePlatforms = null;\n if (detectedAITools.length > 0) {\n p.log.warn(\"No AI tools configured. Run `baton ai-tools scan` to configure your tools.\");\n p.log.info(`Falling back to detected tools: ${detectedAITools.join(\", \")}`);\n }\n }\n\n if (syncedAiTools.length === 0 && detectedAITools.length === 0) {\n spinner.stop(\"No AI tools available\");\n p.cancel(\"No AI tools found. Install an AI coding tool first.\");\n process.exit(1);\n }\n\n if (syncedAiTools.length === 0) {\n spinner.stop(\"No AI tools in intersection\");\n p.cancel(\n \"No AI tools match between your configuration and profile support. \" +\n \"Run `baton ai-tools scan` or check your profile's supported tools.\",\n );\n process.exit(1);\n }\n\n if (allIntersections) {\n for (const [source, intersection] of allIntersections) {\n if (verbose) {\n p.log.step(`Intersection for ${source}`);\n displayIntersection(intersection);\n } else {\n const summary = formatIntersectionSummary(intersection);\n p.log.info(`Applying for: ${summary}`);\n }\n }\n }\n\n const ideSummary =\n syncedIdePlatforms && syncedIdePlatforms.length > 0\n ? ` | IDE platforms: ${syncedIdePlatforms.join(\", \")}`\n : \"\";\n spinner.stop(`Applying to AI tools: ${syncedAiTools.join(\", \")}${ideSummary}`);\n\n // Step 4: Migrate legacy paths\n spinner.start(\"Checking for legacy paths...\");\n\n const legacyFiles = await detectLegacyPaths(projectRoot);\n\n if (legacyFiles.length > 0 && !dryRun) {\n spinner.stop(`Found ${legacyFiles.length} legacy file(s)`);\n\n if (!autoYes) {\n p.note(\n `Found legacy configuration files:\\n${legacyFiles.map((f) => ` - ${f.legacyPath}`).join(\"\\n\")}`,\n \"Legacy Files\",\n );\n p.log.warn(\"Run migration manually with appropriate action (migrate/copy/skip)\");\n }\n } else {\n spinner.stop(\"No legacy files found\");\n }\n\n // Step 5-7: Transform, Place, and Link\n spinner.start(\"Processing configurations...\");\n\n const adapters = getAIToolAdaptersForKeys(syncedAiTools);\n\n const placementConfig = {\n mode: \"copy\" as const,\n projectRoot,\n };\n\n const placedFiles = new Map<string, Record<string, LockFileEntry>>();\n\n // Build a map from profile name to local directory path\n const profileLocalPaths = new Map<string, string>();\n for (const profileSource of projectManifest.profiles || []) {\n const parsed = parseSource(profileSource.source);\n if (parsed.provider === \"local\" || parsed.provider === \"file\") {\n const localPath = parsed.path.startsWith(\"/\")\n ? parsed.path\n : resolve(projectRoot, parsed.path);\n for (const prof of allProfiles) {\n if (prof.source === profileSource.source) {\n profileLocalPaths.set(prof.name, localPath);\n }\n }\n } else if (\n parsed.provider === \"github\" ||\n parsed.provider === \"gitlab\" ||\n parsed.provider === \"git\"\n ) {\n const url = parsed.provider === \"git\" ? parsed.url : parsed.url;\n\n // Use locked SHA for deterministic clone\n let ref = profileSource.version;\n if (lockfile) {\n const packageName = getPackageNameFromSource(profileSource.source, parsed);\n const lockedPkg = lockfile.packages[packageName];\n if (lockedPkg?.sha && lockedPkg.sha !== \"unknown\") {\n ref = lockedPkg.sha;\n }\n }\n\n const cloned = await cloneGitSource({\n url,\n ref,\n subpath: \"subpath\" in parsed ? parsed.subpath : undefined,\n useCache: true,\n maxCacheAgeMs,\n });\n for (const prof of allProfiles) {\n if (prof.source === profileSource.source) {\n profileLocalPaths.set(prof.name, cloned.localPath);\n }\n }\n }\n }\n\n // Register local paths for inherited profiles (from extends chains)\n for (const prof of allProfiles) {\n if (!profileLocalPaths.has(prof.name) && prof.localPath) {\n profileLocalPaths.set(prof.name, prof.localPath);\n }\n }\n\n // Content accumulator for files that may receive content from multiple categories\n const contentAccumulator = new Map<\n string,\n {\n parts: string[];\n adapter: AIToolAdapter;\n type: \"memory\" | \"rules\" | \"agents\";\n name: string;\n profiles: Set<string>;\n }\n >();\n\n // Accumulate memory file content\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing memory files...`);\n }\n for (const memoryEntry of mergedMemory) {\n try {\n const contentParts: string[] = [];\n for (const contribution of memoryEntry.contributions) {\n const profileDir = profileLocalPaths.get(contribution.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${contribution.profileName}`,\n );\n continue;\n }\n\n const memoryFilePath = resolve(profileDir, \"ai\", \"memory\", memoryEntry.filename);\n try {\n const content = await readFile(memoryFilePath, \"utf-8\");\n contentParts.push(content);\n } catch {\n spinner.message(`Warning: Could not read ${memoryFilePath}`);\n }\n }\n\n if (contentParts.length === 0) continue;\n\n const mergedContent = mergeContentParts(contentParts, memoryEntry.mergeStrategy);\n\n const transformed = adapter.transformMemory({\n filename: memoryEntry.filename,\n content: mergedContent,\n });\n\n const targetPath = adapter.getPath(\"memory\", \"project\", transformed.filename);\n const absolutePath = targetPath.startsWith(\"/\")\n ? targetPath\n : resolve(projectRoot, targetPath);\n\n const existing = contentAccumulator.get(absolutePath);\n if (existing) {\n existing.parts.push(transformed.content);\n for (const c of memoryEntry.contributions) existing.profiles.add(c.profileName);\n } else {\n const profiles = new Set<string>();\n for (const c of memoryEntry.contributions) profiles.add(c.profileName);\n contentAccumulator.set(absolutePath, {\n parts: [transformed.content],\n adapter,\n type: \"memory\",\n name: transformed.filename,\n profiles,\n });\n }\n } catch (error) {\n spinner.message(\n `Error placing ${memoryEntry.filename} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n\n // Place skill directories\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing skills...`);\n }\n for (const skillItem of mergedSkills) {\n try {\n const profileDir = profileLocalPaths.get(skillItem.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${skillItem.profileName}`,\n );\n continue;\n }\n\n const skillSourceDir = resolve(profileDir, \"ai\", \"skills\", skillItem.name);\n\n try {\n await stat(skillSourceDir);\n } catch {\n spinner.message(`Warning: Skill directory not found: ${skillSourceDir}`);\n continue;\n }\n\n const targetSkillPath = adapter.getPath(\"skills\", skillItem.scope, skillItem.name);\n const absoluteTargetDir = targetSkillPath.startsWith(\"/\")\n ? targetSkillPath\n : resolve(projectRoot, targetSkillPath);\n\n const placed = await copyDirectoryRecursive(skillSourceDir, absoluteTargetDir);\n stats.created += placed;\n\n const profileFiles = getOrCreatePlacedFiles(placedFiles, skillItem.profileName);\n try {\n const entryContent = await readFile(resolve(skillSourceDir, \"index.md\"), \"utf-8\");\n profileFiles[targetSkillPath] = {\n content: entryContent,\n tool: adapter.key,\n category: \"ai\",\n };\n } catch {\n profileFiles[targetSkillPath] = {\n content: skillItem.name,\n tool: adapter.key,\n category: \"ai\",\n };\n }\n\n if (verbose) {\n const label = placed > 0 ? `${placed} file(s) created` : \"unchanged, skipped\";\n p.log.info(` -> ${absoluteTargetDir}/ (${label})`);\n }\n } catch (error) {\n spinner.message(\n `Error placing skill ${skillItem.name} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n\n // Accumulate rule file content\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing rules...`);\n }\n for (const ruleEntry of mergedRules) {\n try {\n const ruleName = ruleEntry.name.replace(/\\.md$/, \"\");\n\n const isUniversal = ruleEntry.agents.length === 0;\n const isForThisAdapter = ruleEntry.agents.includes(adapter.key);\n if (!isUniversal && !isForThisAdapter) continue;\n\n const profileDir = profileLocalPaths.get(ruleEntry.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${ruleEntry.profileName}`,\n );\n continue;\n }\n\n const ruleSubdir = isUniversal ? \"universal\" : ruleEntry.agents[0];\n const ruleSourcePath = resolve(\n profileDir,\n \"ai\",\n \"rules\",\n ruleSubdir,\n `${ruleName}.md`,\n );\n\n let rawContent: string;\n try {\n rawContent = await readFile(ruleSourcePath, \"utf-8\");\n } catch {\n spinner.message(`Warning: Could not read rule file: ${ruleSourcePath}`);\n continue;\n }\n\n const parsed = parseFrontmatter(rawContent);\n\n const ruleFile: RuleFile = {\n name: ruleName,\n content: rawContent,\n frontmatter:\n Object.keys(parsed.data).length > 0\n ? (parsed.data as RuleFile[\"frontmatter\"])\n : undefined,\n };\n\n const transformed = adapter.transformRule(ruleFile);\n\n const targetPath = adapter.getPath(\"rules\", \"project\", ruleName);\n const absolutePath = targetPath.startsWith(\"/\")\n ? targetPath\n : resolve(projectRoot, targetPath);\n\n const existing = contentAccumulator.get(absolutePath);\n if (existing) {\n existing.parts.push(transformed.content);\n existing.profiles.add(ruleEntry.profileName);\n } else {\n contentAccumulator.set(absolutePath, {\n parts: [transformed.content],\n adapter,\n type: \"rules\",\n name: ruleName,\n profiles: new Set([ruleEntry.profileName]),\n });\n }\n } catch (error) {\n spinner.message(`Error placing rule ${ruleEntry.name} for ${adapter.name}: ${error}`);\n stats.errors++;\n }\n }\n }\n }\n\n // Accumulate agent file content\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing agents...`);\n }\n for (const agentEntry of mergedAgents) {\n try {\n const agentName = agentEntry.name.replace(/\\.md$/, \"\");\n\n const isUniversal = agentEntry.agents.length === 0;\n const isForThisAdapter = agentEntry.agents.includes(adapter.key);\n if (!isUniversal && !isForThisAdapter) continue;\n\n const profileDir = profileLocalPaths.get(agentEntry.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${agentEntry.profileName}`,\n );\n continue;\n }\n\n const agentSubdir = isUniversal ? \"universal\" : agentEntry.agents[0];\n const agentSourcePath = resolve(\n profileDir,\n \"ai\",\n \"agents\",\n agentSubdir,\n `${agentName}.md`,\n );\n\n let rawContent: string;\n try {\n rawContent = await readFile(agentSourcePath, \"utf-8\");\n } catch {\n spinner.message(`Warning: Could not read agent file: ${agentSourcePath}`);\n continue;\n }\n\n const parsed = parseFrontmatter(rawContent);\n\n const frontmatter =\n Object.keys(parsed.data).length > 0\n ? (parsed.data as AgentFile[\"frontmatter\"])\n : { name: agentName };\n const agentFile: AgentFile = {\n name: agentName,\n content: rawContent,\n description: (frontmatter as Record<string, unknown>).description as\n | string\n | undefined,\n frontmatter,\n };\n\n const transformed = adapter.transformAgent(agentFile);\n\n const targetPath = adapter.getPath(\"agents\", \"project\", agentName);\n const absolutePath = targetPath.startsWith(\"/\")\n ? targetPath\n : resolve(projectRoot, targetPath);\n\n const existing = contentAccumulator.get(absolutePath);\n if (existing) {\n existing.parts.push(transformed.content);\n existing.profiles.add(agentEntry.profileName);\n } else {\n contentAccumulator.set(absolutePath, {\n parts: [transformed.content],\n adapter,\n type: \"agents\",\n name: agentName,\n profiles: new Set([agentEntry.profileName]),\n });\n }\n } catch (error) {\n spinner.message(\n `Error placing agent ${agentEntry.name} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n\n // Flush accumulated content\n if (!dryRun && syncAi) {\n for (const [absolutePath, entry] of contentAccumulator) {\n try {\n const combinedContent = entry.parts.join(\"\\n\\n\");\n const result = await placeFile(\n combinedContent,\n entry.adapter,\n entry.type,\n \"project\",\n entry.name,\n placementConfig,\n );\n\n if (result.action !== \"skipped\") {\n stats.created++;\n }\n\n const relPath = isAbsolute(result.path)\n ? relative(projectRoot, result.path)\n : result.path;\n for (const profileName of entry.profiles) {\n const pf = getOrCreatePlacedFiles(placedFiles, profileName);\n pf[relPath] = {\n content: combinedContent,\n tool: entry.adapter.key,\n category: \"ai\",\n };\n }\n\n if (verbose) {\n const label = result.action === \"skipped\" ? \"unchanged, skipped\" : result.action;\n p.log.info(` -> ${result.path} (${label})`);\n }\n } catch (error) {\n spinner.message(`Error placing accumulated content to ${absolutePath}: ${error}`);\n stats.errors++;\n }\n }\n }\n\n // Place command files\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing commands...`);\n }\n for (const profile of allProfiles) {\n const profileDir = profileLocalPaths.get(profile.name);\n if (!profileDir) continue;\n\n const commandNames = profile.manifest.ai?.commands || [];\n for (const commandName of commandNames) {\n try {\n const commandSourcePath = resolve(\n profileDir,\n \"ai\",\n \"commands\",\n `${commandName}.md`,\n );\n\n let content: string;\n try {\n content = await readFile(commandSourcePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const result = await placeFile(\n content,\n adapter,\n \"commands\",\n \"project\",\n commandName,\n placementConfig,\n );\n\n if (result.action !== \"skipped\") {\n stats.created++;\n }\n\n const cmdRelPath = isAbsolute(result.path)\n ? relative(projectRoot, result.path)\n : result.path;\n const pf = getOrCreatePlacedFiles(placedFiles, profile.name);\n pf[cmdRelPath] = { content, tool: adapter.key, category: \"ai\" };\n\n if (verbose) {\n const label = result.action === \"skipped\" ? \"unchanged, skipped\" : result.action;\n p.log.info(` -> ${result.path} (${label})`);\n }\n } catch (error) {\n spinner.message(\n `Error placing command ${commandName} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n }\n\n // Place project files\n if (!dryRun && syncFiles) {\n for (const fileEntry of fileMap.values()) {\n try {\n const profileDir = profileLocalPaths.get(fileEntry.profileName);\n if (!profileDir) continue;\n\n const fileSourcePath = resolve(profileDir, \"files\", fileEntry.source);\n\n let content: string;\n try {\n content = await readFile(fileSourcePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const targetPath = resolve(projectRoot, fileEntry.target);\n\n await mkdir(dirname(targetPath), { recursive: true });\n\n const existing = await readFile(targetPath, \"utf-8\").catch(() => undefined);\n if (existing !== content) {\n await writeFile(targetPath, content, \"utf-8\");\n stats.created++;\n if (verbose) {\n p.log.info(` -> ${fileEntry.target} (created)`);\n }\n } else if (verbose) {\n p.log.info(` -> ${fileEntry.target} (unchanged, skipped)`);\n }\n\n const fpf = getOrCreatePlacedFiles(placedFiles, fileEntry.profileName);\n fpf[fileEntry.target] = { content, category: \"files\" };\n } catch (error) {\n spinner.message(`Error placing file ${fileEntry.source}: ${error}`);\n stats.errors++;\n }\n }\n }\n\n // Place IDE config files\n if (!dryRun && syncIde) {\n for (const ideEntry of ideMap.values()) {\n try {\n if (syncedIdePlatforms !== null && !syncedIdePlatforms.includes(ideEntry.ideKey)) {\n if (verbose) {\n p.log.info(\n ` -> ${ideEntry.targetDir}/${ideEntry.fileName} (skipped — IDE platform \"${ideEntry.ideKey}\" not in intersection)`,\n );\n }\n continue;\n }\n\n const profileDir = profileLocalPaths.get(ideEntry.profileName);\n if (!profileDir) continue;\n\n const ideSourcePath = resolve(profileDir, \"ide\", ideEntry.ideKey, ideEntry.fileName);\n\n let content: string;\n try {\n content = await readFile(ideSourcePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const targetPath = resolve(projectRoot, ideEntry.targetDir, ideEntry.fileName);\n\n await mkdir(dirname(targetPath), { recursive: true });\n\n const existing = await readFile(targetPath, \"utf-8\").catch(() => undefined);\n if (existing !== content) {\n await writeFile(targetPath, content, \"utf-8\");\n stats.created++;\n if (verbose) {\n p.log.info(` -> ${ideEntry.targetDir}/${ideEntry.fileName} (created)`);\n }\n } else if (verbose) {\n p.log.info(` -> ${ideEntry.targetDir}/${ideEntry.fileName} (unchanged, skipped)`);\n }\n\n const ideRelPath = `${ideEntry.targetDir}/${ideEntry.fileName}`;\n const ipf = getOrCreatePlacedFiles(placedFiles, ideEntry.profileName);\n ipf[ideRelPath] = {\n content,\n tool: ideEntry.ideKey,\n category: \"ide\",\n };\n } catch (error) {\n spinner.message(`Error placing IDE config ${ideEntry.fileName}: ${error}`);\n stats.errors++;\n }\n }\n }\n\n spinner.stop(\n dryRun\n ? `Would place files for ${adapters.length} agent(s)`\n : `Placed ${stats.created} file(s) for ${adapters.length} agent(s)`,\n );\n\n // Step 8: Update .gitignore\n if (!dryRun) {\n await handleGitignoreUpdate({\n projectManifest,\n fileMap,\n projectRoot,\n spinner,\n });\n }\n\n // Step 9: Write lockfile\n if (!dryRun) {\n await writeLockData({ allProfiles, sourceShas, placedFiles, projectRoot, spinner });\n }\n\n // Step 10: Remove orphaned files\n await cleanupOrphanedFiles({\n previousPaths,\n placedFiles,\n projectRoot,\n dryRun,\n autoYes,\n spinner,\n });\n\n // Summary\n if (dryRun) {\n const parts: string[] = [];\n if (syncAi) {\n parts.push(` • ${mergedSkills.length} skills`);\n parts.push(` • ${mergedRules.length} rules`);\n parts.push(` • ${mergedAgents.length} agents`);\n parts.push(` • ${mergedMemory.length} memory files`);\n parts.push(` • ${mergedCommandCount} commands`);\n }\n if (syncFiles) {\n parts.push(` • ${mergedFileCount} files`);\n }\n if (syncIde) {\n const filteredIdeCount =\n syncedIdePlatforms !== null\n ? [...ideMap.values()].filter((e) => syncedIdePlatforms.includes(e.ideKey)).length\n : mergedIdeCount;\n parts.push(` • ${filteredIdeCount} IDE configs`);\n }\n const categoryLabel = category ? ` (category: ${category})` : \"\";\n p.outro(\n `[Dry Run${categoryLabel}] Would apply:\\n${parts.join(\"\\n\")}\\n\\nFor ${adapters.length} agent(s): ${syncedAiTools.join(\", \")}`,\n );\n } else {\n const categoryLabel = category ? ` (category: ${category})` : \"\";\n p.outro(`✅ Apply complete${categoryLabel}! Locked configurations applied.`);\n }\n\n process.exit(stats.errors > 0 ? 1 : 0);\n } catch (error) {\n p.cancel(`Apply failed: ${error}`);\n process.exit(1);\n }\n },\n});\n","import { loadGlobalConfig, saveGlobalConfig } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\n\n/**\n * Set a value in the global Baton config (~/.baton/config.yaml).\n *\n * Supports dotted paths like \"sync.cacheTtlHours\" to set nested values.\n * Usage: baton config set <key> <value>\n */\nexport const configSetCommand = defineCommand({\n meta: {\n name: \"set\",\n description: \"Set a global config value (e.g., baton config set sync.cacheTtlHours 1)\",\n },\n args: {\n key: {\n type: \"positional\",\n description: \"Config key using dot notation (e.g., sync.cacheTtlHours)\",\n required: true,\n },\n value: {\n type: \"positional\",\n description: \"Value to set\",\n required: true,\n },\n },\n async run({ args }) {\n const { key, value } = args;\n const segments = key.split(\".\");\n\n if (segments.length === 0 || segments.some((s: string) => s === \"\")) {\n p.cancel(`Invalid config key: \"${key}\"`);\n process.exit(1);\n }\n\n // Load current config\n const config = await loadGlobalConfig();\n\n // Parse the value into the appropriate type\n const parsed = parseValue(value);\n\n // Set the value at the dotted path\n setNestedValue(config, segments, parsed);\n\n // Save the updated config (Zod validates on save)\n try {\n await saveGlobalConfig(config);\n } catch (error) {\n p.cancel(`Invalid config value: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n\n p.log.success(`Set ${key} = ${JSON.stringify(parsed)}`);\n },\n});\n\n/** Parse a string value into a number, boolean, or string. */\nfunction parseValue(raw: string): unknown {\n if (raw === \"true\") return true;\n if (raw === \"false\") return false;\n const num = Number(raw);\n if (!Number.isNaN(num) && raw.trim() !== \"\") return num;\n return raw;\n}\n\n/** Set a value at a dotted path on an object, creating intermediate objects as needed. */\nfunction setNestedValue(obj: Record<string, unknown>, segments: string[], value: unknown): void {\n let current: Record<string, unknown> = obj;\n for (let i = 0; i < segments.length - 1; i++) {\n const seg = segments[i];\n if (current[seg] === undefined || current[seg] === null) {\n current[seg] = {};\n }\n current = current[seg] as Record<string, unknown>;\n }\n current[segments[segments.length - 1]] = value;\n}\n","import { join } from \"node:path\";\nimport { getAIToolConfig } from \"@baton-dx/ai-tool-paths\";\nimport type { ProjectManifest } from \"@baton-dx/core\";\nimport {\n getGlobalAiTools,\n getGlobalIdePlatforms,\n getGlobalSources,\n loadProjectManifest,\n resolvePreferences,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { buildIntersection } from \"../../utils/build-intersection.js\";\nimport { formatIntersectionSummary } from \"../../utils/intersection-display.js\";\nimport { configSetCommand } from \"./set.js\";\n\nasync function showDashboard(): Promise<void> {\n p.intro(\"Baton Dashboard\");\n\n // Fetch all data in parallel\n const [sources, aiTools, idePlatforms, projectManifest] = await Promise.all([\n getGlobalSources(),\n getGlobalAiTools(),\n getGlobalIdePlatforms(),\n loadProjectManifestSafe(),\n ]);\n\n // --- Global Sources ---\n console.log(\"\");\n p.log.step(\"Global Sources\");\n if (sources.length === 0) {\n p.log.info(\" No sources configured. Run: baton source connect <url>\");\n } else {\n for (const source of sources) {\n const defaultBadge = source.default ? \" (default)\" : \"\";\n const desc = source.description ? ` — ${source.description}` : \"\";\n p.log.info(` ${source.name}${defaultBadge}: ${source.url}${desc}`);\n }\n }\n\n // --- Developer Tools ---\n console.log(\"\");\n p.log.step(\"Developer Tools\");\n\n // Use resolved preferences if in a project directory, otherwise show global config\n if (projectManifest) {\n const prefs = await resolvePreferences(process.cwd());\n const resolvedAiTools = prefs.ai.tools;\n const resolvedIdePlatforms = prefs.ide.platforms;\n\n if (resolvedAiTools.length === 0 && resolvedIdePlatforms.length === 0) {\n p.log.info(\" No tools configured. Run: baton ai-tools scan && baton ides scan\");\n } else {\n if (resolvedAiTools.length > 0) {\n const toolNames = resolvedAiTools.map((key) => {\n try {\n return getAIToolConfig(key).name;\n } catch {\n return key;\n }\n });\n const aiSourceLabel =\n prefs.ai.source === \"project\" ? \"project preferences\" : \"global config\";\n p.log.info(` AI Tools: ${toolNames.join(\", \")} (from ${aiSourceLabel})`);\n }\n if (resolvedIdePlatforms.length > 0) {\n const ideSourceLabel =\n prefs.ide.source === \"project\" ? \"project preferences\" : \"global config\";\n p.log.info(` IDE Platforms: ${resolvedIdePlatforms.join(\", \")} (from ${ideSourceLabel})`);\n }\n }\n } else {\n if (aiTools.length === 0 && idePlatforms.length === 0) {\n p.log.info(\" No tools configured. Run: baton ai-tools scan && baton ides scan\");\n } else {\n if (aiTools.length > 0) {\n const toolNames = aiTools.map((key) => {\n try {\n return getAIToolConfig(key).name;\n } catch {\n return key;\n }\n });\n p.log.info(` AI Tools: ${toolNames.join(\", \")} (from global config)`);\n }\n if (idePlatforms.length > 0) {\n p.log.info(` IDE Platforms: ${idePlatforms.join(\", \")} (from global config)`);\n }\n }\n }\n\n // --- Current Project ---\n console.log(\"\");\n p.log.step(\"Current Project\");\n if (!projectManifest) {\n p.log.info(\" Not inside a Baton project. Run: baton init\");\n } else if (projectManifest.profiles.length === 0) {\n p.log.info(\" No profiles installed. Run: baton manage\");\n } else {\n for (const profile of projectManifest.profiles) {\n const version = profile.version ? ` (${profile.version})` : \"\";\n p.log.info(` ${profile.source}${version}`);\n }\n }\n\n // --- Active Intersections ---\n if (projectManifest && projectManifest.profiles.length > 0) {\n const hasDeveloperTools = aiTools.length > 0 || idePlatforms.length > 0;\n\n if (hasDeveloperTools) {\n const developerTools = { aiTools, idePlatforms };\n console.log(\"\");\n p.log.step(\"Active Intersections\");\n\n for (const profile of projectManifest.profiles) {\n try {\n const intersection = await buildIntersection(\n profile.source,\n developerTools,\n process.cwd(),\n );\n if (intersection) {\n const summary = formatIntersectionSummary(intersection);\n p.log.info(` ${profile.source}: ${summary}`);\n }\n } catch {\n // Best-effort — skip if intersection cannot be computed\n }\n }\n }\n }\n\n console.log(\"\");\n p.outro(\"Manage tools: 'baton ai-tools configure' | 'baton ides configure'\");\n}\n\nasync function loadProjectManifestSafe(): Promise<ProjectManifest | null> {\n try {\n return await loadProjectManifest(join(process.cwd(), \"baton.yaml\"));\n } catch {\n return null;\n }\n}\n\nexport const configCommand = defineCommand({\n meta: {\n name: \"config\",\n description: \"Show Baton dashboard overview or configure settings\",\n },\n subCommands: {\n set: configSetCommand,\n },\n async run() {\n await showDashboard();\n },\n});\n","import { readFile, readdir, stat } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport {\n type MemoryEntry,\n type MergedSkillItem,\n type RuleEntry,\n type RuleFile,\n cloneGitSource,\n detectInstalledAITools,\n getAIToolAdaptersForKeys,\n getGlobalAiTools,\n getGlobalIdePlatforms,\n getIdePlatformTargetDir,\n loadProfileManifest,\n loadProjectManifest,\n mergeContentParts,\n mergeMemory,\n mergeRules,\n mergeSkills,\n parseFrontmatter,\n parseSource,\n resolveProfileChain,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { buildIntersection } from \"../utils/build-intersection.js\";\n\ninterface DiffEntry {\n /** Relative display path (e.g. \".claude/rules/coding-standards.md\") */\n file: string;\n status: \"added\" | \"modified\" | \"removed\";\n remoteContent?: string;\n localContent?: string;\n}\n\nexport const diffCommand = defineCommand({\n meta: {\n name: \"diff\",\n description: \"Compare local installed files with remote source versions to see what changed\",\n },\n args: {\n nameOnly: {\n type: \"boolean\",\n description: \"Show only changed filenames without content diff\",\n alias: \"n\",\n },\n },\n async run({ args }) {\n p.intro(\"🔍 Baton Diff\");\n\n try {\n const projectRoot = process.cwd();\n const manifestPath = resolve(projectRoot, \"baton.yaml\");\n const manifest = await loadProjectManifest(manifestPath);\n\n if (!manifest.profiles || manifest.profiles.length === 0) {\n p.outro(\"⚠️ No profiles configured in baton.yaml\");\n process.exit(0);\n }\n\n // Step 1: Resolve profile chains (same as sync.ts)\n const spinner = p.spinner();\n spinner.start(\"Resolving profile chain...\");\n\n const allProfiles = [];\n const profileLocalPaths = new Map<string, string>();\n\n for (const profileSource of manifest.profiles) {\n try {\n const parsed = parseSource(profileSource.source);\n\n let profileManifestPath: string;\n let localPath: string;\n\n if (parsed.provider === \"local\" || parsed.provider === \"file\") {\n localPath = parsed.path.startsWith(\"/\")\n ? parsed.path\n : resolve(projectRoot, parsed.path);\n profileManifestPath = resolve(localPath, \"baton.profile.yaml\");\n } else if (parsed.provider === \"npm\") {\n spinner.message(\"NPM provider not yet supported for diff\");\n continue;\n } else {\n const url = parsed.url;\n const subpath =\n parsed.provider === \"github\" || parsed.provider === \"gitlab\"\n ? parsed.subpath\n : undefined;\n const cloned = await cloneGitSource({\n url,\n ref: profileSource.version || undefined,\n subpath,\n useCache: false, // Always fetch fresh for diff\n });\n localPath = cloned.localPath;\n profileManifestPath = resolve(cloned.localPath, \"baton.profile.yaml\");\n }\n\n const profileManifest = await loadProfileManifest(profileManifestPath);\n const profileDir = dirname(profileManifestPath);\n const chain = await resolveProfileChain(\n profileManifest,\n profileSource.source,\n profileDir,\n );\n\n for (const prof of chain) {\n profileLocalPaths.set(prof.name, localPath);\n }\n allProfiles.push(...chain);\n } catch (error) {\n spinner.message(\n `Failed to resolve profile ${profileSource.source}: ${error instanceof Error ? error.message : error}`,\n );\n }\n }\n\n if (allProfiles.length === 0) {\n spinner.stop(\"No profiles resolved\");\n p.outro(\"Nothing to diff. Run `baton manage` to add a profile.\");\n process.exit(0);\n }\n\n spinner.stop(`Resolved ${allProfiles.length} profile(s)`);\n\n // Step 2: Merge configurations (same as sync.ts)\n spinner.start(\"Merging configurations...\");\n\n const mergedSkills: MergedSkillItem[] = mergeSkills(allProfiles);\n const mergedRules: RuleEntry[] = mergeRules(allProfiles);\n const mergedMemory: MemoryEntry[] = mergeMemory(allProfiles);\n\n // Collect commands\n const commandMap = new Map<string, string>();\n for (const profile of allProfiles) {\n for (const cmd of profile.manifest.ai?.commands || []) {\n commandMap.set(cmd, profile.name);\n }\n }\n\n // Collect files\n const fileMap = new Map<string, { source: string; target: string; profileName: string }>();\n for (const profile of allProfiles) {\n for (const fileConfig of profile.manifest.files || []) {\n const target = fileConfig.target || fileConfig.source;\n fileMap.set(target, { source: fileConfig.source, target, profileName: profile.name });\n }\n }\n\n // Collect IDE configs (uses central IDE platform registry)\n const ideMap = new Map<\n string,\n { ideKey: string; fileName: string; targetDir: string; profileName: string }\n >();\n for (const profile of allProfiles) {\n if (!profile.manifest.ide) continue;\n for (const [ideKey, files] of Object.entries(profile.manifest.ide)) {\n if (!files) continue;\n const targetDir = getIdePlatformTargetDir(ideKey);\n if (!targetDir) continue;\n for (const fileName of files) {\n const targetPath = `${targetDir}/${fileName}`;\n ideMap.set(targetPath, { ideKey, fileName, targetDir, profileName: profile.name });\n }\n }\n }\n\n spinner.stop(\"Configurations merged\");\n\n // Step 3: Determine which AI tools to diff (intersection-based, like sync.ts)\n spinner.start(\"Computing tool intersection...\");\n\n const globalAiTools = await getGlobalAiTools();\n const detectedAITools = await detectInstalledAITools();\n\n let syncedAiTools: string[];\n if (globalAiTools.length > 0) {\n const developerTools = {\n aiTools: globalAiTools,\n idePlatforms: await getGlobalIdePlatforms(),\n };\n const aggregatedSyncedAi = new Set<string>();\n for (const profileSource of manifest.profiles) {\n try {\n const intersection = await buildIntersection(\n profileSource.source,\n developerTools,\n projectRoot,\n );\n if (intersection) {\n for (const tool of intersection.aiTools.synced) aggregatedSyncedAi.add(tool);\n }\n } catch {\n /* skip */\n }\n }\n syncedAiTools = aggregatedSyncedAi.size > 0 ? [...aggregatedSyncedAi] : [];\n } else {\n syncedAiTools = detectedAITools;\n }\n\n if (syncedAiTools.length === 0) {\n spinner.stop(\"No AI tools in intersection\");\n p.cancel(\"No AI tools match. Run `baton ai-tools scan`.\");\n process.exit(1);\n }\n\n const adapters = getAIToolAdaptersForKeys(syncedAiTools);\n spinner.stop(`Comparing for: ${syncedAiTools.join(\", \")}`);\n\n // Step 4: Build expected file map (remote content → placed path)\n spinner.start(\"Comparing remote sources with placed files...\");\n\n const diffs: DiffEntry[] = [];\n // Track all expected placed paths to detect \"removed\" files\n const expectedPaths = new Set<string>();\n\n // Content accumulator for files that may receive content from multiple categories\n // (e.g., GitHub Copilot uses .github/copilot-instructions.md for both memory AND rules)\n // Key: relativePath, Value: { parts }\n const contentAccumulator = new Map<string, { parts: string[]; absolutePath: string }>();\n\n // --- Memory files (accumulate) ---\n for (const adapter of adapters) {\n for (const memoryEntry of mergedMemory) {\n const contentParts: string[] = [];\n for (const contribution of memoryEntry.contributions) {\n const profileDir = profileLocalPaths.get(contribution.profileName);\n if (!profileDir) continue;\n const memoryFilePath = resolve(profileDir, \"ai\", \"memory\", memoryEntry.filename);\n try {\n contentParts.push(await readFile(memoryFilePath, \"utf-8\"));\n } catch {\n // skip missing\n }\n }\n if (contentParts.length === 0) continue;\n\n const mergedContent = mergeContentParts(contentParts, memoryEntry.mergeStrategy);\n\n const transformed = adapter.transformMemory({\n filename: memoryEntry.filename,\n content: mergedContent,\n });\n const targetPath = adapter.getPath(\"memory\", \"project\", transformed.filename);\n const absolutePath = resolveAbsolutePath(targetPath, projectRoot);\n const relativePath = toRelativePath(absolutePath, projectRoot);\n expectedPaths.add(relativePath);\n\n // Accumulate instead of directly adding diff entry\n const existing = contentAccumulator.get(relativePath);\n if (existing) {\n existing.parts.push(transformed.content);\n } else {\n contentAccumulator.set(relativePath, {\n parts: [transformed.content],\n absolutePath,\n });\n }\n }\n }\n\n // --- Skills ---\n for (const adapter of adapters) {\n for (const skillItem of mergedSkills) {\n const profileDir = profileLocalPaths.get(skillItem.profileName);\n if (!profileDir) continue;\n const skillSourceDir = resolve(profileDir, \"ai\", \"skills\", skillItem.name);\n try {\n await stat(skillSourceDir);\n } catch {\n continue;\n }\n const targetSkillPath = adapter.getPath(\"skills\", skillItem.scope, skillItem.name);\n const absoluteTargetDir = resolveAbsolutePath(targetSkillPath, projectRoot);\n\n // Compare all files in skill directory\n const remoteSkillFiles = await loadFilesFromDirectory(skillSourceDir);\n const localSkillFiles = await loadFilesFromDirectory(absoluteTargetDir);\n\n for (const [file, remoteContent] of Object.entries(remoteSkillFiles)) {\n const relPath = toRelativePath(resolve(absoluteTargetDir, file), projectRoot);\n expectedPaths.add(relPath);\n addDiffEntry(diffs, relPath, remoteContent, localSkillFiles[file] ?? undefined);\n }\n // Check for local-only files (removed in remote)\n for (const file of Object.keys(localSkillFiles)) {\n const relPath = toRelativePath(resolve(absoluteTargetDir, file), projectRoot);\n if (!expectedPaths.has(relPath)) {\n addDiffEntry(diffs, relPath, undefined, localSkillFiles[file]);\n }\n }\n }\n }\n\n // --- Rules (accumulate) ---\n for (const adapter of adapters) {\n for (const ruleEntry of mergedRules) {\n const isUniversal = ruleEntry.agents.length === 0;\n const isForThisAdapter = ruleEntry.agents.includes(adapter.key);\n if (!isUniversal && !isForThisAdapter) continue;\n\n const profileDir = profileLocalPaths.get(ruleEntry.profileName);\n if (!profileDir) continue;\n\n const ruleSubdir = isUniversal ? \"universal\" : ruleEntry.agents[0];\n const ruleSourcePath = resolve(\n profileDir,\n \"ai\",\n \"rules\",\n ruleSubdir,\n `${ruleEntry.name}.md`,\n );\n\n let rawContent: string;\n try {\n rawContent = await readFile(ruleSourcePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const parsed = parseFrontmatter(rawContent);\n const ruleFile: RuleFile = {\n name: ruleEntry.name,\n content: rawContent,\n frontmatter:\n Object.keys(parsed.data).length > 0\n ? (parsed.data as RuleFile[\"frontmatter\"])\n : undefined,\n };\n\n const transformed = adapter.transformRule(ruleFile);\n const targetPath = adapter.getPath(\"rules\", \"project\", ruleEntry.name);\n const absolutePath = resolveAbsolutePath(targetPath, projectRoot);\n const relativePath = toRelativePath(absolutePath, projectRoot);\n expectedPaths.add(relativePath);\n\n // Accumulate instead of directly adding diff entry\n const existing = contentAccumulator.get(relativePath);\n if (existing) {\n existing.parts.push(transformed.content);\n } else {\n contentAccumulator.set(relativePath, {\n parts: [transformed.content],\n absolutePath,\n });\n }\n }\n }\n\n // --- Flush accumulated content (memory + rules combined per target path) ---\n for (const [relativePath, entry] of contentAccumulator) {\n const combinedContent = entry.parts.join(\"\\n\\n\");\n addDiffEntry(diffs, relativePath, combinedContent, await readSafe(entry.absolutePath));\n }\n\n // --- Commands ---\n for (const adapter of adapters) {\n for (const [commandName, profileName] of commandMap) {\n const profileDir = profileLocalPaths.get(profileName);\n if (!profileDir) continue;\n\n const commandSourcePath = resolve(profileDir, \"ai\", \"commands\", `${commandName}.md`);\n let content: string;\n try {\n content = await readFile(commandSourcePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const targetPath = adapter.getPath(\"commands\", \"project\", commandName);\n const absolutePath = resolveAbsolutePath(targetPath, projectRoot);\n const relativePath = toRelativePath(absolutePath, projectRoot);\n expectedPaths.add(relativePath);\n\n addDiffEntry(diffs, relativePath, content, await readSafe(absolutePath));\n }\n }\n\n // --- Files (project root, no adapter) ---\n for (const fileEntry of fileMap.values()) {\n const profileDir = profileLocalPaths.get(fileEntry.profileName);\n if (!profileDir) continue;\n\n const fileSourcePath = resolve(profileDir, \"files\", fileEntry.source);\n let content: string;\n try {\n content = await readFile(fileSourcePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const absolutePath = resolve(projectRoot, fileEntry.target);\n const relativePath = fileEntry.target;\n expectedPaths.add(relativePath);\n\n addDiffEntry(diffs, relativePath, content, await readSafe(absolutePath));\n }\n\n // --- IDE configs (project root, no adapter) ---\n for (const ideEntry of ideMap.values()) {\n const profileDir = profileLocalPaths.get(ideEntry.profileName);\n if (!profileDir) continue;\n\n const ideSourcePath = resolve(profileDir, \"ide\", ideEntry.ideKey, ideEntry.fileName);\n let content: string;\n try {\n content = await readFile(ideSourcePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const absolutePath = resolve(projectRoot, ideEntry.targetDir, ideEntry.fileName);\n const relativePath = `${ideEntry.targetDir}/${ideEntry.fileName}`;\n expectedPaths.add(relativePath);\n\n addDiffEntry(diffs, relativePath, content, await readSafe(absolutePath));\n }\n\n spinner.stop();\n\n // Step 5: Display results\n if (diffs.length === 0) {\n p.log.success(\"No differences found\");\n p.outro(\"✅ Diff complete - all placed files match remote sources\");\n process.exit(0);\n }\n\n p.log.warning(`${diffs.length} file(s) with differences`);\n\n for (const diff of diffs) {\n if (args.nameOnly) {\n const statusSymbol =\n diff.status === \"added\" ? \"+\" : diff.status === \"removed\" ? \"-\" : \"~\";\n console.log(` ${statusSymbol} ${diff.file}`);\n } else {\n console.log(`\\n 📄 ${diff.file} (${diff.status})`);\n\n if (diff.status === \"modified\") {\n const localLines = (diff.localContent || \"\").split(\"\\n\");\n const remoteLines = (diff.remoteContent || \"\").split(\"\\n\");\n\n const maxLines = Math.max(localLines.length, remoteLines.length);\n let diffLines = 0;\n for (let i = 0; i < maxLines && diffLines < 10; i++) {\n const localLine = localLines[i] || \"\";\n const remoteLine = remoteLines[i] || \"\";\n\n if (localLine !== remoteLine) {\n diffLines++;\n if (localLine) {\n console.log(` \\x1b[31m- ${localLine}\\x1b[0m`);\n }\n if (remoteLine) {\n console.log(` \\x1b[32m+ ${remoteLine}\\x1b[0m`);\n }\n }\n }\n\n if (diffLines >= 10) {\n console.log(\" ... (more differences)\");\n }\n } else if (diff.status === \"added\") {\n console.log(\" \\x1b[32m+ New file in remote (not yet placed locally)\\x1b[0m\");\n } else {\n console.log(\" \\x1b[31m- File exists locally but not in remote\\x1b[0m\");\n }\n }\n }\n\n p.outro(\"✅ Diff complete - differences found. Run `baton sync` to update.\");\n process.exit(1);\n } catch (error) {\n p.log.error(\n `Failed to run diff: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n process.exit(1);\n }\n },\n});\n\n/**\n * Add a diff entry if remote and local content differ.\n */\nfunction addDiffEntry(\n diffs: DiffEntry[],\n file: string,\n remoteContent: string | undefined,\n localContent: string | undefined,\n): void {\n // Deduplicate: skip if this file already has a diff entry\n if (diffs.some((d) => d.file === file)) return;\n\n if (remoteContent !== undefined && localContent === undefined) {\n diffs.push({ file, status: \"added\", remoteContent });\n } else if (remoteContent === undefined && localContent !== undefined) {\n diffs.push({ file, status: \"removed\", localContent });\n } else if (\n remoteContent !== undefined &&\n localContent !== undefined &&\n remoteContent !== localContent\n ) {\n diffs.push({ file, status: \"modified\", remoteContent, localContent });\n }\n}\n\n/**\n * Read a file safely, returning undefined if it doesn't exist.\n */\nasync function readSafe(path: string): Promise<string | undefined> {\n try {\n return await readFile(path, \"utf-8\");\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolve a path to absolute, handling both absolute and relative paths.\n */\nfunction resolveAbsolutePath(path: string, projectRoot: string): string {\n if (path.startsWith(\"/\")) return path;\n return resolve(projectRoot, path);\n}\n\n/**\n * Convert an absolute path to a relative path from project root.\n */\nfunction toRelativePath(absolutePath: string, projectRoot: string): string {\n if (absolutePath.startsWith(projectRoot)) {\n const rel = absolutePath.slice(projectRoot.length);\n return rel.startsWith(\"/\") ? rel.slice(1) : rel;\n }\n return absolutePath;\n}\n\n/**\n * Load all files from a directory recursively\n */\nasync function loadFilesFromDirectory(dirPath: string): Promise<Record<string, string>> {\n const files: Record<string, string> = {};\n\n try {\n const entries = await readdir(dirPath, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = resolve(dirPath, entry.name);\n\n if (entry.isDirectory()) {\n const subFiles = await loadFilesFromDirectory(fullPath);\n for (const [subPath, content] of Object.entries(subFiles)) {\n files[`${entry.name}/${subPath}`] = content;\n }\n } else if (entry.isFile()) {\n const content = await readFile(fullPath, \"utf-8\");\n files[entry.name] = content;\n }\n }\n } catch {\n return {};\n }\n\n return files;\n}\n","/**\n * Format an IDE platform key into a display name.\n */\nexport function formatIdeName(ideKey: string): string {\n const names: Record<string, string> = {\n vscode: \"VS Code\",\n jetbrains: \"JetBrains\",\n cursor: \"Cursor\",\n windsurf: \"Windsurf\",\n antigravity: \"Antigravity\",\n zed: \"Zed\",\n };\n return names[ideKey] ?? ideKey;\n}\n","import { stat } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport {\n getGlobalIdePlatforms,\n getRegisteredIdePlatforms,\n readProjectPreferences,\n setGlobalIdePlatforms,\n writeProjectPreferences,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { formatIdeName } from \"./utils.js\";\n\nexport const idesConfigureCommand = defineCommand({\n meta: {\n name: \"configure\",\n description: \"Manually configure which IDE platforms Baton manages\",\n },\n args: {\n yes: {\n type: \"boolean\",\n alias: \"y\",\n description:\n \"Keep current selection unchanged (no-op), or with --project write useGlobal: true\",\n },\n project: {\n type: \"boolean\",\n description: \"Configure IDE platforms for this project instead of globally\",\n },\n },\n async run({ args }) {\n if (args.project) {\n await runProjectMode(args.yes ?? false);\n } else {\n await runGlobalMode(args.yes ?? false);\n }\n },\n});\n\nasync function runGlobalMode(nonInteractive: boolean): Promise<void> {\n p.intro(\"Baton - Configure IDE Platforms\");\n\n const currentPlatforms = await getGlobalIdePlatforms();\n\n // --yes flag is a no-op (keeps current selection unchanged)\n if (nonInteractive) {\n if (currentPlatforms.length > 0) {\n p.log.info(`Current IDE platforms: ${currentPlatforms.join(\", \")}`);\n } else {\n p.log.info(\"No IDE platforms currently configured.\");\n }\n p.outro(\"No changes made.\");\n return;\n }\n\n const allIdeKeys = getRegisteredIdePlatforms();\n\n const options = allIdeKeys.map((ideKey) => {\n const isSaved = currentPlatforms.includes(ideKey);\n return {\n value: ideKey,\n label: isSaved ? `${formatIdeName(ideKey)} (currently saved)` : formatIdeName(ideKey),\n };\n });\n\n const selected = await p.multiselect({\n message: \"Select which IDE platforms to save:\",\n options,\n initialValues: currentPlatforms,\n });\n\n if (p.isCancel(selected)) {\n p.outro(\"No changes made.\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n const hasChanges =\n selectedKeys.length !== currentPlatforms.length ||\n selectedKeys.some((key) => !currentPlatforms.includes(key));\n\n if (hasChanges) {\n await setGlobalIdePlatforms(selectedKeys);\n p.log.success(`Saved ${selectedKeys.length} platform(s) to global config.`);\n } else {\n p.log.info(\"No changes made.\");\n }\n\n p.outro(\"Configuration complete.\");\n}\n\nasync function runProjectMode(nonInteractive: boolean): Promise<void> {\n p.intro(\"Baton - Configure IDE Platforms (Project)\");\n\n const projectRoot = process.cwd();\n const manifestPath = resolve(projectRoot, \"baton.yaml\");\n\n // Check that baton.yaml exists\n try {\n await stat(manifestPath);\n } catch {\n p.cancel(\"No baton.yaml found in current directory. Run `baton init` first.\");\n process.exit(1);\n }\n\n // --yes with --project writes useGlobal: true\n if (nonInteractive) {\n const existing = await readProjectPreferences(projectRoot);\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: existing?.ai ?? { useGlobal: true, tools: [] },\n ide: { useGlobal: true, platforms: existing?.ide.platforms ?? [] },\n });\n p.log.info(\"Set IDE platforms to use global config for this project.\");\n p.outro(\"Configuration complete.\");\n return;\n }\n\n const existing = await readProjectPreferences(projectRoot);\n const globalPlatforms = await getGlobalIdePlatforms();\n\n // Show current state\n if (globalPlatforms.length > 0) {\n p.log.info(`Global IDE platforms: ${globalPlatforms.join(\", \")}`);\n }\n\n // Ask useGlobal first\n const mode = await p.select({\n message: \"How should this project resolve IDE platforms?\",\n options: [\n {\n value: \"global\",\n label: \"Use global config\",\n hint: \"always follows your global IDE platforms setting\",\n },\n {\n value: \"project\",\n label: \"Customize for this project\",\n hint: \"choose specific IDEs for this project\",\n },\n ],\n initialValue: existing?.ide.useGlobal === false ? \"project\" : \"global\",\n });\n\n if (p.isCancel(mode)) {\n p.outro(\"No changes made.\");\n return;\n }\n\n if (mode === \"global\") {\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: existing?.ai ?? { useGlobal: true, tools: [] },\n ide: { useGlobal: true, platforms: [] },\n });\n p.log.success(\"Project configured to use global IDE platforms.\");\n p.outro(\"Configuration complete.\");\n return;\n }\n\n // Customize: show multiselect\n const allIdeKeys = getRegisteredIdePlatforms();\n const currentProjectPlatforms =\n existing?.ide.useGlobal === false ? existing.ide.platforms : globalPlatforms;\n\n const options = allIdeKeys.map((ideKey) => {\n const isGlobal = globalPlatforms.includes(ideKey);\n return {\n value: ideKey,\n label: isGlobal ? `${formatIdeName(ideKey)} (in global config)` : formatIdeName(ideKey),\n };\n });\n\n const selected = await p.multiselect({\n message: \"Select IDE platforms for this project:\",\n options,\n initialValues: currentProjectPlatforms,\n });\n\n if (p.isCancel(selected)) {\n p.outro(\"No changes made.\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: existing?.ai ?? { useGlobal: true, tools: [] },\n ide: { useGlobal: false, platforms: selectedKeys },\n });\n p.log.success(`Project configured with ${selectedKeys.length} IDE platform(s).`);\n p.outro(\"Configuration complete.\");\n}\n","import {\n getGlobalIdePlatforms,\n getRegisteredIdePlatforms,\n idePlatformRegistry,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { formatIdeName } from \"./utils.js\";\n\nexport const idesListCommand = defineCommand({\n meta: {\n name: \"list\",\n description: \"Show saved IDE platforms from global config\",\n },\n args: {\n all: {\n type: \"boolean\",\n alias: \"a\",\n description: \"Show all supported platforms, not just saved ones\",\n },\n json: {\n type: \"boolean\",\n description: \"Output machine-readable JSON\",\n alias: \"j\",\n },\n },\n async run({ args }) {\n if (!args.json) {\n p.intro(\"Baton - IDE Platforms\");\n }\n\n // Load saved platforms from global config\n const savedPlatforms = await getGlobalIdePlatforms();\n const allIdeKeys = getRegisteredIdePlatforms();\n\n // Determine which platforms to show\n const keysToShow = args.all\n ? allIdeKeys\n : savedPlatforms.length > 0\n ? savedPlatforms\n : allIdeKeys;\n\n const platformStatuses = keysToShow.map((ideKey) => {\n const isSaved = savedPlatforms.includes(ideKey);\n const entry = idePlatformRegistry[ideKey];\n\n return {\n key: ideKey,\n name: formatIdeName(ideKey),\n saved: isSaved,\n targetDir: entry?.targetDir ?? \"unknown\",\n };\n });\n\n // JSON output\n if (args.json) {\n console.log(JSON.stringify(platformStatuses, null, 2));\n return;\n }\n\n // Formatted output\n if (savedPlatforms.length === 0) {\n p.log.warn(\"No IDE platforms saved in global config.\");\n p.log.info(\"Run 'baton ides scan' to detect and save your IDE platforms.\");\n console.log(\"\");\n p.log.info(`All ${allIdeKeys.length} supported platforms:`);\n for (const key of allIdeKeys) {\n const entry = idePlatformRegistry[key];\n console.log(` \\x1b[90m- ${formatIdeName(key)} (${entry?.targetDir ?? key})\\x1b[0m`);\n }\n p.outro(\"Run 'baton ides scan' to get started.\");\n return;\n }\n\n console.log(`\\nSaved IDE platforms (${savedPlatforms.length}):\\n`);\n\n for (const platform of platformStatuses) {\n const statusColor = platform.saved ? \"\\x1b[32m\" : \"\\x1b[90m\";\n const status = platform.saved ? \"✓\" : \"✗\";\n const resetColor = \"\\x1b[0m\";\n\n console.log(\n `${statusColor}${status}${resetColor} ${platform.name.padEnd(20)} → ${platform.targetDir}`,\n );\n }\n\n console.log(\"\");\n p.outro(\"Manage platforms: 'baton ides scan' (detect)\");\n },\n});\n","import {\n clearIdeCache,\n detectInstalledIdes,\n getGlobalIdePlatforms,\n getRegisteredIdePlatforms,\n setGlobalIdePlatforms,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { formatIdeName } from \"./utils.js\";\n\nexport const idesScanCommand = defineCommand({\n meta: {\n name: \"scan\",\n description: \"Scan your system for IDE platforms and save results to global config\",\n },\n args: {\n yes: {\n type: \"boolean\",\n alias: \"y\",\n description: \"Automatically save detected platforms without confirmation\",\n },\n },\n async run({ args }) {\n p.intro(\"Baton - IDE Platform Scanner\");\n\n const spinner = p.spinner();\n spinner.start(\"Scanning for IDE platforms...\");\n\n // Clear cache to force fresh detection\n clearIdeCache();\n\n const detectedIdes = await detectInstalledIdes();\n const allIdeKeys = getRegisteredIdePlatforms();\n const currentPlatforms = await getGlobalIdePlatforms();\n\n spinner.stop(\"Scan complete.\");\n\n if (detectedIdes.length > 0) {\n p.log.success(\n `Found ${detectedIdes.length} IDE platform${detectedIdes.length !== 1 ? \"s\" : \"\"} on your system.`,\n );\n } else {\n p.log.warn(\"No IDE platforms detected on your system.\");\n }\n\n // --yes flag: save only detected platforms (preserves current behavior)\n if (args.yes) {\n const hasChanges =\n detectedIdes.length !== currentPlatforms.length ||\n detectedIdes.some((key) => !currentPlatforms.includes(key));\n\n if (hasChanges) {\n await setGlobalIdePlatforms(detectedIdes);\n p.log.success(`Saved ${detectedIdes.length} detected platform(s) to global config.`);\n } else {\n p.log.info(\"Global config is already up to date.\");\n }\n\n p.outro(\"Scan finished.\");\n return;\n }\n\n // Interactive: show multiselect with all 6 IDE platforms\n const options = allIdeKeys.map((ideKey) => {\n const isDetected = detectedIdes.includes(ideKey);\n return {\n value: ideKey,\n label: isDetected ? `${formatIdeName(ideKey)} (detected)` : formatIdeName(ideKey),\n };\n });\n\n const selected = await p.multiselect({\n message: \"Select which IDE platforms to save:\",\n options,\n initialValues: detectedIdes,\n });\n\n if (p.isCancel(selected)) {\n p.outro(\"Scan finished (not saved).\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n const hasChanges =\n selectedKeys.length !== currentPlatforms.length ||\n selectedKeys.some((key) => !currentPlatforms.includes(key));\n\n if (hasChanges) {\n await setGlobalIdePlatforms(selectedKeys);\n p.log.success(`Saved ${selectedKeys.length} platform(s) to global config.`);\n } else {\n p.log.info(\"Global config is already up to date.\");\n }\n\n p.outro(\"Scan finished.\");\n },\n});\n","import { defineCommand } from \"citty\";\nimport { idesConfigureCommand } from \"./configure.js\";\nimport { idesListCommand } from \"./list.js\";\nimport { idesScanCommand } from \"./scan.js\";\n\nexport const idesCommand = defineCommand({\n meta: {\n name: \"ides\",\n description: \"Manage IDE platform detection and configuration\",\n },\n subCommands: {\n configure: idesConfigureCommand,\n list: idesListCommand,\n scan: idesScanCommand,\n },\n});\n","import { resolve } from \"node:path\";\nimport { cloneGitSource, discoverProfilesInSourceRepo, parseSource } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\n\n/**\n * Discovers and prompts user to select a profile from a source.\n * Used by `baton init --profile` and `baton manage` (add profile).\n *\n * @param sourceString - Source string to discover profiles from (e.g., \"github:org/repo\")\n * @returns Final source string with selected profile path (e.g., \"github:org/repo/frontend\")\n */\nexport async function selectProfileFromSource(sourceString: string): Promise<string> {\n const parsedSource = parseSource(sourceString);\n\n // Only GitHub/GitLab sources without subpath require interactive selection\n if (\n (parsedSource.provider === \"github\" || parsedSource.provider === \"gitlab\") &&\n !parsedSource.subpath\n ) {\n const spinner = p.spinner();\n spinner.start(\"Cloning repository to discover profiles...\");\n\n try {\n // Clone repo temporarily to discover profiles\n const cloned = await cloneGitSource({\n url: parsedSource.url,\n ref: parsedSource.ref,\n useCache: true,\n });\n\n spinner.stop(\"✅ Repository cloned\");\n\n // Discover all profiles in the source repo\n const profiles = await discoverProfilesInSourceRepo(cloned.localPath);\n\n if (profiles.length === 0) {\n p.cancel(\"❌ No profiles found in the source repository\");\n process.exit(1);\n }\n\n // Show profile selection\n const selectedProfilePath = (await p.select({\n message: \"Select a profile from this source:\",\n options: profiles.map((profile) => ({\n value: profile.path,\n label: profile.name,\n hint: profile.description\n ? `${profile.description} (v${profile.version})`\n : `v${profile.version}`,\n })),\n })) as string;\n\n if (p.isCancel(selectedProfilePath)) {\n p.cancel(\"❌ Profile selection cancelled\");\n process.exit(0);\n }\n\n // Construct final source string with selected profile path\n // Format: github:org/repo[@ref]/profile\n if (selectedProfilePath === \".\") {\n // Root profile - no subpath needed\n return sourceString;\n }\n // Sub-profile - append to source string\n const baseSource = parsedSource.ref\n ? `${parsedSource.provider}:${parsedSource.org}/${parsedSource.repo}@${parsedSource.ref}`\n : `${parsedSource.provider}:${parsedSource.org}/${parsedSource.repo}`;\n return `${baseSource}/${selectedProfilePath}`;\n } catch (error) {\n spinner.stop(\"❌ Failed to clone repository\");\n p.cancel(\n `❌ Failed to discover profiles: ${error instanceof Error ? error.message : String(error)}`,\n );\n process.exit(1);\n }\n }\n\n // Local/file sources: discover profiles from local directory\n if (parsedSource.provider === \"file\" || parsedSource.provider === \"local\") {\n const absolutePath = parsedSource.path.startsWith(\"/\")\n ? parsedSource.path\n : resolve(process.cwd(), parsedSource.path);\n\n const profiles = await discoverProfilesInSourceRepo(absolutePath);\n\n if (profiles.length === 0) {\n // Possibly pointing directly at a single profile\n return sourceString;\n }\n\n if (profiles.length === 1) {\n const profilePath =\n profiles[0].path === \".\" ? sourceString : `${sourceString}/${profiles[0].path}`;\n return profilePath;\n }\n\n // Multiple profiles - show single-select\n const selectedProfilePath = (await p.select({\n message: \"Select a profile from this source:\",\n options: profiles.map((profile) => ({\n value: profile.path,\n label: profile.name,\n hint: profile.description\n ? `${profile.description} (v${profile.version})`\n : `v${profile.version}`,\n })),\n })) as string;\n\n if (p.isCancel(selectedProfilePath)) {\n p.cancel(\"❌ Profile selection cancelled\");\n process.exit(0);\n }\n\n if (selectedProfilePath === \".\") {\n return sourceString;\n }\n return `${sourceString}/${selectedProfilePath}`;\n }\n\n // Direct path provided or non-GitHub/GitLab source - return as-is\n return sourceString;\n}\n\n/**\n * Discovers and prompts user to select multiple profiles from a source.\n * Returns array of full source strings with profile paths.\n *\n * Used by `baton init` to allow installing multiple profiles at once.\n *\n * @param sourceString - Source string to discover profiles from (e.g., \"github:org/repo\")\n * @returns Array of source strings with selected profile paths (e.g., [\"github:org/repo/frontend\", \"github:org/repo/backend\"])\n */\nexport async function selectMultipleProfilesFromSource(\n sourceString: string,\n options?: { nonInteractive?: boolean },\n): Promise<string[]> {\n const parsedSource = parseSource(sourceString);\n\n // Only GitHub/GitLab sources without subpath require interactive selection\n if (\n (parsedSource.provider === \"github\" || parsedSource.provider === \"gitlab\") &&\n !parsedSource.subpath\n ) {\n const spinner = p.spinner();\n spinner.start(\"Cloning repository to discover profiles...\");\n\n try {\n const cloned = await cloneGitSource({\n url: parsedSource.url,\n ref: parsedSource.ref,\n useCache: true,\n });\n\n spinner.stop(\"✅ Repository cloned\");\n\n const profiles = await discoverProfilesInSourceRepo(cloned.localPath);\n\n if (profiles.length === 0) {\n p.cancel(\"❌ No profiles found in the source repository\");\n process.exit(1);\n }\n\n // Single profile - auto-select\n if (profiles.length === 1) {\n p.note(`Using profile: ${profiles[0].name}`, \"Profile\");\n const fullPath = constructProfilePath(parsedSource, profiles[0].path);\n return [fullPath];\n }\n\n // Non-interactive: auto-select all profiles\n if (options?.nonInteractive) {\n p.note(`Auto-selecting all ${profiles.length} profile(s)`, \"Non-interactive mode\");\n return profiles.map((prof) => constructProfilePath(parsedSource, prof.path));\n }\n\n // Multiple profiles - show multi-select\n const selected = (await p.multiselect({\n message: \"Select profile(s) to install: (Space to select, Enter to continue)\",\n options: profiles.map((prof) => ({\n value: prof.path,\n label: prof.name,\n hint: prof.description ? `${prof.description} (v${prof.version})` : `v${prof.version}`,\n })),\n required: true,\n })) as string[];\n\n if (p.isCancel(selected)) {\n p.cancel(\"❌ Profile selection cancelled\");\n process.exit(0);\n }\n\n // Map selected paths to full source strings\n return selected.map((path) => constructProfilePath(parsedSource, path));\n } catch (error) {\n spinner.stop(\"❌ Failed to clone repository\");\n p.cancel(\n `❌ Failed to discover profiles: ${error instanceof Error ? error.message : String(error)}`,\n );\n process.exit(1);\n }\n }\n\n // Local/file sources: discover profiles from local directory\n if (parsedSource.provider === \"file\" || parsedSource.provider === \"local\") {\n const absolutePath = parsedSource.path.startsWith(\"/\")\n ? parsedSource.path\n : resolve(process.cwd(), parsedSource.path);\n\n const profiles = await discoverProfilesInSourceRepo(absolutePath);\n\n if (profiles.length === 0) {\n // Possibly pointing directly at a single profile\n return [sourceString];\n }\n\n if (profiles.length === 1) {\n p.note(`Using profile: ${profiles[0].name}`, \"Profile\");\n const profilePath =\n profiles[0].path === \".\" ? sourceString : `${sourceString}/${profiles[0].path}`;\n return [profilePath];\n }\n\n // Non-interactive: auto-select all profiles\n if (options?.nonInteractive) {\n p.note(`Auto-selecting all ${profiles.length} profile(s)`, \"Non-interactive mode\");\n return profiles.map((prof) =>\n prof.path === \".\" ? sourceString : `${sourceString}/${prof.path}`,\n );\n }\n\n // Multiple profiles - show multi-select\n const selected = (await p.multiselect({\n message: \"Select profile(s) to install: (Space to select, Enter to continue)\",\n options: profiles.map((prof) => ({\n value: prof.path,\n label: prof.name,\n hint: prof.description ? `${prof.description} (v${prof.version})` : `v${prof.version}`,\n })),\n required: true,\n })) as string[];\n\n if (p.isCancel(selected)) {\n p.cancel(\"❌ Profile selection cancelled\");\n process.exit(0);\n }\n\n return selected.map((path) => (path === \".\" ? sourceString : `${sourceString}/${path}`));\n }\n\n // Direct path provided - return as-is (single profile)\n return [sourceString];\n}\n\n/**\n * Helper: Constructs full source path with profile subpath.\n *\n * @param parsed - Parsed source object (github or gitlab only)\n * @param profilePath - Profile path (e.g., \".\", \"frontend\", \"backend\")\n * @returns Full source string (e.g., \"github:org/repo/frontend\")\n */\nfunction constructProfilePath(\n parsed: Extract<ReturnType<typeof parseSource>, { provider: \"github\" | \"gitlab\" }>,\n profilePath: string,\n): string {\n // Root profile\n if (profilePath === \".\") {\n const baseSource = parsed.ref\n ? `${parsed.provider}:${parsed.org}/${parsed.repo}@${parsed.ref}`\n : `${parsed.provider}:${parsed.org}/${parsed.repo}`;\n return baseSource;\n }\n\n // Sub-profile: github:org/repo[@ref]/profilePath\n const baseSource = parsed.ref\n ? `${parsed.provider}:${parsed.org}/${parsed.repo}@${parsed.ref}`\n : `${parsed.provider}:${parsed.org}/${parsed.repo}`;\n\n return `${baseSource}/${profilePath}`;\n}\n","import * as p from \"@clack/prompts\";\n\n/**\n * Run `baton sync` as a child process, inheriting stdio for interactive output.\n */\nexport async function runBatonSync(cwd: string): Promise<void> {\n const { spawn } = await import(\"node:child_process\");\n await new Promise<void>((done) => {\n const syncProcess = spawn(\"baton\", [\"sync\"], { cwd, stdio: \"inherit\" });\n syncProcess.on(\"close\", (code) => {\n if (code === 0) {\n p.log.success(\"Profiles synced successfully!\");\n } else {\n p.log.warn(`Sync finished with exit code ${code}`);\n }\n done();\n });\n syncProcess.on(\"error\", (error) => {\n p.log.warn(`Failed to run sync: ${error.message}`);\n done();\n });\n });\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport type { ProjectManifest, SourceManifest } from \"@baton-dx/core\";\nimport {\n clearAIToolCache,\n clearIdeCache,\n cloneGitSource,\n collectComprehensivePatterns,\n computeIntersection,\n detectInstalledAITools,\n detectInstalledIdes,\n findSourceManifest,\n getDefaultGlobalSource,\n getGlobalAiTools,\n getGlobalIdePlatforms,\n getGlobalSources,\n loadProfileManifest,\n parseSource,\n resolveProfileSupport,\n setGlobalAiTools,\n setGlobalIdePlatforms,\n updateGitignore,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { stringify } from \"yaml\";\nimport { findSourceRoot } from \"../utils/context-detection.js\";\nimport { promptFirstRunPreferences } from \"../utils/first-run-preferences.js\";\nimport { displayIntersection } from \"../utils/intersection-display.js\";\nimport { selectMultipleProfilesFromSource } from \"../utils/profile-selection.js\";\nimport { runBatonSync } from \"../utils/run-baton-sync.js\";\n\nexport const initCommand = defineCommand({\n meta: {\n name: \"init\",\n description: \"Initialize Baton in your project with an interactive setup wizard\",\n },\n args: {\n yes: {\n type: \"boolean\",\n alias: \"y\",\n description: \"Skip all prompts and use defaults\",\n },\n force: {\n type: \"boolean\",\n description: \"Overwrite existing baton.yaml\",\n },\n profile: {\n type: \"string\",\n description: \"Profile source to install (skips profile selection)\",\n },\n },\n async run({ args }) {\n const isInteractive = !args.yes;\n const cwd = process.cwd();\n\n p.intro(\"🎯 Welcome to Baton\");\n\n // 1. Check if baton.yaml already exists\n try {\n await readFile(join(cwd, \"baton.yaml\"));\n if (!args.force) {\n p.cancel(\"baton.yaml already exists in this directory.\");\n p.note(\n \"Use `baton manage` to modify your project configuration\\nor `baton sync` to sync your profiles.\\n\\nTo reinitialize, use `baton init --force`.\",\n \"Already initialized\",\n );\n process.exit(1);\n }\n p.log.warn(\"Overwriting existing baton.yaml (--force)\");\n } catch (_error) {\n // File doesn't exist, continue\n }\n\n // 2. Auto-scan AI tools and IDEs if not yet configured\n const spinner = p.spinner();\n await autoScanAiTools(spinner, isInteractive);\n await autoScanIdePlatforms(spinner, isInteractive);\n\n // 3. Determine source URL(s) with global sources integration\n let profileSources: string[];\n\n if (args.profile) {\n // Explicit --profile flag: use it (may trigger multi-select)\n profileSources = await selectMultipleProfilesFromSource(args.profile, {\n nonInteractive: !isInteractive,\n });\n } else {\n // No --profile flag: check global sources\n const globalSources = await getGlobalSources();\n\n if (globalSources.length === 0) {\n // No global sources: abort with guidance\n p.cancel(\"No sources configured.\");\n p.note(\n \"Connect a source repository first:\\n\\n baton source connect <url>\\n\\nExample:\\n baton source connect github:my-org/dx-config\",\n \"No sources found\",\n );\n process.exit(1);\n } else if (globalSources.length === 1 && globalSources[0].default) {\n // Single default source: auto-use it\n const defaultSource = globalSources[0];\n p.note(`Using default source: ${defaultSource.name}\\n${defaultSource.url}`, \"Source\");\n profileSources = await selectMultipleProfilesFromSource(defaultSource.url, {\n nonInteractive: !isInteractive,\n });\n } else {\n // Multiple sources: show source selection\n if (!isInteractive) {\n // Non-interactive: use default source if available, otherwise first source\n const defaultSource = await getDefaultGlobalSource();\n const sourceUrl = defaultSource?.url || globalSources[0].url;\n profileSources = await selectMultipleProfilesFromSource(sourceUrl, {\n nonInteractive: true,\n });\n } else {\n const defaultSource = await getDefaultGlobalSource();\n\n const selectedUrl = (await p.select({\n message: \"Select a source repository:\",\n options: globalSources.map((s) => ({\n value: s.url,\n label: s.default ? `${s.name} [default]` : s.name,\n hint: s.description || s.url,\n })),\n initialValue: defaultSource?.url,\n })) as string;\n\n if (p.isCancel(selectedUrl)) {\n p.cancel(\"Setup cancelled.\");\n process.exit(0);\n }\n\n profileSources = await selectMultipleProfilesFromSource(selectedUrl);\n }\n }\n }\n\n // 4. Show intersection between developer tools and profile support\n await showProfileIntersections(profileSources);\n\n // 5. Ask whether synced files should be gitignored\n let gitignoreSetting = true; // default for --yes mode\n if (isInteractive) {\n const shouldGitignore = await p.confirm({\n message: \"Add synced AI tool and IDE config files to .gitignore?\",\n initialValue: true,\n });\n\n if (p.isCancel(shouldGitignore)) {\n p.cancel(\"Setup cancelled.\");\n process.exit(0);\n }\n\n gitignoreSetting = shouldGitignore;\n }\n\n // 6. Generate baton.yaml with multiple profiles and gitignore setting\n const manifest: ProjectManifest = {\n profiles: profileSources.map((source) => ({ source })),\n gitignore: gitignoreSetting,\n };\n\n const yamlContent = stringify(manifest);\n\n spinner.start(\"Creating baton.yaml...\");\n await writeFile(join(cwd, \"baton.yaml\"), yamlContent, \"utf-8\");\n spinner.stop(\"✅ Created baton.yaml\");\n\n // 7. Update .gitignore\n spinner.start(\"Updating .gitignore...\");\n const gitignorePath = join(cwd, \".gitignore\");\n let gitignoreContent = \"\";\n\n try {\n gitignoreContent = await readFile(gitignorePath, \"utf-8\");\n } catch (_error) {\n // .gitignore doesn't exist, create new\n }\n\n // Always ensure .baton/ is gitignored\n if (!gitignoreContent.includes(\".baton/\")) {\n const newContent = gitignoreContent\n ? `${gitignoreContent}\\n\\n# Baton local\\n.baton/\\n`\n : \"# Baton local\\n.baton/\\n\";\n await writeFile(gitignorePath, newContent, \"utf-8\");\n }\n\n // If gitignore enabled, write comprehensive patterns for all known tools\n if (gitignoreSetting) {\n const patterns = collectComprehensivePatterns({ fileTargets: [] });\n await updateGitignore(cwd, patterns);\n spinner.stop(\"✅ Updated .gitignore with managed file patterns\");\n } else {\n spinner.stop(\"✅ Added .baton/ to .gitignore\");\n }\n\n // 8. Create .baton directory\n spinner.start(\"Creating .baton directory...\");\n try {\n await mkdir(join(cwd, \".baton\"), { recursive: true });\n spinner.stop(\"✅ Created .baton directory\");\n } catch (_error) {\n spinner.stop(\"✅ .baton directory already exists\");\n }\n\n // 9. First-run preferences prompt\n await promptFirstRunPreferences(cwd, !isInteractive);\n\n // 10. Offer to sync profiles\n if (profileSources.length > 0) {\n const shouldSync = isInteractive\n ? await p.confirm({\n message: \"Fetch profiles and sync now?\",\n initialValue: true,\n })\n : true; // --yes mode: auto-sync\n\n if (!p.isCancel(shouldSync) && shouldSync) {\n await runBatonSync(cwd);\n } else {\n p.log.info(\"Run 'baton sync' later to fetch and apply your profiles.\");\n }\n }\n\n // 11. Summary\n p.outro(\"Baton initialized successfully!\");\n },\n});\n\n/**\n * Auto-scan AI tools if none are configured in global config.\n * In interactive mode: shows results and asks for confirmation.\n * In non-interactive mode (--yes): auto-saves detected tools.\n */\nasync function autoScanAiTools(\n spinner: ReturnType<typeof p.spinner>,\n isInteractive: boolean,\n): Promise<void> {\n const existingTools = await getGlobalAiTools();\n if (existingTools.length > 0) {\n p.log.info(`AI tools already configured: ${existingTools.join(\", \")}`);\n return;\n }\n\n spinner.start(\"Scanning for installed AI tools...\");\n clearAIToolCache();\n const detectedTools = await detectInstalledAITools();\n spinner.stop(\n detectedTools.length > 0\n ? `Found ${detectedTools.length} AI tool${detectedTools.length !== 1 ? \"s\" : \"\"}: ${detectedTools.join(\", \")}`\n : \"No AI tools detected.\",\n );\n\n if (detectedTools.length === 0) {\n p.log.warn(\"No AI tools detected. You can run 'baton ai-tools scan' later.\");\n return;\n }\n\n if (isInteractive) {\n const shouldSave = await p.confirm({\n message: \"Save detected AI tools to global config?\",\n initialValue: true,\n });\n\n if (p.isCancel(shouldSave) || !shouldSave) {\n p.log.info(\"Skipped saving AI tools. Run 'baton ai-tools scan' later.\");\n return;\n }\n }\n\n await setGlobalAiTools(detectedTools);\n p.log.success(\"AI tools saved to global config.\");\n}\n\n/**\n * Auto-scan IDE platforms if none are configured in global config.\n * In interactive mode: shows results and asks for confirmation.\n * In non-interactive mode (--yes): auto-saves detected platforms.\n */\nasync function autoScanIdePlatforms(\n spinner: ReturnType<typeof p.spinner>,\n isInteractive: boolean,\n): Promise<void> {\n const existingPlatforms = await getGlobalIdePlatforms();\n if (existingPlatforms.length > 0) {\n p.log.info(`IDE platforms already configured: ${existingPlatforms.join(\", \")}`);\n return;\n }\n\n spinner.start(\"Scanning for installed IDE platforms...\");\n clearIdeCache();\n const detectedIdes = await detectInstalledIdes();\n spinner.stop(\n detectedIdes.length > 0\n ? `Found ${detectedIdes.length} IDE platform${detectedIdes.length !== 1 ? \"s\" : \"\"}: ${detectedIdes.join(\", \")}`\n : \"No IDE platforms detected.\",\n );\n\n if (detectedIdes.length === 0) {\n p.log.warn(\"No IDE platforms detected. You can run 'baton ides scan' later.\");\n return;\n }\n\n if (isInteractive) {\n const shouldSave = await p.confirm({\n message: \"Save detected IDE platforms to global config?\",\n initialValue: true,\n });\n\n if (p.isCancel(shouldSave) || !shouldSave) {\n p.log.info(\"Skipped saving IDE platforms. Run 'baton ides scan' later.\");\n return;\n }\n }\n\n await setGlobalIdePlatforms(detectedIdes);\n p.log.success(\"IDE platforms saved to global config.\");\n}\n\n/**\n * Load source/profile manifests for each selected profile and display\n * the intersection between developer tools and profile support.\n *\n * Gracefully handles errors (e.g., missing source manifest) — the intersection\n * display is informational and should not block init.\n */\nasync function showProfileIntersections(profileSources: string[]): Promise<void> {\n const aiTools = await getGlobalAiTools();\n const idePlatforms = await getGlobalIdePlatforms();\n\n // No developer tools configured — nothing to intersect\n if (aiTools.length === 0 && idePlatforms.length === 0) {\n return;\n }\n\n const developerTools = { aiTools, idePlatforms };\n\n for (const sourceString of profileSources) {\n try {\n const parsed = parseSource(sourceString);\n\n let repoRoot: string;\n let profileDir: string;\n\n if (parsed.provider === \"github\" || parsed.provider === \"gitlab\") {\n // Clone repo (cache hit) — without subpath to get the repo root\n const repoClone = await cloneGitSource({\n url: parsed.url,\n ref: parsed.ref,\n useCache: true,\n });\n repoRoot = repoClone.localPath;\n profileDir = parsed.subpath ? resolve(repoRoot, parsed.subpath) : repoRoot;\n } else if (parsed.provider === \"local\" || parsed.provider === \"file\") {\n const absolutePath = parsed.path.startsWith(\"/\")\n ? parsed.path\n : resolve(process.cwd(), parsed.path);\n profileDir = absolutePath;\n // Walk up from profile dir to find source root (containing baton.source.yaml)\n repoRoot = (await findSourceRoot(absolutePath, { fallbackToStart: true })) as string;\n } else {\n // git/npm providers — skip intersection display\n continue;\n }\n\n // Load source manifest (optional — source may not have one)\n let sourceManifest: SourceManifest;\n try {\n sourceManifest = await findSourceManifest(repoRoot);\n } catch {\n // No source manifest — use empty defaults\n sourceManifest = { name: \"unknown\", version: \"0.0.0\" } as SourceManifest;\n }\n\n // Load profile manifest\n const profileManifestPath = resolve(profileDir, \"baton.profile.yaml\");\n const profileManifest = await loadProfileManifest(profileManifestPath).catch(() => null);\n if (!profileManifest) continue;\n\n // Compute intersection\n const profileSupport = resolveProfileSupport(profileManifest, sourceManifest);\n const intersection = computeIntersection(developerTools, profileSupport);\n\n // Only display if there's meaningful data\n const hasData =\n intersection.aiTools.synced.length > 0 ||\n intersection.aiTools.unavailable.length > 0 ||\n intersection.idePlatforms.synced.length > 0 ||\n intersection.idePlatforms.unavailable.length > 0;\n\n if (hasData) {\n p.log.step(`Intersection for ${profileManifest.name}`);\n displayIntersection(intersection);\n }\n } catch {\n // Intersection display is best-effort — don't block init\n }\n }\n}\n","import { access, rm, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { ProjectManifest } from \"@baton-dx/core\";\nimport {\n FileNotFoundError,\n getAllAIToolAdapters,\n getDefaultGlobalSource,\n getGlobalAiTools,\n getGlobalIdePlatforms,\n getGlobalSources,\n getRegisteredIdePlatforms,\n loadProjectManifest,\n readLock,\n readProjectPreferences,\n removePlacedFiles,\n writeProjectPreferences,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { stringify } from \"yaml\";\nimport { buildIntersection } from \"../utils/build-intersection.js\";\nimport { displayIntersection, formatIntersectionSummary } from \"../utils/intersection-display.js\";\nimport { selectProfileFromSource } from \"../utils/profile-selection.js\";\nimport { runBatonSync } from \"../utils/run-baton-sync.js\";\n\nasync function loadProjectManifestSafe(cwd: string): Promise<ProjectManifest | null> {\n try {\n return await loadProjectManifest(join(cwd, \"baton.yaml\"));\n } catch {\n return null;\n }\n}\n\nasync function hasLockfile(cwd: string): Promise<boolean> {\n try {\n await access(join(cwd, \"baton.lock\"));\n return true;\n } catch {\n return false;\n }\n}\n\nasync function showOverview(cwd: string): Promise<void> {\n const [manifest, sources, synced] = await Promise.all([\n loadProjectManifestSafe(cwd),\n getGlobalSources(),\n hasLockfile(cwd),\n ]);\n\n if (!manifest) {\n p.log.warn(\"Could not load baton.yaml\");\n return;\n }\n\n // --- Installed Profiles ---\n p.log.step(\"Installed Profiles\");\n if (manifest.profiles.length === 0) {\n p.log.info(\" No profiles installed.\");\n } else {\n for (const profile of manifest.profiles) {\n const version = profile.version ? ` (${profile.version})` : \"\";\n const matchingSource = sources.find(\n (s) => profile.source.includes(s.url) || profile.source.includes(s.name),\n );\n const sourceName = matchingSource ? ` [${matchingSource.name}]` : \"\";\n p.log.info(` ${profile.source}${version}${sourceName}`);\n }\n }\n\n // --- Intersection per Profile ---\n if (manifest.profiles.length > 0) {\n const aiTools = await getGlobalAiTools();\n const idePlatforms = await getGlobalIdePlatforms();\n\n if (aiTools.length > 0 || idePlatforms.length > 0) {\n const developerTools = { aiTools, idePlatforms };\n console.log(\"\");\n p.log.step(\"Tool Intersection\");\n\n for (const profile of manifest.profiles) {\n try {\n const intersection = await buildIntersection(profile.source, developerTools, cwd);\n if (intersection) {\n const summary = formatIntersectionSummary(intersection);\n p.log.info(` ${profile.source}: ${summary}`);\n displayIntersection(intersection);\n }\n } catch {\n // Best-effort — skip if intersection cannot be computed\n }\n }\n }\n }\n\n // --- Sync Status ---\n console.log(\"\");\n p.log.step(\"Sync Status\");\n if (synced) {\n p.log.info(\" Synced (baton.lock exists)\");\n } else {\n p.log.info(\" Not synced — run 'baton sync' to sync profiles\");\n }\n\n // --- Global Sources ---\n console.log(\"\");\n p.log.step(\"Global Sources\");\n if (sources.length === 0) {\n p.log.info(\" No sources configured. Run: baton source connect <url>\");\n } else {\n for (const source of sources) {\n const defaultBadge = source.default ? \" (default)\" : \"\";\n p.log.info(` ${source.name}${defaultBadge}: ${source.url}`);\n }\n }\n}\n\nasync function handleAddProfile(cwd: string): Promise<void> {\n const manifestPath = join(cwd, \"baton.yaml\");\n const manifest = await loadProjectManifestSafe(cwd);\n if (!manifest) {\n p.log.error(\"Could not load baton.yaml\");\n return;\n }\n\n // 1. Get global sources\n const globalSources = await getGlobalSources();\n if (globalSources.length === 0) {\n p.log.warn(\"No global sources configured. Run: baton source connect <url>\");\n return;\n }\n\n // 2. Select a source\n let sourceString: string;\n if (globalSources.length === 1) {\n sourceString = globalSources[0].url;\n p.log.info(`Using source: ${globalSources[0].name} (${sourceString})`);\n } else {\n const defaultSource = await getDefaultGlobalSource();\n const selectedUrl = await p.select({\n message: \"Select a source repository:\",\n options: globalSources.map((s) => ({\n value: s.url,\n label: s.default ? `${s.name} [default]` : s.name,\n hint: s.description || s.url,\n })),\n initialValue: defaultSource?.url,\n });\n\n if (p.isCancel(selectedUrl)) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n sourceString = selectedUrl as string;\n }\n\n // 3. Select a profile from the source\n const selectedSource = await selectProfileFromSource(sourceString);\n\n // 4. Check for duplicates\n const alreadyExists = manifest.profiles.some((pr) => pr.source === selectedSource);\n if (alreadyExists) {\n p.log.warn(`Profile \"${selectedSource}\" is already installed.`);\n return;\n }\n\n // 5. Add to manifest and write\n manifest.profiles.push({ source: selectedSource });\n const updatedYaml = stringify(manifest);\n await writeFile(manifestPath, updatedYaml, \"utf-8\");\n p.log.success(`Added profile: ${selectedSource}`);\n\n // 6. Offer to sync\n const shouldSync = await p.confirm({\n message: \"Sync profiles now?\",\n initialValue: true,\n });\n\n if (p.isCancel(shouldSync) || !shouldSync) {\n p.log.info(\"Run 'baton sync' later to apply the new profile.\");\n return;\n }\n\n await runBatonSync(cwd);\n}\n\nasync function handleRemoveProfile(cwd: string): Promise<void> {\n const manifestPath = join(cwd, \"baton.yaml\");\n const manifest = await loadProjectManifestSafe(cwd);\n if (!manifest) {\n p.log.error(\"Could not load baton.yaml\");\n return;\n }\n\n if (manifest.profiles.length === 0) {\n p.log.warn(\"No profiles installed.\");\n return;\n }\n\n // 1. Select profile to remove\n const selected = await p.select({\n message: \"Which profile do you want to remove?\",\n options: manifest.profiles.map((pr) => ({\n value: pr.source,\n label: pr.source,\n hint: pr.version ? `v${pr.version}` : undefined,\n })),\n });\n\n if (p.isCancel(selected)) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n\n const profileSource = selected as string;\n\n // 2. Confirm removal\n const confirmed = await p.confirm({\n message: `Remove profile \"${profileSource}\"?`,\n initialValue: false,\n });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n\n // 3. Remove from manifest and write\n const profileIndex = manifest.profiles.findIndex((pr) => pr.source === profileSource);\n manifest.profiles.splice(profileIndex, 1);\n\n const updatedYaml = stringify(manifest);\n await writeFile(manifestPath, updatedYaml, \"utf-8\");\n p.log.success(`Removed profile: ${profileSource}`);\n p.log.info(\"Run 'baton sync' to clean up synced files.\");\n}\n\nasync function handleRemoveBaton(cwd: string): Promise<boolean> {\n // 1. Warning\n p.log.warn(\"This will remove Baton from your project:\");\n p.log.info(\" - baton.yaml (project manifest)\");\n p.log.info(\" - baton.lock (lockfile)\");\n\n // 2. Confirm\n const confirmed = await p.confirm({\n message: \"Are you sure you want to remove Baton from this project?\",\n initialValue: false,\n });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.log.warn(\"Cancelled.\");\n return false;\n }\n\n // 3. Offer to clean up placed files from lockfile\n const lockPath = join(cwd, \"baton.lock\");\n await cleanupPlacedFilesFromLock(lockPath, cwd);\n\n // 4. Delete baton.yaml\n const manifestPath = join(cwd, \"baton.yaml\");\n await rm(manifestPath, { force: true });\n\n // 5. Delete baton.lock\n await rm(lockPath, { force: true });\n\n p.log.success(\"Baton has been removed from this project.\");\n return true;\n}\n\nasync function cleanupPlacedFilesFromLock(lockPath: string, projectRoot: string): Promise<void> {\n let placedPaths: string[];\n try {\n const lockfile = await readLock(lockPath);\n placedPaths = Object.values(lockfile.packages).flatMap((pkg) => Object.keys(pkg.integrity));\n } catch (error) {\n if (error instanceof FileNotFoundError) return;\n // Invalid lockfile — skip cleanup silently\n return;\n }\n\n if (placedPaths.length === 0) return;\n\n p.log.info(`Found ${placedPaths.length} placed file(s):`);\n for (const filePath of placedPaths) {\n p.log.info(` ${filePath}`);\n }\n\n const shouldClean = await p.confirm({\n message: `Also remove ${placedPaths.length} placed file(s)?`,\n initialValue: false,\n });\n\n if (p.isCancel(shouldClean) || !shouldClean) return;\n\n const removedCount = await removePlacedFiles(placedPaths, projectRoot);\n p.log.success(`Removed ${removedCount} placed file(s).`);\n}\n\nfunction formatIdeName(ideKey: string): string {\n const names: Record<string, string> = {\n vscode: \"VS Code\",\n jetbrains: \"JetBrains\",\n cursor: \"Cursor\",\n windsurf: \"Windsurf\",\n antigravity: \"Antigravity\",\n zed: \"Zed\",\n };\n return names[ideKey] ?? ideKey;\n}\n\nasync function handleConfigureAiTools(cwd: string): Promise<void> {\n const existing = await readProjectPreferences(cwd);\n const globalTools = await getGlobalAiTools();\n\n if (globalTools.length > 0) {\n p.log.info(`Global AI tools: ${globalTools.join(\", \")}`);\n }\n\n // Ask useGlobal first\n const mode = await p.select({\n message: \"How should this project resolve AI tools?\",\n options: [\n {\n value: \"global\",\n label: \"Use global config\",\n hint: \"always follows your global AI tools setting\",\n },\n {\n value: \"project\",\n label: \"Customize for this project\",\n hint: \"choose specific tools for this project\",\n },\n ],\n initialValue: existing?.ai.useGlobal === false ? \"project\" : \"global\",\n });\n\n if (p.isCancel(mode)) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n\n if (mode === \"global\") {\n await writeProjectPreferences(cwd, {\n version: \"1.0\",\n ai: { useGlobal: true, tools: [] },\n ide: existing?.ide ?? { useGlobal: true, platforms: [] },\n });\n p.log.success(\"Project configured to use global AI tools.\");\n return;\n }\n\n // Customize: show multiselect\n const allAdapters = getAllAIToolAdapters();\n const currentProjectTools = existing?.ai.useGlobal === false ? existing.ai.tools : globalTools;\n\n const options = allAdapters.map((adapter) => ({\n value: adapter.key,\n label: globalTools.includes(adapter.key) ? `${adapter.name} (in global config)` : adapter.name,\n }));\n\n const selected = await p.multiselect({\n message: \"Select AI tools for this project:\",\n options,\n initialValues: currentProjectTools,\n });\n\n if (p.isCancel(selected)) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n await writeProjectPreferences(cwd, {\n version: \"1.0\",\n ai: { useGlobal: false, tools: selectedKeys },\n ide: existing?.ide ?? { useGlobal: true, platforms: [] },\n });\n\n p.log.success(`Project configured with ${selectedKeys.length} AI tool(s).`);\n}\n\nasync function handleConfigureIdes(cwd: string): Promise<void> {\n const existing = await readProjectPreferences(cwd);\n const globalPlatforms = await getGlobalIdePlatforms();\n\n if (globalPlatforms.length > 0) {\n p.log.info(`Global IDE platforms: ${globalPlatforms.join(\", \")}`);\n }\n\n // Ask useGlobal first\n const mode = await p.select({\n message: \"How should this project resolve IDE platforms?\",\n options: [\n {\n value: \"global\",\n label: \"Use global config\",\n hint: \"always follows your global IDE platforms setting\",\n },\n {\n value: \"project\",\n label: \"Customize for this project\",\n hint: \"choose specific IDEs for this project\",\n },\n ],\n initialValue: existing?.ide.useGlobal === false ? \"project\" : \"global\",\n });\n\n if (p.isCancel(mode)) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n\n if (mode === \"global\") {\n await writeProjectPreferences(cwd, {\n version: \"1.0\",\n ai: existing?.ai ?? { useGlobal: true, tools: [] },\n ide: { useGlobal: true, platforms: [] },\n });\n p.log.success(\"Project configured to use global IDE platforms.\");\n return;\n }\n\n // Customize: show multiselect\n const allIdeKeys = getRegisteredIdePlatforms();\n const currentProjectPlatforms =\n existing?.ide.useGlobal === false ? existing.ide.platforms : globalPlatforms;\n\n const options = allIdeKeys.map((ideKey) => ({\n value: ideKey,\n label: globalPlatforms.includes(ideKey)\n ? `${formatIdeName(ideKey)} (in global config)`\n : formatIdeName(ideKey),\n }));\n\n const selected = await p.multiselect({\n message: \"Select IDE platforms for this project:\",\n options,\n initialValues: currentProjectPlatforms,\n });\n\n if (p.isCancel(selected)) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n await writeProjectPreferences(cwd, {\n version: \"1.0\",\n ai: existing?.ai ?? { useGlobal: true, tools: [] },\n ide: { useGlobal: false, platforms: selectedKeys },\n });\n\n p.log.success(`Project configured with ${selectedKeys.length} IDE platform(s).`);\n}\n\nasync function handleConfigureGitignore(cwd: string): Promise<void> {\n const manifestPath = join(cwd, \"baton.yaml\");\n const manifest = await loadProjectManifestSafe(cwd);\n if (!manifest) {\n p.log.error(\"Could not load baton.yaml\");\n return;\n }\n\n const currentSetting = manifest.gitignore !== false;\n p.log.info(\n currentSetting\n ? \"Currently: synced files ARE gitignored\"\n : \"Currently: synced files are NOT gitignored (committed to repo)\",\n );\n\n const newSetting = await p.confirm({\n message: \"Add synced AI tool and IDE config files to .gitignore?\",\n initialValue: currentSetting,\n });\n\n if (p.isCancel(newSetting)) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n\n if (newSetting === currentSetting) {\n p.log.info(\"No change.\");\n return;\n }\n\n manifest.gitignore = newSetting;\n const updatedYaml = stringify(manifest);\n await writeFile(manifestPath, updatedYaml, \"utf-8\");\n p.log.success(\n newSetting\n ? \"Enabled .gitignore management. Run 'baton sync' to update.\"\n : \"Disabled .gitignore management. Run 'baton sync' to clean up.\",\n );\n}\n\nexport const manageCommand = defineCommand({\n meta: {\n name: \"manage\",\n description: \"Interactive project management wizard for Baton\",\n },\n async run() {\n const cwd = process.cwd();\n\n // Guard: must be in an initialized project\n const manifest = await loadProjectManifestSafe(cwd);\n if (!manifest) {\n p.intro(\"Baton Manage\");\n p.cancel(\"baton.yaml not found. Run 'baton init' first.\");\n process.exit(1);\n }\n\n p.intro(\"Baton Manage\");\n\n // Loop-based wizard\n while (true) {\n const action = await p.select({\n message: \"What would you like to do?\",\n options: [\n { value: \"overview\", label: \"Overview\", hint: \"Show project configuration\" },\n { value: \"add-profile\", label: \"Add profile\", hint: \"Add a profile from a source\" },\n { value: \"remove-profile\", label: \"Remove profile\", hint: \"Remove an installed profile\" },\n {\n value: \"configure-ai\",\n label: \"Configure AI tools for this project\",\n hint: \"Choose which AI tools to sync\",\n },\n {\n value: \"configure-ides\",\n label: \"Configure IDEs for this project\",\n hint: \"Choose which IDEs to sync\",\n },\n {\n value: \"configure-gitignore\",\n label: \"Configure .gitignore\",\n hint: \"Choose whether synced files are gitignored\",\n },\n { value: \"remove-baton\", label: \"Remove Baton\", hint: \"Remove Baton from this project\" },\n { value: \"quit\", label: \"Quit\" },\n ],\n });\n\n if (p.isCancel(action) || action === \"quit\") {\n p.outro(\"Goodbye!\");\n return;\n }\n\n if (action === \"overview\") {\n console.log(\"\");\n await showOverview(cwd);\n console.log(\"\");\n } else if (action === \"add-profile\") {\n console.log(\"\");\n await handleAddProfile(cwd);\n console.log(\"\");\n } else if (action === \"remove-profile\") {\n console.log(\"\");\n await handleRemoveProfile(cwd);\n console.log(\"\");\n } else if (action === \"configure-ai\") {\n console.log(\"\");\n await handleConfigureAiTools(cwd);\n console.log(\"\");\n } else if (action === \"configure-ides\") {\n console.log(\"\");\n await handleConfigureIdes(cwd);\n console.log(\"\");\n } else if (action === \"configure-gitignore\") {\n console.log(\"\");\n await handleConfigureGitignore(cwd);\n console.log(\"\");\n } else if (action === \"remove-baton\") {\n console.log(\"\");\n const removed = await handleRemoveBaton(cwd);\n if (removed) {\n p.outro(\"Goodbye!\");\n return;\n }\n console.log(\"\");\n }\n }\n },\n});\n","import { defineCommand } from \"citty\";\n\nexport const profileCommand = defineCommand({\n meta: {\n name: \"profile\",\n description: \"Manage profiles (create, list, remove)\",\n },\n subCommands: {\n create: () => import(\"./create.js\").then((m) => m.createCommand),\n list: () => import(\"./list.js\").then((m) => m.profileListCommand),\n remove: () => import(\"./remove.js\").then((m) => m.profileRemoveCommand),\n },\n});\n","import { execFile } from \"node:child_process\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n checkLatestVersion,\n detectInstallMethod,\n formatInstallCommand,\n isUpdateAvailable,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nasync function readCurrentVersion(): Promise<string> {\n try {\n const pkg = JSON.parse(await readFile(join(__dirname, \"../package.json\"), \"utf-8\"));\n return typeof pkg.version === \"string\" ? pkg.version : \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\nexport const selfUpdateCommand = defineCommand({\n meta: {\n name: \"self-update\",\n description: \"Update Baton to the latest stable version\",\n },\n args: {\n changelog: {\n type: \"boolean\",\n description: \"Show release notes for the new version\",\n default: false,\n },\n \"dry-run\": {\n type: \"boolean\",\n description: \"Check for updates without performing the update\",\n default: false,\n },\n yes: {\n type: \"boolean\",\n alias: \"y\",\n description: \"Skip confirmation prompt\",\n default: false,\n },\n },\n async run({ args }) {\n p.intro(\"baton self-update\");\n\n const currentVersion = await readCurrentVersion();\n\n // Check latest version\n const s = p.spinner();\n s.start(\"Checking for updates...\");\n\n let latestVersion: string;\n try {\n const result = await checkLatestVersion();\n latestVersion = result.version;\n } catch (error) {\n s.stop(\"Failed to check for updates\");\n p.log.error(error instanceof Error ? error.message : \"Unknown error occurred\");\n p.outro(\"Update check failed.\");\n process.exit(1);\n }\n\n s.stop(\"Version check complete\");\n\n // Compare versions\n const { updateAvailable } = isUpdateAvailable(currentVersion, latestVersion);\n if (!updateAvailable) {\n p.log.success(`Already up to date (v${currentVersion}).`);\n p.outro(\"No update needed.\");\n return;\n }\n\n // Detect install method\n const installMethod = await detectInstallMethod();\n const displayCommand = formatInstallCommand(installMethod);\n\n p.log.info(\n [\n `Current version: v${currentVersion}`,\n `Latest version: v${latestVersion}`,\n installMethod.type !== \"unknown\" ? `Install method: ${installMethod.type}` : \"\",\n ]\n .filter(Boolean)\n .join(\"\\n\"),\n );\n\n // Handle unknown install method\n if (installMethod.type === \"unknown\") {\n p.log.warn(\"Could not detect installation method.\");\n p.log.message(\n [\n \"Please update manually using one of:\",\n \" npm update -g @baton-dx/cli\",\n \" pnpm update -g @baton-dx/cli\",\n \" bun update -g @baton-dx/cli\",\n \" brew upgrade baton-dx\",\n ].join(\"\\n\"),\n );\n p.outro(\"Manual update required.\");\n return;\n }\n\n // Dry-run: stop here\n if (args[\"dry-run\"]) {\n p.log.info(`Would run: ${displayCommand}`);\n p.outro(\"Dry run complete.\");\n return;\n }\n\n // Changelog (optional)\n if (args.changelog) {\n const changelogUrl = `https://github.com/baton-dx/baton/releases/tag/v${latestVersion}`;\n p.log.info(`Release notes: ${changelogUrl}`);\n }\n\n // Confirmation prompt\n if (!args.yes) {\n const confirmed = await p.confirm({\n message: `Update to v${latestVersion}?`,\n });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.outro(\"Update cancelled.\");\n return;\n }\n }\n\n // Execute update\n const updateSpinner = p.spinner();\n updateSpinner.start(`Running: ${displayCommand}`);\n\n try {\n await new Promise<void>((resolve, reject) => {\n execFile(installMethod.bin, installMethod.args, (error) => {\n if (error) reject(error);\n else resolve();\n });\n });\n updateSpinner.stop(`Successfully updated to v${latestVersion}`);\n p.outro(\"Update complete!\");\n } catch (error) {\n updateSpinner.stop(\"Update failed\");\n const message = error instanceof Error ? error.message : \"Unknown error\";\n p.log.error(`Failed to run: ${displayCommand}`);\n p.log.error(message);\n p.outro(\"Update failed. Please try updating manually.\");\n process.exit(1);\n }\n },\n});\n","import { KEBAB_CASE_REGEX, SourceParseError, addGlobalSource, parseSource } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { selectMultipleProfilesFromSource } from \"../../utils/profile-selection.js\";\n\n/**\n * Command: baton source connect\n *\n * Connects a source repository to the global configuration (~/.baton/config.yaml).\n * Once connected, sources can be auto-selected in `baton init`.\n */\nexport const connectCommand = defineCommand({\n meta: {\n name: \"connect\",\n description: \"Connect a source repository to your global config\",\n },\n args: {\n url: {\n type: \"positional\",\n description: \"Source URL (github:org/repo, ../path)\",\n required: true,\n },\n name: {\n type: \"string\",\n description: \"Custom name for the source (kebab-case)\",\n },\n description: {\n type: \"string\",\n description: \"Source description\",\n },\n },\n async run({ args }) {\n const url = args.url as string;\n const customName = args.name as string | undefined;\n\n if (customName && !KEBAB_CASE_REGEX.test(customName)) {\n p.cancel(\"Source name must be kebab-case (e.g., my-source)\");\n process.exit(1);\n }\n\n try {\n parseSource(url);\n } catch (error) {\n const message =\n error instanceof SourceParseError\n ? error.message\n : `Invalid source: ${(error as Error).message}`;\n p.cancel(message);\n process.exit(1);\n }\n\n try {\n await addGlobalSource(url, {\n name: args.name as string | undefined,\n description: args.description as string | undefined,\n });\n\n const displayName = args.name || url;\n p.log.success(`Connected source: ${displayName}`);\n\n const shouldSync = await p.confirm({\n message: \"Would you like to sync profiles from this source now?\",\n initialValue: false,\n });\n\n if (p.isCancel(shouldSync) || !shouldSync) {\n p.outro(\"Source connected. Run 'baton init' to set up profiles.\");\n return;\n }\n\n p.outro(\"Starting profile sync...\");\n\n const profiles = await selectMultipleProfilesFromSource(url);\n if (profiles.length > 0) {\n p.log.success(`Selected ${profiles.length} profile(s) for sync.`);\n p.note(\n \"Run 'baton init' in your project directory to install these profiles.\",\n \"Next step\",\n );\n }\n } catch (error) {\n p.cancel(`Failed to connect source: ${(error as Error).message}`);\n process.exit(1);\n }\n },\n});\n","import { mkdir, readFile, readdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { KEBAB_CASE_REGEX } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport Handlebars from \"handlebars\";\nimport simpleGit from \"simple-git\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\ninterface WizardOptions {\n name: string;\n git: boolean;\n withInitialProfile: boolean;\n}\n\ninterface WizardOverrides {\n name?: string;\n git?: boolean;\n withInitialProfile?: boolean;\n}\n\nasync function runInteractiveWizard(overrides: WizardOverrides = {}): Promise<WizardOptions> {\n p.intro(\"Create a new Baton source repository\");\n\n // 1. Name (with validation)\n let name: string;\n if (overrides.name) {\n name = overrides.name;\n } else {\n const result = await p.text({\n message: \"What is the name of your source repository?\",\n placeholder: \"my-team-profile\",\n validate: (value) => {\n if (!value) return \"Name is required\";\n if (!KEBAB_CASE_REGEX.test(value))\n return \"Name must be in kebab-case (lowercase, hyphens only)\";\n },\n });\n if (p.isCancel(result)) {\n p.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n name = String(result);\n }\n\n // 2. Git Initialization\n let git: boolean;\n if (overrides.git !== undefined) {\n git = overrides.git;\n } else {\n const result = (await p.confirm({\n message: \"Initialize Git repository?\",\n initialValue: true,\n })) as boolean;\n if (p.isCancel(result)) {\n p.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n git = result;\n }\n\n // 3. Initial Profile\n let withInitialProfile: boolean;\n if (overrides.withInitialProfile !== undefined) {\n withInitialProfile = overrides.withInitialProfile;\n } else {\n const result = (await p.confirm({\n message: \"Create initial profile in profiles/default/?\",\n initialValue: true,\n })) as boolean;\n if (p.isCancel(result)) {\n p.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n withInitialProfile = result;\n }\n\n return {\n name,\n git,\n withInitialProfile,\n };\n}\n\n/**\n * Recursively copy a directory and apply Handlebars variable substitution to text files\n */\nasync function copyDirectory(\n src: string,\n dest: string,\n variables: Record<string, unknown>,\n): Promise<void> {\n await mkdir(dest, { recursive: true });\n\n const entries = await readdir(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(src, entry.name);\n const destPath = join(dest, entry.name);\n\n if (entry.isDirectory()) {\n await copyDirectory(srcPath, destPath, variables);\n } else if (entry.isFile()) {\n const content = await readFile(srcPath, \"utf-8\");\n\n // Binary file detection (skip substitution for binary files)\n const binaryExtensions = new Set([\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".gif\",\n \".ico\",\n \".woff\",\n \".woff2\",\n \".ttf\",\n \".eot\",\n ]);\n const isBinary = binaryExtensions.has(entry.name.substring(entry.name.lastIndexOf(\".\")));\n\n if (isBinary) {\n await writeFile(destPath, content);\n } else {\n // Substitute variables with Handlebars\n const template = Handlebars.compile(content, { noEscape: true });\n const substituted = template(variables);\n await writeFile(destPath, substituted);\n }\n }\n }\n}\n\n/**\n * Initialize Git repository and create initial commit\n */\nasync function initializeGit(targetDir: string): Promise<void> {\n const git = simpleGit(targetDir);\n\n // Initialize repository\n await git.init();\n\n // Add all files\n await git.add(\".\");\n\n // Create initial commit\n await git.commit(\"Initial baton source setup\");\n}\n\n/**\n * Generate README.md with next steps\n */\nasync function generateReadme(targetDir: string, options: WizardOptions): Promise<void> {\n const { name, withInitialProfile } = options;\n const org = name.includes(\"-\") ? name.split(\"-\")[0] : name;\n\n const readmeContent = `# ${name}\n\nBaton source repository.\n\n## Usage\n\nAdd profiles from this source repository to your project:\n\n\\`\\`\\`bash\n# From GitHub (after you push)\nbaton init --profile github:${org}/${name}/profiles/default\n\n# Or locally (for testing)\nbaton init --profile file:./${name}/profiles/default\n\\`\\`\\`\n\n## Next Steps\n\n1. **Customize your profiles:**\n - Edit \\`baton.source.yaml\\` to configure the source metadata\n - Modify profiles in \\`profiles/*/baton.profile.yaml\\`\n - Add project-specific configurations to \\`profiles/*/files/\\`\n - Customize AI tool configs in \\`profiles/*/ai/\\`\n\n2. **Create additional profiles:**\n \\`\\`\\`bash\n cd ${name}\n baton profile create frontend\n baton profile create backend\n \\`\\`\\`\n\n3. **Set up Git remote:**\n \\`\\`\\`bash\n git remote add origin https://github.com/${org}/${name}.git\n git push -u origin main\n \\`\\`\\`\n\n4. **Share with your team:**\n - Publish to GitHub for team-wide access\n - Team members can use: \\`baton init --profile github:${org}/${name}/profiles/default\\`\n\n## Structure\n\n- \\`baton.source.yaml\\` - Source repository manifest\n- \\`profiles/\\` - Container for all profiles\n${withInitialProfile ? \" - `profiles/default/` - Default profile\\n - `baton.profile.yaml` - Profile manifest\\n - `ai/` - AI tool configurations\\n - `files/` - Dotfiles and configs to sync\\n - `ide/` - IDE settings\\n\" : \"\"}\n## Learn More\n\n- [Baton Documentation](https://github.com/baton-dx/baton)\n- [Source Schema](https://github.com/baton-dx/baton/blob/main/docs/source-schema.md)\n- [Profile Schema](https://github.com/baton-dx/baton/blob/main/docs/profile-schema.md)\n\n---\n\nGenerated with \\`baton source create\\`\n`;\n\n await writeFile(join(targetDir, \"README.md\"), readmeContent);\n}\n\n/**\n * Scaffold a source repository\n */\nexport async function scaffoldSourceRepo(options: WizardOptions): Promise<string> {\n const { name, git, withInitialProfile } = options;\n\n // Target directory is always ./<name>\n const targetDir = join(process.cwd(), name);\n\n // Create base directory and profiles/ folder\n await mkdir(join(targetDir, \"profiles\"), { recursive: true });\n\n // Create baton.source.yaml\n const sourceManifest = `name: \"${name}\"\nversion: \"0.1.0\"\ndescription: \"Baton source repository\"\n\n${\n withInitialProfile\n ? `profiles:\n - name: \"default\"\n path: \"profiles/default\"\n description: \"Default profile configuration\"\n`\n : \"\"\n}\nmetadata:\n created: \"${new Date().getFullYear()}\"\n`;\n await writeFile(join(targetDir, \"baton.source.yaml\"), sourceManifest);\n\n // Create initial profile if requested\n if (withInitialProfile) {\n const profileDir = join(targetDir, \"profiles\", \"default\");\n await mkdir(profileDir, { recursive: true });\n\n // Copy minimal profile template\n const profileTemplateDir = join(__dirname, \"templates\", \"profile\", \"minimal\");\n await copyDirectory(profileTemplateDir, profileDir, { name: \"default\" });\n }\n\n // Generate README.md\n await generateReadme(targetDir, options);\n\n // Initialize Git if requested\n if (git) {\n await initializeGit(targetDir);\n }\n\n return targetDir;\n}\n\nexport const sourceCreateCommand = defineCommand({\n meta: {\n name: \"source create\",\n description: \"Create a new source repository with an interactive wizard\",\n },\n args: {\n name: {\n type: \"positional\",\n description: \"Name of the source repository (kebab-case)\",\n required: false,\n },\n yes: {\n type: \"boolean\",\n description: \"Skip interactive wizard and use defaults\",\n default: false,\n },\n },\n async run({ args }) {\n const providedName = args.name as string | undefined;\n const yesArg = args.yes as boolean | undefined;\n\n // Validate name if provided\n if (providedName && !KEBAB_CASE_REGEX.test(providedName)) {\n console.error(\"Error: Name must be in kebab-case (lowercase, hyphens only)\");\n process.exit(1);\n }\n\n // Build overrides from CLI args\n const overrides: WizardOverrides = {\n name: providedName || undefined,\n };\n\n // If --yes flag: fill in defaults for anything not provided\n if (yesArg) {\n overrides.name = overrides.name || \"my-source\";\n overrides.git = true;\n overrides.withInitialProfile = false;\n }\n\n // Run wizard (skips steps where overrides are provided)\n const options = await runInteractiveWizard(overrides);\n\n // Scaffold the source repository\n const spinner = p.spinner();\n spinner.start(\"Creating source repository...\");\n\n try {\n const targetDir = await scaffoldSourceRepo(options);\n spinner.stop(`Source repository created at ${targetDir}`);\n\n // Build summary message\n const features: string[] = [];\n if (options.withInitialProfile) {\n features.push(\"Initial Profile: profiles/default/\");\n }\n if (options.git) {\n features.push(\"Git: Initialized with initial commit\");\n }\n\n if (features.length > 0) {\n p.note(features.join(\"\\n\"), \"Features\");\n }\n\n const org = options.name.includes(\"-\") ? options.name.split(\"-\")[0] : options.name;\n const nextSteps: string[] = [];\n nextSteps.push(` cd ${options.name}`);\n nextSteps.push(\" # Customize your profile (see README.md)\");\n if (options.git) {\n nextSteps.push(` git remote add origin https://github.com/${org}/${options.name}.git`);\n nextSteps.push(\" git push -u origin main\");\n }\n nextSteps.push(\"\");\n nextSteps.push(\" # Share with your team:\");\n nextSteps.push(` baton source connect https://github.com/${org}/${options.name}.git`);\n\n p.outro(\n `Source repository \"${options.name}\" created successfully!\\n\\nNext steps:\\n${nextSteps.join(\"\\n\")}`,\n );\n } catch (error) {\n spinner.stop(\"Failed to create source repository\");\n throw error;\n }\n },\n});\n","import { type GlobalSourceEntry, getGlobalSources, removeGlobalSource } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\n\n/**\n * Command: baton source disconnect\n *\n * Disconnects a source repository from the global configuration.\n * Shows a warning about profiles that depend on this source before removing.\n */\nexport const disconnectCommand = defineCommand({\n meta: {\n name: \"disconnect\",\n description: \"Disconnect a source repository from your global config\",\n },\n args: {\n source: {\n type: \"positional\",\n description: \"Source name or URL to disconnect\",\n required: true,\n },\n },\n async run({ args }) {\n const sourceIdentifier = args.source as string;\n\n // Find the matching source in global config\n const sources = await getGlobalSources();\n const matchedSource = sources.find(\n (s: GlobalSourceEntry) => s.name === sourceIdentifier || s.url === sourceIdentifier,\n );\n\n if (!matchedSource) {\n p.cancel(`Source \"${sourceIdentifier}\" not found in global configuration.`);\n process.exit(1);\n }\n\n // Warn about dependent projects/profiles\n p.log.warn(\n `Disconnecting source \"${matchedSource.name}\" (${matchedSource.url}) will affect any projects using profiles from this source.`,\n );\n p.log.info(\n \"Projects that reference this source will no longer be able to sync or update their profiles.\",\n );\n\n // Confirm before removing\n const confirmed = await p.confirm({\n message: `Are you sure you want to disconnect source \"${matchedSource.name}\"?`,\n initialValue: false,\n });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n try {\n await removeGlobalSource(sourceIdentifier);\n p.outro(`Disconnected source: ${matchedSource.name}`);\n } catch (error) {\n p.cancel(`Failed to disconnect source: ${(error as Error).message}`);\n process.exit(1);\n }\n },\n});\n","import { getGlobalSources } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\n\n/**\n * Command: baton source list\n *\n * Lists all registered global sources from ~/.baton/config.yaml.\n */\nexport const listCommand = defineCommand({\n meta: {\n name: \"list\",\n description: \"List all global sources\",\n },\n async run() {\n const sources = await getGlobalSources();\n\n if (sources.length === 0) {\n p.log.info(\"No global sources configured.\");\n p.note(\"Add a source with:\\n baton source connect <url>\", \"Tip\");\n return;\n }\n\n console.log(\"\\n🌐 Global Sources\\n\");\n console.log(\"┌──────────────────┬─────────────────────────────────────┬─────────┐\");\n console.log(\"│ Name │ URL │ Default │\");\n console.log(\"├──────────────────┼─────────────────────────────────────┼─────────┤\");\n\n for (const source of sources) {\n const name = source.name.padEnd(16);\n const url = truncate(source.url, 35).padEnd(35);\n const def = source.default ? \"✓\" : \"\";\n\n console.log(`│ ${name} │ ${url} │ ${def.padEnd(7)} │`);\n\n if (source.description) {\n const desc = ` ${truncate(source.description, 33)}`.padEnd(35);\n console.log(`│ │ ${desc} │ │`);\n }\n }\n\n console.log(\"└──────────────────┴─────────────────────────────────────┴─────────┘\\n\");\n },\n});\n\n/**\n * Truncates a string to the specified length, adding \"...\" if truncated.\n */\nfunction truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) {\n return str;\n }\n return `${str.slice(0, maxLength - 3)}...`;\n}\n","import { defineCommand } from \"citty\";\nimport { connectCommand } from \"./connect.js\";\nimport { sourceCreateCommand } from \"./create.js\";\nimport { disconnectCommand } from \"./disconnect.js\";\nimport { listCommand } from \"./list.js\";\n\nexport const sourceCommand = defineCommand({\n meta: {\n name: \"source\",\n description: \"Manage source repositories (create, list, connect, disconnect)\",\n },\n subCommands: {\n create: sourceCreateCommand,\n list: listCommand,\n connect: connectCommand,\n disconnect: disconnectCommand,\n },\n});\n","import { mkdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, relative, resolve } from \"node:path\";\nimport {\n type AIToolAdapter,\n type AgentEntry,\n type AgentFile,\n type CloneContext,\n FileNotFoundError,\n type LockFileEntry,\n type MemoryEntry,\n type MergedSkillItem,\n type ProjectManifest,\n type RuleEntry,\n type RuleFile,\n type WeightConflictWarning,\n cloneGitSource,\n detectInstalledAITools,\n detectLegacyPaths,\n getAIToolAdaptersForKeys,\n getIdePlatformTargetDir,\n getProfileWeight,\n isKnownIdePlatform,\n isLockedProfile,\n loadProfileManifest,\n loadProjectManifest,\n mergeAgentsWithWarnings,\n mergeContentParts,\n mergeMemoryWithWarnings,\n mergeRulesWithWarnings,\n mergeSkillsWithWarnings,\n parseFrontmatter,\n parseSource,\n placeFile,\n readLock,\n resolvePreferences,\n resolveProfileChain,\n resolveVersion,\n sortProfilesByWeight,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport simpleGit from \"simple-git\";\nimport { buildIntersection } from \"../utils/build-intersection.js\";\nimport { promptFirstRunPreferences } from \"../utils/first-run-preferences.js\";\nimport { displayIntersection, formatIntersectionSummary } from \"../utils/intersection-display.js\";\nimport {\n type SyncCategory,\n type SyncStats,\n cleanupOrphanedFiles,\n copyDirectoryRecursive,\n getOrCreatePlacedFiles,\n handleGitignoreUpdate,\n validCategories,\n writeLockData,\n} from \"./sync-pipeline.js\";\n\nexport const syncCommand = defineCommand({\n meta: {\n name: \"sync\",\n description: \"Fetch latest versions, sync all configurations, and update lockfile\",\n },\n args: {\n \"dry-run\": {\n type: \"boolean\",\n description: \"Show what would be done without writing files\",\n default: false,\n },\n category: {\n type: \"string\",\n description: \"Sync only a specific category: ai, files, or ide\",\n required: false,\n },\n yes: {\n type: \"boolean\",\n description: \"Run non-interactively (no prompts)\",\n default: false,\n },\n verbose: {\n type: \"boolean\",\n alias: \"v\",\n description: \"Show detailed output for each placed file\",\n default: false,\n },\n },\n async run({ args }) {\n const dryRun = args[\"dry-run\"];\n const categoryArg = args.category as string | undefined;\n const autoYes = args.yes;\n const verbose = args.verbose;\n\n // Validate --category flag\n let category: SyncCategory | undefined;\n if (categoryArg) {\n if (!validCategories.includes(categoryArg as SyncCategory)) {\n p.cancel(\n `Invalid category \"${categoryArg}\". Valid categories: ${validCategories.join(\", \")}`,\n );\n process.exit(1);\n }\n category = categoryArg as SyncCategory;\n }\n\n const syncAi = !category || category === \"ai\";\n const syncFiles = !category || category === \"files\";\n const syncIde = !category || category === \"ide\";\n\n p.intro(category ? `🔄 Baton Sync (category: ${category})` : \"🔄 Baton Sync\");\n\n // Statistics tracking\n const stats: SyncStats = {\n created: 0,\n errors: 0,\n };\n\n try {\n // Step 0: Load project manifest\n const projectRoot = process.cwd();\n const manifestPath = resolve(projectRoot, \"baton.yaml\");\n\n let projectManifest: ProjectManifest;\n try {\n projectManifest = await loadProjectManifest(manifestPath);\n } catch (error) {\n if (error instanceof FileNotFoundError) {\n p.cancel(\"baton.yaml not found. Run `baton init` first.\");\n } else {\n p.cancel(\n `Failed to load baton.yaml: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n process.exit(1);\n }\n\n // Step 0a: First-run preferences check\n await promptFirstRunPreferences(projectRoot, !!args.yes);\n\n // Step 0b: Read existing lockfile to detect orphaned files later\n const previousPaths = new Set<string>();\n try {\n const lockfilePath = resolve(projectRoot, \"baton.lock\");\n const previousLock = await readLock(lockfilePath);\n for (const pkg of Object.values(previousLock.packages)) {\n for (const filePath of Object.keys(pkg.integrity)) {\n previousPaths.add(filePath);\n }\n }\n } catch {\n // No existing lockfile — nothing to clean up\n }\n\n // Step 1: Resolve profile chain\n const spinner = p.spinner();\n spinner.start(\"Resolving profile chain...\");\n\n const allProfiles = [];\n // Track SHA per source for lockfile\n const sourceShas = new Map<string, string>();\n for (const profileSource of projectManifest.profiles || []) {\n try {\n if (verbose) {\n p.log.info(`Resolving source: ${profileSource.source}`);\n }\n // Load the profile manifest first\n const parsed = parseSource(profileSource.source);\n\n let manifestPath: string;\n let cloneContext: CloneContext | undefined;\n if (parsed.provider === \"local\" || parsed.provider === \"file\") {\n const absolutePath = parsed.path.startsWith(\"/\")\n ? parsed.path\n : resolve(projectRoot, parsed.path);\n manifestPath = resolve(absolutePath, \"baton.profile.yaml\");\n // Try to get SHA from local git repo, fallback to \"local\"\n try {\n const git = simpleGit(absolutePath);\n await git.checkIsRepo();\n const sha = await git.revparse([\"HEAD\"]);\n sourceShas.set(profileSource.source, sha.trim());\n } catch {\n sourceShas.set(profileSource.source, \"local\");\n }\n } else {\n // For remote sources, clone first\n const url =\n parsed.provider === \"github\" || parsed.provider === \"gitlab\"\n ? parsed.url\n : parsed.provider === \"git\"\n ? parsed.url\n : \"\";\n\n if (!url) {\n throw new Error(`Invalid source: ${profileSource.source}`);\n }\n\n // Always resolve to latest version\n let resolvedRef: string;\n try {\n resolvedRef = await resolveVersion(url, \"latest\");\n if (verbose) {\n p.log.info(\n `Resolved latest: ${profileSource.source} → ${resolvedRef.slice(0, 12)}`,\n );\n }\n } catch {\n // Fallback to profileSource.version if resolution fails\n resolvedRef = profileSource.version || \"HEAD\";\n if (verbose) {\n p.log.warn(`Could not resolve latest for ${url}, using ${resolvedRef}`);\n }\n }\n\n const cloned = await cloneGitSource({\n url,\n ref: resolvedRef,\n subpath: \"subpath\" in parsed ? parsed.subpath : undefined,\n useCache: false,\n });\n manifestPath = resolve(cloned.localPath, \"baton.profile.yaml\");\n sourceShas.set(profileSource.source, cloned.sha);\n cloneContext = {\n cachePath: cloned.cachePath,\n sparseCheckout: cloned.sparseCheckout,\n };\n }\n\n const manifest = await loadProfileManifest(manifestPath);\n const profileDir = dirname(manifestPath);\n const chain = await resolveProfileChain(\n manifest,\n profileSource.source,\n profileDir,\n cloneContext,\n );\n allProfiles.push(...chain);\n } catch (error) {\n spinner.stop(`Failed to resolve profile ${profileSource.source}: ${error}`);\n stats.errors++;\n }\n }\n\n if (allProfiles.length === 0) {\n spinner.stop(\"No profiles configured\");\n p.outro(\"Nothing to sync. Run `baton manage` to add a profile.\");\n process.exit(2);\n }\n\n spinner.stop(`Resolved ${allProfiles.length} profile(s)`);\n\n // Step 1b: Sort profiles by weight for merge ordering\n // Higher-weight profiles appear later → win in \"last-wins\" merge logic\n // Stable sort preserves declaration order for same-weight profiles\n const weightSortedProfiles = sortProfilesByWeight(allProfiles);\n\n // Step 2: Merge configurations\n spinner.start(\"Merging configurations...\");\n\n // Collect all weight conflict warnings across merge operations\n const allWeightWarnings: WeightConflictWarning[] = [];\n\n const skillsResult = mergeSkillsWithWarnings(weightSortedProfiles);\n const mergedSkills: MergedSkillItem[] = skillsResult.skills;\n allWeightWarnings.push(...skillsResult.warnings);\n\n const rulesResult = mergeRulesWithWarnings(weightSortedProfiles);\n const mergedRules: RuleEntry[] = rulesResult.rules;\n allWeightWarnings.push(...rulesResult.warnings);\n\n const agentsResult = mergeAgentsWithWarnings(weightSortedProfiles);\n const mergedAgents: AgentEntry[] = agentsResult.agents;\n allWeightWarnings.push(...agentsResult.warnings);\n\n const memoryResult = mergeMemoryWithWarnings(weightSortedProfiles);\n const mergedMemory: MemoryEntry[] = memoryResult.entries;\n allWeightWarnings.push(...memoryResult.warnings);\n\n // Collect all commands from all profiles (deduplicated by name, last wins)\n // Respects weight lock: commands from weight -1 profiles cannot be overridden\n const commandMap = new Map<string, string>();\n const lockedCommands = new Set<string>();\n const commandOwner = new Map<string, { profileName: string; weight: number }>();\n for (const profile of weightSortedProfiles) {\n const weight = getProfileWeight(profile);\n const locked = isLockedProfile(profile);\n for (const cmd of profile.manifest.ai?.commands || []) {\n if (lockedCommands.has(cmd)) continue;\n\n const existing = commandOwner.get(cmd);\n if (existing && existing.weight === weight && existing.profileName !== profile.name) {\n allWeightWarnings.push({\n key: cmd,\n category: \"command\",\n profileA: existing.profileName,\n profileB: profile.name,\n weight,\n });\n }\n\n commandMap.set(cmd, profile.name);\n commandOwner.set(cmd, { profileName: profile.name, weight });\n if (locked) lockedCommands.add(cmd);\n }\n }\n const mergedCommandCount = commandMap.size;\n\n // Collect all files from all profiles (deduplicated by target path, last wins)\n // Respects weight lock: files from weight -1 profiles cannot be overridden\n const fileMap = new Map<string, { source: string; target: string; profileName: string }>();\n const lockedFiles = new Set<string>();\n const fileOwner = new Map<string, { profileName: string; weight: number }>();\n for (const profile of weightSortedProfiles) {\n const weight = getProfileWeight(profile);\n const locked = isLockedProfile(profile);\n for (const fileConfig of profile.manifest.files || []) {\n const target = fileConfig.target || fileConfig.source;\n if (lockedFiles.has(target)) continue;\n\n const existing = fileOwner.get(target);\n if (existing && existing.weight === weight && existing.profileName !== profile.name) {\n allWeightWarnings.push({\n key: target,\n category: \"file\",\n profileA: existing.profileName,\n profileB: profile.name,\n weight,\n });\n }\n\n fileMap.set(target, { source: fileConfig.source, target, profileName: profile.name });\n fileOwner.set(target, { profileName: profile.name, weight });\n if (locked) lockedFiles.add(target);\n }\n }\n const mergedFileCount = fileMap.size;\n\n // Collect all IDE configs from all profiles (deduplicated by target path, last wins)\n // Uses central IDE platform registry for key → directory mapping\n // Respects weight lock: IDE configs from weight -1 profiles cannot be overridden\n const ideMap = new Map<\n string,\n { ideKey: string; fileName: string; targetDir: string; profileName: string }\n >();\n const lockedIdeConfigs = new Set<string>();\n const ideOwner = new Map<string, { profileName: string; weight: number }>();\n for (const profile of weightSortedProfiles) {\n if (!profile.manifest.ide) continue;\n const weight = getProfileWeight(profile);\n const locked = isLockedProfile(profile);\n for (const [ideKey, files] of Object.entries(profile.manifest.ide)) {\n if (!files) continue;\n const targetDir = getIdePlatformTargetDir(ideKey);\n if (!targetDir) {\n if (!isKnownIdePlatform(ideKey)) {\n p.log.warn(\n `Unknown IDE platform \"${ideKey}\" in profile \"${profile.name}\" — skipping. Register it in the IDE platform registry.`,\n );\n }\n continue;\n }\n for (const fileName of files) {\n const targetPath = `${targetDir}/${fileName}`;\n if (lockedIdeConfigs.has(targetPath)) continue;\n\n const existing = ideOwner.get(targetPath);\n if (existing && existing.weight === weight && existing.profileName !== profile.name) {\n allWeightWarnings.push({\n key: targetPath,\n category: \"ide\",\n profileA: existing.profileName,\n profileB: profile.name,\n weight,\n });\n }\n\n ideMap.set(targetPath, { ideKey, fileName, targetDir, profileName: profile.name });\n ideOwner.set(targetPath, { profileName: profile.name, weight });\n if (locked) lockedIdeConfigs.add(targetPath);\n }\n }\n }\n const mergedIdeCount = ideMap.size;\n\n spinner.stop(\n `Merged: ${mergedSkills.length} skills, ${mergedRules.length} rules, ${mergedAgents.length} agents, ${mergedMemory.length} memory files, ${mergedCommandCount} commands, ${mergedFileCount} files, ${mergedIdeCount} IDE configs`,\n );\n\n // Emit weight conflict warnings (same weight, conflicting values)\n if (allWeightWarnings.length > 0) {\n for (const w of allWeightWarnings) {\n p.log.warn(\n `Weight conflict: \"${w.profileA}\" and \"${w.profileB}\" both define ${w.category} \"${w.key}\" with weight ${w.weight}. Last declared wins.`,\n );\n }\n }\n\n // Step 3: Determine which AI tools and IDE platforms to sync (intersection-based)\n spinner.start(\"Computing tool intersection...\");\n\n const prefs = await resolvePreferences(projectRoot);\n const detectedAITools = await detectInstalledAITools();\n\n if (verbose) {\n p.log.info(\n `AI tools: ${prefs.ai.tools.join(\", \") || \"(none)\"} (from ${prefs.ai.source} preferences)`,\n );\n p.log.info(\n `IDE platforms: ${prefs.ide.platforms.join(\", \") || \"(none)\"} (from ${prefs.ide.source} preferences)`,\n );\n }\n\n // Compute aggregated intersection across all profiles\n // A tool/platform is \"synced\" if the developer has it AND at least one profile supports it\n let syncedAiTools: string[];\n let syncedIdePlatforms: string[] | null = null;\n let allIntersections: Map<string, import(\"@baton-dx/core\").IntersectionResult> | null = null;\n\n if (prefs.ai.tools.length > 0) {\n const developerTools = { aiTools: prefs.ai.tools, idePlatforms: prefs.ide.platforms };\n const aggregatedSyncedAi = new Set<string>();\n const aggregatedSyncedIde = new Set<string>();\n allIntersections = new Map();\n\n for (const profileSource of projectManifest.profiles || []) {\n try {\n const intersection = await buildIntersection(\n profileSource.source,\n developerTools,\n projectRoot,\n );\n if (intersection) {\n allIntersections.set(profileSource.source, intersection);\n for (const tool of intersection.aiTools.synced) {\n aggregatedSyncedAi.add(tool);\n }\n for (const platform of intersection.idePlatforms.synced) {\n aggregatedSyncedIde.add(platform);\n }\n }\n } catch {\n // Best-effort — skip if intersection cannot be computed for this profile\n }\n }\n\n syncedAiTools = aggregatedSyncedAi.size > 0 ? [...aggregatedSyncedAi] : [];\n syncedIdePlatforms = [...aggregatedSyncedIde];\n } else {\n // No global config — fall back to detected agents for backward compatibility\n syncedAiTools = detectedAITools;\n // No IDE filtering when no global config exists (place all IDE files)\n syncedIdePlatforms = null;\n if (detectedAITools.length > 0) {\n p.log.warn(\"No AI tools configured. Run `baton ai-tools scan` to configure your tools.\");\n p.log.info(`Falling back to detected tools: ${detectedAITools.join(\", \")}`);\n }\n }\n\n if (syncedAiTools.length === 0 && detectedAITools.length === 0) {\n spinner.stop(\"No AI tools available\");\n p.cancel(\"No AI tools found. Install an AI coding tool first.\");\n process.exit(1);\n }\n\n if (syncedAiTools.length === 0) {\n spinner.stop(\"No AI tools in intersection\");\n p.cancel(\n \"No AI tools match between your configuration and profile support. \" +\n \"Run `baton ai-tools scan` or check your profile's supported tools.\",\n );\n process.exit(1);\n }\n\n // Show intersection or synced tools\n if (allIntersections) {\n for (const [source, intersection] of allIntersections) {\n if (verbose) {\n p.log.step(`Intersection for ${source}`);\n displayIntersection(intersection);\n } else {\n const summary = formatIntersectionSummary(intersection);\n p.log.info(`Syncing for: ${summary}`);\n }\n }\n }\n\n const ideSummary =\n syncedIdePlatforms && syncedIdePlatforms.length > 0\n ? ` | IDE platforms: ${syncedIdePlatforms.join(\", \")}`\n : \"\";\n spinner.stop(`Syncing AI tools: ${syncedAiTools.join(\", \")}${ideSummary}`);\n\n // Step 4: Migrate legacy paths\n spinner.start(\"Checking for legacy paths...\");\n\n const legacyFiles = await detectLegacyPaths(projectRoot);\n\n if (legacyFiles.length > 0 && !dryRun) {\n spinner.stop(`Found ${legacyFiles.length} legacy file(s)`);\n\n if (!autoYes) {\n p.note(\n `Found legacy configuration files:\\n${legacyFiles.map((f) => ` - ${f.legacyPath}`).join(\"\\n\")}`,\n \"Legacy Files\",\n );\n p.log.warn(\"Run migration manually with appropriate action (migrate/copy/skip)\");\n }\n } else {\n spinner.stop(\"No legacy files found\");\n }\n\n // Step 5-7: Transform, Place, and Link\n spinner.start(\"Processing configurations...\");\n\n // Use intersection-filtered AI tools instead of all detected agents\n const adapters = getAIToolAdaptersForKeys(syncedAiTools);\n\n // Placement configuration\n const placementConfig = {\n mode: \"copy\" as const, // Start with copy mode (symlink can be added later)\n projectRoot,\n };\n\n // Track placed file contents per profile for lockfile integrity hashes\n // Each entry includes content, tool key, and category for precise tool-to-file tracking\n const placedFiles = new Map<string, Record<string, LockFileEntry>>();\n\n // Build a map from profile name to local directory path\n // This is needed because profile.source may be a remote URL (e.g., \"github:org/repo/subpath\")\n const profileLocalPaths = new Map<string, string>();\n for (const profileSource of projectManifest.profiles || []) {\n const parsed = parseSource(profileSource.source);\n if (parsed.provider === \"local\" || parsed.provider === \"file\") {\n const localPath = parsed.path.startsWith(\"/\")\n ? parsed.path\n : resolve(projectRoot, parsed.path);\n // Discover which profile name lives at this path\n for (const prof of allProfiles) {\n if (prof.source === profileSource.source) {\n profileLocalPaths.set(prof.name, localPath);\n }\n }\n } else if (\n parsed.provider === \"github\" ||\n parsed.provider === \"gitlab\" ||\n parsed.provider === \"git\"\n ) {\n const url = parsed.provider === \"git\" ? parsed.url : parsed.url;\n\n // Use the already-resolved SHA from sourceShas (resolved in Step 1)\n const resolvedSha = sourceShas.get(profileSource.source);\n\n const cloned = await cloneGitSource({\n url,\n ref: resolvedSha || profileSource.version,\n subpath: \"subpath\" in parsed ? parsed.subpath : undefined,\n useCache: true,\n });\n for (const prof of allProfiles) {\n if (prof.source === profileSource.source) {\n profileLocalPaths.set(prof.name, cloned.localPath);\n }\n }\n }\n }\n\n // Register local paths for inherited profiles (from extends chains)\n // These profiles are not in baton.yaml but were resolved via resolveProfileChain\n for (const prof of allProfiles) {\n if (!profileLocalPaths.has(prof.name) && prof.localPath) {\n profileLocalPaths.set(prof.name, prof.localPath);\n }\n }\n\n // Content accumulator for files that may receive content from multiple categories\n // (e.g., GitHub Copilot uses .github/copilot-instructions.md for both memory AND rules)\n // Key: absolute target path, Value: { parts, adapter, profiles }\n const contentAccumulator = new Map<\n string,\n {\n parts: string[];\n adapter: AIToolAdapter;\n type: \"memory\" | \"rules\" | \"agents\";\n name: string;\n profiles: Set<string>;\n }\n >();\n\n // Accumulate memory file content\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing memory files...`);\n }\n for (const memoryEntry of mergedMemory) {\n try {\n // Read content from all contributing profiles\n const contentParts: string[] = [];\n for (const contribution of memoryEntry.contributions) {\n const profileDir = profileLocalPaths.get(contribution.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${contribution.profileName}`,\n );\n continue;\n }\n\n const memoryFilePath = resolve(profileDir, \"ai\", \"memory\", memoryEntry.filename);\n try {\n const content = await readFile(memoryFilePath, \"utf-8\");\n contentParts.push(content);\n } catch {\n spinner.message(`Warning: Could not read ${memoryFilePath}`);\n }\n }\n\n if (contentParts.length === 0) continue;\n\n // Merge content according to strategy\n const mergedContent = mergeContentParts(contentParts, memoryEntry.mergeStrategy);\n\n // Transform memory file for this adapter\n const transformed = adapter.transformMemory({\n filename: memoryEntry.filename,\n content: mergedContent,\n });\n\n // Compute target path to detect shared file destinations\n const targetPath = adapter.getPath(\"memory\", \"project\", transformed.filename);\n const absolutePath = targetPath.startsWith(\"/\")\n ? targetPath\n : resolve(projectRoot, targetPath);\n\n // Accumulate content for this target path\n const existing = contentAccumulator.get(absolutePath);\n if (existing) {\n existing.parts.push(transformed.content);\n for (const c of memoryEntry.contributions) existing.profiles.add(c.profileName);\n } else {\n const profiles = new Set<string>();\n for (const c of memoryEntry.contributions) profiles.add(c.profileName);\n contentAccumulator.set(absolutePath, {\n parts: [transformed.content],\n adapter,\n type: \"memory\",\n name: transformed.filename,\n profiles,\n });\n }\n } catch (error) {\n spinner.message(\n `Error placing ${memoryEntry.filename} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n\n // Place skill directories\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing skills...`);\n }\n for (const skillItem of mergedSkills) {\n try {\n const profileDir = profileLocalPaths.get(skillItem.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${skillItem.profileName}`,\n );\n continue;\n }\n\n const skillSourceDir = resolve(profileDir, \"ai\", \"skills\", skillItem.name);\n\n // Check if skill directory exists\n try {\n await stat(skillSourceDir);\n } catch {\n spinner.message(`Warning: Skill directory not found: ${skillSourceDir}`);\n continue;\n }\n\n // Resolve target skill directory\n const targetSkillPath = adapter.getPath(\"skills\", skillItem.scope, skillItem.name);\n const absoluteTargetDir = targetSkillPath.startsWith(\"/\")\n ? targetSkillPath\n : resolve(projectRoot, targetSkillPath);\n\n // Recursively copy skill files\n const placed = await copyDirectoryRecursive(skillSourceDir, absoluteTargetDir);\n stats.created += placed;\n\n // Track skill directory for lockfile integrity\n const profileFiles = getOrCreatePlacedFiles(placedFiles, skillItem.profileName);\n try {\n const entryContent = await readFile(resolve(skillSourceDir, \"index.md\"), \"utf-8\");\n profileFiles[targetSkillPath] = {\n content: entryContent,\n tool: adapter.key,\n category: \"ai\",\n };\n } catch {\n // Fallback: use skill name as marker\n profileFiles[targetSkillPath] = {\n content: skillItem.name,\n tool: adapter.key,\n category: \"ai\",\n };\n }\n\n if (verbose) {\n const label = placed > 0 ? `${placed} file(s) created` : \"unchanged, skipped\";\n p.log.info(` -> ${absoluteTargetDir}/ (${label})`);\n }\n } catch (error) {\n spinner.message(\n `Error placing skill ${skillItem.name} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n\n // Accumulate rule file content\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing rules...`);\n }\n for (const ruleEntry of mergedRules) {\n try {\n // Normalize: strip .md extension to prevent double-extension bug\n // (manifest may declare \"coding-standards.md\", path template appends \".md\" again)\n const ruleName = ruleEntry.name.replace(/\\.md$/, \"\");\n\n // Check if this rule should be placed for this adapter\n const isUniversal = ruleEntry.agents.length === 0;\n const isForThisAdapter = ruleEntry.agents.includes(adapter.key);\n if (!isUniversal && !isForThisAdapter) continue;\n\n const profileDir = profileLocalPaths.get(ruleEntry.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${ruleEntry.profileName}`,\n );\n continue;\n }\n\n // Determine source file path based on rule type\n const ruleSubdir = isUniversal ? \"universal\" : ruleEntry.agents[0];\n const ruleSourcePath = resolve(\n profileDir,\n \"ai\",\n \"rules\",\n ruleSubdir,\n `${ruleName}.md`,\n );\n\n // Read rule content\n let rawContent: string;\n try {\n rawContent = await readFile(ruleSourcePath, \"utf-8\");\n } catch {\n spinner.message(`Warning: Could not read rule file: ${ruleSourcePath}`);\n continue;\n }\n\n // Parse frontmatter\n const parsed = parseFrontmatter(rawContent);\n\n // Build canonical RuleFile\n const ruleFile: RuleFile = {\n name: ruleName,\n content: rawContent,\n frontmatter:\n Object.keys(parsed.data).length > 0\n ? (parsed.data as RuleFile[\"frontmatter\"])\n : undefined,\n };\n\n // Transform rule for this adapter\n const transformed = adapter.transformRule(ruleFile);\n\n // Compute target path to detect shared file destinations\n const targetPath = adapter.getPath(\"rules\", \"project\", ruleName);\n const absolutePath = targetPath.startsWith(\"/\")\n ? targetPath\n : resolve(projectRoot, targetPath);\n\n // Accumulate content for this target path\n const existing = contentAccumulator.get(absolutePath);\n if (existing) {\n existing.parts.push(transformed.content);\n existing.profiles.add(ruleEntry.profileName);\n } else {\n contentAccumulator.set(absolutePath, {\n parts: [transformed.content],\n adapter,\n type: \"rules\",\n name: ruleName,\n profiles: new Set([ruleEntry.profileName]),\n });\n }\n } catch (error) {\n spinner.message(`Error placing rule ${ruleEntry.name} for ${adapter.name}: ${error}`);\n stats.errors++;\n }\n }\n }\n }\n\n // Accumulate agent file content\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing agents...`);\n }\n for (const agentEntry of mergedAgents) {\n try {\n // Normalize: strip .md extension to prevent double-extension bug\n // (manifest may declare \"code-reviewer.md\", path template appends \".md\" again)\n const agentName = agentEntry.name.replace(/\\.md$/, \"\");\n\n // Check if this agent should be placed for this adapter\n const isUniversal = agentEntry.agents.length === 0;\n const isForThisAdapter = agentEntry.agents.includes(adapter.key);\n if (!isUniversal && !isForThisAdapter) continue;\n\n const profileDir = profileLocalPaths.get(agentEntry.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${agentEntry.profileName}`,\n );\n continue;\n }\n\n // Determine source file path based on agent type\n const agentSubdir = isUniversal ? \"universal\" : agentEntry.agents[0];\n const agentSourcePath = resolve(\n profileDir,\n \"ai\",\n \"agents\",\n agentSubdir,\n `${agentName}.md`,\n );\n\n // Read agent content\n let rawContent: string;\n try {\n rawContent = await readFile(agentSourcePath, \"utf-8\");\n } catch {\n spinner.message(`Warning: Could not read agent file: ${agentSourcePath}`);\n continue;\n }\n\n // Parse frontmatter\n const parsed = parseFrontmatter(rawContent);\n\n // Build canonical AgentFile (frontmatter is REQUIRED)\n const frontmatter =\n Object.keys(parsed.data).length > 0\n ? (parsed.data as AgentFile[\"frontmatter\"])\n : { name: agentName };\n const agentFile: AgentFile = {\n name: agentName,\n content: rawContent,\n description: (frontmatter as Record<string, unknown>).description as\n | string\n | undefined,\n frontmatter,\n };\n\n // Transform agent for this adapter\n const transformed = adapter.transformAgent(agentFile);\n\n // Compute target path to detect shared file destinations\n const targetPath = adapter.getPath(\"agents\", \"project\", agentName);\n const absolutePath = targetPath.startsWith(\"/\")\n ? targetPath\n : resolve(projectRoot, targetPath);\n\n // Accumulate content for this target path\n const existing = contentAccumulator.get(absolutePath);\n if (existing) {\n existing.parts.push(transformed.content);\n existing.profiles.add(agentEntry.profileName);\n } else {\n contentAccumulator.set(absolutePath, {\n parts: [transformed.content],\n adapter,\n type: \"agents\",\n name: agentName,\n profiles: new Set([agentEntry.profileName]),\n });\n }\n } catch (error) {\n spinner.message(\n `Error placing agent ${agentEntry.name} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n\n // Flush accumulated content: write combined memory+rules+agents to shared file paths\n if (!dryRun && syncAi) {\n for (const [absolutePath, entry] of contentAccumulator) {\n try {\n const combinedContent = entry.parts.join(\"\\n\\n\");\n const result = await placeFile(\n combinedContent,\n entry.adapter,\n entry.type,\n \"project\",\n entry.name,\n placementConfig,\n );\n\n if (result.action !== \"skipped\") {\n stats.created++;\n }\n\n // Track content for lockfile integrity (normalize to relative path)\n const relPath = isAbsolute(result.path)\n ? relative(projectRoot, result.path)\n : result.path;\n for (const profileName of entry.profiles) {\n const pf = getOrCreatePlacedFiles(placedFiles, profileName);\n pf[relPath] = {\n content: combinedContent,\n tool: entry.adapter.key,\n category: \"ai\",\n };\n }\n\n if (verbose) {\n const label = result.action === \"skipped\" ? \"unchanged, skipped\" : result.action;\n p.log.info(` -> ${result.path} (${label})`);\n }\n } catch (error) {\n spinner.message(`Error placing accumulated content to ${absolutePath}: ${error}`);\n stats.errors++;\n }\n }\n }\n\n // Place command files\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing commands...`);\n }\n for (const profile of allProfiles) {\n const profileDir = profileLocalPaths.get(profile.name);\n if (!profileDir) continue;\n\n const commandNames = profile.manifest.ai?.commands || [];\n for (const commandName of commandNames) {\n try {\n const commandSourcePath = resolve(\n profileDir,\n \"ai\",\n \"commands\",\n `${commandName}.md`,\n );\n\n let content: string;\n try {\n content = await readFile(commandSourcePath, \"utf-8\");\n } catch {\n // Gracefully skip missing command files\n continue;\n }\n\n const result = await placeFile(\n content,\n adapter,\n \"commands\",\n \"project\",\n commandName,\n placementConfig,\n );\n\n if (result.action !== \"skipped\") {\n stats.created++;\n }\n\n // Track content for lockfile integrity (normalize to relative path)\n const cmdRelPath = isAbsolute(result.path)\n ? relative(projectRoot, result.path)\n : result.path;\n const pf = getOrCreatePlacedFiles(placedFiles, profile.name);\n pf[cmdRelPath] = { content, tool: adapter.key, category: \"ai\" };\n\n if (verbose) {\n const label = result.action === \"skipped\" ? \"unchanged, skipped\" : result.action;\n p.log.info(` -> ${result.path} (${label})`);\n }\n } catch (error) {\n spinner.message(\n `Error placing command ${commandName} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n }\n\n // Place project files (files/ -> project root)\n if (!dryRun && syncFiles) {\n for (const fileEntry of fileMap.values()) {\n try {\n const profileDir = profileLocalPaths.get(fileEntry.profileName);\n if (!profileDir) continue;\n\n const fileSourcePath = resolve(profileDir, \"files\", fileEntry.source);\n\n let content: string;\n try {\n content = await readFile(fileSourcePath, \"utf-8\");\n } catch {\n // Gracefully skip missing files directories\n continue;\n }\n\n const targetPath = resolve(projectRoot, fileEntry.target);\n\n // Ensure target directory exists\n await mkdir(dirname(targetPath), { recursive: true });\n\n // Idempotency: skip if content is identical\n const existing = await readFile(targetPath, \"utf-8\").catch(() => undefined);\n if (existing !== content) {\n await writeFile(targetPath, content, \"utf-8\");\n stats.created++;\n if (verbose) {\n p.log.info(` -> ${fileEntry.target} (created)`);\n }\n } else if (verbose) {\n p.log.info(` -> ${fileEntry.target} (unchanged, skipped)`);\n }\n\n // Track content for lockfile integrity\n const fpf = getOrCreatePlacedFiles(placedFiles, fileEntry.profileName);\n fpf[fileEntry.target] = { content, category: \"files\" };\n } catch (error) {\n spinner.message(`Error placing file ${fileEntry.source}: ${error}`);\n stats.errors++;\n }\n }\n }\n\n // Place IDE config files (ide/vscode/ -> .vscode/, ide/jetbrains/ -> .idea/)\n // Only place files for IDE platforms in the intersection (if intersection is available)\n if (!dryRun && syncIde) {\n for (const ideEntry of ideMap.values()) {\n try {\n // Filter by intersection: skip IDE platforms not in the developer's synced set\n if (syncedIdePlatforms !== null && !syncedIdePlatforms.includes(ideEntry.ideKey)) {\n if (verbose) {\n p.log.info(\n ` -> ${ideEntry.targetDir}/${ideEntry.fileName} (skipped — IDE platform \"${ideEntry.ideKey}\" not in intersection)`,\n );\n }\n continue;\n }\n\n const profileDir = profileLocalPaths.get(ideEntry.profileName);\n if (!profileDir) continue;\n\n const ideSourcePath = resolve(profileDir, \"ide\", ideEntry.ideKey, ideEntry.fileName);\n\n let content: string;\n try {\n content = await readFile(ideSourcePath, \"utf-8\");\n } catch {\n // Gracefully skip missing IDE config files\n continue;\n }\n\n const targetPath = resolve(projectRoot, ideEntry.targetDir, ideEntry.fileName);\n\n // Ensure target directory exists\n await mkdir(dirname(targetPath), { recursive: true });\n\n // Idempotency: skip if content is identical\n const existing = await readFile(targetPath, \"utf-8\").catch(() => undefined);\n if (existing !== content) {\n await writeFile(targetPath, content, \"utf-8\");\n stats.created++;\n if (verbose) {\n p.log.info(` -> ${ideEntry.targetDir}/${ideEntry.fileName} (created)`);\n }\n } else if (verbose) {\n p.log.info(` -> ${ideEntry.targetDir}/${ideEntry.fileName} (unchanged, skipped)`);\n }\n\n // Track content for lockfile integrity\n const ideRelPath = `${ideEntry.targetDir}/${ideEntry.fileName}`;\n const ipf = getOrCreatePlacedFiles(placedFiles, ideEntry.profileName);\n ipf[ideRelPath] = {\n content,\n tool: ideEntry.ideKey,\n category: \"ide\",\n };\n } catch (error) {\n spinner.message(`Error placing IDE config ${ideEntry.fileName}: ${error}`);\n stats.errors++;\n }\n }\n }\n\n spinner.stop(\n dryRun\n ? `Would place files for ${adapters.length} agent(s)`\n : `Placed ${stats.created} file(s) for ${adapters.length} agent(s)`,\n );\n\n // Step 8: Update .gitignore\n if (!dryRun) {\n await handleGitignoreUpdate({\n projectManifest,\n fileMap,\n projectRoot,\n spinner,\n });\n }\n\n // Step 9: Write lockfile\n if (!dryRun) {\n await writeLockData({ allProfiles, sourceShas, placedFiles, projectRoot, spinner });\n }\n\n // Step 10: Remove orphaned files\n await cleanupOrphanedFiles({\n previousPaths,\n placedFiles,\n projectRoot,\n dryRun,\n autoYes,\n spinner,\n });\n\n // Summary\n if (dryRun) {\n const parts: string[] = [];\n if (syncAi) {\n parts.push(` • ${mergedSkills.length} skills`);\n parts.push(` • ${mergedRules.length} rules`);\n parts.push(` • ${mergedAgents.length} agents`);\n parts.push(` • ${mergedMemory.length} memory files`);\n parts.push(` • ${mergedCommandCount} commands`);\n }\n if (syncFiles) {\n parts.push(` • ${mergedFileCount} files`);\n }\n if (syncIde) {\n // Show filtered count when intersection is active\n const filteredIdeCount =\n syncedIdePlatforms !== null\n ? [...ideMap.values()].filter((e) => syncedIdePlatforms.includes(e.ideKey)).length\n : mergedIdeCount;\n parts.push(` • ${filteredIdeCount} IDE configs`);\n }\n const categoryLabel = category ? ` (category: ${category})` : \"\";\n p.outro(\n `[Dry Run${categoryLabel}] Would sync:\\n${parts.join(\"\\n\")}\\n\\nFor ${adapters.length} agent(s): ${syncedAiTools.join(\", \")}`,\n );\n } else {\n const categoryLabel = category ? ` (category: ${category})` : \"\";\n p.outro(`✅ Sync complete${categoryLabel}! Configurations updated.`);\n }\n\n process.exit(stats.errors > 0 ? 1 : 0);\n } catch (error) {\n p.cancel(`Sync failed: ${error}`);\n process.exit(1);\n }\n },\n});\n","import * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { syncCommand } from \"./sync.js\";\n\nexport const updateCommand = defineCommand({\n meta: {\n name: \"update\",\n description: \"(deprecated) Use 'baton sync' instead\",\n },\n args: {\n \"dry-run\": {\n type: \"boolean\",\n description: \"Show what would be done without writing files\",\n default: false,\n },\n category: {\n type: \"string\",\n description: \"Sync only a specific category: ai, files, or ide\",\n required: false,\n },\n yes: {\n type: \"boolean\",\n description: \"Run non-interactively (no prompts)\",\n default: false,\n },\n verbose: {\n type: \"boolean\",\n alias: \"v\",\n description: \"Show detailed output for each placed file\",\n default: false,\n },\n },\n async run(context) {\n p.log.warn(\"`baton update` is deprecated. Use `baton sync` instead.\");\n p.log.info(\"\");\n // Delegate to sync — pass full context through\n if (syncCommand.run) {\n await syncCommand.run(context);\n }\n },\n});\n","import { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { defineCommand, runMain } from \"citty\";\nimport { aiToolsCommand } from \"./commands/ai-tools/index.js\";\nimport { applyCommand } from \"./commands/apply.js\";\nimport { configCommand } from \"./commands/config/index.js\";\nimport { diffCommand } from \"./commands/diff.js\";\nimport { idesCommand } from \"./commands/ides/index.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { manageCommand } from \"./commands/manage.js\";\nimport { profileCommand } from \"./commands/profile/index.js\";\nimport { selfUpdateCommand } from \"./commands/self-update.js\";\nimport { sourceCommand } from \"./commands/source/index.js\";\nimport { syncCommand } from \"./commands/sync.js\";\nimport { updateCommand } from \"./commands/update.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nlet packageJson: { version?: string } = {};\ntry {\n packageJson = JSON.parse(await readFile(join(__dirname, \"../package.json\"), \"utf-8\"));\n} catch {\n // Gracefully handle missing or malformed package.json\n}\n\nconst main = defineCommand({\n meta: {\n name: \"baton\",\n version: packageJson.version,\n description:\n \"The package manager for Developer Experience & AI configuration. Manages Skills, Rules, Agents, Memory Files as versioned profiles.\",\n },\n args: {\n version: {\n type: \"boolean\",\n alias: \"v\",\n description: \"Show version number\",\n },\n yes: {\n type: \"boolean\",\n alias: \"y\",\n description: \"Suppress all interactive prompts (non-interactive mode)\",\n },\n \"dry-run\": {\n type: \"boolean\",\n description: \"Show what would be done without writing any files\",\n },\n verbose: {\n type: \"boolean\",\n description: \"Enable debug logging\",\n },\n },\n subCommands: {\n init: initCommand,\n apply: applyCommand,\n sync: syncCommand,\n update: updateCommand,\n diff: diffCommand,\n manage: manageCommand,\n config: configCommand,\n source: sourceCommand,\n profile: profileCommand,\n \"ai-tools\": aiToolsCommand,\n ides: idesCommand,\n \"self-update\": selfUpdateCommand,\n },\n run({ args }) {\n // Show help when no arguments provided\n if (Object.keys(args).length === 0) {\n console.log(`baton v${packageJson.version}`);\n console.log(\"\");\n console.log(\"The package manager for Developer Experience & AI configuration.\");\n console.log(\"\");\n console.log(\"Usage:\");\n console.log(\" baton <command> [options]\");\n console.log(\"\");\n console.log(\"Available commands:\");\n console.log(\" init Initialize Baton in your project\");\n console.log(\" apply Apply locked configurations (deterministic, reproducible)\");\n console.log(\" sync Fetch latest versions, sync, and update lockfile\");\n console.log(\" update (deprecated) Use 'baton sync' instead\");\n console.log(\" diff Compare local files with remote source versions\");\n console.log(\" manage Interactive project management wizard\");\n console.log(\" config Show dashboard overview or configure settings\");\n console.log(\"\");\n console.log(\"Resource commands:\");\n console.log(\" source Manage source repositories (create, list, connect, disconnect)\");\n console.log(\" profile Manage profiles (create, list, remove)\");\n console.log(\" ai-tools Manage AI tool detection and configuration\");\n console.log(\" ides Manage IDE platform detection and configuration\");\n console.log(\"\");\n console.log(\"Maintenance:\");\n console.log(\" self-update Update Baton to the latest stable version\");\n console.log(\"\");\n console.log(\"Global Options:\");\n console.log(\" --help, -h Show this help message\");\n console.log(\" --version, -v Show version number\");\n console.log(\" --yes, -y Suppress all interactive prompts\");\n console.log(\" --dry-run Show what would be done without writing files\");\n console.log(\" --verbose Enable debug logging\");\n return;\n }\n },\n});\n\nrunMain(main);\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["runProjectMode","runGlobalMode","p.multiselect","p.isCancel","p.select","p.spinner","p.multiselect","p.isCancel","formatIdeName","p.select","p.isCancel","p.multiselect","p.confirm","p.isCancel","p.spinner","simpleGit","loadProjectManifestSafe","p.spinner","formatIdeName","formatIdeName","p.multiselect","p.isCancel","p.select","formatIdeName","p.spinner","formatIdeName","p.multiselect","p.isCancel","p.spinner","p.select","p.isCancel","p.multiselect","p.spinner","p.select","p.isCancel","p.confirm","p.select","p.isCancel","p.confirm","p.multiselect","__dirname","p.spinner","p.confirm","p.isCancel","p.confirm","p.isCancel","__dirname","p.text","p.isCancel","p.confirm","Handlebars","simpleGit","p.spinner","p.confirm","p.isCancel","p.spinner","simpleGit"],"sources":["../src/commands/ai-tools/configure.ts","../src/commands/ai-tools/list.ts","../src/commands/ai-tools/scan.ts","../src/commands/ai-tools/index.ts","../src/utils/build-intersection.ts","../src/utils/first-run-preferences.ts","../src/utils/intersection-display.ts","../src/commands/sync-pipeline.ts","../src/commands/apply.ts","../src/commands/config/set.ts","../src/commands/config/index.ts","../src/commands/diff.ts","../src/commands/ides/utils.ts","../src/commands/ides/configure.ts","../src/commands/ides/list.ts","../src/commands/ides/scan.ts","../src/commands/ides/index.ts","../src/utils/profile-selection.ts","../src/utils/run-baton-sync.ts","../src/commands/init.ts","../src/commands/manage.ts","../src/commands/profile/index.ts","../src/commands/self-update.ts","../src/commands/source/connect.ts","../src/commands/source/create.ts","../src/commands/source/disconnect.ts","../src/commands/source/list.ts","../src/commands/source/index.ts","../src/commands/sync.ts","../src/commands/update.ts","../src/index.ts"],"sourcesContent":["import { stat } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport {\n getAllAIToolAdapters,\n getGlobalAiTools,\n readProjectPreferences,\n setGlobalAiTools,\n writeProjectPreferences,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\n\nexport const aiToolsConfigureCommand = defineCommand({\n meta: {\n name: \"configure\",\n description: \"Manually configure which AI tools Baton manages\",\n },\n args: {\n yes: {\n type: \"boolean\",\n alias: \"y\",\n description:\n \"Keep current selection unchanged (no-op), or with --project write useGlobal: true\",\n },\n project: {\n type: \"boolean\",\n description: \"Configure AI tools for this project instead of globally\",\n },\n },\n async run({ args }) {\n if (args.project) {\n await runProjectMode(args.yes ?? false);\n } else {\n await runGlobalMode(args.yes ?? false);\n }\n },\n});\n\nasync function runGlobalMode(nonInteractive: boolean): Promise<void> {\n p.intro(\"Baton - Configure AI Tools\");\n\n const currentTools = await getGlobalAiTools();\n\n // --yes flag is a no-op (keeps current selection unchanged)\n if (nonInteractive) {\n if (currentTools.length > 0) {\n p.log.info(`Current AI tools: ${currentTools.join(\", \")}`);\n } else {\n p.log.info(\"No AI tools currently configured.\");\n }\n p.outro(\"No changes made.\");\n return;\n }\n\n const allAdapters = getAllAIToolAdapters();\n\n const options = allAdapters.map((adapter) => {\n const isSaved = currentTools.includes(adapter.key);\n return {\n value: adapter.key,\n label: isSaved ? `${adapter.name} (currently saved)` : adapter.name,\n };\n });\n\n const selected = await p.multiselect({\n message: \"Select which AI tools to save:\",\n options,\n initialValues: currentTools,\n });\n\n if (p.isCancel(selected)) {\n p.outro(\"No changes made.\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n const hasChanges =\n selectedKeys.length !== currentTools.length ||\n selectedKeys.some((key) => !currentTools.includes(key));\n\n if (hasChanges) {\n await setGlobalAiTools(selectedKeys);\n p.log.success(`Saved ${selectedKeys.length} tool(s) to global config.`);\n } else {\n p.log.info(\"No changes made.\");\n }\n\n p.outro(\"Configuration complete.\");\n}\n\nasync function runProjectMode(nonInteractive: boolean): Promise<void> {\n p.intro(\"Baton - Configure AI Tools (Project)\");\n\n const projectRoot = process.cwd();\n const manifestPath = resolve(projectRoot, \"baton.yaml\");\n\n // Check that baton.yaml exists\n try {\n await stat(manifestPath);\n } catch {\n p.cancel(\"No baton.yaml found in current directory. Run `baton init` first.\");\n process.exit(1);\n }\n\n // --yes with --project writes useGlobal: true\n if (nonInteractive) {\n const existing = await readProjectPreferences(projectRoot);\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: { useGlobal: true, tools: existing?.ai.tools ?? [] },\n ide: existing?.ide ?? { useGlobal: true, platforms: [] },\n });\n p.log.info(\"Set AI tools to use global config for this project.\");\n p.outro(\"Configuration complete.\");\n return;\n }\n\n const existing = await readProjectPreferences(projectRoot);\n const globalTools = await getGlobalAiTools();\n\n // Show current state\n if (globalTools.length > 0) {\n p.log.info(`Global AI tools: ${globalTools.join(\", \")}`);\n }\n\n // Ask useGlobal first\n const mode = await p.select({\n message: \"How should this project resolve AI tools?\",\n options: [\n {\n value: \"global\",\n label: \"Use global config\",\n hint: \"always follows your global AI tools setting\",\n },\n {\n value: \"project\",\n label: \"Customize for this project\",\n hint: \"choose specific tools for this project\",\n },\n ],\n initialValue: existing?.ai.useGlobal === false ? \"project\" : \"global\",\n });\n\n if (p.isCancel(mode)) {\n p.outro(\"No changes made.\");\n return;\n }\n\n if (mode === \"global\") {\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: { useGlobal: true, tools: [] },\n ide: existing?.ide ?? { useGlobal: true, platforms: [] },\n });\n p.log.success(\"Project configured to use global AI tools.\");\n p.outro(\"Configuration complete.\");\n return;\n }\n\n // Customize: show multiselect\n const allAdapters = getAllAIToolAdapters();\n const currentProjectTools = existing?.ai.useGlobal === false ? existing.ai.tools : globalTools;\n\n const options = allAdapters.map((adapter) => {\n const isGlobal = globalTools.includes(adapter.key);\n return {\n value: adapter.key,\n label: isGlobal ? `${adapter.name} (in global config)` : adapter.name,\n };\n });\n\n const selected = await p.multiselect({\n message: \"Select AI tools for this project:\",\n options,\n initialValues: currentProjectTools,\n });\n\n if (p.isCancel(selected)) {\n p.outro(\"No changes made.\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: { useGlobal: false, tools: selectedKeys },\n ide: existing?.ide ?? { useGlobal: true, platforms: [] },\n });\n p.log.success(`Project configured with ${selectedKeys.length} AI tool(s).`);\n p.outro(\"Configuration complete.\");\n}\n","import { readdir, stat } from \"node:fs/promises\";\nimport { getAIToolConfig, getAIToolPath, getAllAIToolKeys } from \"@baton-dx/ai-tool-paths\";\nimport { getGlobalAiTools } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\n\nexport const aiToolsListCommand = defineCommand({\n meta: {\n name: \"list\",\n description: \"Show saved AI tools from global config and their configuration status\",\n },\n args: {\n all: {\n type: \"boolean\",\n alias: \"a\",\n description: \"Show all supported tools, not just saved ones\",\n },\n json: {\n type: \"boolean\",\n description: \"Output machine-readable JSON\",\n alias: \"j\",\n },\n },\n async run({ args }) {\n if (!args.json) {\n p.intro(\"Baton - AI Tools\");\n }\n\n // Load saved tools from global config\n const savedTools = await getGlobalAiTools();\n const allAIToolKeys = getAllAIToolKeys();\n\n // Determine which tools to show\n const keysToShow = args.all\n ? allAIToolKeys\n : savedTools.length > 0\n ? savedTools\n : allAIToolKeys;\n\n const toolStatuses = await Promise.all(\n keysToShow.map(async (toolKey) => {\n const isSaved = savedTools.includes(toolKey);\n\n // Count installed configs for this tool\n let skillCount = 0;\n let ruleCount = 0;\n let aiToolConfigCount = 0;\n let memoryCount = 0;\n let commandCount = 0;\n\n if (isSaved) {\n skillCount = await countConfigs(toolKey, \"skills\", \"project\");\n ruleCount = await countConfigs(toolKey, \"rules\", \"project\");\n aiToolConfigCount = await countConfigs(toolKey, \"agents\", \"project\");\n memoryCount = await countConfigs(toolKey, \"memory\", \"project\");\n commandCount = await countConfigs(toolKey, \"commands\", \"project\");\n }\n\n // Get path locations for each config type\n const paths = {\n skills: getAIToolPath(toolKey, \"skills\", \"project\", \"\"),\n rules: getAIToolPath(toolKey, \"rules\", \"project\", \"\"),\n agents: getAIToolPath(toolKey, \"agents\", \"project\", \"\"),\n memory: getAIToolPath(toolKey, \"memory\", \"project\", \"\"),\n commands: getAIToolPath(toolKey, \"commands\", \"project\", \"\"),\n };\n\n const config = getAIToolConfig(toolKey);\n\n return {\n key: toolKey,\n name: config.name,\n saved: isSaved,\n counts: {\n skills: skillCount,\n rules: ruleCount,\n agents: aiToolConfigCount,\n memory: memoryCount,\n commands: commandCount,\n },\n paths,\n };\n }),\n );\n\n // JSON output\n if (args.json) {\n console.log(JSON.stringify(toolStatuses, null, 2));\n return;\n }\n\n // Formatted output\n if (savedTools.length === 0) {\n p.log.warn(\"No AI tools saved in global config.\");\n p.log.info(\"Run 'baton ai-tools scan' to detect and save your AI tools.\");\n console.log(\"\");\n p.log.info(`All ${allAIToolKeys.length} supported tools:`);\n for (const key of allAIToolKeys) {\n const config = getAIToolConfig(key);\n console.log(` \\x1b[90m- ${config.name}\\x1b[0m`);\n }\n p.outro(\"Run 'baton ai-tools scan' to get started.\");\n return;\n }\n\n console.log(`\\nSaved AI tools (${savedTools.length}):\\n`);\n\n for (const agent of toolStatuses) {\n const statusColor = agent.saved ? \"\\x1b[32m\" : \"\\x1b[90m\";\n const status = agent.saved ? \"✓\" : \"✗\";\n const resetColor = \"\\x1b[0m\";\n\n console.log(`${statusColor}${status}${resetColor} ${agent.name.padEnd(20)}`);\n\n if (agent.saved) {\n const totalConfigs =\n agent.counts.skills +\n agent.counts.rules +\n agent.counts.agents +\n agent.counts.memory +\n agent.counts.commands;\n\n if (totalConfigs > 0) {\n const details = [];\n if (agent.counts.skills > 0) details.push(`${agent.counts.skills} skills`);\n if (agent.counts.rules > 0) details.push(`${agent.counts.rules} rules`);\n if (agent.counts.agents > 0) details.push(`${agent.counts.agents} agents`);\n if (agent.counts.memory > 0) details.push(`${agent.counts.memory} memory`);\n if (agent.counts.commands > 0) details.push(`${agent.counts.commands} commands`);\n\n console.log(` → ${details.join(\", \")}`);\n }\n }\n\n console.log(\"\");\n }\n\n p.outro(\"Manage tools: 'baton ai-tools scan' (detect) | 'baton ai-tools configure' (select)\");\n },\n});\n\n/**\n * Count config files of a given type for a tool\n */\nasync function countConfigs(\n toolKey: string,\n configType: \"skills\" | \"rules\" | \"agents\" | \"memory\" | \"commands\",\n scope: \"project\" | \"global\",\n): Promise<number> {\n try {\n const basePath = getAIToolPath(toolKey, configType, scope, \"\");\n const dirPath = basePath.replace(/{name}.*$/, \"\").replace(/\\/$/, \"\");\n\n const stats = await stat(dirPath);\n if (!stats.isDirectory()) {\n return 0;\n }\n\n const items = await readdir(dirPath);\n return items.length;\n } catch (_error) {\n return 0;\n }\n}\n","import {\n clearAIToolCache,\n detectInstalledAITools,\n getAllAIToolAdapters,\n getGlobalAiTools,\n setGlobalAiTools,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\n\nexport const aiToolsScanCommand = defineCommand({\n meta: {\n name: \"scan\",\n description: \"Scan your system for AI tools and save results to global config\",\n },\n args: {\n yes: {\n type: \"boolean\",\n alias: \"y\",\n description: \"Automatically save detected tools without confirmation\",\n },\n },\n async run({ args }) {\n p.intro(\"Baton - AI Tool Scanner\");\n\n const spinner = p.spinner();\n spinner.start(\"Scanning for AI tools...\");\n\n // Clear cache to force fresh detection\n clearAIToolCache();\n\n const detectedAITools = await detectInstalledAITools();\n const allAdapters = getAllAIToolAdapters();\n const currentTools = await getGlobalAiTools();\n\n spinner.stop(\"Scan complete.\");\n\n if (detectedAITools.length > 0) {\n p.log.success(\n `Found ${detectedAITools.length} AI tool${detectedAITools.length !== 1 ? \"s\" : \"\"} on your system.`,\n );\n } else {\n p.log.warn(\"No AI tools detected on your system.\");\n }\n\n // --yes flag: save only detected tools (preserves current behavior)\n if (args.yes) {\n const detectedKeys = detectedAITools;\n const hasChanges =\n detectedKeys.length !== currentTools.length ||\n detectedKeys.some((key) => !currentTools.includes(key));\n\n if (hasChanges) {\n await setGlobalAiTools(detectedKeys);\n p.log.success(`Saved ${detectedKeys.length} detected tool(s) to global config.`);\n } else {\n p.log.info(\"Global config is already up to date.\");\n }\n\n p.outro(\"Scan finished.\");\n return;\n }\n\n // Interactive: show multiselect with all 14 tools\n const options = allAdapters.map((adapter) => {\n const isDetected = detectedAITools.includes(adapter.key);\n return {\n value: adapter.key,\n label: isDetected ? `${adapter.name} (detected)` : adapter.name,\n };\n });\n\n const selected = await p.multiselect({\n message: \"Select which AI tools to save:\",\n options,\n initialValues: detectedAITools,\n });\n\n if (p.isCancel(selected)) {\n p.outro(\"Scan finished (not saved).\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n const hasChanges =\n selectedKeys.length !== currentTools.length ||\n selectedKeys.some((key) => !currentTools.includes(key));\n\n if (hasChanges) {\n await setGlobalAiTools(selectedKeys);\n p.log.success(`Saved ${selectedKeys.length} tool(s) to global config.`);\n } else {\n p.log.info(\"Global config is already up to date.\");\n }\n\n p.outro(\"Scan finished.\");\n },\n});\n","import { defineCommand } from \"citty\";\nimport { aiToolsConfigureCommand } from \"./configure.js\";\nimport { aiToolsListCommand } from \"./list.js\";\nimport { aiToolsScanCommand } from \"./scan.js\";\n\nexport const aiToolsCommand = defineCommand({\n meta: {\n name: \"ai-tools\",\n description: \"Manage AI tool detection and configuration\",\n },\n subCommands: {\n configure: aiToolsConfigureCommand,\n list: aiToolsListCommand,\n scan: aiToolsScanCommand,\n },\n});\n","import { resolve } from \"node:path\";\nimport type { IntersectionResult, SourceManifest } from \"@baton-dx/core\";\nimport {\n cloneGitSource,\n computeIntersection,\n findSourceManifest,\n loadProfileManifest,\n parseSource,\n resolveProfileSupport,\n} from \"@baton-dx/core\";\nimport { findSourceRoot } from \"./context-detection.js\";\n\n/**\n * Compute the intersection for a single profile source string.\n * Shared utility used by sync, config, and manage commands.\n *\n * @returns IntersectionResult or null if intersection cannot be computed\n */\nexport async function buildIntersection(\n sourceString: string,\n developerTools: { aiTools: string[]; idePlatforms: string[] },\n cwd: string,\n): Promise<IntersectionResult | null> {\n const parsed = parseSource(sourceString);\n\n let repoRoot: string;\n let profileDir: string;\n\n if (parsed.provider === \"github\" || parsed.provider === \"gitlab\") {\n const repoClone = await cloneGitSource({\n url: parsed.url,\n ref: parsed.ref,\n useCache: true,\n });\n repoRoot = repoClone.localPath;\n profileDir = parsed.subpath ? resolve(repoRoot, parsed.subpath) : repoRoot;\n } else if (parsed.provider === \"local\" || parsed.provider === \"file\") {\n const absolutePath = parsed.path.startsWith(\"/\") ? parsed.path : resolve(cwd, parsed.path);\n profileDir = absolutePath;\n repoRoot = (await findSourceRoot(absolutePath, { fallbackToStart: true })) as string;\n } else {\n return null;\n }\n\n // Load source manifest (optional)\n let sourceManifest: SourceManifest;\n try {\n sourceManifest = await findSourceManifest(repoRoot);\n } catch {\n sourceManifest = { name: \"unknown\", version: \"0.0.0\" } as SourceManifest;\n }\n\n // Load profile manifest\n const profileManifestPath = resolve(profileDir, \"baton.profile.yaml\");\n const profileManifest = await loadProfileManifest(profileManifestPath).catch(() => null);\n if (!profileManifest) return null;\n\n const profileSupport = resolveProfileSupport(profileManifest, sourceManifest);\n return computeIntersection(developerTools, profileSupport);\n}\n","import {\n getAllAIToolAdapters,\n getGlobalAiTools,\n getGlobalIdePlatforms,\n getRegisteredIdePlatforms,\n readProjectPreferences,\n writeProjectPreferences,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\n\n/**\n * Format an IDE platform key into a display name.\n * Duplicated here to avoid circular dependency with ides/utils.\n */\nfunction formatIdeName(ideKey: string): string {\n const names: Record<string, string> = {\n vscode: \"VS Code\",\n jetbrains: \"JetBrains\",\n cursor: \"Cursor\",\n windsurf: \"Windsurf\",\n antigravity: \"Antigravity\",\n zed: \"Zed\",\n };\n return names[ideKey] ?? ideKey;\n}\n\n/**\n * Shows the first-run preferences prompt if .baton/preferences.yaml doesn't exist.\n *\n * Asks the user whether to use global config or customize AI tools and IDEs\n * for this project, then writes the preferences file.\n *\n * @param projectRoot - Absolute path to the project root\n * @param nonInteractive - If true, writes useGlobal: true silently\n * @returns true if preferences were written, false if already existed\n */\nexport async function promptFirstRunPreferences(\n projectRoot: string,\n nonInteractive: boolean,\n): Promise<boolean> {\n const existing = await readProjectPreferences(projectRoot);\n if (existing) {\n return false;\n }\n\n // --yes mode: write useGlobal: true silently\n if (nonInteractive) {\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: { useGlobal: true, tools: [] },\n ide: { useGlobal: true, platforms: [] },\n });\n return true;\n }\n\n // AI tools prompt\n const aiMode = await p.select({\n message: \"How do you want to configure AI tools for this project?\",\n options: [\n { value: \"global\", label: \"Use global config\", hint: \"recommended\" },\n { value: \"customize\", label: \"Customize for this project\" },\n ],\n });\n\n if (p.isCancel(aiMode)) {\n return false;\n }\n\n let aiUseGlobal = true;\n let aiTools: string[] = [];\n\n if (aiMode === \"customize\") {\n const globalTools = await getGlobalAiTools();\n const allAdapters = getAllAIToolAdapters();\n\n const selected = await p.multiselect({\n message: \"Select AI tools for this project:\",\n options: allAdapters.map((adapter) => ({\n value: adapter.key,\n label: globalTools.includes(adapter.key)\n ? `${adapter.name} (in global config)`\n : adapter.name,\n })),\n initialValues: globalTools,\n });\n\n if (p.isCancel(selected)) {\n return false;\n }\n\n aiUseGlobal = false;\n aiTools = selected as string[];\n }\n\n // IDE platforms prompt\n const ideMode = await p.select({\n message: \"How do you want to configure IDE platforms for this project?\",\n options: [\n { value: \"global\", label: \"Use global config\", hint: \"recommended\" },\n { value: \"customize\", label: \"Customize for this project\" },\n ],\n });\n\n if (p.isCancel(ideMode)) {\n return false;\n }\n\n let ideUseGlobal = true;\n let idePlatforms: string[] = [];\n\n if (ideMode === \"customize\") {\n const globalPlatforms = await getGlobalIdePlatforms();\n const allIdeKeys = getRegisteredIdePlatforms();\n\n const selected = await p.multiselect({\n message: \"Select IDE platforms for this project:\",\n options: allIdeKeys.map((ideKey) => ({\n value: ideKey,\n label: globalPlatforms.includes(ideKey)\n ? `${formatIdeName(ideKey)} (in global config)`\n : formatIdeName(ideKey),\n })),\n initialValues: globalPlatforms,\n });\n\n if (p.isCancel(selected)) {\n return false;\n }\n\n ideUseGlobal = false;\n idePlatforms = selected as string[];\n }\n\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: { useGlobal: aiUseGlobal, tools: aiTools },\n ide: { useGlobal: ideUseGlobal, platforms: idePlatforms },\n });\n\n return true;\n}\n","import type { DimensionIntersection, IntersectionResult } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\n\n/**\n * Display the intersection between developer tools and profile support.\n * Shows which tools/platforms will be synced, which are unsupported, and which are unavailable.\n *\n * Used by `baton init` (after profile selection) and `baton manage` (overview).\n */\nexport function displayIntersection(intersection: IntersectionResult): void {\n const hasAiData =\n intersection.aiTools.synced.length > 0 ||\n intersection.aiTools.unsupported.length > 0 ||\n intersection.aiTools.unavailable.length > 0;\n\n const hasIdeData =\n intersection.idePlatforms.synced.length > 0 ||\n intersection.idePlatforms.unsupported.length > 0 ||\n intersection.idePlatforms.unavailable.length > 0;\n\n if (!hasAiData && !hasIdeData) {\n p.log.info(\"No tool or IDE intersection data available.\");\n return;\n }\n\n if (hasAiData) {\n displayDimension(\"AI Tools\", intersection.aiTools);\n }\n\n if (hasIdeData) {\n displayDimension(\"IDE Platforms\", intersection.idePlatforms);\n }\n}\n\n/**\n * Display a single dimension (AI tools or IDE platforms) of the intersection.\n */\nfunction displayDimension(label: string, dimension: DimensionIntersection): void {\n const lines: string[] = [];\n\n if (dimension.synced.length > 0) {\n for (const item of dimension.synced) {\n lines.push(` \\u2713 ${item}`);\n }\n }\n\n if (dimension.unavailable.length > 0) {\n for (const item of dimension.unavailable) {\n lines.push(` - ${item} (not installed)`);\n }\n }\n\n if (dimension.unsupported.length > 0) {\n for (const item of dimension.unsupported) {\n lines.push(` ~ ${item} (not supported by profile)`);\n }\n }\n\n if (lines.length > 0) {\n p.note(lines.join(\"\\n\"), label);\n }\n}\n\n/**\n * Format a compact intersection summary for inline display.\n * Example: \"claude-code, cursor (AI) + vscode (IDE)\"\n */\nexport function formatIntersectionSummary(intersection: IntersectionResult): string {\n const parts: string[] = [];\n\n if (intersection.aiTools.synced.length > 0) {\n parts.push(`${intersection.aiTools.synced.join(\", \")} (AI)`);\n }\n\n if (intersection.idePlatforms.synced.length > 0) {\n parts.push(`${intersection.idePlatforms.synced.join(\", \")} (IDE)`);\n }\n\n if (parts.length === 0) {\n return \"No matching tools\";\n }\n\n return parts.join(\" + \");\n}\n","import { mkdir, readFile, readdir, writeFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport {\n type LockFileEntry,\n type PlacementState,\n type ProjectManifest,\n collectComprehensivePatterns,\n ensureBatonDirGitignored,\n generateLock,\n readState,\n removeGitignoreManagedSection,\n removePlacedFiles,\n updateGitignore,\n writeLock,\n writeState,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\n\nexport type SyncCategory = \"ai\" | \"files\" | \"ide\";\nexport const validCategories: SyncCategory[] = [\"ai\", \"files\", \"ide\"];\n\nexport interface SyncStats {\n created: number;\n errors: number;\n}\n\n/** Get or initialize placed files for a profile, avoiding unsafe `as` casts on Map.get(). */\nexport function getOrCreatePlacedFiles(\n map: Map<string, Record<string, LockFileEntry>>,\n profileName: string,\n): Record<string, LockFileEntry> {\n let files = map.get(profileName);\n if (!files) {\n files = {};\n map.set(profileName, files);\n }\n return files;\n}\n\n/**\n * Recursively copy all files from sourceDir to targetDir.\n * Returns the number of files written (skips identical content).\n */\nexport async function copyDirectoryRecursive(\n sourceDir: string,\n targetDir: string,\n): Promise<number> {\n await mkdir(targetDir, { recursive: true });\n const entries = await readdir(sourceDir, { withFileTypes: true });\n let placed = 0;\n\n for (const entry of entries) {\n const sourcePath = resolve(sourceDir, entry.name);\n const targetPath = resolve(targetDir, entry.name);\n\n if (entry.isDirectory()) {\n placed += await copyDirectoryRecursive(sourcePath, targetPath);\n } else {\n const content = await readFile(sourcePath, \"utf-8\");\n // Idempotency: skip if content is identical\n const existing = await readFile(targetPath, \"utf-8\").catch(() => undefined);\n if (existing !== content) {\n await writeFile(targetPath, content, \"utf-8\");\n placed++;\n }\n }\n }\n\n return placed;\n}\n\n/**\n * Handle .gitignore update based on the project manifest's gitignore setting.\n *\n * When gitignore is enabled (default): writes comprehensive patterns for ALL\n * known AI tools and IDE platforms to ensure stable, dev-independent content.\n * When disabled: removes any existing managed section.\n * Always ensures .baton/ is gitignored regardless of setting.\n */\nexport async function handleGitignoreUpdate(params: {\n projectManifest: ProjectManifest;\n fileMap: Map<string, { source: string; target: string; profileName: string }>;\n projectRoot: string;\n spinner: ReturnType<typeof p.spinner>;\n}): Promise<void> {\n const { projectManifest, fileMap, projectRoot, spinner } = params;\n const gitignoreEnabled = projectManifest.gitignore !== false;\n\n // Always ensure .baton/ is gitignored\n await ensureBatonDirGitignored(projectRoot);\n\n if (gitignoreEnabled) {\n spinner.start(\"Updating .gitignore...\");\n const fileTargets = [...fileMap.values()].map((f) => f.target);\n const patterns = collectComprehensivePatterns({ fileTargets });\n const updated = await updateGitignore(projectRoot, patterns);\n spinner.stop(\n updated ? \"Updated .gitignore with managed patterns\" : \".gitignore already up to date\",\n );\n } else {\n spinner.start(\"Checking .gitignore...\");\n const removed = await removeGitignoreManagedSection(projectRoot);\n spinner.stop(removed ? \"Removed managed section from .gitignore\" : \".gitignore unchanged\");\n }\n}\n\n/**\n * Generate and write the baton.lock lockfile from placed files and profile metadata.\n */\nexport async function writeLockData(params: {\n allProfiles: Array<{ name: string; source: string; manifest: { version: string } }>;\n sourceShas: Map<string, string>;\n placedFiles: Map<string, Record<string, LockFileEntry>>;\n projectRoot: string;\n spinner: ReturnType<typeof p.spinner>;\n}): Promise<void> {\n const { allProfiles, sourceShas, placedFiles, projectRoot, spinner } = params;\n\n spinner.start(\"Updating lockfile...\");\n\n const lockPackages: Record<\n string,\n {\n source: string;\n resolved: string;\n version: string;\n sha: string;\n files: Record<string, string | LockFileEntry>;\n }\n > = {};\n\n for (const profile of allProfiles) {\n lockPackages[profile.name] = {\n source: profile.source,\n resolved: profile.source,\n version: profile.manifest.version,\n sha: sourceShas.get(profile.source) || \"unknown\",\n files: placedFiles.get(profile.name) || {},\n };\n }\n\n const lockData = generateLock(lockPackages);\n await writeLock(lockData, resolve(projectRoot, \"baton.lock\"));\n\n spinner.stop(\"Lockfile updated\");\n}\n\n/**\n * Write local placement state to `.baton/state.yaml`.\n * Tracks tool-specific file paths placed on disk for orphan detection.\n */\nexport async function writeStateData(params: {\n actualPlacedPaths: Set<string>;\n syncedAiTools: string[];\n projectRoot: string;\n spinner: ReturnType<typeof p.spinner>;\n}): Promise<void> {\n const { actualPlacedPaths, syncedAiTools, projectRoot, spinner } = params;\n\n spinner.start(\"Writing local state...\");\n\n const state: PlacementState = {\n synced_at: new Date().toISOString(),\n tools: syncedAiTools,\n placed_files: [...actualPlacedPaths].sort(),\n };\n\n await writeState(projectRoot, state);\n spinner.stop(\"Local state updated\");\n}\n\n/**\n * Load previous tool-specific paths for orphan detection.\n *\n * Reads from `.baton/state.yaml` (preferred). Falls back to extracting paths\n * from an old-format `baton.lock` (legacy tool-specific keys) for migration.\n */\nexport async function loadPreviousPlacedPaths(projectRoot: string): Promise<Set<string>> {\n // Preferred: read from local state\n const state = await readState(projectRoot);\n if (state) {\n return new Set(state.placed_files);\n }\n\n // Legacy fallback: extract tool-specific paths from old baton.lock\n // (These are paths like `.claude/skills/foo` which were used as lockfile keys before)\n try {\n const { readLock } = await import(\"@baton-dx/core\");\n const lockfilePath = resolve(projectRoot, \"baton.lock\");\n const previousLock = await readLock(lockfilePath);\n const paths = new Set<string>();\n for (const pkg of Object.values(previousLock.packages)) {\n for (const filePath of Object.keys(pkg.integrity)) {\n // Only include paths that look tool-specific (contain a dot-prefixed directory)\n // Canonical paths like `skills/foo` are NOT tool-specific disk paths\n if (filePath.startsWith(\".\") || filePath.includes(\"/\")) {\n paths.add(filePath);\n }\n }\n }\n return paths;\n } catch {\n return new Set();\n }\n}\n\n/**\n * Detect and remove files that were previously placed but are no longer\n * part of the current sync. Compares tool-specific paths from state.yaml\n * against currently placed paths. Cleans up empty parent directories.\n */\nexport async function cleanupOrphanedFiles(params: {\n previousPaths: Set<string>;\n currentPaths: Set<string>;\n projectRoot: string;\n dryRun: boolean;\n autoYes: boolean;\n spinner: ReturnType<typeof p.spinner>;\n}): Promise<void> {\n const { previousPaths, currentPaths, projectRoot, dryRun, autoYes, spinner } = params;\n\n if (previousPaths.size === 0) return;\n\n // Find orphaned paths (in previous state but not in current sync)\n const orphanedPaths = [...previousPaths].filter((prev) => !currentPaths.has(prev));\n if (orphanedPaths.length === 0) return;\n\n if (dryRun) {\n p.log.warn(`Would remove ${orphanedPaths.length} orphaned file(s):`);\n for (const orphanedPath of orphanedPaths) {\n p.log.info(` Removed: ${orphanedPath}`);\n }\n return;\n }\n\n p.log.warn(`Found ${orphanedPaths.length} orphaned file(s) to remove:`);\n for (const orphanedPath of orphanedPaths) {\n p.log.info(` Removed: ${orphanedPath}`);\n }\n\n let shouldRemove = autoYes;\n if (!autoYes) {\n const confirmed = await p.confirm({\n message: `Remove ${orphanedPaths.length} orphaned file(s)?`,\n initialValue: true,\n });\n if (p.isCancel(confirmed)) {\n p.log.info(\"Skipped orphan removal.\");\n shouldRemove = false;\n } else {\n shouldRemove = confirmed;\n }\n }\n\n if (!shouldRemove) {\n p.log.info(\"Orphan removal skipped.\");\n return;\n }\n\n spinner.start(\"Removing orphaned files...\");\n const removedCount = await removePlacedFiles(orphanedPaths, projectRoot);\n spinner.stop(`Removed ${removedCount} orphaned file(s)`);\n}\n","import { mkdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, relative, resolve } from \"node:path\";\nimport {\n type AIToolAdapter,\n type AgentEntry,\n type AgentFile,\n type CloneContext,\n FileNotFoundError,\n type LockFile,\n type LockFileEntry,\n type MemoryEntry,\n type MergedSkillItem,\n type ParsedSource,\n type ProjectManifest,\n type RuleEntry,\n type RuleFile,\n type WeightConflictWarning,\n cloneGitSource,\n detectInstalledAITools,\n detectLegacyPaths,\n getAIToolAdaptersForKeys,\n getIdePlatformTargetDir,\n getProfileWeight,\n isKnownIdePlatform,\n isLockedProfile,\n loadProfileManifest,\n loadProjectManifest,\n mergeAgentsWithWarnings,\n mergeContentParts,\n mergeMemoryWithWarnings,\n mergeRulesWithWarnings,\n mergeSkillsWithWarnings,\n parseFrontmatter,\n parseSource,\n placeFile,\n readLock,\n resolvePreferences,\n resolveProfileChain,\n sortProfilesByWeight,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport simpleGit from \"simple-git\";\nimport { buildIntersection } from \"../utils/build-intersection.js\";\nimport { promptFirstRunPreferences } from \"../utils/first-run-preferences.js\";\nimport { displayIntersection, formatIntersectionSummary } from \"../utils/intersection-display.js\";\nimport {\n type SyncCategory,\n type SyncStats,\n cleanupOrphanedFiles,\n copyDirectoryRecursive,\n getOrCreatePlacedFiles,\n handleGitignoreUpdate,\n loadPreviousPlacedPaths,\n validCategories,\n writeLockData,\n writeStateData,\n} from \"./sync-pipeline.js\";\n\n/** Extract the package name from a source string for lockfile lookup. */\nfunction getPackageNameFromSource(source: string, parsed: ParsedSource): string {\n if (parsed.provider === \"github\" || parsed.provider === \"gitlab\") {\n return `${parsed.org}/${parsed.repo}`;\n }\n if (parsed.provider === \"npm\") {\n return parsed.scope ? `${parsed.scope}/${parsed.package}` : parsed.package;\n }\n if (parsed.provider === \"git\") {\n return parsed.url;\n }\n return source;\n}\n\nexport const applyCommand = defineCommand({\n meta: {\n name: \"apply\",\n description: \"Apply locked configurations to the project (deterministic, reproducible)\",\n },\n args: {\n \"dry-run\": {\n type: \"boolean\",\n description: \"Show what would be done without writing files\",\n default: false,\n },\n category: {\n type: \"string\",\n description: \"Apply only a specific category: ai, files, or ide\",\n required: false,\n },\n yes: {\n type: \"boolean\",\n description: \"Run non-interactively (no prompts)\",\n default: false,\n },\n verbose: {\n type: \"boolean\",\n alias: \"v\",\n description: \"Show detailed output for each placed file\",\n default: false,\n },\n fresh: {\n type: \"boolean\",\n description: \"Force cache bypass (re-clone even if cached)\",\n default: false,\n },\n },\n async run({ args }) {\n const dryRun = args[\"dry-run\"];\n const categoryArg = args.category as string | undefined;\n const autoYes = args.yes;\n const verbose = args.verbose;\n const fresh = args.fresh;\n\n // Validate --category flag\n let category: SyncCategory | undefined;\n if (categoryArg) {\n if (!validCategories.includes(categoryArg as SyncCategory)) {\n p.cancel(\n `Invalid category \"${categoryArg}\". Valid categories: ${validCategories.join(\", \")}`,\n );\n process.exit(1);\n }\n category = categoryArg as SyncCategory;\n }\n\n const syncAi = !category || category === \"ai\";\n const syncFiles = !category || category === \"files\";\n const syncIde = !category || category === \"ide\";\n\n p.intro(category ? `📦 Baton Apply (category: ${category})` : \"📦 Baton Apply\");\n\n // Statistics tracking\n const stats: SyncStats = {\n created: 0,\n errors: 0,\n };\n\n try {\n // Step 0: Load project manifest\n const projectRoot = process.cwd();\n const manifestPath = resolve(projectRoot, \"baton.yaml\");\n\n let projectManifest: ProjectManifest;\n try {\n projectManifest = await loadProjectManifest(manifestPath);\n } catch (error) {\n if (error instanceof FileNotFoundError) {\n p.cancel(\"baton.yaml not found. Run `baton init` first.\");\n } else {\n p.cancel(\n `Failed to load baton.yaml: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n process.exit(1);\n }\n\n // Step 0a: First-run preferences check\n await promptFirstRunPreferences(projectRoot, !!args.yes);\n\n // Step 0b: Read lockfile for locked SHAs\n const lockfilePath = resolve(projectRoot, \"baton.lock\");\n let lockfile: LockFile | null = null;\n try {\n lockfile = await readLock(lockfilePath);\n } catch {\n // No lockfile — fall back to manifest versions\n if (verbose) {\n p.log.warn(\"No lockfile found. Falling back to manifest versions.\");\n }\n }\n\n // Step 0c: Compute cache TTL (apply uses cache by default, --fresh bypasses)\n const maxCacheAgeMs = fresh ? 0 : undefined;\n\n // Step 0d: Read previous placement state to detect orphaned files later\n // Uses .baton/state.yaml (preferred) or falls back to old lockfile keys (legacy migration)\n const previousPaths = await loadPreviousPlacedPaths(projectRoot);\n\n // Step 1: Resolve profile chain\n const spinner = p.spinner();\n spinner.start(\"Resolving profile chain...\");\n\n const allProfiles = [];\n // Track SHA per source for lockfile\n const sourceShas = new Map<string, string>();\n for (const profileSource of projectManifest.profiles || []) {\n try {\n if (verbose) {\n p.log.info(`Resolving source: ${profileSource.source}`);\n }\n // Load the profile manifest first\n const parsed = parseSource(profileSource.source);\n\n let manifestPath: string;\n let cloneContext: CloneContext | undefined;\n if (parsed.provider === \"local\" || parsed.provider === \"file\") {\n const absolutePath = parsed.path.startsWith(\"/\")\n ? parsed.path\n : resolve(projectRoot, parsed.path);\n manifestPath = resolve(absolutePath, \"baton.profile.yaml\");\n // Try to get SHA from local git repo, fallback to \"local\"\n try {\n const git = simpleGit(absolutePath);\n await git.checkIsRepo();\n const sha = await git.revparse([\"HEAD\"]);\n sourceShas.set(profileSource.source, sha.trim());\n } catch {\n sourceShas.set(profileSource.source, \"local\");\n }\n } else {\n // For remote sources, clone first\n const url =\n parsed.provider === \"github\" || parsed.provider === \"gitlab\"\n ? parsed.url\n : parsed.provider === \"git\"\n ? parsed.url\n : \"\";\n\n if (!url) {\n throw new Error(`Invalid source: ${profileSource.source}`);\n }\n\n // Determine ref: use locked SHA if available, otherwise profileSource.version\n let ref = profileSource.version;\n if (lockfile) {\n const packageName = getPackageNameFromSource(profileSource.source, parsed);\n const lockedPkg = lockfile.packages[packageName];\n if (lockedPkg?.sha && lockedPkg.sha !== \"unknown\") {\n ref = lockedPkg.sha;\n if (verbose) {\n p.log.info(`Using locked SHA for ${profileSource.source}: ${ref.slice(0, 12)}`);\n }\n }\n }\n\n const cloned = await cloneGitSource({\n url,\n ref,\n subpath: \"subpath\" in parsed ? parsed.subpath : undefined,\n useCache: true,\n maxCacheAgeMs,\n });\n manifestPath = resolve(cloned.localPath, \"baton.profile.yaml\");\n sourceShas.set(profileSource.source, cloned.sha);\n cloneContext = {\n cachePath: cloned.cachePath,\n sparseCheckout: cloned.sparseCheckout,\n };\n }\n\n const manifest = await loadProfileManifest(manifestPath);\n const profileDir = dirname(manifestPath);\n const chain = await resolveProfileChain(\n manifest,\n profileSource.source,\n profileDir,\n cloneContext,\n );\n allProfiles.push(...chain);\n } catch (error) {\n spinner.stop(`Failed to resolve profile ${profileSource.source}: ${error}`);\n stats.errors++;\n }\n }\n\n if (allProfiles.length === 0) {\n spinner.stop(\"No profiles configured\");\n p.outro(\"Nothing to apply. Run `baton manage` to add a profile.\");\n process.exit(2);\n }\n\n spinner.stop(`Resolved ${allProfiles.length} profile(s)`);\n\n // Step 1b: Sort profiles by weight for merge ordering\n const weightSortedProfiles = sortProfilesByWeight(allProfiles);\n\n // Step 2: Merge configurations\n spinner.start(\"Merging configurations...\");\n\n const allWeightWarnings: WeightConflictWarning[] = [];\n\n const skillsResult = mergeSkillsWithWarnings(weightSortedProfiles);\n const mergedSkills: MergedSkillItem[] = skillsResult.skills;\n allWeightWarnings.push(...skillsResult.warnings);\n\n const rulesResult = mergeRulesWithWarnings(weightSortedProfiles);\n const mergedRules: RuleEntry[] = rulesResult.rules;\n allWeightWarnings.push(...rulesResult.warnings);\n\n const agentsResult = mergeAgentsWithWarnings(weightSortedProfiles);\n const mergedAgents: AgentEntry[] = agentsResult.agents;\n allWeightWarnings.push(...agentsResult.warnings);\n\n const memoryResult = mergeMemoryWithWarnings(weightSortedProfiles);\n const mergedMemory: MemoryEntry[] = memoryResult.entries;\n allWeightWarnings.push(...memoryResult.warnings);\n\n // Collect all commands from all profiles (deduplicated by name, last wins)\n const commandMap = new Map<string, string>();\n const lockedCommands = new Set<string>();\n const commandOwner = new Map<string, { profileName: string; weight: number }>();\n for (const profile of weightSortedProfiles) {\n const weight = getProfileWeight(profile);\n const locked = isLockedProfile(profile);\n for (const cmd of profile.manifest.ai?.commands || []) {\n if (lockedCommands.has(cmd)) continue;\n\n const existing = commandOwner.get(cmd);\n if (existing && existing.weight === weight && existing.profileName !== profile.name) {\n allWeightWarnings.push({\n key: cmd,\n category: \"command\",\n profileA: existing.profileName,\n profileB: profile.name,\n weight,\n });\n }\n\n commandMap.set(cmd, profile.name);\n commandOwner.set(cmd, { profileName: profile.name, weight });\n if (locked) lockedCommands.add(cmd);\n }\n }\n const mergedCommandCount = commandMap.size;\n\n // Collect all files from all profiles (deduplicated by target path, last wins)\n const fileMap = new Map<string, { source: string; target: string; profileName: string }>();\n const lockedFiles = new Set<string>();\n const fileOwner = new Map<string, { profileName: string; weight: number }>();\n for (const profile of weightSortedProfiles) {\n const weight = getProfileWeight(profile);\n const locked = isLockedProfile(profile);\n for (const fileConfig of profile.manifest.files || []) {\n const target = fileConfig.target || fileConfig.source;\n if (lockedFiles.has(target)) continue;\n\n const existing = fileOwner.get(target);\n if (existing && existing.weight === weight && existing.profileName !== profile.name) {\n allWeightWarnings.push({\n key: target,\n category: \"file\",\n profileA: existing.profileName,\n profileB: profile.name,\n weight,\n });\n }\n\n fileMap.set(target, { source: fileConfig.source, target, profileName: profile.name });\n fileOwner.set(target, { profileName: profile.name, weight });\n if (locked) lockedFiles.add(target);\n }\n }\n const mergedFileCount = fileMap.size;\n\n // Collect all IDE configs from all profiles\n const ideMap = new Map<\n string,\n { ideKey: string; fileName: string; targetDir: string; profileName: string }\n >();\n const lockedIdeConfigs = new Set<string>();\n const ideOwner = new Map<string, { profileName: string; weight: number }>();\n for (const profile of weightSortedProfiles) {\n if (!profile.manifest.ide) continue;\n const weight = getProfileWeight(profile);\n const locked = isLockedProfile(profile);\n for (const [ideKey, files] of Object.entries(profile.manifest.ide)) {\n if (!files) continue;\n const targetDir = getIdePlatformTargetDir(ideKey);\n if (!targetDir) {\n if (!isKnownIdePlatform(ideKey)) {\n p.log.warn(\n `Unknown IDE platform \"${ideKey}\" in profile \"${profile.name}\" — skipping. Register it in the IDE platform registry.`,\n );\n }\n continue;\n }\n for (const fileName of files) {\n const targetPath = `${targetDir}/${fileName}`;\n if (lockedIdeConfigs.has(targetPath)) continue;\n\n const existing = ideOwner.get(targetPath);\n if (existing && existing.weight === weight && existing.profileName !== profile.name) {\n allWeightWarnings.push({\n key: targetPath,\n category: \"ide\",\n profileA: existing.profileName,\n profileB: profile.name,\n weight,\n });\n }\n\n ideMap.set(targetPath, { ideKey, fileName, targetDir, profileName: profile.name });\n ideOwner.set(targetPath, { profileName: profile.name, weight });\n if (locked) lockedIdeConfigs.add(targetPath);\n }\n }\n }\n const mergedIdeCount = ideMap.size;\n\n spinner.stop(\n `Merged: ${mergedSkills.length} skills, ${mergedRules.length} rules, ${mergedAgents.length} agents, ${mergedMemory.length} memory files, ${mergedCommandCount} commands, ${mergedFileCount} files, ${mergedIdeCount} IDE configs`,\n );\n\n // Emit weight conflict warnings\n if (allWeightWarnings.length > 0) {\n for (const w of allWeightWarnings) {\n p.log.warn(\n `Weight conflict: \"${w.profileA}\" and \"${w.profileB}\" both define ${w.category} \"${w.key}\" with weight ${w.weight}. Last declared wins.`,\n );\n }\n }\n\n // Step 3: Determine which AI tools and IDE platforms to sync (intersection-based)\n spinner.start(\"Computing tool intersection...\");\n\n const prefs = await resolvePreferences(projectRoot);\n const detectedAITools = await detectInstalledAITools();\n\n if (verbose) {\n p.log.info(\n `AI tools: ${prefs.ai.tools.join(\", \") || \"(none)\"} (from ${prefs.ai.source} preferences)`,\n );\n p.log.info(\n `IDE platforms: ${prefs.ide.platforms.join(\", \") || \"(none)\"} (from ${prefs.ide.source} preferences)`,\n );\n }\n\n let syncedAiTools: string[];\n let syncedIdePlatforms: string[] | null = null;\n let allIntersections: Map<string, import(\"@baton-dx/core\").IntersectionResult> | null = null;\n\n if (prefs.ai.tools.length > 0) {\n const developerTools = { aiTools: prefs.ai.tools, idePlatforms: prefs.ide.platforms };\n const aggregatedSyncedAi = new Set<string>();\n const aggregatedSyncedIde = new Set<string>();\n allIntersections = new Map();\n\n for (const profileSource of projectManifest.profiles || []) {\n try {\n const intersection = await buildIntersection(\n profileSource.source,\n developerTools,\n projectRoot,\n );\n if (intersection) {\n allIntersections.set(profileSource.source, intersection);\n for (const tool of intersection.aiTools.synced) {\n aggregatedSyncedAi.add(tool);\n }\n for (const platform of intersection.idePlatforms.synced) {\n aggregatedSyncedIde.add(platform);\n }\n }\n } catch {\n // Best-effort — skip if intersection cannot be computed for this profile\n }\n }\n\n syncedAiTools = aggregatedSyncedAi.size > 0 ? [...aggregatedSyncedAi] : [];\n syncedIdePlatforms = [...aggregatedSyncedIde];\n } else {\n syncedAiTools = detectedAITools;\n syncedIdePlatforms = null;\n if (detectedAITools.length > 0) {\n p.log.warn(\"No AI tools configured. Run `baton ai-tools scan` to configure your tools.\");\n p.log.info(`Falling back to detected tools: ${detectedAITools.join(\", \")}`);\n }\n }\n\n if (syncedAiTools.length === 0 && detectedAITools.length === 0) {\n spinner.stop(\"No AI tools available\");\n p.cancel(\"No AI tools found. Install an AI coding tool first.\");\n process.exit(1);\n }\n\n if (syncedAiTools.length === 0) {\n spinner.stop(\"No AI tools in intersection\");\n p.cancel(\n \"No AI tools match between your configuration and profile support. \" +\n \"Run `baton ai-tools scan` or check your profile's supported tools.\",\n );\n process.exit(1);\n }\n\n if (allIntersections) {\n for (const [source, intersection] of allIntersections) {\n if (verbose) {\n p.log.step(`Intersection for ${source}`);\n displayIntersection(intersection);\n } else {\n const summary = formatIntersectionSummary(intersection);\n p.log.info(`Applying for: ${summary}`);\n }\n }\n }\n\n const ideSummary =\n syncedIdePlatforms && syncedIdePlatforms.length > 0\n ? ` | IDE platforms: ${syncedIdePlatforms.join(\", \")}`\n : \"\";\n spinner.stop(`Applying to AI tools: ${syncedAiTools.join(\", \")}${ideSummary}`);\n\n // Step 4: Migrate legacy paths\n spinner.start(\"Checking for legacy paths...\");\n\n const legacyFiles = await detectLegacyPaths(projectRoot);\n\n if (legacyFiles.length > 0 && !dryRun) {\n spinner.stop(`Found ${legacyFiles.length} legacy file(s)`);\n\n if (!autoYes) {\n p.note(\n `Found legacy configuration files:\\n${legacyFiles.map((f) => ` - ${f.legacyPath}`).join(\"\\n\")}`,\n \"Legacy Files\",\n );\n p.log.warn(\"Run migration manually with appropriate action (migrate/copy/skip)\");\n }\n } else {\n spinner.stop(\"No legacy files found\");\n }\n\n // Step 5-7: Transform, Place, and Link\n spinner.start(\"Processing configurations...\");\n\n const adapters = getAIToolAdaptersForKeys(syncedAiTools);\n\n const placementConfig = {\n mode: \"copy\" as const,\n projectRoot,\n };\n\n // Track placed file contents per profile for lockfile integrity hashes\n // Keys are CANONICAL paths (e.g., \"skills/add-adapter\", \"memory/MEMORY.md\")\n const placedFiles = new Map<string, Record<string, LockFileEntry>>();\n\n // Track ACTUAL tool-specific file paths placed on disk\n const actualPlacedPaths = new Set<string>();\n\n // Build a map from profile name to local directory path\n const profileLocalPaths = new Map<string, string>();\n for (const profileSource of projectManifest.profiles || []) {\n const parsed = parseSource(profileSource.source);\n if (parsed.provider === \"local\" || parsed.provider === \"file\") {\n const localPath = parsed.path.startsWith(\"/\")\n ? parsed.path\n : resolve(projectRoot, parsed.path);\n for (const prof of allProfiles) {\n if (prof.source === profileSource.source) {\n profileLocalPaths.set(prof.name, localPath);\n }\n }\n } else if (\n parsed.provider === \"github\" ||\n parsed.provider === \"gitlab\" ||\n parsed.provider === \"git\"\n ) {\n const url = parsed.provider === \"git\" ? parsed.url : parsed.url;\n\n // Use locked SHA for deterministic clone\n let ref = profileSource.version;\n if (lockfile) {\n const packageName = getPackageNameFromSource(profileSource.source, parsed);\n const lockedPkg = lockfile.packages[packageName];\n if (lockedPkg?.sha && lockedPkg.sha !== \"unknown\") {\n ref = lockedPkg.sha;\n }\n }\n\n const cloned = await cloneGitSource({\n url,\n ref,\n subpath: \"subpath\" in parsed ? parsed.subpath : undefined,\n useCache: true,\n maxCacheAgeMs,\n });\n for (const prof of allProfiles) {\n if (prof.source === profileSource.source) {\n profileLocalPaths.set(prof.name, cloned.localPath);\n }\n }\n }\n }\n\n // Register local paths for inherited profiles (from extends chains)\n for (const prof of allProfiles) {\n if (!profileLocalPaths.has(prof.name) && prof.localPath) {\n profileLocalPaths.set(prof.name, prof.localPath);\n }\n }\n\n // Content accumulator for files that may receive content from multiple categories\n const contentAccumulator = new Map<\n string,\n {\n parts: string[];\n adapter: AIToolAdapter;\n type: \"memory\" | \"rules\" | \"agents\";\n name: string;\n profiles: Set<string>;\n }\n >();\n\n // Accumulate memory file content\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing memory files...`);\n }\n for (const memoryEntry of mergedMemory) {\n try {\n const contentParts: string[] = [];\n for (const contribution of memoryEntry.contributions) {\n const profileDir = profileLocalPaths.get(contribution.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${contribution.profileName}`,\n );\n continue;\n }\n\n const memoryFilePath = resolve(profileDir, \"ai\", \"memory\", memoryEntry.filename);\n try {\n const content = await readFile(memoryFilePath, \"utf-8\");\n contentParts.push(content);\n } catch {\n spinner.message(`Warning: Could not read ${memoryFilePath}`);\n }\n }\n\n if (contentParts.length === 0) continue;\n\n const mergedContent = mergeContentParts(contentParts, memoryEntry.mergeStrategy);\n\n const transformed = adapter.transformMemory({\n filename: memoryEntry.filename,\n content: mergedContent,\n });\n\n const targetPath = adapter.getPath(\"memory\", \"project\", transformed.filename);\n const absolutePath = targetPath.startsWith(\"/\")\n ? targetPath\n : resolve(projectRoot, targetPath);\n\n const existing = contentAccumulator.get(absolutePath);\n if (existing) {\n existing.parts.push(transformed.content);\n for (const c of memoryEntry.contributions) existing.profiles.add(c.profileName);\n } else {\n const profiles = new Set<string>();\n for (const c of memoryEntry.contributions) profiles.add(c.profileName);\n contentAccumulator.set(absolutePath, {\n parts: [transformed.content],\n adapter,\n type: \"memory\",\n name: transformed.filename,\n profiles,\n });\n }\n } catch (error) {\n spinner.message(\n `Error placing ${memoryEntry.filename} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n\n // Place skill directories\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing skills...`);\n }\n for (const skillItem of mergedSkills) {\n try {\n const profileDir = profileLocalPaths.get(skillItem.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${skillItem.profileName}`,\n );\n continue;\n }\n\n const skillSourceDir = resolve(profileDir, \"ai\", \"skills\", skillItem.name);\n\n try {\n await stat(skillSourceDir);\n } catch {\n spinner.message(`Warning: Skill directory not found: ${skillSourceDir}`);\n continue;\n }\n\n const targetSkillPath = adapter.getPath(\"skills\", skillItem.scope, skillItem.name);\n const absoluteTargetDir = targetSkillPath.startsWith(\"/\")\n ? targetSkillPath\n : resolve(projectRoot, targetSkillPath);\n\n const placed = await copyDirectoryRecursive(skillSourceDir, absoluteTargetDir);\n stats.created += placed;\n\n // Track tool-specific disk path for state/orphan detection\n actualPlacedPaths.add(targetSkillPath);\n\n // Track canonical key + source content for lockfile integrity (once per skill)\n const canonicalKey = `skills/${skillItem.name}`;\n const profileFiles = getOrCreatePlacedFiles(placedFiles, skillItem.profileName);\n if (!profileFiles[canonicalKey]) {\n try {\n const entryContent = await readFile(resolve(skillSourceDir, \"index.md\"), \"utf-8\");\n profileFiles[canonicalKey] = { content: entryContent, type: \"skills\" };\n } catch {\n profileFiles[canonicalKey] = { content: skillItem.name, type: \"skills\" };\n }\n }\n\n if (verbose) {\n const label = placed > 0 ? `${placed} file(s) created` : \"unchanged, skipped\";\n p.log.info(` -> ${absoluteTargetDir}/ (${label})`);\n }\n } catch (error) {\n spinner.message(\n `Error placing skill ${skillItem.name} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n\n // Accumulate rule file content\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing rules...`);\n }\n for (const ruleEntry of mergedRules) {\n try {\n const ruleName = ruleEntry.name.replace(/\\.md$/, \"\");\n\n const isUniversal = ruleEntry.agents.length === 0;\n const isForThisAdapter = ruleEntry.agents.includes(adapter.key);\n if (!isUniversal && !isForThisAdapter) continue;\n\n const profileDir = profileLocalPaths.get(ruleEntry.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${ruleEntry.profileName}`,\n );\n continue;\n }\n\n const ruleSubdir = isUniversal ? \"universal\" : ruleEntry.agents[0];\n const ruleSourcePath = resolve(\n profileDir,\n \"ai\",\n \"rules\",\n ruleSubdir,\n `${ruleName}.md`,\n );\n\n let rawContent: string;\n try {\n rawContent = await readFile(ruleSourcePath, \"utf-8\");\n } catch {\n spinner.message(`Warning: Could not read rule file: ${ruleSourcePath}`);\n continue;\n }\n\n const parsed = parseFrontmatter(rawContent);\n\n const ruleFile: RuleFile = {\n name: ruleName,\n content: rawContent,\n frontmatter:\n Object.keys(parsed.data).length > 0\n ? (parsed.data as RuleFile[\"frontmatter\"])\n : undefined,\n };\n\n const transformed = adapter.transformRule(ruleFile);\n\n const targetPath = adapter.getPath(\"rules\", \"project\", ruleName);\n const absolutePath = targetPath.startsWith(\"/\")\n ? targetPath\n : resolve(projectRoot, targetPath);\n\n const existing = contentAccumulator.get(absolutePath);\n if (existing) {\n existing.parts.push(transformed.content);\n existing.profiles.add(ruleEntry.profileName);\n } else {\n contentAccumulator.set(absolutePath, {\n parts: [transformed.content],\n adapter,\n type: \"rules\",\n name: ruleName,\n profiles: new Set([ruleEntry.profileName]),\n });\n }\n } catch (error) {\n spinner.message(`Error placing rule ${ruleEntry.name} for ${adapter.name}: ${error}`);\n stats.errors++;\n }\n }\n }\n }\n\n // Accumulate agent file content\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing agents...`);\n }\n for (const agentEntry of mergedAgents) {\n try {\n const agentName = agentEntry.name.replace(/\\.md$/, \"\");\n\n const isUniversal = agentEntry.agents.length === 0;\n const isForThisAdapter = agentEntry.agents.includes(adapter.key);\n if (!isUniversal && !isForThisAdapter) continue;\n\n const profileDir = profileLocalPaths.get(agentEntry.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${agentEntry.profileName}`,\n );\n continue;\n }\n\n const agentSubdir = isUniversal ? \"universal\" : agentEntry.agents[0];\n const agentSourcePath = resolve(\n profileDir,\n \"ai\",\n \"agents\",\n agentSubdir,\n `${agentName}.md`,\n );\n\n let rawContent: string;\n try {\n rawContent = await readFile(agentSourcePath, \"utf-8\");\n } catch {\n spinner.message(`Warning: Could not read agent file: ${agentSourcePath}`);\n continue;\n }\n\n const parsed = parseFrontmatter(rawContent);\n\n const frontmatter =\n Object.keys(parsed.data).length > 0\n ? (parsed.data as AgentFile[\"frontmatter\"])\n : { name: agentName };\n const agentFile: AgentFile = {\n name: agentName,\n content: rawContent,\n description: (frontmatter as Record<string, unknown>).description as\n | string\n | undefined,\n frontmatter,\n };\n\n const transformed = adapter.transformAgent(agentFile);\n\n const targetPath = adapter.getPath(\"agents\", \"project\", agentName);\n const absolutePath = targetPath.startsWith(\"/\")\n ? targetPath\n : resolve(projectRoot, targetPath);\n\n const existing = contentAccumulator.get(absolutePath);\n if (existing) {\n existing.parts.push(transformed.content);\n existing.profiles.add(agentEntry.profileName);\n } else {\n contentAccumulator.set(absolutePath, {\n parts: [transformed.content],\n adapter,\n type: \"agents\",\n name: agentName,\n profiles: new Set([agentEntry.profileName]),\n });\n }\n } catch (error) {\n spinner.message(\n `Error placing agent ${agentEntry.name} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n\n // Flush accumulated content\n if (!dryRun && syncAi) {\n for (const [absolutePath, entry] of contentAccumulator) {\n try {\n const combinedContent = entry.parts.join(\"\\n\\n\");\n const result = await placeFile(\n combinedContent,\n entry.adapter,\n entry.type,\n \"project\",\n entry.name,\n placementConfig,\n );\n\n if (result.action !== \"skipped\") {\n stats.created++;\n }\n\n // Track tool-specific disk path for state/orphan detection\n const relPath = isAbsolute(result.path)\n ? relative(projectRoot, result.path)\n : result.path;\n actualPlacedPaths.add(relPath);\n\n // Track canonical key + source content for lockfile integrity\n const canonicalKey = `${entry.type}/${entry.name}`;\n for (const profileName of entry.profiles) {\n const pf = getOrCreatePlacedFiles(placedFiles, profileName);\n if (!pf[canonicalKey]) {\n pf[canonicalKey] = {\n content: combinedContent,\n type: entry.type as LockFileEntry[\"type\"],\n };\n }\n }\n\n if (verbose) {\n const label = result.action === \"skipped\" ? \"unchanged, skipped\" : result.action;\n p.log.info(` -> ${result.path} (${label})`);\n }\n } catch (error) {\n spinner.message(`Error placing accumulated content to ${absolutePath}: ${error}`);\n stats.errors++;\n }\n }\n }\n\n // Place command files\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing commands...`);\n }\n for (const profile of allProfiles) {\n const profileDir = profileLocalPaths.get(profile.name);\n if (!profileDir) continue;\n\n const commandNames = profile.manifest.ai?.commands || [];\n for (const commandName of commandNames) {\n try {\n const commandSourcePath = resolve(\n profileDir,\n \"ai\",\n \"commands\",\n `${commandName}.md`,\n );\n\n let content: string;\n try {\n content = await readFile(commandSourcePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const result = await placeFile(\n content,\n adapter,\n \"commands\",\n \"project\",\n commandName,\n placementConfig,\n );\n\n if (result.action !== \"skipped\") {\n stats.created++;\n }\n\n // Track tool-specific disk path for state/orphan detection\n const cmdRelPath = isAbsolute(result.path)\n ? relative(projectRoot, result.path)\n : result.path;\n actualPlacedPaths.add(cmdRelPath);\n\n // Track canonical key + source content for lockfile (once per command)\n const canonicalKey = `commands/${commandName}`;\n const pf = getOrCreatePlacedFiles(placedFiles, profile.name);\n if (!pf[canonicalKey]) {\n pf[canonicalKey] = { content, type: \"commands\" };\n }\n\n if (verbose) {\n const label = result.action === \"skipped\" ? \"unchanged, skipped\" : result.action;\n p.log.info(` -> ${result.path} (${label})`);\n }\n } catch (error) {\n spinner.message(\n `Error placing command ${commandName} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n }\n\n // Place project files\n if (!dryRun && syncFiles) {\n for (const fileEntry of fileMap.values()) {\n try {\n const profileDir = profileLocalPaths.get(fileEntry.profileName);\n if (!profileDir) continue;\n\n const fileSourcePath = resolve(profileDir, \"files\", fileEntry.source);\n\n let content: string;\n try {\n content = await readFile(fileSourcePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const targetPath = resolve(projectRoot, fileEntry.target);\n\n await mkdir(dirname(targetPath), { recursive: true });\n\n const existing = await readFile(targetPath, \"utf-8\").catch(() => undefined);\n if (existing !== content) {\n await writeFile(targetPath, content, \"utf-8\");\n stats.created++;\n if (verbose) {\n p.log.info(` -> ${fileEntry.target} (created)`);\n }\n } else if (verbose) {\n p.log.info(` -> ${fileEntry.target} (unchanged, skipped)`);\n }\n\n // Track disk path for state/orphan detection\n actualPlacedPaths.add(fileEntry.target);\n\n // Track canonical key for lockfile integrity\n const canonicalKey = `files/${fileEntry.target}`;\n const fpf = getOrCreatePlacedFiles(placedFiles, fileEntry.profileName);\n if (!fpf[canonicalKey]) {\n fpf[canonicalKey] = { content, type: \"files\" };\n }\n } catch (error) {\n spinner.message(`Error placing file ${fileEntry.source}: ${error}`);\n stats.errors++;\n }\n }\n }\n\n // Place IDE config files\n if (!dryRun && syncIde) {\n for (const ideEntry of ideMap.values()) {\n try {\n if (syncedIdePlatforms !== null && !syncedIdePlatforms.includes(ideEntry.ideKey)) {\n if (verbose) {\n p.log.info(\n ` -> ${ideEntry.targetDir}/${ideEntry.fileName} (skipped — IDE platform \"${ideEntry.ideKey}\" not in intersection)`,\n );\n }\n continue;\n }\n\n const profileDir = profileLocalPaths.get(ideEntry.profileName);\n if (!profileDir) continue;\n\n const ideSourcePath = resolve(profileDir, \"ide\", ideEntry.ideKey, ideEntry.fileName);\n\n let content: string;\n try {\n content = await readFile(ideSourcePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const targetPath = resolve(projectRoot, ideEntry.targetDir, ideEntry.fileName);\n\n await mkdir(dirname(targetPath), { recursive: true });\n\n const existing = await readFile(targetPath, \"utf-8\").catch(() => undefined);\n if (existing !== content) {\n await writeFile(targetPath, content, \"utf-8\");\n stats.created++;\n if (verbose) {\n p.log.info(` -> ${ideEntry.targetDir}/${ideEntry.fileName} (created)`);\n }\n } else if (verbose) {\n p.log.info(` -> ${ideEntry.targetDir}/${ideEntry.fileName} (unchanged, skipped)`);\n }\n\n // Track disk path for state/orphan detection\n const ideRelPath = `${ideEntry.targetDir}/${ideEntry.fileName}`;\n actualPlacedPaths.add(ideRelPath);\n\n // Track canonical key for lockfile integrity\n const canonicalKey = `ide/${ideEntry.ideKey}/${ideEntry.fileName}`;\n const ipf = getOrCreatePlacedFiles(placedFiles, ideEntry.profileName);\n if (!ipf[canonicalKey]) {\n ipf[canonicalKey] = { content, type: \"ide\" };\n }\n } catch (error) {\n spinner.message(`Error placing IDE config ${ideEntry.fileName}: ${error}`);\n stats.errors++;\n }\n }\n }\n\n spinner.stop(\n dryRun\n ? `Would place files for ${adapters.length} agent(s)`\n : `Placed ${stats.created} file(s) for ${adapters.length} agent(s)`,\n );\n\n // Step 8: Update .gitignore\n if (!dryRun) {\n await handleGitignoreUpdate({\n projectManifest,\n fileMap,\n projectRoot,\n spinner,\n });\n }\n\n // Step 9: Write lockfile (canonical keys, tool-agnostic)\n if (!dryRun) {\n await writeLockData({ allProfiles, sourceShas, placedFiles, projectRoot, spinner });\n }\n\n // Step 9b: Write local state (tool-specific disk paths, never committed)\n if (!dryRun) {\n await writeStateData({\n actualPlacedPaths,\n syncedAiTools,\n projectRoot,\n spinner,\n });\n }\n\n // Step 10: Remove orphaned files (comparing tool-specific disk paths)\n await cleanupOrphanedFiles({\n previousPaths,\n currentPaths: actualPlacedPaths,\n projectRoot,\n dryRun,\n autoYes,\n spinner,\n });\n\n // Summary\n if (dryRun) {\n const parts: string[] = [];\n if (syncAi) {\n parts.push(` • ${mergedSkills.length} skills`);\n parts.push(` • ${mergedRules.length} rules`);\n parts.push(` • ${mergedAgents.length} agents`);\n parts.push(` • ${mergedMemory.length} memory files`);\n parts.push(` • ${mergedCommandCount} commands`);\n }\n if (syncFiles) {\n parts.push(` • ${mergedFileCount} files`);\n }\n if (syncIde) {\n const filteredIdeCount =\n syncedIdePlatforms !== null\n ? [...ideMap.values()].filter((e) => syncedIdePlatforms.includes(e.ideKey)).length\n : mergedIdeCount;\n parts.push(` • ${filteredIdeCount} IDE configs`);\n }\n const categoryLabel = category ? ` (category: ${category})` : \"\";\n p.outro(\n `[Dry Run${categoryLabel}] Would apply:\\n${parts.join(\"\\n\")}\\n\\nFor ${adapters.length} agent(s): ${syncedAiTools.join(\", \")}`,\n );\n } else {\n const categoryLabel = category ? ` (category: ${category})` : \"\";\n p.outro(`✅ Apply complete${categoryLabel}! Locked configurations applied.`);\n }\n\n process.exit(stats.errors > 0 ? 1 : 0);\n } catch (error) {\n p.cancel(`Apply failed: ${error}`);\n process.exit(1);\n }\n },\n});\n","import { loadGlobalConfig, saveGlobalConfig } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\n\n/**\n * Set a value in the global Baton config (~/.baton/config.yaml).\n *\n * Supports dotted paths like \"sync.cacheTtlHours\" to set nested values.\n * Usage: baton config set <key> <value>\n */\nexport const configSetCommand = defineCommand({\n meta: {\n name: \"set\",\n description: \"Set a global config value (e.g., baton config set sync.cacheTtlHours 1)\",\n },\n args: {\n key: {\n type: \"positional\",\n description: \"Config key using dot notation (e.g., sync.cacheTtlHours)\",\n required: true,\n },\n value: {\n type: \"positional\",\n description: \"Value to set\",\n required: true,\n },\n },\n async run({ args }) {\n const { key, value } = args;\n const segments = key.split(\".\");\n\n if (segments.length === 0 || segments.some((s: string) => s === \"\")) {\n p.cancel(`Invalid config key: \"${key}\"`);\n process.exit(1);\n }\n\n // Load current config\n const config = await loadGlobalConfig();\n\n // Parse the value into the appropriate type\n const parsed = parseValue(value);\n\n // Set the value at the dotted path\n setNestedValue(config, segments, parsed);\n\n // Save the updated config (Zod validates on save)\n try {\n await saveGlobalConfig(config);\n } catch (error) {\n p.cancel(`Invalid config value: ${error instanceof Error ? error.message : String(error)}`);\n process.exit(1);\n }\n\n p.log.success(`Set ${key} = ${JSON.stringify(parsed)}`);\n },\n});\n\n/** Parse a string value into a number, boolean, or string. */\nfunction parseValue(raw: string): unknown {\n if (raw === \"true\") return true;\n if (raw === \"false\") return false;\n const num = Number(raw);\n if (!Number.isNaN(num) && raw.trim() !== \"\") return num;\n return raw;\n}\n\n/** Set a value at a dotted path on an object, creating intermediate objects as needed. */\nfunction setNestedValue(obj: Record<string, unknown>, segments: string[], value: unknown): void {\n let current: Record<string, unknown> = obj;\n for (let i = 0; i < segments.length - 1; i++) {\n const seg = segments[i];\n if (current[seg] === undefined || current[seg] === null) {\n current[seg] = {};\n }\n current = current[seg] as Record<string, unknown>;\n }\n current[segments[segments.length - 1]] = value;\n}\n","import { join } from \"node:path\";\nimport { getAIToolConfig } from \"@baton-dx/ai-tool-paths\";\nimport type { ProjectManifest } from \"@baton-dx/core\";\nimport {\n getGlobalAiTools,\n getGlobalIdePlatforms,\n getGlobalSources,\n loadProjectManifest,\n resolvePreferences,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { buildIntersection } from \"../../utils/build-intersection.js\";\nimport { formatIntersectionSummary } from \"../../utils/intersection-display.js\";\nimport { configSetCommand } from \"./set.js\";\n\nasync function showDashboard(): Promise<void> {\n p.intro(\"Baton Dashboard\");\n\n // Fetch all data in parallel\n const [sources, aiTools, idePlatforms, projectManifest] = await Promise.all([\n getGlobalSources(),\n getGlobalAiTools(),\n getGlobalIdePlatforms(),\n loadProjectManifestSafe(),\n ]);\n\n // --- Global Sources ---\n console.log(\"\");\n p.log.step(\"Global Sources\");\n if (sources.length === 0) {\n p.log.info(\" No sources configured. Run: baton source connect <url>\");\n } else {\n for (const source of sources) {\n const defaultBadge = source.default ? \" (default)\" : \"\";\n const desc = source.description ? ` — ${source.description}` : \"\";\n p.log.info(` ${source.name}${defaultBadge}: ${source.url}${desc}`);\n }\n }\n\n // --- Developer Tools ---\n console.log(\"\");\n p.log.step(\"Developer Tools\");\n\n // Use resolved preferences if in a project directory, otherwise show global config\n if (projectManifest) {\n const prefs = await resolvePreferences(process.cwd());\n const resolvedAiTools = prefs.ai.tools;\n const resolvedIdePlatforms = prefs.ide.platforms;\n\n if (resolvedAiTools.length === 0 && resolvedIdePlatforms.length === 0) {\n p.log.info(\" No tools configured. Run: baton ai-tools scan && baton ides scan\");\n } else {\n if (resolvedAiTools.length > 0) {\n const toolNames = resolvedAiTools.map((key) => {\n try {\n return getAIToolConfig(key).name;\n } catch {\n return key;\n }\n });\n const aiSourceLabel =\n prefs.ai.source === \"project\" ? \"project preferences\" : \"global config\";\n p.log.info(` AI Tools: ${toolNames.join(\", \")} (from ${aiSourceLabel})`);\n }\n if (resolvedIdePlatforms.length > 0) {\n const ideSourceLabel =\n prefs.ide.source === \"project\" ? \"project preferences\" : \"global config\";\n p.log.info(` IDE Platforms: ${resolvedIdePlatforms.join(\", \")} (from ${ideSourceLabel})`);\n }\n }\n } else {\n if (aiTools.length === 0 && idePlatforms.length === 0) {\n p.log.info(\" No tools configured. Run: baton ai-tools scan && baton ides scan\");\n } else {\n if (aiTools.length > 0) {\n const toolNames = aiTools.map((key) => {\n try {\n return getAIToolConfig(key).name;\n } catch {\n return key;\n }\n });\n p.log.info(` AI Tools: ${toolNames.join(\", \")} (from global config)`);\n }\n if (idePlatforms.length > 0) {\n p.log.info(` IDE Platforms: ${idePlatforms.join(\", \")} (from global config)`);\n }\n }\n }\n\n // --- Current Project ---\n console.log(\"\");\n p.log.step(\"Current Project\");\n if (!projectManifest) {\n p.log.info(\" Not inside a Baton project. Run: baton init\");\n } else if (projectManifest.profiles.length === 0) {\n p.log.info(\" No profiles installed. Run: baton manage\");\n } else {\n for (const profile of projectManifest.profiles) {\n const version = profile.version ? ` (${profile.version})` : \"\";\n p.log.info(` ${profile.source}${version}`);\n }\n }\n\n // --- Active Intersections ---\n if (projectManifest && projectManifest.profiles.length > 0) {\n const hasDeveloperTools = aiTools.length > 0 || idePlatforms.length > 0;\n\n if (hasDeveloperTools) {\n const developerTools = { aiTools, idePlatforms };\n console.log(\"\");\n p.log.step(\"Active Intersections\");\n\n for (const profile of projectManifest.profiles) {\n try {\n const intersection = await buildIntersection(\n profile.source,\n developerTools,\n process.cwd(),\n );\n if (intersection) {\n const summary = formatIntersectionSummary(intersection);\n p.log.info(` ${profile.source}: ${summary}`);\n }\n } catch {\n // Best-effort — skip if intersection cannot be computed\n }\n }\n }\n }\n\n console.log(\"\");\n p.outro(\"Manage tools: 'baton ai-tools configure' | 'baton ides configure'\");\n}\n\nasync function loadProjectManifestSafe(): Promise<ProjectManifest | null> {\n try {\n return await loadProjectManifest(join(process.cwd(), \"baton.yaml\"));\n } catch {\n return null;\n }\n}\n\nexport const configCommand = defineCommand({\n meta: {\n name: \"config\",\n description: \"Show Baton dashboard overview or configure settings\",\n },\n subCommands: {\n set: configSetCommand,\n },\n async run() {\n await showDashboard();\n },\n});\n","import { readFile, readdir, stat } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport {\n type MemoryEntry,\n type MergedSkillItem,\n type RuleEntry,\n type RuleFile,\n cloneGitSource,\n detectInstalledAITools,\n getAIToolAdaptersForKeys,\n getGlobalAiTools,\n getGlobalIdePlatforms,\n getIdePlatformTargetDir,\n loadProfileManifest,\n loadProjectManifest,\n mergeContentParts,\n mergeMemory,\n mergeRules,\n mergeSkills,\n parseFrontmatter,\n parseSource,\n resolveProfileChain,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { buildIntersection } from \"../utils/build-intersection.js\";\n\ninterface DiffEntry {\n /** Relative display path (e.g. \".claude/rules/coding-standards.md\") */\n file: string;\n status: \"added\" | \"modified\" | \"removed\";\n remoteContent?: string;\n localContent?: string;\n}\n\nexport const diffCommand = defineCommand({\n meta: {\n name: \"diff\",\n description: \"Compare local installed files with remote source versions to see what changed\",\n },\n args: {\n nameOnly: {\n type: \"boolean\",\n description: \"Show only changed filenames without content diff\",\n alias: \"n\",\n },\n },\n async run({ args }) {\n p.intro(\"🔍 Baton Diff\");\n\n try {\n const projectRoot = process.cwd();\n const manifestPath = resolve(projectRoot, \"baton.yaml\");\n const manifest = await loadProjectManifest(manifestPath);\n\n if (!manifest.profiles || manifest.profiles.length === 0) {\n p.outro(\"⚠️ No profiles configured in baton.yaml\");\n process.exit(0);\n }\n\n // Step 1: Resolve profile chains (same as sync.ts)\n const spinner = p.spinner();\n spinner.start(\"Resolving profile chain...\");\n\n const allProfiles = [];\n const profileLocalPaths = new Map<string, string>();\n\n for (const profileSource of manifest.profiles) {\n try {\n const parsed = parseSource(profileSource.source);\n\n let profileManifestPath: string;\n let localPath: string;\n\n if (parsed.provider === \"local\" || parsed.provider === \"file\") {\n localPath = parsed.path.startsWith(\"/\")\n ? parsed.path\n : resolve(projectRoot, parsed.path);\n profileManifestPath = resolve(localPath, \"baton.profile.yaml\");\n } else if (parsed.provider === \"npm\") {\n spinner.message(\"NPM provider not yet supported for diff\");\n continue;\n } else {\n const url = parsed.url;\n const subpath =\n parsed.provider === \"github\" || parsed.provider === \"gitlab\"\n ? parsed.subpath\n : undefined;\n const cloned = await cloneGitSource({\n url,\n ref: profileSource.version || undefined,\n subpath,\n useCache: false, // Always fetch fresh for diff\n });\n localPath = cloned.localPath;\n profileManifestPath = resolve(cloned.localPath, \"baton.profile.yaml\");\n }\n\n const profileManifest = await loadProfileManifest(profileManifestPath);\n const profileDir = dirname(profileManifestPath);\n const chain = await resolveProfileChain(\n profileManifest,\n profileSource.source,\n profileDir,\n );\n\n for (const prof of chain) {\n profileLocalPaths.set(prof.name, localPath);\n }\n allProfiles.push(...chain);\n } catch (error) {\n spinner.message(\n `Failed to resolve profile ${profileSource.source}: ${error instanceof Error ? error.message : error}`,\n );\n }\n }\n\n if (allProfiles.length === 0) {\n spinner.stop(\"No profiles resolved\");\n p.outro(\"Nothing to diff. Run `baton manage` to add a profile.\");\n process.exit(0);\n }\n\n spinner.stop(`Resolved ${allProfiles.length} profile(s)`);\n\n // Step 2: Merge configurations (same as sync.ts)\n spinner.start(\"Merging configurations...\");\n\n const mergedSkills: MergedSkillItem[] = mergeSkills(allProfiles);\n const mergedRules: RuleEntry[] = mergeRules(allProfiles);\n const mergedMemory: MemoryEntry[] = mergeMemory(allProfiles);\n\n // Collect commands\n const commandMap = new Map<string, string>();\n for (const profile of allProfiles) {\n for (const cmd of profile.manifest.ai?.commands || []) {\n commandMap.set(cmd, profile.name);\n }\n }\n\n // Collect files\n const fileMap = new Map<string, { source: string; target: string; profileName: string }>();\n for (const profile of allProfiles) {\n for (const fileConfig of profile.manifest.files || []) {\n const target = fileConfig.target || fileConfig.source;\n fileMap.set(target, { source: fileConfig.source, target, profileName: profile.name });\n }\n }\n\n // Collect IDE configs (uses central IDE platform registry)\n const ideMap = new Map<\n string,\n { ideKey: string; fileName: string; targetDir: string; profileName: string }\n >();\n for (const profile of allProfiles) {\n if (!profile.manifest.ide) continue;\n for (const [ideKey, files] of Object.entries(profile.manifest.ide)) {\n if (!files) continue;\n const targetDir = getIdePlatformTargetDir(ideKey);\n if (!targetDir) continue;\n for (const fileName of files) {\n const targetPath = `${targetDir}/${fileName}`;\n ideMap.set(targetPath, { ideKey, fileName, targetDir, profileName: profile.name });\n }\n }\n }\n\n spinner.stop(\"Configurations merged\");\n\n // Step 3: Determine which AI tools to diff (intersection-based, like sync.ts)\n spinner.start(\"Computing tool intersection...\");\n\n const globalAiTools = await getGlobalAiTools();\n const detectedAITools = await detectInstalledAITools();\n\n let syncedAiTools: string[];\n if (globalAiTools.length > 0) {\n const developerTools = {\n aiTools: globalAiTools,\n idePlatforms: await getGlobalIdePlatforms(),\n };\n const aggregatedSyncedAi = new Set<string>();\n for (const profileSource of manifest.profiles) {\n try {\n const intersection = await buildIntersection(\n profileSource.source,\n developerTools,\n projectRoot,\n );\n if (intersection) {\n for (const tool of intersection.aiTools.synced) aggregatedSyncedAi.add(tool);\n }\n } catch {\n /* skip */\n }\n }\n syncedAiTools = aggregatedSyncedAi.size > 0 ? [...aggregatedSyncedAi] : [];\n } else {\n syncedAiTools = detectedAITools;\n }\n\n if (syncedAiTools.length === 0) {\n spinner.stop(\"No AI tools in intersection\");\n p.cancel(\"No AI tools match. Run `baton ai-tools scan`.\");\n process.exit(1);\n }\n\n const adapters = getAIToolAdaptersForKeys(syncedAiTools);\n spinner.stop(`Comparing for: ${syncedAiTools.join(\", \")}`);\n\n // Step 4: Build expected file map (remote content → placed path)\n spinner.start(\"Comparing remote sources with placed files...\");\n\n const diffs: DiffEntry[] = [];\n // Track all expected placed paths to detect \"removed\" files\n const expectedPaths = new Set<string>();\n\n // Content accumulator for files that may receive content from multiple categories\n // (e.g., GitHub Copilot uses .github/copilot-instructions.md for both memory AND rules)\n // Key: relativePath, Value: { parts }\n const contentAccumulator = new Map<string, { parts: string[]; absolutePath: string }>();\n\n // --- Memory files (accumulate) ---\n for (const adapter of adapters) {\n for (const memoryEntry of mergedMemory) {\n const contentParts: string[] = [];\n for (const contribution of memoryEntry.contributions) {\n const profileDir = profileLocalPaths.get(contribution.profileName);\n if (!profileDir) continue;\n const memoryFilePath = resolve(profileDir, \"ai\", \"memory\", memoryEntry.filename);\n try {\n contentParts.push(await readFile(memoryFilePath, \"utf-8\"));\n } catch {\n // skip missing\n }\n }\n if (contentParts.length === 0) continue;\n\n const mergedContent = mergeContentParts(contentParts, memoryEntry.mergeStrategy);\n\n const transformed = adapter.transformMemory({\n filename: memoryEntry.filename,\n content: mergedContent,\n });\n const targetPath = adapter.getPath(\"memory\", \"project\", transformed.filename);\n const absolutePath = resolveAbsolutePath(targetPath, projectRoot);\n const relativePath = toRelativePath(absolutePath, projectRoot);\n expectedPaths.add(relativePath);\n\n // Accumulate instead of directly adding diff entry\n const existing = contentAccumulator.get(relativePath);\n if (existing) {\n existing.parts.push(transformed.content);\n } else {\n contentAccumulator.set(relativePath, {\n parts: [transformed.content],\n absolutePath,\n });\n }\n }\n }\n\n // --- Skills ---\n for (const adapter of adapters) {\n for (const skillItem of mergedSkills) {\n const profileDir = profileLocalPaths.get(skillItem.profileName);\n if (!profileDir) continue;\n const skillSourceDir = resolve(profileDir, \"ai\", \"skills\", skillItem.name);\n try {\n await stat(skillSourceDir);\n } catch {\n continue;\n }\n const targetSkillPath = adapter.getPath(\"skills\", skillItem.scope, skillItem.name);\n const absoluteTargetDir = resolveAbsolutePath(targetSkillPath, projectRoot);\n\n // Compare all files in skill directory\n const remoteSkillFiles = await loadFilesFromDirectory(skillSourceDir);\n const localSkillFiles = await loadFilesFromDirectory(absoluteTargetDir);\n\n for (const [file, remoteContent] of Object.entries(remoteSkillFiles)) {\n const relPath = toRelativePath(resolve(absoluteTargetDir, file), projectRoot);\n expectedPaths.add(relPath);\n addDiffEntry(diffs, relPath, remoteContent, localSkillFiles[file] ?? undefined);\n }\n // Check for local-only files (removed in remote)\n for (const file of Object.keys(localSkillFiles)) {\n const relPath = toRelativePath(resolve(absoluteTargetDir, file), projectRoot);\n if (!expectedPaths.has(relPath)) {\n addDiffEntry(diffs, relPath, undefined, localSkillFiles[file]);\n }\n }\n }\n }\n\n // --- Rules (accumulate) ---\n for (const adapter of adapters) {\n for (const ruleEntry of mergedRules) {\n const isUniversal = ruleEntry.agents.length === 0;\n const isForThisAdapter = ruleEntry.agents.includes(adapter.key);\n if (!isUniversal && !isForThisAdapter) continue;\n\n const profileDir = profileLocalPaths.get(ruleEntry.profileName);\n if (!profileDir) continue;\n\n const ruleSubdir = isUniversal ? \"universal\" : ruleEntry.agents[0];\n const ruleSourcePath = resolve(\n profileDir,\n \"ai\",\n \"rules\",\n ruleSubdir,\n `${ruleEntry.name}.md`,\n );\n\n let rawContent: string;\n try {\n rawContent = await readFile(ruleSourcePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const parsed = parseFrontmatter(rawContent);\n const ruleFile: RuleFile = {\n name: ruleEntry.name,\n content: rawContent,\n frontmatter:\n Object.keys(parsed.data).length > 0\n ? (parsed.data as RuleFile[\"frontmatter\"])\n : undefined,\n };\n\n const transformed = adapter.transformRule(ruleFile);\n const targetPath = adapter.getPath(\"rules\", \"project\", ruleEntry.name);\n const absolutePath = resolveAbsolutePath(targetPath, projectRoot);\n const relativePath = toRelativePath(absolutePath, projectRoot);\n expectedPaths.add(relativePath);\n\n // Accumulate instead of directly adding diff entry\n const existing = contentAccumulator.get(relativePath);\n if (existing) {\n existing.parts.push(transformed.content);\n } else {\n contentAccumulator.set(relativePath, {\n parts: [transformed.content],\n absolutePath,\n });\n }\n }\n }\n\n // --- Flush accumulated content (memory + rules combined per target path) ---\n for (const [relativePath, entry] of contentAccumulator) {\n const combinedContent = entry.parts.join(\"\\n\\n\");\n addDiffEntry(diffs, relativePath, combinedContent, await readSafe(entry.absolutePath));\n }\n\n // --- Commands ---\n for (const adapter of adapters) {\n for (const [commandName, profileName] of commandMap) {\n const profileDir = profileLocalPaths.get(profileName);\n if (!profileDir) continue;\n\n const commandSourcePath = resolve(profileDir, \"ai\", \"commands\", `${commandName}.md`);\n let content: string;\n try {\n content = await readFile(commandSourcePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const targetPath = adapter.getPath(\"commands\", \"project\", commandName);\n const absolutePath = resolveAbsolutePath(targetPath, projectRoot);\n const relativePath = toRelativePath(absolutePath, projectRoot);\n expectedPaths.add(relativePath);\n\n addDiffEntry(diffs, relativePath, content, await readSafe(absolutePath));\n }\n }\n\n // --- Files (project root, no adapter) ---\n for (const fileEntry of fileMap.values()) {\n const profileDir = profileLocalPaths.get(fileEntry.profileName);\n if (!profileDir) continue;\n\n const fileSourcePath = resolve(profileDir, \"files\", fileEntry.source);\n let content: string;\n try {\n content = await readFile(fileSourcePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const absolutePath = resolve(projectRoot, fileEntry.target);\n const relativePath = fileEntry.target;\n expectedPaths.add(relativePath);\n\n addDiffEntry(diffs, relativePath, content, await readSafe(absolutePath));\n }\n\n // --- IDE configs (project root, no adapter) ---\n for (const ideEntry of ideMap.values()) {\n const profileDir = profileLocalPaths.get(ideEntry.profileName);\n if (!profileDir) continue;\n\n const ideSourcePath = resolve(profileDir, \"ide\", ideEntry.ideKey, ideEntry.fileName);\n let content: string;\n try {\n content = await readFile(ideSourcePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const absolutePath = resolve(projectRoot, ideEntry.targetDir, ideEntry.fileName);\n const relativePath = `${ideEntry.targetDir}/${ideEntry.fileName}`;\n expectedPaths.add(relativePath);\n\n addDiffEntry(diffs, relativePath, content, await readSafe(absolutePath));\n }\n\n spinner.stop();\n\n // Step 5: Display results\n if (diffs.length === 0) {\n p.log.success(\"No differences found\");\n p.outro(\"✅ Diff complete - all placed files match remote sources\");\n process.exit(0);\n }\n\n p.log.warning(`${diffs.length} file(s) with differences`);\n\n for (const diff of diffs) {\n if (args.nameOnly) {\n const statusSymbol =\n diff.status === \"added\" ? \"+\" : diff.status === \"removed\" ? \"-\" : \"~\";\n console.log(` ${statusSymbol} ${diff.file}`);\n } else {\n console.log(`\\n 📄 ${diff.file} (${diff.status})`);\n\n if (diff.status === \"modified\") {\n const localLines = (diff.localContent || \"\").split(\"\\n\");\n const remoteLines = (diff.remoteContent || \"\").split(\"\\n\");\n\n const maxLines = Math.max(localLines.length, remoteLines.length);\n let diffLines = 0;\n for (let i = 0; i < maxLines && diffLines < 10; i++) {\n const localLine = localLines[i] || \"\";\n const remoteLine = remoteLines[i] || \"\";\n\n if (localLine !== remoteLine) {\n diffLines++;\n if (localLine) {\n console.log(` \\x1b[31m- ${localLine}\\x1b[0m`);\n }\n if (remoteLine) {\n console.log(` \\x1b[32m+ ${remoteLine}\\x1b[0m`);\n }\n }\n }\n\n if (diffLines >= 10) {\n console.log(\" ... (more differences)\");\n }\n } else if (diff.status === \"added\") {\n console.log(\" \\x1b[32m+ New file in remote (not yet placed locally)\\x1b[0m\");\n } else {\n console.log(\" \\x1b[31m- File exists locally but not in remote\\x1b[0m\");\n }\n }\n }\n\n p.outro(\"✅ Diff complete - differences found. Run `baton sync` to update.\");\n process.exit(1);\n } catch (error) {\n p.log.error(\n `Failed to run diff: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n process.exit(1);\n }\n },\n});\n\n/**\n * Add a diff entry if remote and local content differ.\n */\nfunction addDiffEntry(\n diffs: DiffEntry[],\n file: string,\n remoteContent: string | undefined,\n localContent: string | undefined,\n): void {\n // Deduplicate: skip if this file already has a diff entry\n if (diffs.some((d) => d.file === file)) return;\n\n if (remoteContent !== undefined && localContent === undefined) {\n diffs.push({ file, status: \"added\", remoteContent });\n } else if (remoteContent === undefined && localContent !== undefined) {\n diffs.push({ file, status: \"removed\", localContent });\n } else if (\n remoteContent !== undefined &&\n localContent !== undefined &&\n remoteContent !== localContent\n ) {\n diffs.push({ file, status: \"modified\", remoteContent, localContent });\n }\n}\n\n/**\n * Read a file safely, returning undefined if it doesn't exist.\n */\nasync function readSafe(path: string): Promise<string | undefined> {\n try {\n return await readFile(path, \"utf-8\");\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolve a path to absolute, handling both absolute and relative paths.\n */\nfunction resolveAbsolutePath(path: string, projectRoot: string): string {\n if (path.startsWith(\"/\")) return path;\n return resolve(projectRoot, path);\n}\n\n/**\n * Convert an absolute path to a relative path from project root.\n */\nfunction toRelativePath(absolutePath: string, projectRoot: string): string {\n if (absolutePath.startsWith(projectRoot)) {\n const rel = absolutePath.slice(projectRoot.length);\n return rel.startsWith(\"/\") ? rel.slice(1) : rel;\n }\n return absolutePath;\n}\n\n/**\n * Load all files from a directory recursively\n */\nasync function loadFilesFromDirectory(dirPath: string): Promise<Record<string, string>> {\n const files: Record<string, string> = {};\n\n try {\n const entries = await readdir(dirPath, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = resolve(dirPath, entry.name);\n\n if (entry.isDirectory()) {\n const subFiles = await loadFilesFromDirectory(fullPath);\n for (const [subPath, content] of Object.entries(subFiles)) {\n files[`${entry.name}/${subPath}`] = content;\n }\n } else if (entry.isFile()) {\n const content = await readFile(fullPath, \"utf-8\");\n files[entry.name] = content;\n }\n }\n } catch {\n return {};\n }\n\n return files;\n}\n","/**\n * Format an IDE platform key into a display name.\n */\nexport function formatIdeName(ideKey: string): string {\n const names: Record<string, string> = {\n vscode: \"VS Code\",\n jetbrains: \"JetBrains\",\n cursor: \"Cursor\",\n windsurf: \"Windsurf\",\n antigravity: \"Antigravity\",\n zed: \"Zed\",\n };\n return names[ideKey] ?? ideKey;\n}\n","import { stat } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport {\n getGlobalIdePlatforms,\n getRegisteredIdePlatforms,\n readProjectPreferences,\n setGlobalIdePlatforms,\n writeProjectPreferences,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { formatIdeName } from \"./utils.js\";\n\nexport const idesConfigureCommand = defineCommand({\n meta: {\n name: \"configure\",\n description: \"Manually configure which IDE platforms Baton manages\",\n },\n args: {\n yes: {\n type: \"boolean\",\n alias: \"y\",\n description:\n \"Keep current selection unchanged (no-op), or with --project write useGlobal: true\",\n },\n project: {\n type: \"boolean\",\n description: \"Configure IDE platforms for this project instead of globally\",\n },\n },\n async run({ args }) {\n if (args.project) {\n await runProjectMode(args.yes ?? false);\n } else {\n await runGlobalMode(args.yes ?? false);\n }\n },\n});\n\nasync function runGlobalMode(nonInteractive: boolean): Promise<void> {\n p.intro(\"Baton - Configure IDE Platforms\");\n\n const currentPlatforms = await getGlobalIdePlatforms();\n\n // --yes flag is a no-op (keeps current selection unchanged)\n if (nonInteractive) {\n if (currentPlatforms.length > 0) {\n p.log.info(`Current IDE platforms: ${currentPlatforms.join(\", \")}`);\n } else {\n p.log.info(\"No IDE platforms currently configured.\");\n }\n p.outro(\"No changes made.\");\n return;\n }\n\n const allIdeKeys = getRegisteredIdePlatforms();\n\n const options = allIdeKeys.map((ideKey) => {\n const isSaved = currentPlatforms.includes(ideKey);\n return {\n value: ideKey,\n label: isSaved ? `${formatIdeName(ideKey)} (currently saved)` : formatIdeName(ideKey),\n };\n });\n\n const selected = await p.multiselect({\n message: \"Select which IDE platforms to save:\",\n options,\n initialValues: currentPlatforms,\n });\n\n if (p.isCancel(selected)) {\n p.outro(\"No changes made.\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n const hasChanges =\n selectedKeys.length !== currentPlatforms.length ||\n selectedKeys.some((key) => !currentPlatforms.includes(key));\n\n if (hasChanges) {\n await setGlobalIdePlatforms(selectedKeys);\n p.log.success(`Saved ${selectedKeys.length} platform(s) to global config.`);\n } else {\n p.log.info(\"No changes made.\");\n }\n\n p.outro(\"Configuration complete.\");\n}\n\nasync function runProjectMode(nonInteractive: boolean): Promise<void> {\n p.intro(\"Baton - Configure IDE Platforms (Project)\");\n\n const projectRoot = process.cwd();\n const manifestPath = resolve(projectRoot, \"baton.yaml\");\n\n // Check that baton.yaml exists\n try {\n await stat(manifestPath);\n } catch {\n p.cancel(\"No baton.yaml found in current directory. Run `baton init` first.\");\n process.exit(1);\n }\n\n // --yes with --project writes useGlobal: true\n if (nonInteractive) {\n const existing = await readProjectPreferences(projectRoot);\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: existing?.ai ?? { useGlobal: true, tools: [] },\n ide: { useGlobal: true, platforms: existing?.ide.platforms ?? [] },\n });\n p.log.info(\"Set IDE platforms to use global config for this project.\");\n p.outro(\"Configuration complete.\");\n return;\n }\n\n const existing = await readProjectPreferences(projectRoot);\n const globalPlatforms = await getGlobalIdePlatforms();\n\n // Show current state\n if (globalPlatforms.length > 0) {\n p.log.info(`Global IDE platforms: ${globalPlatforms.join(\", \")}`);\n }\n\n // Ask useGlobal first\n const mode = await p.select({\n message: \"How should this project resolve IDE platforms?\",\n options: [\n {\n value: \"global\",\n label: \"Use global config\",\n hint: \"always follows your global IDE platforms setting\",\n },\n {\n value: \"project\",\n label: \"Customize for this project\",\n hint: \"choose specific IDEs for this project\",\n },\n ],\n initialValue: existing?.ide.useGlobal === false ? \"project\" : \"global\",\n });\n\n if (p.isCancel(mode)) {\n p.outro(\"No changes made.\");\n return;\n }\n\n if (mode === \"global\") {\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: existing?.ai ?? { useGlobal: true, tools: [] },\n ide: { useGlobal: true, platforms: [] },\n });\n p.log.success(\"Project configured to use global IDE platforms.\");\n p.outro(\"Configuration complete.\");\n return;\n }\n\n // Customize: show multiselect\n const allIdeKeys = getRegisteredIdePlatforms();\n const currentProjectPlatforms =\n existing?.ide.useGlobal === false ? existing.ide.platforms : globalPlatforms;\n\n const options = allIdeKeys.map((ideKey) => {\n const isGlobal = globalPlatforms.includes(ideKey);\n return {\n value: ideKey,\n label: isGlobal ? `${formatIdeName(ideKey)} (in global config)` : formatIdeName(ideKey),\n };\n });\n\n const selected = await p.multiselect({\n message: \"Select IDE platforms for this project:\",\n options,\n initialValues: currentProjectPlatforms,\n });\n\n if (p.isCancel(selected)) {\n p.outro(\"No changes made.\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n await writeProjectPreferences(projectRoot, {\n version: \"1.0\",\n ai: existing?.ai ?? { useGlobal: true, tools: [] },\n ide: { useGlobal: false, platforms: selectedKeys },\n });\n p.log.success(`Project configured with ${selectedKeys.length} IDE platform(s).`);\n p.outro(\"Configuration complete.\");\n}\n","import {\n getGlobalIdePlatforms,\n getRegisteredIdePlatforms,\n idePlatformRegistry,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { formatIdeName } from \"./utils.js\";\n\nexport const idesListCommand = defineCommand({\n meta: {\n name: \"list\",\n description: \"Show saved IDE platforms from global config\",\n },\n args: {\n all: {\n type: \"boolean\",\n alias: \"a\",\n description: \"Show all supported platforms, not just saved ones\",\n },\n json: {\n type: \"boolean\",\n description: \"Output machine-readable JSON\",\n alias: \"j\",\n },\n },\n async run({ args }) {\n if (!args.json) {\n p.intro(\"Baton - IDE Platforms\");\n }\n\n // Load saved platforms from global config\n const savedPlatforms = await getGlobalIdePlatforms();\n const allIdeKeys = getRegisteredIdePlatforms();\n\n // Determine which platforms to show\n const keysToShow = args.all\n ? allIdeKeys\n : savedPlatforms.length > 0\n ? savedPlatforms\n : allIdeKeys;\n\n const platformStatuses = keysToShow.map((ideKey) => {\n const isSaved = savedPlatforms.includes(ideKey);\n const entry = idePlatformRegistry[ideKey];\n\n return {\n key: ideKey,\n name: formatIdeName(ideKey),\n saved: isSaved,\n targetDir: entry?.targetDir ?? \"unknown\",\n };\n });\n\n // JSON output\n if (args.json) {\n console.log(JSON.stringify(platformStatuses, null, 2));\n return;\n }\n\n // Formatted output\n if (savedPlatforms.length === 0) {\n p.log.warn(\"No IDE platforms saved in global config.\");\n p.log.info(\"Run 'baton ides scan' to detect and save your IDE platforms.\");\n console.log(\"\");\n p.log.info(`All ${allIdeKeys.length} supported platforms:`);\n for (const key of allIdeKeys) {\n const entry = idePlatformRegistry[key];\n console.log(` \\x1b[90m- ${formatIdeName(key)} (${entry?.targetDir ?? key})\\x1b[0m`);\n }\n p.outro(\"Run 'baton ides scan' to get started.\");\n return;\n }\n\n console.log(`\\nSaved IDE platforms (${savedPlatforms.length}):\\n`);\n\n for (const platform of platformStatuses) {\n const statusColor = platform.saved ? \"\\x1b[32m\" : \"\\x1b[90m\";\n const status = platform.saved ? \"✓\" : \"✗\";\n const resetColor = \"\\x1b[0m\";\n\n console.log(\n `${statusColor}${status}${resetColor} ${platform.name.padEnd(20)} → ${platform.targetDir}`,\n );\n }\n\n console.log(\"\");\n p.outro(\"Manage platforms: 'baton ides scan' (detect)\");\n },\n});\n","import {\n clearIdeCache,\n detectInstalledIdes,\n getGlobalIdePlatforms,\n getRegisteredIdePlatforms,\n setGlobalIdePlatforms,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { formatIdeName } from \"./utils.js\";\n\nexport const idesScanCommand = defineCommand({\n meta: {\n name: \"scan\",\n description: \"Scan your system for IDE platforms and save results to global config\",\n },\n args: {\n yes: {\n type: \"boolean\",\n alias: \"y\",\n description: \"Automatically save detected platforms without confirmation\",\n },\n },\n async run({ args }) {\n p.intro(\"Baton - IDE Platform Scanner\");\n\n const spinner = p.spinner();\n spinner.start(\"Scanning for IDE platforms...\");\n\n // Clear cache to force fresh detection\n clearIdeCache();\n\n const detectedIdes = await detectInstalledIdes();\n const allIdeKeys = getRegisteredIdePlatforms();\n const currentPlatforms = await getGlobalIdePlatforms();\n\n spinner.stop(\"Scan complete.\");\n\n if (detectedIdes.length > 0) {\n p.log.success(\n `Found ${detectedIdes.length} IDE platform${detectedIdes.length !== 1 ? \"s\" : \"\"} on your system.`,\n );\n } else {\n p.log.warn(\"No IDE platforms detected on your system.\");\n }\n\n // --yes flag: save only detected platforms (preserves current behavior)\n if (args.yes) {\n const hasChanges =\n detectedIdes.length !== currentPlatforms.length ||\n detectedIdes.some((key) => !currentPlatforms.includes(key));\n\n if (hasChanges) {\n await setGlobalIdePlatforms(detectedIdes);\n p.log.success(`Saved ${detectedIdes.length} detected platform(s) to global config.`);\n } else {\n p.log.info(\"Global config is already up to date.\");\n }\n\n p.outro(\"Scan finished.\");\n return;\n }\n\n // Interactive: show multiselect with all 6 IDE platforms\n const options = allIdeKeys.map((ideKey) => {\n const isDetected = detectedIdes.includes(ideKey);\n return {\n value: ideKey,\n label: isDetected ? `${formatIdeName(ideKey)} (detected)` : formatIdeName(ideKey),\n };\n });\n\n const selected = await p.multiselect({\n message: \"Select which IDE platforms to save:\",\n options,\n initialValues: detectedIdes,\n });\n\n if (p.isCancel(selected)) {\n p.outro(\"Scan finished (not saved).\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n const hasChanges =\n selectedKeys.length !== currentPlatforms.length ||\n selectedKeys.some((key) => !currentPlatforms.includes(key));\n\n if (hasChanges) {\n await setGlobalIdePlatforms(selectedKeys);\n p.log.success(`Saved ${selectedKeys.length} platform(s) to global config.`);\n } else {\n p.log.info(\"Global config is already up to date.\");\n }\n\n p.outro(\"Scan finished.\");\n },\n});\n","import { defineCommand } from \"citty\";\nimport { idesConfigureCommand } from \"./configure.js\";\nimport { idesListCommand } from \"./list.js\";\nimport { idesScanCommand } from \"./scan.js\";\n\nexport const idesCommand = defineCommand({\n meta: {\n name: \"ides\",\n description: \"Manage IDE platform detection and configuration\",\n },\n subCommands: {\n configure: idesConfigureCommand,\n list: idesListCommand,\n scan: idesScanCommand,\n },\n});\n","import { resolve } from \"node:path\";\nimport { cloneGitSource, discoverProfilesInSourceRepo, parseSource } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\n\n/**\n * Discovers and prompts user to select a profile from a source.\n * Used by `baton init --profile` and `baton manage` (add profile).\n *\n * @param sourceString - Source string to discover profiles from (e.g., \"github:org/repo\")\n * @returns Final source string with selected profile path (e.g., \"github:org/repo/frontend\")\n */\nexport async function selectProfileFromSource(sourceString: string): Promise<string> {\n const parsedSource = parseSource(sourceString);\n\n // Only GitHub/GitLab sources without subpath require interactive selection\n if (\n (parsedSource.provider === \"github\" || parsedSource.provider === \"gitlab\") &&\n !parsedSource.subpath\n ) {\n const spinner = p.spinner();\n spinner.start(\"Cloning repository to discover profiles...\");\n\n try {\n // Clone repo temporarily to discover profiles\n const cloned = await cloneGitSource({\n url: parsedSource.url,\n ref: parsedSource.ref,\n useCache: true,\n });\n\n spinner.stop(\"✅ Repository cloned\");\n\n // Discover all profiles in the source repo\n const profiles = await discoverProfilesInSourceRepo(cloned.localPath);\n\n if (profiles.length === 0) {\n p.cancel(\"❌ No profiles found in the source repository\");\n process.exit(1);\n }\n\n // Show profile selection\n const selectedProfilePath = (await p.select({\n message: \"Select a profile from this source:\",\n options: profiles.map((profile) => ({\n value: profile.path,\n label: profile.name,\n hint: profile.description\n ? `${profile.description} (v${profile.version})`\n : `v${profile.version}`,\n })),\n })) as string;\n\n if (p.isCancel(selectedProfilePath)) {\n p.cancel(\"❌ Profile selection cancelled\");\n process.exit(0);\n }\n\n // Construct final source string with selected profile path\n // Format: github:org/repo[@ref]/profile\n if (selectedProfilePath === \".\") {\n // Root profile - no subpath needed\n return sourceString;\n }\n // Sub-profile - append to source string\n const baseSource = parsedSource.ref\n ? `${parsedSource.provider}:${parsedSource.org}/${parsedSource.repo}@${parsedSource.ref}`\n : `${parsedSource.provider}:${parsedSource.org}/${parsedSource.repo}`;\n return `${baseSource}/${selectedProfilePath}`;\n } catch (error) {\n spinner.stop(\"❌ Failed to clone repository\");\n p.cancel(\n `❌ Failed to discover profiles: ${error instanceof Error ? error.message : String(error)}`,\n );\n process.exit(1);\n }\n }\n\n // Local/file sources: discover profiles from local directory\n if (parsedSource.provider === \"file\" || parsedSource.provider === \"local\") {\n const absolutePath = parsedSource.path.startsWith(\"/\")\n ? parsedSource.path\n : resolve(process.cwd(), parsedSource.path);\n\n const profiles = await discoverProfilesInSourceRepo(absolutePath);\n\n if (profiles.length === 0) {\n // Possibly pointing directly at a single profile\n return sourceString;\n }\n\n if (profiles.length === 1) {\n const profilePath =\n profiles[0].path === \".\" ? sourceString : `${sourceString}/${profiles[0].path}`;\n return profilePath;\n }\n\n // Multiple profiles - show single-select\n const selectedProfilePath = (await p.select({\n message: \"Select a profile from this source:\",\n options: profiles.map((profile) => ({\n value: profile.path,\n label: profile.name,\n hint: profile.description\n ? `${profile.description} (v${profile.version})`\n : `v${profile.version}`,\n })),\n })) as string;\n\n if (p.isCancel(selectedProfilePath)) {\n p.cancel(\"❌ Profile selection cancelled\");\n process.exit(0);\n }\n\n if (selectedProfilePath === \".\") {\n return sourceString;\n }\n return `${sourceString}/${selectedProfilePath}`;\n }\n\n // Direct path provided or non-GitHub/GitLab source - return as-is\n return sourceString;\n}\n\n/**\n * Discovers and prompts user to select multiple profiles from a source.\n * Returns array of full source strings with profile paths.\n *\n * Used by `baton init` to allow installing multiple profiles at once.\n *\n * @param sourceString - Source string to discover profiles from (e.g., \"github:org/repo\")\n * @returns Array of source strings with selected profile paths (e.g., [\"github:org/repo/frontend\", \"github:org/repo/backend\"])\n */\nexport async function selectMultipleProfilesFromSource(\n sourceString: string,\n options?: { nonInteractive?: boolean },\n): Promise<string[]> {\n const parsedSource = parseSource(sourceString);\n\n // Only GitHub/GitLab sources without subpath require interactive selection\n if (\n (parsedSource.provider === \"github\" || parsedSource.provider === \"gitlab\") &&\n !parsedSource.subpath\n ) {\n const spinner = p.spinner();\n spinner.start(\"Cloning repository to discover profiles...\");\n\n try {\n const cloned = await cloneGitSource({\n url: parsedSource.url,\n ref: parsedSource.ref,\n useCache: true,\n });\n\n spinner.stop(\"✅ Repository cloned\");\n\n const profiles = await discoverProfilesInSourceRepo(cloned.localPath);\n\n if (profiles.length === 0) {\n p.cancel(\"❌ No profiles found in the source repository\");\n process.exit(1);\n }\n\n // Single profile - auto-select\n if (profiles.length === 1) {\n p.note(`Using profile: ${profiles[0].name}`, \"Profile\");\n const fullPath = constructProfilePath(parsedSource, profiles[0].path);\n return [fullPath];\n }\n\n // Non-interactive: auto-select all profiles\n if (options?.nonInteractive) {\n p.note(`Auto-selecting all ${profiles.length} profile(s)`, \"Non-interactive mode\");\n return profiles.map((prof) => constructProfilePath(parsedSource, prof.path));\n }\n\n // Multiple profiles - show multi-select\n const selected = (await p.multiselect({\n message: \"Select profile(s) to install: (Space to select, Enter to continue)\",\n options: profiles.map((prof) => ({\n value: prof.path,\n label: prof.name,\n hint: prof.description ? `${prof.description} (v${prof.version})` : `v${prof.version}`,\n })),\n required: true,\n })) as string[];\n\n if (p.isCancel(selected)) {\n p.cancel(\"❌ Profile selection cancelled\");\n process.exit(0);\n }\n\n // Map selected paths to full source strings\n return selected.map((path) => constructProfilePath(parsedSource, path));\n } catch (error) {\n spinner.stop(\"❌ Failed to clone repository\");\n p.cancel(\n `❌ Failed to discover profiles: ${error instanceof Error ? error.message : String(error)}`,\n );\n process.exit(1);\n }\n }\n\n // Local/file sources: discover profiles from local directory\n if (parsedSource.provider === \"file\" || parsedSource.provider === \"local\") {\n const absolutePath = parsedSource.path.startsWith(\"/\")\n ? parsedSource.path\n : resolve(process.cwd(), parsedSource.path);\n\n const profiles = await discoverProfilesInSourceRepo(absolutePath);\n\n if (profiles.length === 0) {\n // Possibly pointing directly at a single profile\n return [sourceString];\n }\n\n if (profiles.length === 1) {\n p.note(`Using profile: ${profiles[0].name}`, \"Profile\");\n const profilePath =\n profiles[0].path === \".\" ? sourceString : `${sourceString}/${profiles[0].path}`;\n return [profilePath];\n }\n\n // Non-interactive: auto-select all profiles\n if (options?.nonInteractive) {\n p.note(`Auto-selecting all ${profiles.length} profile(s)`, \"Non-interactive mode\");\n return profiles.map((prof) =>\n prof.path === \".\" ? sourceString : `${sourceString}/${prof.path}`,\n );\n }\n\n // Multiple profiles - show multi-select\n const selected = (await p.multiselect({\n message: \"Select profile(s) to install: (Space to select, Enter to continue)\",\n options: profiles.map((prof) => ({\n value: prof.path,\n label: prof.name,\n hint: prof.description ? `${prof.description} (v${prof.version})` : `v${prof.version}`,\n })),\n required: true,\n })) as string[];\n\n if (p.isCancel(selected)) {\n p.cancel(\"❌ Profile selection cancelled\");\n process.exit(0);\n }\n\n return selected.map((path) => (path === \".\" ? sourceString : `${sourceString}/${path}`));\n }\n\n // Direct path provided - return as-is (single profile)\n return [sourceString];\n}\n\n/**\n * Helper: Constructs full source path with profile subpath.\n *\n * @param parsed - Parsed source object (github or gitlab only)\n * @param profilePath - Profile path (e.g., \".\", \"frontend\", \"backend\")\n * @returns Full source string (e.g., \"github:org/repo/frontend\")\n */\nfunction constructProfilePath(\n parsed: Extract<ReturnType<typeof parseSource>, { provider: \"github\" | \"gitlab\" }>,\n profilePath: string,\n): string {\n // Root profile\n if (profilePath === \".\") {\n const baseSource = parsed.ref\n ? `${parsed.provider}:${parsed.org}/${parsed.repo}@${parsed.ref}`\n : `${parsed.provider}:${parsed.org}/${parsed.repo}`;\n return baseSource;\n }\n\n // Sub-profile: github:org/repo[@ref]/profilePath\n const baseSource = parsed.ref\n ? `${parsed.provider}:${parsed.org}/${parsed.repo}@${parsed.ref}`\n : `${parsed.provider}:${parsed.org}/${parsed.repo}`;\n\n return `${baseSource}/${profilePath}`;\n}\n","import * as p from \"@clack/prompts\";\n\n/**\n * Run `baton sync` as a child process, inheriting stdio for interactive output.\n */\nexport async function runBatonSync(cwd: string): Promise<void> {\n const { spawn } = await import(\"node:child_process\");\n await new Promise<void>((done) => {\n const syncProcess = spawn(\"baton\", [\"sync\"], { cwd, stdio: \"inherit\" });\n syncProcess.on(\"close\", (code) => {\n if (code === 0) {\n p.log.success(\"Profiles synced successfully!\");\n } else {\n p.log.warn(`Sync finished with exit code ${code}`);\n }\n done();\n });\n syncProcess.on(\"error\", (error) => {\n p.log.warn(`Failed to run sync: ${error.message}`);\n done();\n });\n });\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport type { ProjectManifest, SourceManifest } from \"@baton-dx/core\";\nimport {\n clearAIToolCache,\n clearIdeCache,\n cloneGitSource,\n collectComprehensivePatterns,\n computeIntersection,\n detectInstalledAITools,\n detectInstalledIdes,\n findSourceManifest,\n getDefaultGlobalSource,\n getGlobalAiTools,\n getGlobalIdePlatforms,\n getGlobalSources,\n loadProfileManifest,\n parseSource,\n resolveProfileSupport,\n setGlobalAiTools,\n setGlobalIdePlatforms,\n updateGitignore,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { stringify } from \"yaml\";\nimport { findSourceRoot } from \"../utils/context-detection.js\";\nimport { promptFirstRunPreferences } from \"../utils/first-run-preferences.js\";\nimport { displayIntersection } from \"../utils/intersection-display.js\";\nimport { selectMultipleProfilesFromSource } from \"../utils/profile-selection.js\";\nimport { runBatonSync } from \"../utils/run-baton-sync.js\";\n\nexport const initCommand = defineCommand({\n meta: {\n name: \"init\",\n description: \"Initialize Baton in your project with an interactive setup wizard\",\n },\n args: {\n yes: {\n type: \"boolean\",\n alias: \"y\",\n description: \"Skip all prompts and use defaults\",\n },\n force: {\n type: \"boolean\",\n description: \"Overwrite existing baton.yaml\",\n },\n profile: {\n type: \"string\",\n description: \"Profile source to install (skips profile selection)\",\n },\n },\n async run({ args }) {\n const isInteractive = !args.yes;\n const cwd = process.cwd();\n\n p.intro(\"🎯 Welcome to Baton\");\n\n // 1. Check if baton.yaml already exists\n try {\n await readFile(join(cwd, \"baton.yaml\"));\n if (!args.force) {\n p.cancel(\"baton.yaml already exists in this directory.\");\n p.note(\n \"Use `baton manage` to modify your project configuration\\nor `baton sync` to sync your profiles.\\n\\nTo reinitialize, use `baton init --force`.\",\n \"Already initialized\",\n );\n process.exit(1);\n }\n p.log.warn(\"Overwriting existing baton.yaml (--force)\");\n } catch (_error) {\n // File doesn't exist, continue\n }\n\n // 2. Auto-scan AI tools and IDEs if not yet configured\n const spinner = p.spinner();\n await autoScanAiTools(spinner, isInteractive);\n await autoScanIdePlatforms(spinner, isInteractive);\n\n // 3. Determine source URL(s) with global sources integration\n let profileSources: string[];\n\n if (args.profile) {\n // Explicit --profile flag: use it (may trigger multi-select)\n profileSources = await selectMultipleProfilesFromSource(args.profile, {\n nonInteractive: !isInteractive,\n });\n } else {\n // No --profile flag: check global sources\n const globalSources = await getGlobalSources();\n\n if (globalSources.length === 0) {\n // No global sources: abort with guidance\n p.cancel(\"No sources configured.\");\n p.note(\n \"Connect a source repository first:\\n\\n baton source connect <url>\\n\\nExample:\\n baton source connect github:my-org/dx-config\",\n \"No sources found\",\n );\n process.exit(1);\n } else if (globalSources.length === 1 && globalSources[0].default) {\n // Single default source: auto-use it\n const defaultSource = globalSources[0];\n p.note(`Using default source: ${defaultSource.name}\\n${defaultSource.url}`, \"Source\");\n profileSources = await selectMultipleProfilesFromSource(defaultSource.url, {\n nonInteractive: !isInteractive,\n });\n } else {\n // Multiple sources: show source selection\n if (!isInteractive) {\n // Non-interactive: use default source if available, otherwise first source\n const defaultSource = await getDefaultGlobalSource();\n const sourceUrl = defaultSource?.url || globalSources[0].url;\n profileSources = await selectMultipleProfilesFromSource(sourceUrl, {\n nonInteractive: true,\n });\n } else {\n const defaultSource = await getDefaultGlobalSource();\n\n const selectedUrl = (await p.select({\n message: \"Select a source repository:\",\n options: globalSources.map((s) => ({\n value: s.url,\n label: s.default ? `${s.name} [default]` : s.name,\n hint: s.description || s.url,\n })),\n initialValue: defaultSource?.url,\n })) as string;\n\n if (p.isCancel(selectedUrl)) {\n p.cancel(\"Setup cancelled.\");\n process.exit(0);\n }\n\n profileSources = await selectMultipleProfilesFromSource(selectedUrl);\n }\n }\n }\n\n // 4. Show intersection between developer tools and profile support\n await showProfileIntersections(profileSources);\n\n // 5. Ask whether synced files should be gitignored\n let gitignoreSetting = true; // default for --yes mode\n if (isInteractive) {\n const shouldGitignore = await p.confirm({\n message: \"Add synced AI tool and IDE config files to .gitignore?\",\n initialValue: true,\n });\n\n if (p.isCancel(shouldGitignore)) {\n p.cancel(\"Setup cancelled.\");\n process.exit(0);\n }\n\n gitignoreSetting = shouldGitignore;\n }\n\n // 6. Generate baton.yaml with multiple profiles and gitignore setting\n const manifest: ProjectManifest = {\n profiles: profileSources.map((source) => ({ source })),\n gitignore: gitignoreSetting,\n };\n\n const yamlContent = stringify(manifest);\n\n spinner.start(\"Creating baton.yaml...\");\n await writeFile(join(cwd, \"baton.yaml\"), yamlContent, \"utf-8\");\n spinner.stop(\"✅ Created baton.yaml\");\n\n // 7. Update .gitignore\n spinner.start(\"Updating .gitignore...\");\n const gitignorePath = join(cwd, \".gitignore\");\n let gitignoreContent = \"\";\n\n try {\n gitignoreContent = await readFile(gitignorePath, \"utf-8\");\n } catch (_error) {\n // .gitignore doesn't exist, create new\n }\n\n // Always ensure .baton/ is gitignored\n if (!gitignoreContent.includes(\".baton/\")) {\n const newContent = gitignoreContent\n ? `${gitignoreContent}\\n\\n# Baton local\\n.baton/\\n`\n : \"# Baton local\\n.baton/\\n\";\n await writeFile(gitignorePath, newContent, \"utf-8\");\n }\n\n // If gitignore enabled, write comprehensive patterns for all known tools\n if (gitignoreSetting) {\n const patterns = collectComprehensivePatterns({ fileTargets: [] });\n await updateGitignore(cwd, patterns);\n spinner.stop(\"✅ Updated .gitignore with managed file patterns\");\n } else {\n spinner.stop(\"✅ Added .baton/ to .gitignore\");\n }\n\n // 8. Create .baton directory\n spinner.start(\"Creating .baton directory...\");\n try {\n await mkdir(join(cwd, \".baton\"), { recursive: true });\n spinner.stop(\"✅ Created .baton directory\");\n } catch (_error) {\n spinner.stop(\"✅ .baton directory already exists\");\n }\n\n // 9. First-run preferences prompt\n await promptFirstRunPreferences(cwd, !isInteractive);\n\n // 10. Offer to sync profiles\n if (profileSources.length > 0) {\n const shouldSync = isInteractive\n ? await p.confirm({\n message: \"Fetch profiles and sync now?\",\n initialValue: true,\n })\n : true; // --yes mode: auto-sync\n\n if (!p.isCancel(shouldSync) && shouldSync) {\n await runBatonSync(cwd);\n } else {\n p.log.info(\"Run 'baton sync' later to fetch and apply your profiles.\");\n }\n }\n\n // 11. Summary\n p.outro(\"Baton initialized successfully!\");\n },\n});\n\n/**\n * Auto-scan AI tools if none are configured in global config.\n * In interactive mode: shows results and asks for confirmation.\n * In non-interactive mode (--yes): auto-saves detected tools.\n */\nasync function autoScanAiTools(\n spinner: ReturnType<typeof p.spinner>,\n isInteractive: boolean,\n): Promise<void> {\n const existingTools = await getGlobalAiTools();\n if (existingTools.length > 0) {\n p.log.info(`AI tools already configured: ${existingTools.join(\", \")}`);\n return;\n }\n\n spinner.start(\"Scanning for installed AI tools...\");\n clearAIToolCache();\n const detectedTools = await detectInstalledAITools();\n spinner.stop(\n detectedTools.length > 0\n ? `Found ${detectedTools.length} AI tool${detectedTools.length !== 1 ? \"s\" : \"\"}: ${detectedTools.join(\", \")}`\n : \"No AI tools detected.\",\n );\n\n if (detectedTools.length === 0) {\n p.log.warn(\"No AI tools detected. You can run 'baton ai-tools scan' later.\");\n return;\n }\n\n if (isInteractive) {\n const shouldSave = await p.confirm({\n message: \"Save detected AI tools to global config?\",\n initialValue: true,\n });\n\n if (p.isCancel(shouldSave) || !shouldSave) {\n p.log.info(\"Skipped saving AI tools. Run 'baton ai-tools scan' later.\");\n return;\n }\n }\n\n await setGlobalAiTools(detectedTools);\n p.log.success(\"AI tools saved to global config.\");\n}\n\n/**\n * Auto-scan IDE platforms if none are configured in global config.\n * In interactive mode: shows results and asks for confirmation.\n * In non-interactive mode (--yes): auto-saves detected platforms.\n */\nasync function autoScanIdePlatforms(\n spinner: ReturnType<typeof p.spinner>,\n isInteractive: boolean,\n): Promise<void> {\n const existingPlatforms = await getGlobalIdePlatforms();\n if (existingPlatforms.length > 0) {\n p.log.info(`IDE platforms already configured: ${existingPlatforms.join(\", \")}`);\n return;\n }\n\n spinner.start(\"Scanning for installed IDE platforms...\");\n clearIdeCache();\n const detectedIdes = await detectInstalledIdes();\n spinner.stop(\n detectedIdes.length > 0\n ? `Found ${detectedIdes.length} IDE platform${detectedIdes.length !== 1 ? \"s\" : \"\"}: ${detectedIdes.join(\", \")}`\n : \"No IDE platforms detected.\",\n );\n\n if (detectedIdes.length === 0) {\n p.log.warn(\"No IDE platforms detected. You can run 'baton ides scan' later.\");\n return;\n }\n\n if (isInteractive) {\n const shouldSave = await p.confirm({\n message: \"Save detected IDE platforms to global config?\",\n initialValue: true,\n });\n\n if (p.isCancel(shouldSave) || !shouldSave) {\n p.log.info(\"Skipped saving IDE platforms. Run 'baton ides scan' later.\");\n return;\n }\n }\n\n await setGlobalIdePlatforms(detectedIdes);\n p.log.success(\"IDE platforms saved to global config.\");\n}\n\n/**\n * Load source/profile manifests for each selected profile and display\n * the intersection between developer tools and profile support.\n *\n * Gracefully handles errors (e.g., missing source manifest) — the intersection\n * display is informational and should not block init.\n */\nasync function showProfileIntersections(profileSources: string[]): Promise<void> {\n const aiTools = await getGlobalAiTools();\n const idePlatforms = await getGlobalIdePlatforms();\n\n // No developer tools configured — nothing to intersect\n if (aiTools.length === 0 && idePlatforms.length === 0) {\n return;\n }\n\n const developerTools = { aiTools, idePlatforms };\n\n for (const sourceString of profileSources) {\n try {\n const parsed = parseSource(sourceString);\n\n let repoRoot: string;\n let profileDir: string;\n\n if (parsed.provider === \"github\" || parsed.provider === \"gitlab\") {\n // Clone repo (cache hit) — without subpath to get the repo root\n const repoClone = await cloneGitSource({\n url: parsed.url,\n ref: parsed.ref,\n useCache: true,\n });\n repoRoot = repoClone.localPath;\n profileDir = parsed.subpath ? resolve(repoRoot, parsed.subpath) : repoRoot;\n } else if (parsed.provider === \"local\" || parsed.provider === \"file\") {\n const absolutePath = parsed.path.startsWith(\"/\")\n ? parsed.path\n : resolve(process.cwd(), parsed.path);\n profileDir = absolutePath;\n // Walk up from profile dir to find source root (containing baton.source.yaml)\n repoRoot = (await findSourceRoot(absolutePath, { fallbackToStart: true })) as string;\n } else {\n // git/npm providers — skip intersection display\n continue;\n }\n\n // Load source manifest (optional — source may not have one)\n let sourceManifest: SourceManifest;\n try {\n sourceManifest = await findSourceManifest(repoRoot);\n } catch {\n // No source manifest — use empty defaults\n sourceManifest = { name: \"unknown\", version: \"0.0.0\" } as SourceManifest;\n }\n\n // Load profile manifest\n const profileManifestPath = resolve(profileDir, \"baton.profile.yaml\");\n const profileManifest = await loadProfileManifest(profileManifestPath).catch(() => null);\n if (!profileManifest) continue;\n\n // Compute intersection\n const profileSupport = resolveProfileSupport(profileManifest, sourceManifest);\n const intersection = computeIntersection(developerTools, profileSupport);\n\n // Only display if there's meaningful data\n const hasData =\n intersection.aiTools.synced.length > 0 ||\n intersection.aiTools.unavailable.length > 0 ||\n intersection.idePlatforms.synced.length > 0 ||\n intersection.idePlatforms.unavailable.length > 0;\n\n if (hasData) {\n p.log.step(`Intersection for ${profileManifest.name}`);\n displayIntersection(intersection);\n }\n } catch {\n // Intersection display is best-effort — don't block init\n }\n }\n}\n","import { access, rm, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { ProjectManifest } from \"@baton-dx/core\";\nimport {\n FileNotFoundError,\n getAllAIToolAdapters,\n getDefaultGlobalSource,\n getGlobalAiTools,\n getGlobalIdePlatforms,\n getGlobalSources,\n getRegisteredIdePlatforms,\n loadProjectManifest,\n readLock,\n readProjectPreferences,\n removePlacedFiles,\n writeProjectPreferences,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { stringify } from \"yaml\";\nimport { buildIntersection } from \"../utils/build-intersection.js\";\nimport { displayIntersection, formatIntersectionSummary } from \"../utils/intersection-display.js\";\nimport { selectProfileFromSource } from \"../utils/profile-selection.js\";\nimport { runBatonSync } from \"../utils/run-baton-sync.js\";\n\nasync function loadProjectManifestSafe(cwd: string): Promise<ProjectManifest | null> {\n try {\n return await loadProjectManifest(join(cwd, \"baton.yaml\"));\n } catch {\n return null;\n }\n}\n\nasync function hasLockfile(cwd: string): Promise<boolean> {\n try {\n await access(join(cwd, \"baton.lock\"));\n return true;\n } catch {\n return false;\n }\n}\n\nasync function showOverview(cwd: string): Promise<void> {\n const [manifest, sources, synced] = await Promise.all([\n loadProjectManifestSafe(cwd),\n getGlobalSources(),\n hasLockfile(cwd),\n ]);\n\n if (!manifest) {\n p.log.warn(\"Could not load baton.yaml\");\n return;\n }\n\n // --- Installed Profiles ---\n p.log.step(\"Installed Profiles\");\n if (manifest.profiles.length === 0) {\n p.log.info(\" No profiles installed.\");\n } else {\n for (const profile of manifest.profiles) {\n const version = profile.version ? ` (${profile.version})` : \"\";\n const matchingSource = sources.find(\n (s) => profile.source.includes(s.url) || profile.source.includes(s.name),\n );\n const sourceName = matchingSource ? ` [${matchingSource.name}]` : \"\";\n p.log.info(` ${profile.source}${version}${sourceName}`);\n }\n }\n\n // --- Intersection per Profile ---\n if (manifest.profiles.length > 0) {\n const aiTools = await getGlobalAiTools();\n const idePlatforms = await getGlobalIdePlatforms();\n\n if (aiTools.length > 0 || idePlatforms.length > 0) {\n const developerTools = { aiTools, idePlatforms };\n console.log(\"\");\n p.log.step(\"Tool Intersection\");\n\n for (const profile of manifest.profiles) {\n try {\n const intersection = await buildIntersection(profile.source, developerTools, cwd);\n if (intersection) {\n const summary = formatIntersectionSummary(intersection);\n p.log.info(` ${profile.source}: ${summary}`);\n displayIntersection(intersection);\n }\n } catch {\n // Best-effort — skip if intersection cannot be computed\n }\n }\n }\n }\n\n // --- Sync Status ---\n console.log(\"\");\n p.log.step(\"Sync Status\");\n if (synced) {\n p.log.info(\" Synced (baton.lock exists)\");\n } else {\n p.log.info(\" Not synced — run 'baton sync' to sync profiles\");\n }\n\n // --- Global Sources ---\n console.log(\"\");\n p.log.step(\"Global Sources\");\n if (sources.length === 0) {\n p.log.info(\" No sources configured. Run: baton source connect <url>\");\n } else {\n for (const source of sources) {\n const defaultBadge = source.default ? \" (default)\" : \"\";\n p.log.info(` ${source.name}${defaultBadge}: ${source.url}`);\n }\n }\n}\n\nasync function handleAddProfile(cwd: string): Promise<void> {\n const manifestPath = join(cwd, \"baton.yaml\");\n const manifest = await loadProjectManifestSafe(cwd);\n if (!manifest) {\n p.log.error(\"Could not load baton.yaml\");\n return;\n }\n\n // 1. Get global sources\n const globalSources = await getGlobalSources();\n if (globalSources.length === 0) {\n p.log.warn(\"No global sources configured. Run: baton source connect <url>\");\n return;\n }\n\n // 2. Select a source\n let sourceString: string;\n if (globalSources.length === 1) {\n sourceString = globalSources[0].url;\n p.log.info(`Using source: ${globalSources[0].name} (${sourceString})`);\n } else {\n const defaultSource = await getDefaultGlobalSource();\n const selectedUrl = await p.select({\n message: \"Select a source repository:\",\n options: globalSources.map((s) => ({\n value: s.url,\n label: s.default ? `${s.name} [default]` : s.name,\n hint: s.description || s.url,\n })),\n initialValue: defaultSource?.url,\n });\n\n if (p.isCancel(selectedUrl)) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n sourceString = selectedUrl as string;\n }\n\n // 3. Select a profile from the source\n const selectedSource = await selectProfileFromSource(sourceString);\n\n // 4. Check for duplicates\n const alreadyExists = manifest.profiles.some((pr) => pr.source === selectedSource);\n if (alreadyExists) {\n p.log.warn(`Profile \"${selectedSource}\" is already installed.`);\n return;\n }\n\n // 5. Add to manifest and write\n manifest.profiles.push({ source: selectedSource });\n const updatedYaml = stringify(manifest);\n await writeFile(manifestPath, updatedYaml, \"utf-8\");\n p.log.success(`Added profile: ${selectedSource}`);\n\n // 6. Offer to sync\n const shouldSync = await p.confirm({\n message: \"Sync profiles now?\",\n initialValue: true,\n });\n\n if (p.isCancel(shouldSync) || !shouldSync) {\n p.log.info(\"Run 'baton sync' later to apply the new profile.\");\n return;\n }\n\n await runBatonSync(cwd);\n}\n\nasync function handleRemoveProfile(cwd: string): Promise<void> {\n const manifestPath = join(cwd, \"baton.yaml\");\n const manifest = await loadProjectManifestSafe(cwd);\n if (!manifest) {\n p.log.error(\"Could not load baton.yaml\");\n return;\n }\n\n if (manifest.profiles.length === 0) {\n p.log.warn(\"No profiles installed.\");\n return;\n }\n\n // 1. Select profile to remove\n const selected = await p.select({\n message: \"Which profile do you want to remove?\",\n options: manifest.profiles.map((pr) => ({\n value: pr.source,\n label: pr.source,\n hint: pr.version ? `v${pr.version}` : undefined,\n })),\n });\n\n if (p.isCancel(selected)) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n\n const profileSource = selected as string;\n\n // 2. Confirm removal\n const confirmed = await p.confirm({\n message: `Remove profile \"${profileSource}\"?`,\n initialValue: false,\n });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n\n // 3. Remove from manifest and write\n const profileIndex = manifest.profiles.findIndex((pr) => pr.source === profileSource);\n manifest.profiles.splice(profileIndex, 1);\n\n const updatedYaml = stringify(manifest);\n await writeFile(manifestPath, updatedYaml, \"utf-8\");\n p.log.success(`Removed profile: ${profileSource}`);\n p.log.info(\"Run 'baton sync' to clean up synced files.\");\n}\n\nasync function handleRemoveBaton(cwd: string): Promise<boolean> {\n // 1. Warning\n p.log.warn(\"This will remove Baton from your project:\");\n p.log.info(\" - baton.yaml (project manifest)\");\n p.log.info(\" - baton.lock (lockfile)\");\n\n // 2. Confirm\n const confirmed = await p.confirm({\n message: \"Are you sure you want to remove Baton from this project?\",\n initialValue: false,\n });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.log.warn(\"Cancelled.\");\n return false;\n }\n\n // 3. Offer to clean up placed files from lockfile\n const lockPath = join(cwd, \"baton.lock\");\n await cleanupPlacedFilesFromLock(lockPath, cwd);\n\n // 4. Delete baton.yaml\n const manifestPath = join(cwd, \"baton.yaml\");\n await rm(manifestPath, { force: true });\n\n // 5. Delete baton.lock\n await rm(lockPath, { force: true });\n\n p.log.success(\"Baton has been removed from this project.\");\n return true;\n}\n\nasync function cleanupPlacedFilesFromLock(lockPath: string, projectRoot: string): Promise<void> {\n let placedPaths: string[];\n try {\n const lockfile = await readLock(lockPath);\n placedPaths = Object.values(lockfile.packages).flatMap((pkg) => Object.keys(pkg.integrity));\n } catch (error) {\n if (error instanceof FileNotFoundError) return;\n // Invalid lockfile — skip cleanup silently\n return;\n }\n\n if (placedPaths.length === 0) return;\n\n p.log.info(`Found ${placedPaths.length} placed file(s):`);\n for (const filePath of placedPaths) {\n p.log.info(` ${filePath}`);\n }\n\n const shouldClean = await p.confirm({\n message: `Also remove ${placedPaths.length} placed file(s)?`,\n initialValue: false,\n });\n\n if (p.isCancel(shouldClean) || !shouldClean) return;\n\n const removedCount = await removePlacedFiles(placedPaths, projectRoot);\n p.log.success(`Removed ${removedCount} placed file(s).`);\n}\n\nfunction formatIdeName(ideKey: string): string {\n const names: Record<string, string> = {\n vscode: \"VS Code\",\n jetbrains: \"JetBrains\",\n cursor: \"Cursor\",\n windsurf: \"Windsurf\",\n antigravity: \"Antigravity\",\n zed: \"Zed\",\n };\n return names[ideKey] ?? ideKey;\n}\n\nasync function handleConfigureAiTools(cwd: string): Promise<void> {\n const existing = await readProjectPreferences(cwd);\n const globalTools = await getGlobalAiTools();\n\n if (globalTools.length > 0) {\n p.log.info(`Global AI tools: ${globalTools.join(\", \")}`);\n }\n\n // Ask useGlobal first\n const mode = await p.select({\n message: \"How should this project resolve AI tools?\",\n options: [\n {\n value: \"global\",\n label: \"Use global config\",\n hint: \"always follows your global AI tools setting\",\n },\n {\n value: \"project\",\n label: \"Customize for this project\",\n hint: \"choose specific tools for this project\",\n },\n ],\n initialValue: existing?.ai.useGlobal === false ? \"project\" : \"global\",\n });\n\n if (p.isCancel(mode)) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n\n if (mode === \"global\") {\n await writeProjectPreferences(cwd, {\n version: \"1.0\",\n ai: { useGlobal: true, tools: [] },\n ide: existing?.ide ?? { useGlobal: true, platforms: [] },\n });\n p.log.success(\"Project configured to use global AI tools.\");\n return;\n }\n\n // Customize: show multiselect\n const allAdapters = getAllAIToolAdapters();\n const currentProjectTools = existing?.ai.useGlobal === false ? existing.ai.tools : globalTools;\n\n const options = allAdapters.map((adapter) => ({\n value: adapter.key,\n label: globalTools.includes(adapter.key) ? `${adapter.name} (in global config)` : adapter.name,\n }));\n\n const selected = await p.multiselect({\n message: \"Select AI tools for this project:\",\n options,\n initialValues: currentProjectTools,\n });\n\n if (p.isCancel(selected)) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n await writeProjectPreferences(cwd, {\n version: \"1.0\",\n ai: { useGlobal: false, tools: selectedKeys },\n ide: existing?.ide ?? { useGlobal: true, platforms: [] },\n });\n\n p.log.success(`Project configured with ${selectedKeys.length} AI tool(s).`);\n}\n\nasync function handleConfigureIdes(cwd: string): Promise<void> {\n const existing = await readProjectPreferences(cwd);\n const globalPlatforms = await getGlobalIdePlatforms();\n\n if (globalPlatforms.length > 0) {\n p.log.info(`Global IDE platforms: ${globalPlatforms.join(\", \")}`);\n }\n\n // Ask useGlobal first\n const mode = await p.select({\n message: \"How should this project resolve IDE platforms?\",\n options: [\n {\n value: \"global\",\n label: \"Use global config\",\n hint: \"always follows your global IDE platforms setting\",\n },\n {\n value: \"project\",\n label: \"Customize for this project\",\n hint: \"choose specific IDEs for this project\",\n },\n ],\n initialValue: existing?.ide.useGlobal === false ? \"project\" : \"global\",\n });\n\n if (p.isCancel(mode)) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n\n if (mode === \"global\") {\n await writeProjectPreferences(cwd, {\n version: \"1.0\",\n ai: existing?.ai ?? { useGlobal: true, tools: [] },\n ide: { useGlobal: true, platforms: [] },\n });\n p.log.success(\"Project configured to use global IDE platforms.\");\n return;\n }\n\n // Customize: show multiselect\n const allIdeKeys = getRegisteredIdePlatforms();\n const currentProjectPlatforms =\n existing?.ide.useGlobal === false ? existing.ide.platforms : globalPlatforms;\n\n const options = allIdeKeys.map((ideKey) => ({\n value: ideKey,\n label: globalPlatforms.includes(ideKey)\n ? `${formatIdeName(ideKey)} (in global config)`\n : formatIdeName(ideKey),\n }));\n\n const selected = await p.multiselect({\n message: \"Select IDE platforms for this project:\",\n options,\n initialValues: currentProjectPlatforms,\n });\n\n if (p.isCancel(selected)) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n\n const selectedKeys = selected as string[];\n\n await writeProjectPreferences(cwd, {\n version: \"1.0\",\n ai: existing?.ai ?? { useGlobal: true, tools: [] },\n ide: { useGlobal: false, platforms: selectedKeys },\n });\n\n p.log.success(`Project configured with ${selectedKeys.length} IDE platform(s).`);\n}\n\nasync function handleConfigureGitignore(cwd: string): Promise<void> {\n const manifestPath = join(cwd, \"baton.yaml\");\n const manifest = await loadProjectManifestSafe(cwd);\n if (!manifest) {\n p.log.error(\"Could not load baton.yaml\");\n return;\n }\n\n const currentSetting = manifest.gitignore !== false;\n p.log.info(\n currentSetting\n ? \"Currently: synced files ARE gitignored\"\n : \"Currently: synced files are NOT gitignored (committed to repo)\",\n );\n\n const newSetting = await p.confirm({\n message: \"Add synced AI tool and IDE config files to .gitignore?\",\n initialValue: currentSetting,\n });\n\n if (p.isCancel(newSetting)) {\n p.log.warn(\"Cancelled.\");\n return;\n }\n\n if (newSetting === currentSetting) {\n p.log.info(\"No change.\");\n return;\n }\n\n manifest.gitignore = newSetting;\n const updatedYaml = stringify(manifest);\n await writeFile(manifestPath, updatedYaml, \"utf-8\");\n p.log.success(\n newSetting\n ? \"Enabled .gitignore management. Run 'baton sync' to update.\"\n : \"Disabled .gitignore management. Run 'baton sync' to clean up.\",\n );\n}\n\nexport const manageCommand = defineCommand({\n meta: {\n name: \"manage\",\n description: \"Interactive project management wizard for Baton\",\n },\n async run() {\n const cwd = process.cwd();\n\n // Guard: must be in an initialized project\n const manifest = await loadProjectManifestSafe(cwd);\n if (!manifest) {\n p.intro(\"Baton Manage\");\n p.cancel(\"baton.yaml not found. Run 'baton init' first.\");\n process.exit(1);\n }\n\n p.intro(\"Baton Manage\");\n\n // Loop-based wizard\n while (true) {\n const action = await p.select({\n message: \"What would you like to do?\",\n options: [\n { value: \"overview\", label: \"Overview\", hint: \"Show project configuration\" },\n { value: \"add-profile\", label: \"Add profile\", hint: \"Add a profile from a source\" },\n { value: \"remove-profile\", label: \"Remove profile\", hint: \"Remove an installed profile\" },\n {\n value: \"configure-ai\",\n label: \"Configure AI tools for this project\",\n hint: \"Choose which AI tools to sync\",\n },\n {\n value: \"configure-ides\",\n label: \"Configure IDEs for this project\",\n hint: \"Choose which IDEs to sync\",\n },\n {\n value: \"configure-gitignore\",\n label: \"Configure .gitignore\",\n hint: \"Choose whether synced files are gitignored\",\n },\n { value: \"remove-baton\", label: \"Remove Baton\", hint: \"Remove Baton from this project\" },\n { value: \"quit\", label: \"Quit\" },\n ],\n });\n\n if (p.isCancel(action) || action === \"quit\") {\n p.outro(\"Goodbye!\");\n return;\n }\n\n if (action === \"overview\") {\n console.log(\"\");\n await showOverview(cwd);\n console.log(\"\");\n } else if (action === \"add-profile\") {\n console.log(\"\");\n await handleAddProfile(cwd);\n console.log(\"\");\n } else if (action === \"remove-profile\") {\n console.log(\"\");\n await handleRemoveProfile(cwd);\n console.log(\"\");\n } else if (action === \"configure-ai\") {\n console.log(\"\");\n await handleConfigureAiTools(cwd);\n console.log(\"\");\n } else if (action === \"configure-ides\") {\n console.log(\"\");\n await handleConfigureIdes(cwd);\n console.log(\"\");\n } else if (action === \"configure-gitignore\") {\n console.log(\"\");\n await handleConfigureGitignore(cwd);\n console.log(\"\");\n } else if (action === \"remove-baton\") {\n console.log(\"\");\n const removed = await handleRemoveBaton(cwd);\n if (removed) {\n p.outro(\"Goodbye!\");\n return;\n }\n console.log(\"\");\n }\n }\n },\n});\n","import { defineCommand } from \"citty\";\n\nexport const profileCommand = defineCommand({\n meta: {\n name: \"profile\",\n description: \"Manage profiles (create, list, remove)\",\n },\n subCommands: {\n create: () => import(\"./create.js\").then((m) => m.createCommand),\n list: () => import(\"./list.js\").then((m) => m.profileListCommand),\n remove: () => import(\"./remove.js\").then((m) => m.profileRemoveCommand),\n },\n});\n","import { execFile } from \"node:child_process\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n checkLatestVersion,\n detectInstallMethod,\n formatInstallCommand,\n isUpdateAvailable,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nasync function readCurrentVersion(): Promise<string> {\n try {\n const pkg = JSON.parse(await readFile(join(__dirname, \"../package.json\"), \"utf-8\"));\n return typeof pkg.version === \"string\" ? pkg.version : \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\nexport const selfUpdateCommand = defineCommand({\n meta: {\n name: \"self-update\",\n description: \"Update Baton to the latest stable version\",\n },\n args: {\n changelog: {\n type: \"boolean\",\n description: \"Show release notes for the new version\",\n default: false,\n },\n \"dry-run\": {\n type: \"boolean\",\n description: \"Check for updates without performing the update\",\n default: false,\n },\n yes: {\n type: \"boolean\",\n alias: \"y\",\n description: \"Skip confirmation prompt\",\n default: false,\n },\n },\n async run({ args }) {\n p.intro(\"baton self-update\");\n\n const currentVersion = await readCurrentVersion();\n\n // Check latest version\n const s = p.spinner();\n s.start(\"Checking for updates...\");\n\n let latestVersion: string;\n try {\n const result = await checkLatestVersion();\n latestVersion = result.version;\n } catch (error) {\n s.stop(\"Failed to check for updates\");\n p.log.error(error instanceof Error ? error.message : \"Unknown error occurred\");\n p.outro(\"Update check failed.\");\n process.exit(1);\n }\n\n s.stop(\"Version check complete\");\n\n // Compare versions\n const { updateAvailable } = isUpdateAvailable(currentVersion, latestVersion);\n if (!updateAvailable) {\n p.log.success(`Already up to date (v${currentVersion}).`);\n p.outro(\"No update needed.\");\n return;\n }\n\n // Detect install method\n const installMethod = await detectInstallMethod();\n const displayCommand = formatInstallCommand(installMethod);\n\n p.log.info(\n [\n `Current version: v${currentVersion}`,\n `Latest version: v${latestVersion}`,\n installMethod.type !== \"unknown\" ? `Install method: ${installMethod.type}` : \"\",\n ]\n .filter(Boolean)\n .join(\"\\n\"),\n );\n\n // Handle unknown install method\n if (installMethod.type === \"unknown\") {\n p.log.warn(\"Could not detect installation method.\");\n p.log.message(\n [\n \"Please update manually using one of:\",\n \" npm install -g @baton-dx/cli@latest\",\n \" pnpm update -g @baton-dx/cli --latest\",\n \" bun update -g @baton-dx/cli --latest\",\n \" brew upgrade baton-dx\",\n ].join(\"\\n\"),\n );\n p.outro(\"Manual update required.\");\n return;\n }\n\n // Dry-run: stop here\n if (args[\"dry-run\"]) {\n p.log.info(`Would run: ${displayCommand}`);\n p.outro(\"Dry run complete.\");\n return;\n }\n\n // Changelog (optional)\n if (args.changelog) {\n const changelogUrl = `https://github.com/baton-dx/baton/releases/tag/v${latestVersion}`;\n p.log.info(`Release notes: ${changelogUrl}`);\n }\n\n // Confirmation prompt\n if (!args.yes) {\n const confirmed = await p.confirm({\n message: `Update to v${latestVersion}?`,\n });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.outro(\"Update cancelled.\");\n return;\n }\n }\n\n // Execute update\n const updateSpinner = p.spinner();\n updateSpinner.start(`Running: ${displayCommand}`);\n\n try {\n await new Promise<void>((resolve, reject) => {\n execFile(installMethod.bin, installMethod.args, (error) => {\n if (error) reject(error);\n else resolve();\n });\n });\n updateSpinner.stop(`Successfully updated to v${latestVersion}`);\n p.outro(\"Update complete!\");\n } catch (error) {\n updateSpinner.stop(\"Update failed\");\n const message = error instanceof Error ? error.message : \"Unknown error\";\n p.log.error(`Failed to run: ${displayCommand}`);\n p.log.error(message);\n p.outro(\"Update failed. Please try updating manually.\");\n process.exit(1);\n }\n },\n});\n","import { KEBAB_CASE_REGEX, SourceParseError, addGlobalSource, parseSource } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { selectMultipleProfilesFromSource } from \"../../utils/profile-selection.js\";\n\n/**\n * Command: baton source connect\n *\n * Connects a source repository to the global configuration (~/.baton/config.yaml).\n * Once connected, sources can be auto-selected in `baton init`.\n */\nexport const connectCommand = defineCommand({\n meta: {\n name: \"connect\",\n description: \"Connect a source repository to your global config\",\n },\n args: {\n url: {\n type: \"positional\",\n description: \"Source URL (github:org/repo, ../path)\",\n required: true,\n },\n name: {\n type: \"string\",\n description: \"Custom name for the source (kebab-case)\",\n },\n description: {\n type: \"string\",\n description: \"Source description\",\n },\n },\n async run({ args }) {\n const url = args.url as string;\n const customName = args.name as string | undefined;\n\n if (customName && !KEBAB_CASE_REGEX.test(customName)) {\n p.cancel(\"Source name must be kebab-case (e.g., my-source)\");\n process.exit(1);\n }\n\n try {\n parseSource(url);\n } catch (error) {\n const message =\n error instanceof SourceParseError\n ? error.message\n : `Invalid source: ${(error as Error).message}`;\n p.cancel(message);\n process.exit(1);\n }\n\n try {\n await addGlobalSource(url, {\n name: args.name as string | undefined,\n description: args.description as string | undefined,\n });\n\n const displayName = args.name || url;\n p.log.success(`Connected source: ${displayName}`);\n\n const shouldSync = await p.confirm({\n message: \"Would you like to sync profiles from this source now?\",\n initialValue: false,\n });\n\n if (p.isCancel(shouldSync) || !shouldSync) {\n p.outro(\"Source connected. Run 'baton init' to set up profiles.\");\n return;\n }\n\n p.outro(\"Starting profile sync...\");\n\n const profiles = await selectMultipleProfilesFromSource(url);\n if (profiles.length > 0) {\n p.log.success(`Selected ${profiles.length} profile(s) for sync.`);\n p.note(\n \"Run 'baton init' in your project directory to install these profiles.\",\n \"Next step\",\n );\n }\n } catch (error) {\n p.cancel(`Failed to connect source: ${(error as Error).message}`);\n process.exit(1);\n }\n },\n});\n","import { mkdir, readFile, readdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { KEBAB_CASE_REGEX } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport Handlebars from \"handlebars\";\nimport simpleGit from \"simple-git\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\ninterface WizardOptions {\n name: string;\n git: boolean;\n withInitialProfile: boolean;\n}\n\ninterface WizardOverrides {\n name?: string;\n git?: boolean;\n withInitialProfile?: boolean;\n}\n\nasync function runInteractiveWizard(overrides: WizardOverrides = {}): Promise<WizardOptions> {\n p.intro(\"Create a new Baton source repository\");\n\n // 1. Name (with validation)\n let name: string;\n if (overrides.name) {\n name = overrides.name;\n } else {\n const result = await p.text({\n message: \"What is the name of your source repository?\",\n placeholder: \"my-team-profile\",\n validate: (value) => {\n if (!value) return \"Name is required\";\n if (!KEBAB_CASE_REGEX.test(value))\n return \"Name must be in kebab-case (lowercase, hyphens only)\";\n },\n });\n if (p.isCancel(result)) {\n p.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n name = String(result);\n }\n\n // 2. Git Initialization\n let git: boolean;\n if (overrides.git !== undefined) {\n git = overrides.git;\n } else {\n const result = (await p.confirm({\n message: \"Initialize Git repository?\",\n initialValue: true,\n })) as boolean;\n if (p.isCancel(result)) {\n p.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n git = result;\n }\n\n // 3. Initial Profile\n let withInitialProfile: boolean;\n if (overrides.withInitialProfile !== undefined) {\n withInitialProfile = overrides.withInitialProfile;\n } else {\n const result = (await p.confirm({\n message: \"Create initial profile in profiles/default/?\",\n initialValue: true,\n })) as boolean;\n if (p.isCancel(result)) {\n p.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n withInitialProfile = result;\n }\n\n return {\n name,\n git,\n withInitialProfile,\n };\n}\n\n/**\n * Recursively copy a directory and apply Handlebars variable substitution to text files\n */\nasync function copyDirectory(\n src: string,\n dest: string,\n variables: Record<string, unknown>,\n): Promise<void> {\n await mkdir(dest, { recursive: true });\n\n const entries = await readdir(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(src, entry.name);\n const destPath = join(dest, entry.name);\n\n if (entry.isDirectory()) {\n await copyDirectory(srcPath, destPath, variables);\n } else if (entry.isFile()) {\n const content = await readFile(srcPath, \"utf-8\");\n\n // Binary file detection (skip substitution for binary files)\n const binaryExtensions = new Set([\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".gif\",\n \".ico\",\n \".woff\",\n \".woff2\",\n \".ttf\",\n \".eot\",\n ]);\n const isBinary = binaryExtensions.has(entry.name.substring(entry.name.lastIndexOf(\".\")));\n\n if (isBinary) {\n await writeFile(destPath, content);\n } else {\n // Substitute variables with Handlebars\n const template = Handlebars.compile(content, { noEscape: true });\n const substituted = template(variables);\n await writeFile(destPath, substituted);\n }\n }\n }\n}\n\n/**\n * Initialize Git repository and create initial commit\n */\nasync function initializeGit(targetDir: string): Promise<void> {\n const git = simpleGit(targetDir);\n\n // Initialize repository\n await git.init();\n\n // Add all files\n await git.add(\".\");\n\n // Create initial commit\n await git.commit(\"Initial baton source setup\");\n}\n\n/**\n * Generate README.md with next steps\n */\nasync function generateReadme(targetDir: string, options: WizardOptions): Promise<void> {\n const { name, withInitialProfile } = options;\n const org = name.includes(\"-\") ? name.split(\"-\")[0] : name;\n\n const readmeContent = `# ${name}\n\nBaton source repository.\n\n## Usage\n\nAdd profiles from this source repository to your project:\n\n\\`\\`\\`bash\n# From GitHub (after you push)\nbaton init --profile github:${org}/${name}/profiles/default\n\n# Or locally (for testing)\nbaton init --profile file:./${name}/profiles/default\n\\`\\`\\`\n\n## Next Steps\n\n1. **Customize your profiles:**\n - Edit \\`baton.source.yaml\\` to configure the source metadata\n - Modify profiles in \\`profiles/*/baton.profile.yaml\\`\n - Add project-specific configurations to \\`profiles/*/files/\\`\n - Customize AI tool configs in \\`profiles/*/ai/\\`\n\n2. **Create additional profiles:**\n \\`\\`\\`bash\n cd ${name}\n baton profile create frontend\n baton profile create backend\n \\`\\`\\`\n\n3. **Set up Git remote:**\n \\`\\`\\`bash\n git remote add origin https://github.com/${org}/${name}.git\n git push -u origin main\n \\`\\`\\`\n\n4. **Share with your team:**\n - Publish to GitHub for team-wide access\n - Team members can use: \\`baton init --profile github:${org}/${name}/profiles/default\\`\n\n## Structure\n\n- \\`baton.source.yaml\\` - Source repository manifest\n- \\`profiles/\\` - Container for all profiles\n${withInitialProfile ? \" - `profiles/default/` - Default profile\\n - `baton.profile.yaml` - Profile manifest\\n - `ai/` - AI tool configurations\\n - `files/` - Dotfiles and configs to sync\\n - `ide/` - IDE settings\\n\" : \"\"}\n## Learn More\n\n- [Baton Documentation](https://github.com/baton-dx/baton)\n- [Source Schema](https://github.com/baton-dx/baton/blob/main/docs/source-schema.md)\n- [Profile Schema](https://github.com/baton-dx/baton/blob/main/docs/profile-schema.md)\n\n---\n\nGenerated with \\`baton source create\\`\n`;\n\n await writeFile(join(targetDir, \"README.md\"), readmeContent);\n}\n\n/**\n * Scaffold a source repository\n */\nexport async function scaffoldSourceRepo(options: WizardOptions): Promise<string> {\n const { name, git, withInitialProfile } = options;\n\n // Target directory is always ./<name>\n const targetDir = join(process.cwd(), name);\n\n // Create base directory and profiles/ folder\n await mkdir(join(targetDir, \"profiles\"), { recursive: true });\n\n // Create baton.source.yaml\n const sourceManifest = `name: \"${name}\"\nversion: \"0.1.0\"\ndescription: \"Baton source repository\"\n\n${\n withInitialProfile\n ? `profiles:\n - name: \"default\"\n path: \"profiles/default\"\n description: \"Default profile configuration\"\n`\n : \"\"\n}\nmetadata:\n created: \"${new Date().getFullYear()}\"\n`;\n await writeFile(join(targetDir, \"baton.source.yaml\"), sourceManifest);\n\n // Create initial profile if requested\n if (withInitialProfile) {\n const profileDir = join(targetDir, \"profiles\", \"default\");\n await mkdir(profileDir, { recursive: true });\n\n // Copy minimal profile template\n const profileTemplateDir = join(__dirname, \"templates\", \"profile\", \"minimal\");\n await copyDirectory(profileTemplateDir, profileDir, { name: \"default\" });\n }\n\n // Generate README.md\n await generateReadme(targetDir, options);\n\n // Initialize Git if requested\n if (git) {\n await initializeGit(targetDir);\n }\n\n return targetDir;\n}\n\nexport const sourceCreateCommand = defineCommand({\n meta: {\n name: \"source create\",\n description: \"Create a new source repository with an interactive wizard\",\n },\n args: {\n name: {\n type: \"positional\",\n description: \"Name of the source repository (kebab-case)\",\n required: false,\n },\n yes: {\n type: \"boolean\",\n description: \"Skip interactive wizard and use defaults\",\n default: false,\n },\n },\n async run({ args }) {\n const providedName = args.name as string | undefined;\n const yesArg = args.yes as boolean | undefined;\n\n // Validate name if provided\n if (providedName && !KEBAB_CASE_REGEX.test(providedName)) {\n console.error(\"Error: Name must be in kebab-case (lowercase, hyphens only)\");\n process.exit(1);\n }\n\n // Build overrides from CLI args\n const overrides: WizardOverrides = {\n name: providedName || undefined,\n };\n\n // If --yes flag: fill in defaults for anything not provided\n if (yesArg) {\n overrides.name = overrides.name || \"my-source\";\n overrides.git = true;\n overrides.withInitialProfile = false;\n }\n\n // Run wizard (skips steps where overrides are provided)\n const options = await runInteractiveWizard(overrides);\n\n // Scaffold the source repository\n const spinner = p.spinner();\n spinner.start(\"Creating source repository...\");\n\n try {\n const targetDir = await scaffoldSourceRepo(options);\n spinner.stop(`Source repository created at ${targetDir}`);\n\n // Build summary message\n const features: string[] = [];\n if (options.withInitialProfile) {\n features.push(\"Initial Profile: profiles/default/\");\n }\n if (options.git) {\n features.push(\"Git: Initialized with initial commit\");\n }\n\n if (features.length > 0) {\n p.note(features.join(\"\\n\"), \"Features\");\n }\n\n const org = options.name.includes(\"-\") ? options.name.split(\"-\")[0] : options.name;\n const nextSteps: string[] = [];\n nextSteps.push(` cd ${options.name}`);\n nextSteps.push(\" # Customize your profile (see README.md)\");\n if (options.git) {\n nextSteps.push(` git remote add origin https://github.com/${org}/${options.name}.git`);\n nextSteps.push(\" git push -u origin main\");\n }\n nextSteps.push(\"\");\n nextSteps.push(\" # Share with your team:\");\n nextSteps.push(` baton source connect https://github.com/${org}/${options.name}.git`);\n\n p.outro(\n `Source repository \"${options.name}\" created successfully!\\n\\nNext steps:\\n${nextSteps.join(\"\\n\")}`,\n );\n } catch (error) {\n spinner.stop(\"Failed to create source repository\");\n throw error;\n }\n },\n});\n","import { type GlobalSourceEntry, getGlobalSources, removeGlobalSource } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\n\n/**\n * Command: baton source disconnect\n *\n * Disconnects a source repository from the global configuration.\n * Shows a warning about profiles that depend on this source before removing.\n */\nexport const disconnectCommand = defineCommand({\n meta: {\n name: \"disconnect\",\n description: \"Disconnect a source repository from your global config\",\n },\n args: {\n source: {\n type: \"positional\",\n description: \"Source name or URL to disconnect\",\n required: true,\n },\n },\n async run({ args }) {\n const sourceIdentifier = args.source as string;\n\n // Find the matching source in global config\n const sources = await getGlobalSources();\n const matchedSource = sources.find(\n (s: GlobalSourceEntry) => s.name === sourceIdentifier || s.url === sourceIdentifier,\n );\n\n if (!matchedSource) {\n p.cancel(`Source \"${sourceIdentifier}\" not found in global configuration.`);\n process.exit(1);\n }\n\n // Warn about dependent projects/profiles\n p.log.warn(\n `Disconnecting source \"${matchedSource.name}\" (${matchedSource.url}) will affect any projects using profiles from this source.`,\n );\n p.log.info(\n \"Projects that reference this source will no longer be able to sync or update their profiles.\",\n );\n\n // Confirm before removing\n const confirmed = await p.confirm({\n message: `Are you sure you want to disconnect source \"${matchedSource.name}\"?`,\n initialValue: false,\n });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.cancel(\"Operation cancelled.\");\n process.exit(0);\n }\n\n try {\n await removeGlobalSource(sourceIdentifier);\n p.outro(`Disconnected source: ${matchedSource.name}`);\n } catch (error) {\n p.cancel(`Failed to disconnect source: ${(error as Error).message}`);\n process.exit(1);\n }\n },\n});\n","import { getGlobalSources } from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\n\n/**\n * Command: baton source list\n *\n * Lists all registered global sources from ~/.baton/config.yaml.\n */\nexport const listCommand = defineCommand({\n meta: {\n name: \"list\",\n description: \"List all global sources\",\n },\n async run() {\n const sources = await getGlobalSources();\n\n if (sources.length === 0) {\n p.log.info(\"No global sources configured.\");\n p.note(\"Add a source with:\\n baton source connect <url>\", \"Tip\");\n return;\n }\n\n console.log(\"\\n🌐 Global Sources\\n\");\n console.log(\"┌──────────────────┬─────────────────────────────────────┬─────────┐\");\n console.log(\"│ Name │ URL │ Default │\");\n console.log(\"├──────────────────┼─────────────────────────────────────┼─────────┤\");\n\n for (const source of sources) {\n const name = source.name.padEnd(16);\n const url = truncate(source.url, 35).padEnd(35);\n const def = source.default ? \"✓\" : \"\";\n\n console.log(`│ ${name} │ ${url} │ ${def.padEnd(7)} │`);\n\n if (source.description) {\n const desc = ` ${truncate(source.description, 33)}`.padEnd(35);\n console.log(`│ │ ${desc} │ │`);\n }\n }\n\n console.log(\"└──────────────────┴─────────────────────────────────────┴─────────┘\\n\");\n },\n});\n\n/**\n * Truncates a string to the specified length, adding \"...\" if truncated.\n */\nfunction truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) {\n return str;\n }\n return `${str.slice(0, maxLength - 3)}...`;\n}\n","import { defineCommand } from \"citty\";\nimport { connectCommand } from \"./connect.js\";\nimport { sourceCreateCommand } from \"./create.js\";\nimport { disconnectCommand } from \"./disconnect.js\";\nimport { listCommand } from \"./list.js\";\n\nexport const sourceCommand = defineCommand({\n meta: {\n name: \"source\",\n description: \"Manage source repositories (create, list, connect, disconnect)\",\n },\n subCommands: {\n create: sourceCreateCommand,\n list: listCommand,\n connect: connectCommand,\n disconnect: disconnectCommand,\n },\n});\n","import { mkdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, relative, resolve } from \"node:path\";\nimport {\n type AIToolAdapter,\n type AgentEntry,\n type AgentFile,\n type CloneContext,\n FileNotFoundError,\n type LockFileEntry,\n type MemoryEntry,\n type MergedSkillItem,\n type ProjectManifest,\n type RuleEntry,\n type RuleFile,\n type WeightConflictWarning,\n cloneGitSource,\n detectInstalledAITools,\n detectLegacyPaths,\n getAIToolAdaptersForKeys,\n getIdePlatformTargetDir,\n getProfileWeight,\n isKnownIdePlatform,\n isLockedProfile,\n loadProfileManifest,\n loadProjectManifest,\n mergeAgentsWithWarnings,\n mergeContentParts,\n mergeMemoryWithWarnings,\n mergeRulesWithWarnings,\n mergeSkillsWithWarnings,\n parseFrontmatter,\n parseSource,\n placeFile,\n resolvePreferences,\n resolveProfileChain,\n resolveVersion,\n sortProfilesByWeight,\n} from \"@baton-dx/core\";\nimport * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport simpleGit from \"simple-git\";\nimport { buildIntersection } from \"../utils/build-intersection.js\";\nimport { promptFirstRunPreferences } from \"../utils/first-run-preferences.js\";\nimport { displayIntersection, formatIntersectionSummary } from \"../utils/intersection-display.js\";\nimport {\n type SyncCategory,\n type SyncStats,\n cleanupOrphanedFiles,\n copyDirectoryRecursive,\n getOrCreatePlacedFiles,\n handleGitignoreUpdate,\n loadPreviousPlacedPaths,\n validCategories,\n writeLockData,\n writeStateData,\n} from \"./sync-pipeline.js\";\n\nexport const syncCommand = defineCommand({\n meta: {\n name: \"sync\",\n description: \"Fetch latest versions, sync all configurations, and update lockfile\",\n },\n args: {\n \"dry-run\": {\n type: \"boolean\",\n description: \"Show what would be done without writing files\",\n default: false,\n },\n category: {\n type: \"string\",\n description: \"Sync only a specific category: ai, files, or ide\",\n required: false,\n },\n yes: {\n type: \"boolean\",\n description: \"Run non-interactively (no prompts)\",\n default: false,\n },\n verbose: {\n type: \"boolean\",\n alias: \"v\",\n description: \"Show detailed output for each placed file\",\n default: false,\n },\n },\n async run({ args }) {\n const dryRun = args[\"dry-run\"];\n const categoryArg = args.category as string | undefined;\n const autoYes = args.yes;\n const verbose = args.verbose;\n\n // Validate --category flag\n let category: SyncCategory | undefined;\n if (categoryArg) {\n if (!validCategories.includes(categoryArg as SyncCategory)) {\n p.cancel(\n `Invalid category \"${categoryArg}\". Valid categories: ${validCategories.join(\", \")}`,\n );\n process.exit(1);\n }\n category = categoryArg as SyncCategory;\n }\n\n const syncAi = !category || category === \"ai\";\n const syncFiles = !category || category === \"files\";\n const syncIde = !category || category === \"ide\";\n\n p.intro(category ? `🔄 Baton Sync (category: ${category})` : \"🔄 Baton Sync\");\n\n // Statistics tracking\n const stats: SyncStats = {\n created: 0,\n errors: 0,\n };\n\n try {\n // Step 0: Load project manifest\n const projectRoot = process.cwd();\n const manifestPath = resolve(projectRoot, \"baton.yaml\");\n\n let projectManifest: ProjectManifest;\n try {\n projectManifest = await loadProjectManifest(manifestPath);\n } catch (error) {\n if (error instanceof FileNotFoundError) {\n p.cancel(\"baton.yaml not found. Run `baton init` first.\");\n } else {\n p.cancel(\n `Failed to load baton.yaml: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n process.exit(1);\n }\n\n // Step 0a: First-run preferences check\n await promptFirstRunPreferences(projectRoot, !!args.yes);\n\n // Step 0b: Read previous placement state to detect orphaned files later\n // Uses .baton/state.yaml (preferred) or falls back to old lockfile keys (legacy migration)\n const previousPaths = await loadPreviousPlacedPaths(projectRoot);\n\n // Step 1: Resolve profile chain\n const spinner = p.spinner();\n spinner.start(\"Resolving profile chain...\");\n\n const allProfiles = [];\n // Track SHA per source for lockfile\n const sourceShas = new Map<string, string>();\n for (const profileSource of projectManifest.profiles || []) {\n try {\n if (verbose) {\n p.log.info(`Resolving source: ${profileSource.source}`);\n }\n // Load the profile manifest first\n const parsed = parseSource(profileSource.source);\n\n let manifestPath: string;\n let cloneContext: CloneContext | undefined;\n if (parsed.provider === \"local\" || parsed.provider === \"file\") {\n const absolutePath = parsed.path.startsWith(\"/\")\n ? parsed.path\n : resolve(projectRoot, parsed.path);\n manifestPath = resolve(absolutePath, \"baton.profile.yaml\");\n // Try to get SHA from local git repo, fallback to \"local\"\n try {\n const git = simpleGit(absolutePath);\n await git.checkIsRepo();\n const sha = await git.revparse([\"HEAD\"]);\n sourceShas.set(profileSource.source, sha.trim());\n } catch {\n sourceShas.set(profileSource.source, \"local\");\n }\n } else {\n // For remote sources, clone first\n const url =\n parsed.provider === \"github\" || parsed.provider === \"gitlab\"\n ? parsed.url\n : parsed.provider === \"git\"\n ? parsed.url\n : \"\";\n\n if (!url) {\n throw new Error(`Invalid source: ${profileSource.source}`);\n }\n\n // Always resolve to latest version\n let resolvedRef: string;\n try {\n resolvedRef = await resolveVersion(url, \"latest\");\n if (verbose) {\n p.log.info(\n `Resolved latest: ${profileSource.source} → ${resolvedRef.slice(0, 12)}`,\n );\n }\n } catch {\n // Fallback to profileSource.version if resolution fails\n resolvedRef = profileSource.version || \"HEAD\";\n if (verbose) {\n p.log.warn(`Could not resolve latest for ${url}, using ${resolvedRef}`);\n }\n }\n\n const cloned = await cloneGitSource({\n url,\n ref: resolvedRef,\n subpath: \"subpath\" in parsed ? parsed.subpath : undefined,\n useCache: false,\n });\n manifestPath = resolve(cloned.localPath, \"baton.profile.yaml\");\n sourceShas.set(profileSource.source, cloned.sha);\n cloneContext = {\n cachePath: cloned.cachePath,\n sparseCheckout: cloned.sparseCheckout,\n };\n }\n\n const manifest = await loadProfileManifest(manifestPath);\n const profileDir = dirname(manifestPath);\n const chain = await resolveProfileChain(\n manifest,\n profileSource.source,\n profileDir,\n cloneContext,\n );\n allProfiles.push(...chain);\n } catch (error) {\n spinner.stop(`Failed to resolve profile ${profileSource.source}: ${error}`);\n stats.errors++;\n }\n }\n\n if (allProfiles.length === 0) {\n spinner.stop(\"No profiles configured\");\n p.outro(\"Nothing to sync. Run `baton manage` to add a profile.\");\n process.exit(2);\n }\n\n spinner.stop(`Resolved ${allProfiles.length} profile(s)`);\n\n // Step 1b: Sort profiles by weight for merge ordering\n // Higher-weight profiles appear later → win in \"last-wins\" merge logic\n // Stable sort preserves declaration order for same-weight profiles\n const weightSortedProfiles = sortProfilesByWeight(allProfiles);\n\n // Step 2: Merge configurations\n spinner.start(\"Merging configurations...\");\n\n // Collect all weight conflict warnings across merge operations\n const allWeightWarnings: WeightConflictWarning[] = [];\n\n const skillsResult = mergeSkillsWithWarnings(weightSortedProfiles);\n const mergedSkills: MergedSkillItem[] = skillsResult.skills;\n allWeightWarnings.push(...skillsResult.warnings);\n\n const rulesResult = mergeRulesWithWarnings(weightSortedProfiles);\n const mergedRules: RuleEntry[] = rulesResult.rules;\n allWeightWarnings.push(...rulesResult.warnings);\n\n const agentsResult = mergeAgentsWithWarnings(weightSortedProfiles);\n const mergedAgents: AgentEntry[] = agentsResult.agents;\n allWeightWarnings.push(...agentsResult.warnings);\n\n const memoryResult = mergeMemoryWithWarnings(weightSortedProfiles);\n const mergedMemory: MemoryEntry[] = memoryResult.entries;\n allWeightWarnings.push(...memoryResult.warnings);\n\n // Collect all commands from all profiles (deduplicated by name, last wins)\n // Respects weight lock: commands from weight -1 profiles cannot be overridden\n const commandMap = new Map<string, string>();\n const lockedCommands = new Set<string>();\n const commandOwner = new Map<string, { profileName: string; weight: number }>();\n for (const profile of weightSortedProfiles) {\n const weight = getProfileWeight(profile);\n const locked = isLockedProfile(profile);\n for (const cmd of profile.manifest.ai?.commands || []) {\n if (lockedCommands.has(cmd)) continue;\n\n const existing = commandOwner.get(cmd);\n if (existing && existing.weight === weight && existing.profileName !== profile.name) {\n allWeightWarnings.push({\n key: cmd,\n category: \"command\",\n profileA: existing.profileName,\n profileB: profile.name,\n weight,\n });\n }\n\n commandMap.set(cmd, profile.name);\n commandOwner.set(cmd, { profileName: profile.name, weight });\n if (locked) lockedCommands.add(cmd);\n }\n }\n const mergedCommandCount = commandMap.size;\n\n // Collect all files from all profiles (deduplicated by target path, last wins)\n // Respects weight lock: files from weight -1 profiles cannot be overridden\n const fileMap = new Map<string, { source: string; target: string; profileName: string }>();\n const lockedFiles = new Set<string>();\n const fileOwner = new Map<string, { profileName: string; weight: number }>();\n for (const profile of weightSortedProfiles) {\n const weight = getProfileWeight(profile);\n const locked = isLockedProfile(profile);\n for (const fileConfig of profile.manifest.files || []) {\n const target = fileConfig.target || fileConfig.source;\n if (lockedFiles.has(target)) continue;\n\n const existing = fileOwner.get(target);\n if (existing && existing.weight === weight && existing.profileName !== profile.name) {\n allWeightWarnings.push({\n key: target,\n category: \"file\",\n profileA: existing.profileName,\n profileB: profile.name,\n weight,\n });\n }\n\n fileMap.set(target, { source: fileConfig.source, target, profileName: profile.name });\n fileOwner.set(target, { profileName: profile.name, weight });\n if (locked) lockedFiles.add(target);\n }\n }\n const mergedFileCount = fileMap.size;\n\n // Collect all IDE configs from all profiles (deduplicated by target path, last wins)\n // Uses central IDE platform registry for key → directory mapping\n // Respects weight lock: IDE configs from weight -1 profiles cannot be overridden\n const ideMap = new Map<\n string,\n { ideKey: string; fileName: string; targetDir: string; profileName: string }\n >();\n const lockedIdeConfigs = new Set<string>();\n const ideOwner = new Map<string, { profileName: string; weight: number }>();\n for (const profile of weightSortedProfiles) {\n if (!profile.manifest.ide) continue;\n const weight = getProfileWeight(profile);\n const locked = isLockedProfile(profile);\n for (const [ideKey, files] of Object.entries(profile.manifest.ide)) {\n if (!files) continue;\n const targetDir = getIdePlatformTargetDir(ideKey);\n if (!targetDir) {\n if (!isKnownIdePlatform(ideKey)) {\n p.log.warn(\n `Unknown IDE platform \"${ideKey}\" in profile \"${profile.name}\" — skipping. Register it in the IDE platform registry.`,\n );\n }\n continue;\n }\n for (const fileName of files) {\n const targetPath = `${targetDir}/${fileName}`;\n if (lockedIdeConfigs.has(targetPath)) continue;\n\n const existing = ideOwner.get(targetPath);\n if (existing && existing.weight === weight && existing.profileName !== profile.name) {\n allWeightWarnings.push({\n key: targetPath,\n category: \"ide\",\n profileA: existing.profileName,\n profileB: profile.name,\n weight,\n });\n }\n\n ideMap.set(targetPath, { ideKey, fileName, targetDir, profileName: profile.name });\n ideOwner.set(targetPath, { profileName: profile.name, weight });\n if (locked) lockedIdeConfigs.add(targetPath);\n }\n }\n }\n const mergedIdeCount = ideMap.size;\n\n spinner.stop(\n `Merged: ${mergedSkills.length} skills, ${mergedRules.length} rules, ${mergedAgents.length} agents, ${mergedMemory.length} memory files, ${mergedCommandCount} commands, ${mergedFileCount} files, ${mergedIdeCount} IDE configs`,\n );\n\n // Emit weight conflict warnings (same weight, conflicting values)\n if (allWeightWarnings.length > 0) {\n for (const w of allWeightWarnings) {\n p.log.warn(\n `Weight conflict: \"${w.profileA}\" and \"${w.profileB}\" both define ${w.category} \"${w.key}\" with weight ${w.weight}. Last declared wins.`,\n );\n }\n }\n\n // Step 3: Determine which AI tools and IDE platforms to sync (intersection-based)\n spinner.start(\"Computing tool intersection...\");\n\n const prefs = await resolvePreferences(projectRoot);\n const detectedAITools = await detectInstalledAITools();\n\n if (verbose) {\n p.log.info(\n `AI tools: ${prefs.ai.tools.join(\", \") || \"(none)\"} (from ${prefs.ai.source} preferences)`,\n );\n p.log.info(\n `IDE platforms: ${prefs.ide.platforms.join(\", \") || \"(none)\"} (from ${prefs.ide.source} preferences)`,\n );\n }\n\n // Compute aggregated intersection across all profiles\n // A tool/platform is \"synced\" if the developer has it AND at least one profile supports it\n let syncedAiTools: string[];\n let syncedIdePlatforms: string[] | null = null;\n let allIntersections: Map<string, import(\"@baton-dx/core\").IntersectionResult> | null = null;\n\n if (prefs.ai.tools.length > 0) {\n const developerTools = { aiTools: prefs.ai.tools, idePlatforms: prefs.ide.platforms };\n const aggregatedSyncedAi = new Set<string>();\n const aggregatedSyncedIde = new Set<string>();\n allIntersections = new Map();\n\n for (const profileSource of projectManifest.profiles || []) {\n try {\n const intersection = await buildIntersection(\n profileSource.source,\n developerTools,\n projectRoot,\n );\n if (intersection) {\n allIntersections.set(profileSource.source, intersection);\n for (const tool of intersection.aiTools.synced) {\n aggregatedSyncedAi.add(tool);\n }\n for (const platform of intersection.idePlatforms.synced) {\n aggregatedSyncedIde.add(platform);\n }\n }\n } catch {\n // Best-effort — skip if intersection cannot be computed for this profile\n }\n }\n\n syncedAiTools = aggregatedSyncedAi.size > 0 ? [...aggregatedSyncedAi] : [];\n syncedIdePlatforms = [...aggregatedSyncedIde];\n } else {\n // No global config — fall back to detected agents for backward compatibility\n syncedAiTools = detectedAITools;\n // No IDE filtering when no global config exists (place all IDE files)\n syncedIdePlatforms = null;\n if (detectedAITools.length > 0) {\n p.log.warn(\"No AI tools configured. Run `baton ai-tools scan` to configure your tools.\");\n p.log.info(`Falling back to detected tools: ${detectedAITools.join(\", \")}`);\n }\n }\n\n if (syncedAiTools.length === 0 && detectedAITools.length === 0) {\n spinner.stop(\"No AI tools available\");\n p.cancel(\"No AI tools found. Install an AI coding tool first.\");\n process.exit(1);\n }\n\n if (syncedAiTools.length === 0) {\n spinner.stop(\"No AI tools in intersection\");\n p.cancel(\n \"No AI tools match between your configuration and profile support. \" +\n \"Run `baton ai-tools scan` or check your profile's supported tools.\",\n );\n process.exit(1);\n }\n\n // Show intersection or synced tools\n if (allIntersections) {\n for (const [source, intersection] of allIntersections) {\n if (verbose) {\n p.log.step(`Intersection for ${source}`);\n displayIntersection(intersection);\n } else {\n const summary = formatIntersectionSummary(intersection);\n p.log.info(`Syncing for: ${summary}`);\n }\n }\n }\n\n const ideSummary =\n syncedIdePlatforms && syncedIdePlatforms.length > 0\n ? ` | IDE platforms: ${syncedIdePlatforms.join(\", \")}`\n : \"\";\n spinner.stop(`Syncing AI tools: ${syncedAiTools.join(\", \")}${ideSummary}`);\n\n // Step 4: Migrate legacy paths\n spinner.start(\"Checking for legacy paths...\");\n\n const legacyFiles = await detectLegacyPaths(projectRoot);\n\n if (legacyFiles.length > 0 && !dryRun) {\n spinner.stop(`Found ${legacyFiles.length} legacy file(s)`);\n\n if (!autoYes) {\n p.note(\n `Found legacy configuration files:\\n${legacyFiles.map((f) => ` - ${f.legacyPath}`).join(\"\\n\")}`,\n \"Legacy Files\",\n );\n p.log.warn(\"Run migration manually with appropriate action (migrate/copy/skip)\");\n }\n } else {\n spinner.stop(\"No legacy files found\");\n }\n\n // Step 5-7: Transform, Place, and Link\n spinner.start(\"Processing configurations...\");\n\n // Use intersection-filtered AI tools instead of all detected agents\n const adapters = getAIToolAdaptersForKeys(syncedAiTools);\n\n // Placement configuration\n const placementConfig = {\n mode: \"copy\" as const, // Start with copy mode (symlink can be added later)\n projectRoot,\n };\n\n // Track placed file contents per profile for lockfile integrity hashes\n // Keys are CANONICAL paths (e.g., \"skills/add-adapter\", \"memory/MEMORY.md\")\n // Content is the SOURCE content (before tool transformation) for deterministic hashes\n const placedFiles = new Map<string, Record<string, LockFileEntry>>();\n\n // Track ACTUAL tool-specific file paths placed on disk (e.g., \".claude/skills/add-adapter\")\n // Used for state.yaml and orphan detection — never written to lockfile\n const actualPlacedPaths = new Set<string>();\n\n // Build a map from profile name to local directory path\n // This is needed because profile.source may be a remote URL (e.g., \"github:org/repo/subpath\")\n const profileLocalPaths = new Map<string, string>();\n for (const profileSource of projectManifest.profiles || []) {\n const parsed = parseSource(profileSource.source);\n if (parsed.provider === \"local\" || parsed.provider === \"file\") {\n const localPath = parsed.path.startsWith(\"/\")\n ? parsed.path\n : resolve(projectRoot, parsed.path);\n // Discover which profile name lives at this path\n for (const prof of allProfiles) {\n if (prof.source === profileSource.source) {\n profileLocalPaths.set(prof.name, localPath);\n }\n }\n } else if (\n parsed.provider === \"github\" ||\n parsed.provider === \"gitlab\" ||\n parsed.provider === \"git\"\n ) {\n const url = parsed.provider === \"git\" ? parsed.url : parsed.url;\n\n // Use the already-resolved SHA from sourceShas (resolved in Step 1)\n const resolvedSha = sourceShas.get(profileSource.source);\n\n const cloned = await cloneGitSource({\n url,\n ref: resolvedSha || profileSource.version,\n subpath: \"subpath\" in parsed ? parsed.subpath : undefined,\n useCache: true,\n });\n for (const prof of allProfiles) {\n if (prof.source === profileSource.source) {\n profileLocalPaths.set(prof.name, cloned.localPath);\n }\n }\n }\n }\n\n // Register local paths for inherited profiles (from extends chains)\n // These profiles are not in baton.yaml but were resolved via resolveProfileChain\n for (const prof of allProfiles) {\n if (!profileLocalPaths.has(prof.name) && prof.localPath) {\n profileLocalPaths.set(prof.name, prof.localPath);\n }\n }\n\n // Content accumulator for files that may receive content from multiple categories\n // (e.g., GitHub Copilot uses .github/copilot-instructions.md for both memory AND rules)\n // Key: absolute target path, Value: { parts, adapter, profiles }\n const contentAccumulator = new Map<\n string,\n {\n parts: string[];\n adapter: AIToolAdapter;\n type: \"memory\" | \"rules\" | \"agents\";\n name: string;\n profiles: Set<string>;\n }\n >();\n\n // Accumulate memory file content\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing memory files...`);\n }\n for (const memoryEntry of mergedMemory) {\n try {\n // Read content from all contributing profiles\n const contentParts: string[] = [];\n for (const contribution of memoryEntry.contributions) {\n const profileDir = profileLocalPaths.get(contribution.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${contribution.profileName}`,\n );\n continue;\n }\n\n const memoryFilePath = resolve(profileDir, \"ai\", \"memory\", memoryEntry.filename);\n try {\n const content = await readFile(memoryFilePath, \"utf-8\");\n contentParts.push(content);\n } catch {\n spinner.message(`Warning: Could not read ${memoryFilePath}`);\n }\n }\n\n if (contentParts.length === 0) continue;\n\n // Merge content according to strategy\n const mergedContent = mergeContentParts(contentParts, memoryEntry.mergeStrategy);\n\n // Transform memory file for this adapter\n const transformed = adapter.transformMemory({\n filename: memoryEntry.filename,\n content: mergedContent,\n });\n\n // Compute target path to detect shared file destinations\n const targetPath = adapter.getPath(\"memory\", \"project\", transformed.filename);\n const absolutePath = targetPath.startsWith(\"/\")\n ? targetPath\n : resolve(projectRoot, targetPath);\n\n // Accumulate content for this target path\n const existing = contentAccumulator.get(absolutePath);\n if (existing) {\n existing.parts.push(transformed.content);\n for (const c of memoryEntry.contributions) existing.profiles.add(c.profileName);\n } else {\n const profiles = new Set<string>();\n for (const c of memoryEntry.contributions) profiles.add(c.profileName);\n contentAccumulator.set(absolutePath, {\n parts: [transformed.content],\n adapter,\n type: \"memory\",\n name: transformed.filename,\n profiles,\n });\n }\n } catch (error) {\n spinner.message(\n `Error placing ${memoryEntry.filename} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n\n // Place skill directories\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing skills...`);\n }\n for (const skillItem of mergedSkills) {\n try {\n const profileDir = profileLocalPaths.get(skillItem.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${skillItem.profileName}`,\n );\n continue;\n }\n\n const skillSourceDir = resolve(profileDir, \"ai\", \"skills\", skillItem.name);\n\n // Check if skill directory exists\n try {\n await stat(skillSourceDir);\n } catch {\n spinner.message(`Warning: Skill directory not found: ${skillSourceDir}`);\n continue;\n }\n\n // Resolve target skill directory\n const targetSkillPath = adapter.getPath(\"skills\", skillItem.scope, skillItem.name);\n const absoluteTargetDir = targetSkillPath.startsWith(\"/\")\n ? targetSkillPath\n : resolve(projectRoot, targetSkillPath);\n\n // Recursively copy skill files\n const placed = await copyDirectoryRecursive(skillSourceDir, absoluteTargetDir);\n stats.created += placed;\n\n // Track tool-specific disk path for state/orphan detection\n actualPlacedPaths.add(targetSkillPath);\n\n // Track canonical key + source content for lockfile integrity (once per skill, not per adapter)\n const canonicalKey = `skills/${skillItem.name}`;\n const profileFiles = getOrCreatePlacedFiles(placedFiles, skillItem.profileName);\n if (!profileFiles[canonicalKey]) {\n try {\n const entryContent = await readFile(resolve(skillSourceDir, \"index.md\"), \"utf-8\");\n profileFiles[canonicalKey] = { content: entryContent, type: \"skills\" };\n } catch {\n profileFiles[canonicalKey] = { content: skillItem.name, type: \"skills\" };\n }\n }\n\n if (verbose) {\n const label = placed > 0 ? `${placed} file(s) created` : \"unchanged, skipped\";\n p.log.info(` -> ${absoluteTargetDir}/ (${label})`);\n }\n } catch (error) {\n spinner.message(\n `Error placing skill ${skillItem.name} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n\n // Accumulate rule file content\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing rules...`);\n }\n for (const ruleEntry of mergedRules) {\n try {\n // Normalize: strip .md extension to prevent double-extension bug\n // (manifest may declare \"coding-standards.md\", path template appends \".md\" again)\n const ruleName = ruleEntry.name.replace(/\\.md$/, \"\");\n\n // Check if this rule should be placed for this adapter\n const isUniversal = ruleEntry.agents.length === 0;\n const isForThisAdapter = ruleEntry.agents.includes(adapter.key);\n if (!isUniversal && !isForThisAdapter) continue;\n\n const profileDir = profileLocalPaths.get(ruleEntry.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${ruleEntry.profileName}`,\n );\n continue;\n }\n\n // Determine source file path based on rule type\n const ruleSubdir = isUniversal ? \"universal\" : ruleEntry.agents[0];\n const ruleSourcePath = resolve(\n profileDir,\n \"ai\",\n \"rules\",\n ruleSubdir,\n `${ruleName}.md`,\n );\n\n // Read rule content\n let rawContent: string;\n try {\n rawContent = await readFile(ruleSourcePath, \"utf-8\");\n } catch {\n spinner.message(`Warning: Could not read rule file: ${ruleSourcePath}`);\n continue;\n }\n\n // Parse frontmatter\n const parsed = parseFrontmatter(rawContent);\n\n // Build canonical RuleFile\n const ruleFile: RuleFile = {\n name: ruleName,\n content: rawContent,\n frontmatter:\n Object.keys(parsed.data).length > 0\n ? (parsed.data as RuleFile[\"frontmatter\"])\n : undefined,\n };\n\n // Transform rule for this adapter\n const transformed = adapter.transformRule(ruleFile);\n\n // Compute target path to detect shared file destinations\n const targetPath = adapter.getPath(\"rules\", \"project\", ruleName);\n const absolutePath = targetPath.startsWith(\"/\")\n ? targetPath\n : resolve(projectRoot, targetPath);\n\n // Accumulate content for this target path\n const existing = contentAccumulator.get(absolutePath);\n if (existing) {\n existing.parts.push(transformed.content);\n existing.profiles.add(ruleEntry.profileName);\n } else {\n contentAccumulator.set(absolutePath, {\n parts: [transformed.content],\n adapter,\n type: \"rules\",\n name: ruleName,\n profiles: new Set([ruleEntry.profileName]),\n });\n }\n } catch (error) {\n spinner.message(`Error placing rule ${ruleEntry.name} for ${adapter.name}: ${error}`);\n stats.errors++;\n }\n }\n }\n }\n\n // Accumulate agent file content\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing agents...`);\n }\n for (const agentEntry of mergedAgents) {\n try {\n // Normalize: strip .md extension to prevent double-extension bug\n // (manifest may declare \"code-reviewer.md\", path template appends \".md\" again)\n const agentName = agentEntry.name.replace(/\\.md$/, \"\");\n\n // Check if this agent should be placed for this adapter\n const isUniversal = agentEntry.agents.length === 0;\n const isForThisAdapter = agentEntry.agents.includes(adapter.key);\n if (!isUniversal && !isForThisAdapter) continue;\n\n const profileDir = profileLocalPaths.get(agentEntry.profileName);\n if (!profileDir) {\n spinner.message(\n `Warning: Could not resolve local path for profile ${agentEntry.profileName}`,\n );\n continue;\n }\n\n // Determine source file path based on agent type\n const agentSubdir = isUniversal ? \"universal\" : agentEntry.agents[0];\n const agentSourcePath = resolve(\n profileDir,\n \"ai\",\n \"agents\",\n agentSubdir,\n `${agentName}.md`,\n );\n\n // Read agent content\n let rawContent: string;\n try {\n rawContent = await readFile(agentSourcePath, \"utf-8\");\n } catch {\n spinner.message(`Warning: Could not read agent file: ${agentSourcePath}`);\n continue;\n }\n\n // Parse frontmatter\n const parsed = parseFrontmatter(rawContent);\n\n // Build canonical AgentFile (frontmatter is REQUIRED)\n const frontmatter =\n Object.keys(parsed.data).length > 0\n ? (parsed.data as AgentFile[\"frontmatter\"])\n : { name: agentName };\n const agentFile: AgentFile = {\n name: agentName,\n content: rawContent,\n description: (frontmatter as Record<string, unknown>).description as\n | string\n | undefined,\n frontmatter,\n };\n\n // Transform agent for this adapter\n const transformed = adapter.transformAgent(agentFile);\n\n // Compute target path to detect shared file destinations\n const targetPath = adapter.getPath(\"agents\", \"project\", agentName);\n const absolutePath = targetPath.startsWith(\"/\")\n ? targetPath\n : resolve(projectRoot, targetPath);\n\n // Accumulate content for this target path\n const existing = contentAccumulator.get(absolutePath);\n if (existing) {\n existing.parts.push(transformed.content);\n existing.profiles.add(agentEntry.profileName);\n } else {\n contentAccumulator.set(absolutePath, {\n parts: [transformed.content],\n adapter,\n type: \"agents\",\n name: agentName,\n profiles: new Set([agentEntry.profileName]),\n });\n }\n } catch (error) {\n spinner.message(\n `Error placing agent ${agentEntry.name} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n\n // Flush accumulated content: write combined memory+rules+agents to shared file paths\n if (!dryRun && syncAi) {\n for (const [absolutePath, entry] of contentAccumulator) {\n try {\n const combinedContent = entry.parts.join(\"\\n\\n\");\n const result = await placeFile(\n combinedContent,\n entry.adapter,\n entry.type,\n \"project\",\n entry.name,\n placementConfig,\n );\n\n if (result.action !== \"skipped\") {\n stats.created++;\n }\n\n // Track tool-specific disk path for state/orphan detection\n const relPath = isAbsolute(result.path)\n ? relative(projectRoot, result.path)\n : result.path;\n actualPlacedPaths.add(relPath);\n\n // Track canonical key + source content for lockfile integrity (once per canonical item)\n const canonicalKey = `${entry.type}/${entry.name}`;\n for (const profileName of entry.profiles) {\n const pf = getOrCreatePlacedFiles(placedFiles, profileName);\n if (!pf[canonicalKey]) {\n pf[canonicalKey] = {\n content: combinedContent,\n type: entry.type as LockFileEntry[\"type\"],\n };\n }\n }\n\n if (verbose) {\n const label = result.action === \"skipped\" ? \"unchanged, skipped\" : result.action;\n p.log.info(` -> ${result.path} (${label})`);\n }\n } catch (error) {\n spinner.message(`Error placing accumulated content to ${absolutePath}: ${error}`);\n stats.errors++;\n }\n }\n }\n\n // Place command files\n if (!dryRun && syncAi) {\n for (const adapter of adapters) {\n if (verbose) {\n p.log.step(`[${adapter.key}] Placing commands...`);\n }\n for (const profile of allProfiles) {\n const profileDir = profileLocalPaths.get(profile.name);\n if (!profileDir) continue;\n\n const commandNames = profile.manifest.ai?.commands || [];\n for (const commandName of commandNames) {\n try {\n const commandSourcePath = resolve(\n profileDir,\n \"ai\",\n \"commands\",\n `${commandName}.md`,\n );\n\n let content: string;\n try {\n content = await readFile(commandSourcePath, \"utf-8\");\n } catch {\n // Gracefully skip missing command files\n continue;\n }\n\n const result = await placeFile(\n content,\n adapter,\n \"commands\",\n \"project\",\n commandName,\n placementConfig,\n );\n\n if (result.action !== \"skipped\") {\n stats.created++;\n }\n\n // Track tool-specific disk path for state/orphan detection\n const cmdRelPath = isAbsolute(result.path)\n ? relative(projectRoot, result.path)\n : result.path;\n actualPlacedPaths.add(cmdRelPath);\n\n // Track canonical key + source content for lockfile (once per command)\n const canonicalKey = `commands/${commandName}`;\n const pf = getOrCreatePlacedFiles(placedFiles, profile.name);\n if (!pf[canonicalKey]) {\n pf[canonicalKey] = { content, type: \"commands\" };\n }\n\n if (verbose) {\n const label = result.action === \"skipped\" ? \"unchanged, skipped\" : result.action;\n p.log.info(` -> ${result.path} (${label})`);\n }\n } catch (error) {\n spinner.message(\n `Error placing command ${commandName} for ${adapter.name}: ${error}`,\n );\n stats.errors++;\n }\n }\n }\n }\n }\n\n // Place project files (files/ -> project root)\n if (!dryRun && syncFiles) {\n for (const fileEntry of fileMap.values()) {\n try {\n const profileDir = profileLocalPaths.get(fileEntry.profileName);\n if (!profileDir) continue;\n\n const fileSourcePath = resolve(profileDir, \"files\", fileEntry.source);\n\n let content: string;\n try {\n content = await readFile(fileSourcePath, \"utf-8\");\n } catch {\n // Gracefully skip missing files directories\n continue;\n }\n\n const targetPath = resolve(projectRoot, fileEntry.target);\n\n // Ensure target directory exists\n await mkdir(dirname(targetPath), { recursive: true });\n\n // Idempotency: skip if content is identical\n const existing = await readFile(targetPath, \"utf-8\").catch(() => undefined);\n if (existing !== content) {\n await writeFile(targetPath, content, \"utf-8\");\n stats.created++;\n if (verbose) {\n p.log.info(` -> ${fileEntry.target} (created)`);\n }\n } else if (verbose) {\n p.log.info(` -> ${fileEntry.target} (unchanged, skipped)`);\n }\n\n // Track disk path for state/orphan detection\n actualPlacedPaths.add(fileEntry.target);\n\n // Track canonical key for lockfile integrity\n const canonicalKey = `files/${fileEntry.target}`;\n const fpf = getOrCreatePlacedFiles(placedFiles, fileEntry.profileName);\n if (!fpf[canonicalKey]) {\n fpf[canonicalKey] = { content, type: \"files\" };\n }\n } catch (error) {\n spinner.message(`Error placing file ${fileEntry.source}: ${error}`);\n stats.errors++;\n }\n }\n }\n\n // Place IDE config files (ide/vscode/ -> .vscode/, ide/jetbrains/ -> .idea/)\n // Only place files for IDE platforms in the intersection (if intersection is available)\n if (!dryRun && syncIde) {\n for (const ideEntry of ideMap.values()) {\n try {\n // Filter by intersection: skip IDE platforms not in the developer's synced set\n if (syncedIdePlatforms !== null && !syncedIdePlatforms.includes(ideEntry.ideKey)) {\n if (verbose) {\n p.log.info(\n ` -> ${ideEntry.targetDir}/${ideEntry.fileName} (skipped — IDE platform \"${ideEntry.ideKey}\" not in intersection)`,\n );\n }\n continue;\n }\n\n const profileDir = profileLocalPaths.get(ideEntry.profileName);\n if (!profileDir) continue;\n\n const ideSourcePath = resolve(profileDir, \"ide\", ideEntry.ideKey, ideEntry.fileName);\n\n let content: string;\n try {\n content = await readFile(ideSourcePath, \"utf-8\");\n } catch {\n // Gracefully skip missing IDE config files\n continue;\n }\n\n const targetPath = resolve(projectRoot, ideEntry.targetDir, ideEntry.fileName);\n\n // Ensure target directory exists\n await mkdir(dirname(targetPath), { recursive: true });\n\n // Idempotency: skip if content is identical\n const existing = await readFile(targetPath, \"utf-8\").catch(() => undefined);\n if (existing !== content) {\n await writeFile(targetPath, content, \"utf-8\");\n stats.created++;\n if (verbose) {\n p.log.info(` -> ${ideEntry.targetDir}/${ideEntry.fileName} (created)`);\n }\n } else if (verbose) {\n p.log.info(` -> ${ideEntry.targetDir}/${ideEntry.fileName} (unchanged, skipped)`);\n }\n\n // Track disk path for state/orphan detection\n const ideRelPath = `${ideEntry.targetDir}/${ideEntry.fileName}`;\n actualPlacedPaths.add(ideRelPath);\n\n // Track canonical key for lockfile integrity\n const canonicalKey = `ide/${ideEntry.ideKey}/${ideEntry.fileName}`;\n const ipf = getOrCreatePlacedFiles(placedFiles, ideEntry.profileName);\n if (!ipf[canonicalKey]) {\n ipf[canonicalKey] = { content, type: \"ide\" };\n }\n } catch (error) {\n spinner.message(`Error placing IDE config ${ideEntry.fileName}: ${error}`);\n stats.errors++;\n }\n }\n }\n\n spinner.stop(\n dryRun\n ? `Would place files for ${adapters.length} agent(s)`\n : `Placed ${stats.created} file(s) for ${adapters.length} agent(s)`,\n );\n\n // Step 8: Update .gitignore\n if (!dryRun) {\n await handleGitignoreUpdate({\n projectManifest,\n fileMap,\n projectRoot,\n spinner,\n });\n }\n\n // Step 9: Write lockfile (canonical keys, tool-agnostic)\n if (!dryRun) {\n await writeLockData({ allProfiles, sourceShas, placedFiles, projectRoot, spinner });\n }\n\n // Step 9b: Write local state (tool-specific disk paths, never committed)\n if (!dryRun) {\n await writeStateData({\n actualPlacedPaths,\n syncedAiTools,\n projectRoot,\n spinner,\n });\n }\n\n // Step 10: Remove orphaned files (comparing tool-specific disk paths)\n await cleanupOrphanedFiles({\n previousPaths,\n currentPaths: actualPlacedPaths,\n projectRoot,\n dryRun,\n autoYes,\n spinner,\n });\n\n // Summary\n if (dryRun) {\n const parts: string[] = [];\n if (syncAi) {\n parts.push(` • ${mergedSkills.length} skills`);\n parts.push(` • ${mergedRules.length} rules`);\n parts.push(` • ${mergedAgents.length} agents`);\n parts.push(` • ${mergedMemory.length} memory files`);\n parts.push(` • ${mergedCommandCount} commands`);\n }\n if (syncFiles) {\n parts.push(` • ${mergedFileCount} files`);\n }\n if (syncIde) {\n // Show filtered count when intersection is active\n const filteredIdeCount =\n syncedIdePlatforms !== null\n ? [...ideMap.values()].filter((e) => syncedIdePlatforms.includes(e.ideKey)).length\n : mergedIdeCount;\n parts.push(` • ${filteredIdeCount} IDE configs`);\n }\n const categoryLabel = category ? ` (category: ${category})` : \"\";\n p.outro(\n `[Dry Run${categoryLabel}] Would sync:\\n${parts.join(\"\\n\")}\\n\\nFor ${adapters.length} agent(s): ${syncedAiTools.join(\", \")}`,\n );\n } else {\n const categoryLabel = category ? ` (category: ${category})` : \"\";\n p.outro(`✅ Sync complete${categoryLabel}! Configurations updated.`);\n }\n\n process.exit(stats.errors > 0 ? 1 : 0);\n } catch (error) {\n p.cancel(`Sync failed: ${error}`);\n process.exit(1);\n }\n },\n});\n","import * as p from \"@clack/prompts\";\nimport { defineCommand } from \"citty\";\nimport { syncCommand } from \"./sync.js\";\n\nexport const updateCommand = defineCommand({\n meta: {\n name: \"update\",\n description: \"(deprecated) Use 'baton sync' instead\",\n },\n args: {\n \"dry-run\": {\n type: \"boolean\",\n description: \"Show what would be done without writing files\",\n default: false,\n },\n category: {\n type: \"string\",\n description: \"Sync only a specific category: ai, files, or ide\",\n required: false,\n },\n yes: {\n type: \"boolean\",\n description: \"Run non-interactively (no prompts)\",\n default: false,\n },\n verbose: {\n type: \"boolean\",\n alias: \"v\",\n description: \"Show detailed output for each placed file\",\n default: false,\n },\n },\n async run(context) {\n p.log.warn(\"`baton update` is deprecated. Use `baton sync` instead.\");\n p.log.info(\"\");\n // Delegate to sync — pass full context through\n if (syncCommand.run) {\n await syncCommand.run(context);\n }\n },\n});\n","import { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { defineCommand, runMain } from \"citty\";\nimport { aiToolsCommand } from \"./commands/ai-tools/index.js\";\nimport { applyCommand } from \"./commands/apply.js\";\nimport { configCommand } from \"./commands/config/index.js\";\nimport { diffCommand } from \"./commands/diff.js\";\nimport { idesCommand } from \"./commands/ides/index.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { manageCommand } from \"./commands/manage.js\";\nimport { profileCommand } from \"./commands/profile/index.js\";\nimport { selfUpdateCommand } from \"./commands/self-update.js\";\nimport { sourceCommand } from \"./commands/source/index.js\";\nimport { syncCommand } from \"./commands/sync.js\";\nimport { updateCommand } from \"./commands/update.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nlet packageJson: { version?: string } = {};\ntry {\n packageJson = JSON.parse(await readFile(join(__dirname, \"../package.json\"), \"utf-8\"));\n} catch {\n // Gracefully handle missing or malformed package.json\n}\n\nconst main = defineCommand({\n meta: {\n name: \"baton\",\n version: packageJson.version,\n description:\n \"The package manager for Developer Experience & AI configuration. Manages Skills, Rules, Agents, Memory Files as versioned profiles.\",\n },\n args: {\n version: {\n type: \"boolean\",\n alias: \"v\",\n description: \"Show version number\",\n },\n yes: {\n type: \"boolean\",\n alias: \"y\",\n description: \"Suppress all interactive prompts (non-interactive mode)\",\n },\n \"dry-run\": {\n type: \"boolean\",\n description: \"Show what would be done without writing any files\",\n },\n verbose: {\n type: \"boolean\",\n description: \"Enable debug logging\",\n },\n },\n subCommands: {\n init: initCommand,\n apply: applyCommand,\n sync: syncCommand,\n update: updateCommand,\n diff: diffCommand,\n manage: manageCommand,\n config: configCommand,\n source: sourceCommand,\n profile: profileCommand,\n \"ai-tools\": aiToolsCommand,\n ides: idesCommand,\n \"self-update\": selfUpdateCommand,\n },\n run({ args }) {\n // Show help when no arguments provided\n if (Object.keys(args).length === 0) {\n console.log(`baton v${packageJson.version}`);\n console.log(\"\");\n console.log(\"The package manager for Developer Experience & AI configuration.\");\n console.log(\"\");\n console.log(\"Usage:\");\n console.log(\" baton <command> [options]\");\n console.log(\"\");\n console.log(\"Available commands:\");\n console.log(\" init Initialize Baton in your project\");\n console.log(\" apply Apply locked configurations (deterministic, reproducible)\");\n console.log(\" sync Fetch latest versions, sync, and update lockfile\");\n console.log(\" update (deprecated) Use 'baton sync' instead\");\n console.log(\" diff Compare local files with remote source versions\");\n console.log(\" manage Interactive project management wizard\");\n console.log(\" config Show dashboard overview or configure settings\");\n console.log(\"\");\n console.log(\"Resource commands:\");\n console.log(\" source Manage source repositories (create, list, connect, disconnect)\");\n console.log(\" profile Manage profiles (create, list, remove)\");\n console.log(\" ai-tools Manage AI tool detection and configuration\");\n console.log(\" ides Manage IDE platform detection and configuration\");\n console.log(\"\");\n console.log(\"Maintenance:\");\n console.log(\" self-update Update Baton to the latest stable version\");\n console.log(\"\");\n console.log(\"Global Options:\");\n console.log(\" --help, -h Show this help message\");\n console.log(\" --version, -v Show version number\");\n console.log(\" --yes, -y Suppress all interactive prompts\");\n console.log(\" --dry-run Show what would be done without writing files\");\n console.log(\" --verbose Enable debug logging\");\n return;\n }\n },\n});\n\nrunMain(main);\n"],"mappings":"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"}